Adding upstream version 20241201.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
5f5109ce41
commit
f8d74cc725
216 changed files with 7490 additions and 0 deletions
423
plugins/55/addnewpage/syntax.php
Normal file
423
plugins/55/addnewpage/syntax.php
Normal file
|
@ -0,0 +1,423 @@
|
|||
<?php
|
||||
/**
|
||||
* Add-New-Page Plugin: a simple form for adding new pages.
|
||||
*
|
||||
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
|
||||
* @author iDO <ido@idotech.info>
|
||||
* @author Sam Wilson <sam@samwilson.id.au>
|
||||
*
|
||||
* @noinspection PhpUnused
|
||||
* @noinspection PhpMissingParamTypeInspection, PhpMissingReturnTypeInspection
|
||||
*/
|
||||
|
||||
use dokuwiki\Extension\SyntaxPlugin;
|
||||
use dokuwiki\File\PageResolver;
|
||||
|
||||
// must be run within Dokuwiki
|
||||
if(!defined('DOKU_INC')) die();
|
||||
|
||||
class syntax_plugin_addnewpage extends SyntaxPlugin {
|
||||
|
||||
/** @var array the parsed options */
|
||||
protected $options;
|
||||
|
||||
/**
|
||||
* Syntax Type
|
||||
*/
|
||||
public function getType() {
|
||||
return 'substition';
|
||||
}
|
||||
|
||||
/**
|
||||
* Paragraph Type
|
||||
*/
|
||||
public function getPType() {
|
||||
return 'block';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getSort() {
|
||||
return 199;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $mode
|
||||
*/
|
||||
public function connectTo($mode) {
|
||||
$this->Lexer->addSpecialPattern('\{\{NEWPAGE[^\}]*\}\}', $mode, 'plugin_addnewpage');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler to prepare matched data for the rendering process.
|
||||
*
|
||||
* Handled syntax options:
|
||||
* - {{NEWPAGE}}
|
||||
* - {{NEWPAGE>your:namespace}}
|
||||
* - {{NEWPAGE>your:namespace:@INPUT@:start}}
|
||||
* - {{NEWPAGE>your:namespace:[date formats]}} {@see strftime()}
|
||||
* - {{NEWPAGE?config_overrides}}
|
||||
* - {{NEWPAGE?label=custom}}
|
||||
* - {{NEWPAGE#newtpl1,newtpl2}}
|
||||
* - {{NEWPAGE#newtpl1|Title1,newtpl2|Title1}}
|
||||
* - {{NEWPAGE>your:namespace#newtpl1|Title1,newtpl2|Title1}}
|
||||
* - {{NEWPAGE>your:namespace#newtpl1|Title1,newtpl2|Title1#@HI@,Howdy}}
|
||||
*
|
||||
* Refer to {@see https://www.dokuwiki.org/plugin:addnewpage} for details.
|
||||
*
|
||||
* @param string $match The text matched by the patterns
|
||||
* @param int $state The lexer state for the match
|
||||
* @param int $pos The character position of the matched text
|
||||
* @param Doku_Handler $handler The Doku_Handler object
|
||||
*
|
||||
* @return array Return an array with all data you want to use in render
|
||||
* @codingStandardsIgnoreStart
|
||||
*/
|
||||
public function handle($match, $state, $pos, Doku_Handler $handler) {
|
||||
/* @codingStandardsIgnoreEnd */
|
||||
$match = substr($match, 9, -2); // strip markup
|
||||
|
||||
$data = array(
|
||||
'namespace' => '',
|
||||
'newpagetemplates' => array(),
|
||||
'newpagevars' => '',
|
||||
'options' => array(
|
||||
'exclude' => $this->getConf('addpage_exclude'),
|
||||
'showroot' => $this->getConf('addpage_showroot'),
|
||||
'hide' => $this->getConf('addpage_hide'),
|
||||
'hideacl' => $this->getConf('addpage_hideACL'),
|
||||
'autopage' => $this->getConf('addpage_autopage'),
|
||||
'label' => 'okbutton',
|
||||
)
|
||||
);
|
||||
|
||||
if(preg_match('/>(.*?)(#|\?|$)/', $match, $m)) {
|
||||
$data['namespace'] = trim($m[1]);
|
||||
}
|
||||
|
||||
# Extract the newpagetemplate plugin parameters
|
||||
# - after the initial #: the template name
|
||||
# - after optional 2nd #: custom variable names
|
||||
if(preg_match('/#(.*?)(?:#(.*?))?(?:\?|$)/', $match, $m)) {
|
||||
$data['newpagetemplates'] = array_map('trim', explode(',', $m[1]));
|
||||
$data['newpagevars'] = trim($m[2] ?? '');
|
||||
}
|
||||
|
||||
if(preg_match('/\?(.*?)(#|$)/', $match, $m)) {
|
||||
$this->_parseOptions($m[1], $data['options']);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the new-page form.
|
||||
*
|
||||
* @param $format string output format being rendered
|
||||
* @param $renderer Doku_Renderer the current renderer object
|
||||
* @param $data array data created by handler()
|
||||
* @return boolean rendered correctly?
|
||||
*/
|
||||
public function render($format, Doku_Renderer $renderer, $data) {
|
||||
global $lang;
|
||||
|
||||
// make options available in class
|
||||
$this->options = $data['options'];
|
||||
|
||||
if($format == 'xhtml') {
|
||||
$disablecache = false;
|
||||
$namespaceinput = $this->_htmlNamespaceInput($data['namespace'], $disablecache);
|
||||
if($namespaceinput === false) {
|
||||
if($this->options['hideacl']) {
|
||||
$renderer->doc .= '';
|
||||
} else {
|
||||
$renderer->doc .= $this->getLang('nooption');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if($disablecache) $renderer->info['cache'] = false;
|
||||
|
||||
$newpagetemplateinput = $this->_htmlTemplateInput($data['newpagetemplates']);
|
||||
|
||||
$input = 'text';
|
||||
if($this->options['autopage']) $input = 'hidden';
|
||||
|
||||
// Button label. If given string is not localized, use it as-is
|
||||
$label = $this->getLang($this->options['label']);
|
||||
if (!$label) {
|
||||
$label = $this->options['label'];
|
||||
}
|
||||
|
||||
$form = '<div class="addnewpage"><p>'
|
||||
. '<form name="addnewpage" method="get" action="' . DOKU_BASE . DOKU_SCRIPT
|
||||
. '" accept-charset="' . $lang['encoding'] . '">'
|
||||
. $namespaceinput
|
||||
. '<input class="edit" type="' . $input . '" name="title" size="20" maxlength="255" tabindex="2" placeholder="'
|
||||
. $this->getLang('name') . '"/>'
|
||||
. $newpagetemplateinput
|
||||
. '<input type="hidden" name="newpagevars" value="' . $data['newpagevars'] . '"/>'
|
||||
. '<input type="hidden" name="do" value="edit" />'
|
||||
. '<input type="hidden" name="id" />'
|
||||
. '<input class="button" type="submit" value="' . $label . '" tabindex="4" />'
|
||||
. '</form>'
|
||||
. '</p></div>';
|
||||
|
||||
$renderer->doc .= $form;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrites the $options with the ones parsed from $optstr
|
||||
*
|
||||
* @param string $optstr
|
||||
* @param array $options
|
||||
* @author Andreas Gohr <gohr@cosmocode.de>
|
||||
*/
|
||||
protected function _parseOptions($optstr, &$options) {
|
||||
$opts = preg_split('/[,&]/', $optstr);
|
||||
|
||||
foreach($opts as $opt) {
|
||||
$opt_lower = strtolower(trim($opt));
|
||||
$val = true;
|
||||
// booleans can be negated with a no prefix
|
||||
if(substr($opt_lower, 0, 2) == 'no') {
|
||||
$opt_lower = substr($opt, 2);
|
||||
$val = false;
|
||||
}
|
||||
|
||||
// not a known option? might be a key=value pair
|
||||
if(!isset($options[$opt_lower])) {
|
||||
$split = array_map('trim', sexplode('=', $opt, 2));
|
||||
$opt_lower = strtolower($split[0]);
|
||||
$val = $split[1];
|
||||
}
|
||||
|
||||
// still unknown? skip it
|
||||
if(!isset($options[$opt_lower])) continue;
|
||||
|
||||
// overwrite the current value
|
||||
$options[$opt_lower] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse namespace request
|
||||
*
|
||||
* This creates the final ID to be created (still having an @INPUT@ variable
|
||||
* which is filled in via JavaScript)
|
||||
*
|
||||
* @author Samuele Tognini <samuele@cli.di.unipi.it>
|
||||
* @author Michael Braun <michael-dev@fami-braun.de>
|
||||
* @author Andreas Gohr <gohr@cosmocode.de>
|
||||
* @param string $ns The namespace as given in the syntax
|
||||
* @return string
|
||||
*/
|
||||
protected function _parseNS($ns) {
|
||||
global $INFO;
|
||||
|
||||
$selfid = $INFO['id'];
|
||||
$selfns = getNS($selfid);
|
||||
// replace the input variable with something unique that survives cleanID
|
||||
$keep = sha1(time());
|
||||
|
||||
// by default append the input to the namespace (except on autopage)
|
||||
if(strpos($ns, '@INPUT@') === false && !$this->options['autopage']) $ns .= ":@INPUT@";
|
||||
|
||||
// date replacements
|
||||
$ns = dformat(null, $ns);
|
||||
|
||||
// placeholders
|
||||
$replacements = array(
|
||||
'/\//' => ':', // forward slashes to colons
|
||||
'/@PAGE@/' => $selfid,
|
||||
'/@NS@/' => $selfns,
|
||||
'/^\.(:|\/|$)/' => "$selfns:",
|
||||
'/@INPUT@/' => $keep,
|
||||
);
|
||||
$ns = preg_replace(array_keys($replacements), array_values($replacements), $ns);
|
||||
|
||||
// clean up, then reinsert the input variable
|
||||
$ns = cleanID($ns);
|
||||
return str_replace($keep, '@INPUT@', $ns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the HTML Select element for namespace selection.
|
||||
*
|
||||
* @param string|false $dest_ns The destination namespace, or false if none provided.
|
||||
* @param bool $disablecache reference indicates if caching need to be disabled
|
||||
* @global string $ID The page ID
|
||||
* @return string Select element with appropriate NS selected.
|
||||
*/
|
||||
protected function _htmlNamespaceInput($dest_ns, &$disablecache) {
|
||||
global $ID;
|
||||
$disablecache = false;
|
||||
|
||||
// If a NS has been provided:
|
||||
// Whether to hide the NS selection (otherwise, show only subnamespaces).
|
||||
$hide = $this->options['hide'];
|
||||
|
||||
$parsed_dest_ns = $this->_parseNS($dest_ns);
|
||||
// Whether the user can create pages in the provided NS (or root, if no
|
||||
// destination NS has been set.
|
||||
$can_create = (auth_quickaclcheck($parsed_dest_ns . ":") >= AUTH_CREATE);
|
||||
|
||||
//namespace given, but hidden
|
||||
if($hide && !empty($dest_ns)) {
|
||||
if($can_create) {
|
||||
return '<input type="hidden" name="np_cat" id="np_cat" value="' . $parsed_dest_ns . '"/>';
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//show select of given namespace
|
||||
$currentns = getNS($ID);
|
||||
|
||||
$ret = '<select class="edit" id="np_cat" name="np_cat" tabindex="1">';
|
||||
|
||||
// Whether the NS select element has any options
|
||||
$someopt = false;
|
||||
|
||||
// Show root namespace if requested and allowed
|
||||
if($this->options['showroot'] && $can_create) {
|
||||
if(empty($dest_ns)) {
|
||||
// If no namespace has been provided, add an option for the root NS.
|
||||
$ret .= '<option ' . (($currentns == '') ? 'selected ' : '') . ' value="">' . $this->getLang('namespaceRoot') . '</option>';
|
||||
} else {
|
||||
// If a namespace has been provided, add an option for it.
|
||||
$ret .= '<option ' . (($currentns == $dest_ns) ? 'selected ' : '') . ' value="' . formText($dest_ns) . '">' . formText($dest_ns) . '</option>';
|
||||
}
|
||||
$someopt = true;
|
||||
}
|
||||
|
||||
$subnamespaces = $this->_getNamespaceList($dest_ns);
|
||||
|
||||
// The top of this stack will always be the last printed ancestor namespace
|
||||
$ancestor_stack = array();
|
||||
if (!empty($dest_ns)) {
|
||||
$ancestor_stack[] = $dest_ns;
|
||||
}
|
||||
|
||||
foreach($subnamespaces as $ns) {
|
||||
|
||||
if(auth_quickaclcheck($ns . ":") < AUTH_CREATE) continue;
|
||||
|
||||
// Pop any elements off the stack that are not ancestors of the current namespace
|
||||
while(!empty($ancestor_stack) && strpos($ns, $ancestor_stack[count($ancestor_stack) - 1] . ':') !== 0) {
|
||||
array_pop($ancestor_stack);
|
||||
}
|
||||
|
||||
$nsparts = explode(':', $ns);
|
||||
$first_unprinted_depth = empty($ancestor_stack) ? 1 : (2 + substr_count($ancestor_stack[count($ancestor_stack) - 1], ':'));
|
||||
for($i = $first_unprinted_depth, $end = count($nsparts); $i <= $end; $i++) {
|
||||
$namespace = implode(':', array_slice($nsparts, 0, $i));
|
||||
$ancestor_stack[] = $namespace;
|
||||
$selectOptionText = str_repeat(' ', substr_count($namespace, ':')) . $nsparts[$i - 1];
|
||||
$ret .= '<option ' .
|
||||
(($currentns == $namespace) ? 'selected ' : '') .
|
||||
($i == $end ? ('value="' . $namespace . '">') : 'disabled>') .
|
||||
$selectOptionText .
|
||||
'</option>';
|
||||
}
|
||||
$someopt = true;
|
||||
$disablecache = true;
|
||||
}
|
||||
|
||||
$ret .= '</select>';
|
||||
|
||||
if($someopt) {
|
||||
return $ret;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of namespaces below the given namespace.
|
||||
* Recursively fetches subnamespaces.
|
||||
*
|
||||
* @param string $topns The top namespace
|
||||
* @return array Multi-dimensional array of all namespaces below $tns
|
||||
*/
|
||||
protected function _getNamespaceList($topns = '') {
|
||||
global $conf;
|
||||
|
||||
$topns = utf8_encodeFN(str_replace(':', '/', $topns));
|
||||
|
||||
$excludes = $this->options['exclude'];
|
||||
if($excludes == "") {
|
||||
$excludes = array();
|
||||
} else {
|
||||
$excludes = @explode(';', strtolower($excludes));
|
||||
}
|
||||
$searchdata = array();
|
||||
search($searchdata, $conf['datadir'], 'search_namespaces', array(), $topns);
|
||||
|
||||
$namespaces = array();
|
||||
foreach($searchdata as $ns) {
|
||||
foreach($excludes as $exclude) {
|
||||
if(!empty($exclude) && strpos($ns['id'], $exclude) === 0) {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
$namespaces[] = $ns['id'];
|
||||
}
|
||||
|
||||
return $namespaces;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create html for selection of namespace templates
|
||||
*
|
||||
* @param array $newpagetemplates array of namespace templates
|
||||
* @return string html of select or hidden input
|
||||
*/
|
||||
public function _htmlTemplateInput($newpagetemplates) {
|
||||
$cnt = count($newpagetemplates);
|
||||
if($cnt < 1 || $cnt == 1 && $newpagetemplates[0] == '') {
|
||||
$input = '';
|
||||
|
||||
} else {
|
||||
if($cnt == 1) {
|
||||
list($template,) = $this->_parseNSTemplatePage($newpagetemplates[0]);
|
||||
$input = '<input type="hidden" name="newpagetemplate" value="' . formText($template) . '" />';
|
||||
} else {
|
||||
$first = true;
|
||||
$input = '<select name="newpagetemplate" tabindex="3">';
|
||||
foreach($newpagetemplates as $template) {
|
||||
$p = ($first ? ' selected="selected"' : '');
|
||||
$first = false;
|
||||
|
||||
list($template, $name) = $this->_parseNSTemplatePage($template);
|
||||
$p .= ' value="' . formText($template) . '"';
|
||||
$input .= "<option $p>" . formText($name) . "</option>";
|
||||
}
|
||||
$input .= '</select>';
|
||||
}
|
||||
$input = DOKU_TAB . DOKU_TAB . $input . DOKU_LF;
|
||||
}
|
||||
return $input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses and resolves the namespace template page
|
||||
*
|
||||
* @param $nstemplate
|
||||
* @return array
|
||||
*/
|
||||
protected function _parseNSTemplatePage($nstemplate) {
|
||||
global $ID;
|
||||
|
||||
@list($template, $name) = explode('|', $nstemplate, 2);
|
||||
$template = (new PageResolver($ID))->resolveId($template);
|
||||
if (is_null($name)) $name = $template;
|
||||
|
||||
return array($template, $name);
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue