はじまりの大地

This commit is contained in:
miteruzo
2024-07-08 03:32:47 +09:00
commit c616a96f53
7749 changed files with 478270 additions and 0 deletions
+136
View File
@@ -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;
}
}
@@ -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:
@@ -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;
}
}
@@ -0,0 +1,464 @@
<?php
use dokuwiki\File\PageResolver;
/**
* 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;
}
}
$resolver = new PageResolver(getNS($ID));
$this->pagename = $resolver->resolveId($this->replace($this->pagename));
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')) ) {
$resolver = new PageResolver($ns);
//template
$templatepage = $this->replace($field->getParam('page_tpl'));
$templatepage = $resolver->resolveId($templatepage);
//target
$relativetargetpage = $resolver->resolveId($field->getParam('page_tgt'));
$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)
$resolver = new PageResolver(getNS($ID));
if(substr($tpl, -1) == ':') {
$tpl = $tpl.'xxx'; // append a fake page name
$tpl = $resolver->resolveId($tpl);
$tpl = substr($tpl, 0, -3); // cut off fake page name again
} else {
$tpl = $resolver->resolveId($tpl);
}
$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,
'type' => null,
);
$data[] = $last_folder[$n];
}
}
$data[] = array('id' => $ID, 'level' => 1 + substr_count($ID, ':'), 'type' => 'f');
}
$index = new dokuwiki\Ui\Index();
$html .= html_buildlist($data, 'idx', array($this, 'html_list_index'), array($index, 'tagListItem'));
// 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:
+508
View File
@@ -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;
}
}
@@ -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);
}
}
@@ -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'))));
}
}
}
@@ -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'))));
}
}
}
@@ -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);
}
}
}
@@ -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'] . ')' );
}
}
}
@@ -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];
}
}
@@ -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') . '');
}
}
@@ -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
)));
}
}
@@ -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;
}
}
@@ -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)
*/
}
@@ -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';
}
}
}
@@ -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));
}
}
}
@@ -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
)));
}
}
@@ -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);
}
}
@@ -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;
}
}
@@ -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);
}
}
@@ -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>';
}
@@ -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';
}
}
}
@@ -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'))));
}
}
}
@@ -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);
}
}
@@ -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'))));
}
}
}
@@ -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'))));
}
}
}
}
@@ -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>';
}
}
@@ -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);
}
}