Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parametric page name and other changes (v2) #102

Merged
merged 23 commits into from
Nov 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
fec857f
fix: Always use id of main page
micgro42 Apr 11, 2017
b8304a8
more flexibility
splitbrain May 29, 2017
19faa28
updated version
splitbrain May 29, 2017
8640cd5
fix script to work on multiple forms again
splitbrain May 30, 2017
cf018a6
removed unneeded options assignment
splitbrain May 30, 2017
88aaa9d
use input event instead of keyup
splitbrain May 30, 2017
7a61600
Merge commit 'c695c89c6220d13ad232a15a3eaf22575649997a' into pr72
dregad May 7, 2023
dc53fa0
Merge commit '5cc7d7358990f860049caa54fce63c5d6f7dd72e' into pr72
dregad May 7, 2023
114e382
Merge commit 'e5d3a18fa9f38378ed9f6b149ee11935d488b887' into pr72
dregad May 7, 2023
0d90564
Add param "newpagevars" for plugin newpagetemplate
dregad May 7, 2023
aee0299
Merge commit '9418ebb801290cfb39b21fcf66b7ff91b61c4bba' into pr72
dregad May 7, 2023
22d9c07
Merge commit 'ed55cb4cce2354808a9d00f643c92c5c9c972933' into pr72
dregad May 7, 2023
0462eda
Merge commit 'ccc8b5fd84846cd712c23144ff33056471b5091c' into pr72
dregad May 7, 2023
f365882
Merge commit '7c0b9c8b0af497b353360b88a9fc849d39a54648' into pr72
dregad May 7, 2023
4fb3ed5
Merge commit '99f48d0389c2600fdcc50239a61bffd1aecc2861' into pr72
dregad May 10, 2023
96b5821
Fix incorrect merge resolution
dregad May 27, 2023
0aa2c11
Fix static analysis warnings
dregad May 27, 2023
31967e0
Fix Array to string conversion warning
dregad Sep 24, 2023
d49ba5b
Skip leading # in newpagevars parameter
dregad Sep 24, 2023
641f048
French translation for autopage config
dregad Sep 24, 2023
d2f6521
PHPDoc
dregad Sep 24, 2023
71d2f1b
Merge branch 'master' into pr72
dregad Sep 14, 2024
6666849
Fix PHP notice
dregad Nov 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions conf/default.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@
$conf['addpage_showroot'] = 1;
$conf['addpage_hide'] = 1;
$conf['addpage_hideACL'] = 0;
$conf['addpage_autopage'] = 0;

1 change: 1 addition & 0 deletions conf/metadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
$meta['addpage_showroot'] = array('onoff');
$meta['addpage_hide'] = array('onoff');
$meta['addpage_hideACL'] = array('onoff');
$meta['addpage_autopage'] = array('onoff');
1 change: 1 addition & 0 deletions lang/en/settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@
$lang['addpage_showroot'] = "Show root namespace";
$lang['addpage_hide'] = "When you use {{NEWPAGE>[ns]}} syntax: Hide namespace selection (unchecked: show only subnamespaces)";
$lang['addpage_hideACL'] = "Hide {{NEWPAGE}} if user does not have rights to add pages (show message if unchecked)";
$lang['addpage_autopage'] = "Don't show the input box, the preconfigured namespace is treated as a full page ID. (makes sense with date placeholders)";
1 change: 1 addition & 0 deletions lang/fr/settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@
$lang['addpage_showroot'] = "Afficher le namespace racine";
$lang['addpage_hide'] = "Quand vous utlisez la syntaxe {{NEWPAGE>[ns]}} : Cache la selection de namespace (décoché: affiche uniquement les sous-namespaces)";
$lang['addpage_hideACL'] = "Si non cochée, affiche un message lorsque l'utlisateur n'a pas les droits d'ajout de page. Sinon, cache simplement {{NEWPAGE}}";
$lang['addpage_autopage'] = "Ne pas afficher le champ de saisie; le namespace préconfiguré est traité comme un identifiant de page complet (utile avec des attributs de date)";
51 changes: 27 additions & 24 deletions script.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,35 @@
jQuery(document).ready(function() {
jQuery(function () {
jQuery(".addnewpage form").each(function () {
var $form = jQuery(this);
var $ns = $form.find("[name='np_cat']");
var $title = $form.find("input[name='title']");
var $id = $form.find("input[name='id']");
var $submit = $form.find(':submit');

// Start with disabled submit button
jQuery(".addnewpage :submit").prop("disabled", true);
// Then enable it when a title is entered
jQuery(".addnewpage input[name='title']").keyup(function(){
var $submit = jQuery(this).parent("form").find(":submit");
if (jQuery(this).val().length > 0) {
$submit.removeAttr("disabled");
} else {
// For when the user deletes the text
$submit.attr("disabled", "disabled");
// disable submit unless something is in input or input is disabled
if ($title.attr('type') === 'text') {
$submit.attr('disabled', 'disabled');
$title.on('input', function () {
if ($title.val().length > 0) {
$submit.removeAttr('disabled');
} else {
$submit.attr('disabled', 'disabled');
}
});
}
}).keyup();

// Change the form's page-ID field on submit
jQuery(".addnewpage form").submit(function(e) {
// Change the form's page-ID field on submit
$form.submit(function () {
// Build the new page ID and save in hidden form field
var id = $ns.val().replace('@INPUT@', $title.val());
$id.val(id);

// Build the new page ID and save in hidden form field
var ns = jQuery(this).find("[name='np_cat']");
var title = jQuery(this).find("input[name='title']");
var id = ns.val()+":"+title.val();
jQuery(this).find("input[name='id']").val(id);
// Clean up the form vars, just to make the resultant URL a bit nicer
$ns.prop("disabled", true);
$title.prop("disabled", true);

// Clean up the form vars, just to make the resultant URL a bit nicer
ns.prop("disabled", true);
title.prop("disabled", true);
return true;
});

return true;
});

});
172 changes: 131 additions & 41 deletions syntax.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@

class syntax_plugin_addnewpage extends SyntaxPlugin {

/** @var array the parsed options */
protected $options;

/**
* Syntax Type
*/
Expand Down Expand Up @@ -47,37 +50,63 @@ public function connectTo($mode) {
}

/**
* Handler to prepare matched data for the rendering process
* Handler to prepare matched data for the rendering process.
*
* Handled syntax options:
* {{NEWPAGE}}
* {{NEWPAGE>your:namespace}}
* {{NEWPAGE#newtpl1,newtpl2}}
* {{NEWPAGE#newtpl1|Title1,newtpl2|Title1}}
* {{NEWPAGE>your:namespace#newtpl1|Title1,newtpl2|Title1}}
* {{NEWPAGE>your:namespace#newtpl1|Title1,newtpl2|Title1#@HI@,Howdy}}
* - {{NEWPAGE}}
* - {{NEWPAGE>your:namespace}}
* - {{NEWPAGE>your:namespace:@INPUT@:start}}
* - {{NEWPAGE>your:namespace:[date formats]}} {@see strftime()}
* - {{NEWPAGE?config_overrides}}
* - {{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 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 */
$options = substr($match, 9, -2); // strip markup
$options = explode('#', $options, 3);

$namespace = trim(ltrim($options[0], '>'));
$templates = explode(',', $options[1] ?? '');
$templates = array_map('trim', $templates);
$newpagevars = trim($options[2] ?? '');
return array(
'namespace' => $namespace,
'newpagetemplates' => $templates,
'newpagevars' => $newpagevars
$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'),
)
);

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;
}

/**
Expand All @@ -91,11 +120,14 @@ public function handle($match, $state, $pos, Doku_Handler $handler) {
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->getConf('addpage_hideACL')) {
if($this->options['hideacl']) {
$renderer->doc .= '';
} else {
$renderer->doc .= $this->getLang('nooption');
Expand All @@ -106,11 +138,14 @@ public function render($format, Doku_Renderer $renderer, $data) {

$newpagetemplateinput = $this->_htmlTemplateInput($data['newpagetemplates']);

$input = 'text';
if($this->options['autopage']) $input = 'hidden';

$form = '<div class="addnewpage"><p>'
. '<form name="addnewpage" method="get" action="' . DOKU_BASE . DOKU_SCRIPT
. '" accept-charset="' . $lang['encoding'] . '">'
. $namespaceinput
. '<input class="edit" type="text" name="title" size="20" maxlength="255" tabindex="2" placeholder="'
. '<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'] . '"/>'
Expand All @@ -127,22 +162,77 @@ public function render($format, Doku_Renderer $renderer, $data) {
return false;
}

/**
* Overwrites the $options with the ones parsed from $optstr
*
* @param string $optstr
* @param array $options
* @author Andreas Gohr <[email protected]>
*/
protected function _parseOptions($optstr, &$options) {
$opts = preg_split('/[,&]/', $optstr);

foreach($opts as $opt) {
$opt = strtolower(trim($opt));
$val = true;
// booleans can be negated with a no prefix
if(substr($opt, 0, 2) == 'no') {
$opt = substr($opt, 2);
$val = false;
}

// not a known option? might be a key=value pair
if(!isset($options[$opt])) {
list($opt, $val) = array_map('trim', sexplode('=', $opt, 2));
}

// still unknown? skip it
if(!isset($options[$opt])) continue;

// overwrite the current value
$options[$opt] = $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 <[email protected]>
* @author Michael Braun <[email protected]>
* @author Andreas Gohr <[email protected]>
* @param string $ns The namespace as given in the syntax
* @return string
*/
protected function _parseNS($ns) {
$ID=getID();
if(strpos($ns, '@PAGE@') !== false) {
return cleanID(str_replace('@PAGE@', $ID, $ns));
}
if($ns == "@NS@") return getNS($ID);
$ns = preg_replace("/^\.(:|$)/", dirname(str_replace(':', '/', $ID)) . "$1", $ns);
$ns = str_replace("/", ":", $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);

return cleanID($ns);
// clean up, then reinsert the input variable
$ns = cleanID($ns);
return str_replace($keep, '@INPUT@', $ns);
}

/**
Expand All @@ -159,7 +249,7 @@ protected function _htmlNamespaceInput($dest_ns, &$disablecache) {

// If a NS has been provided:
// Whether to hide the NS selection (otherwise, show only subnamespaces).
$hide = $this->getConf('addpage_hide');
$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
Expand All @@ -184,7 +274,7 @@ protected function _htmlNamespaceInput($dest_ns, &$disablecache) {
$someopt = false;

// Show root namespace if requested and allowed
if($this->getConf('addpage_showroot') && $can_create) {
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>';
Expand Down Expand Up @@ -213,14 +303,14 @@ protected function _htmlNamespaceInput($dest_ns, &$disablecache) {
}

$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++) {
$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('&nbsp;&nbsp;', substr_count($namespace, ':')) . $nsparts[$i - 1];
$ret .= '<option ' .
(($currentns == $namespace) ? 'selected ' : '') .
($i == $end? ('value="' . $namespace . '">') : 'disabled>') .
($i == $end ? ('value="' . $namespace . '">') : 'disabled>') .
$selectOptionText .
'</option>';
}
Expand Down Expand Up @@ -249,7 +339,7 @@ protected function _getNamespaceList($topns = '') {

$topns = utf8_encodeFN(str_replace(':', '/', $topns));

$excludes = $this->getConf('addpage_exclude');
$excludes = $this->options['exclude'];
if($excludes == "") {
$excludes = array();
} else {
Expand All @@ -261,7 +351,7 @@ protected function _getNamespaceList($topns = '') {
$namespaces = array();
foreach($searchdata as $ns) {
foreach($excludes as $exclude) {
if( ! empty($exclude) && strpos($ns['id'], $exclude) === 0) {
if(!empty($exclude) && strpos($ns['id'], $exclude) === 0) {
continue 2;
}
}
Expand All @@ -284,7 +374,7 @@ public function _htmlTemplateInput($newpagetemplates) {

} else {
if($cnt == 1) {
list($template, ) = $this->_parseNSTemplatePage($newpagetemplates[0]);
list($template,) = $this->_parseNSTemplatePage($newpagetemplates[0]);
$input = '<input type="hidden" name="newpagetemplate" value="' . formText($template) . '" />';
} else {
$first = true;
Expand All @@ -294,8 +384,8 @@ public function _htmlTemplateInput($newpagetemplates) {
$first = false;

list($template, $name) = $this->_parseNSTemplatePage($template);
$p .= ' value="'.formText($template).'"';
$input .= "<option $p>".formText($name)."</option>";
$p .= ' value="' . formText($template) . '"';
$input .= "<option $p>" . formText($name) . "</option>";
}
$input .= '</select>';
}
Expand Down