======= Doodle Plugin ====== ---- plugin ---- description: Helps to schedule meetings or making other decisions in a team. (previous authors: Esther Brunner, Jonathan Tsai) author : François Merciol email : dokuplugin@merciol.fr type : syntax lastupdate : 2021-03-21 compatible : 2012-01-25 "Angua", 2012-10-13 "Adora Belle", 2013-03-06 "Weatherwax", 2016-06-26 "Elenor of Tsort", "Frusterick Manners", "Greebo", Hogfather depends : conflicts : similar : tags : poll, tables, form, calendar, calculation, todo, doodle downloadurl: https://admin.parlenet.org/files/plugins/doodle.tgz ---- The idea is stolen from [[http://www.doodle.ch|Doodle]] by [[naef@acm.org|Michael Näf]]. ^ Download | https://admin.parlenet.org/files/plugins/doodle.tgz | ===== Syntax ===== This plugin can help your team to schedule meetings or making other decisions in a team. The syntax looks like this: ^ [choice] ^ [choice] ^ ... ^ That means, you can simply put ''%%%%'' tags around regular table header to get a check box table with different choices. ^ [id] | the ID of the doodle; must be unique((If it is not, metadata of the doodles with the same id gets mixed up, i.e. answers to choices in a previous doodle appear in the new when the choices are the same.)); appears as title | required | ^ [choice] | an option for which users can tick a checkbox whether it's okay for them or not | required | You may also add more optional parameters... ^ [choice] ^ [choice] ^ ... ^ ^ [disable]| view the result(cannot vote) | ^ [single] | only can check one choice | ^ [login] | voter must login first & use fullname to be voter name | You can see this plugin in action [[http://www.ichiayi.com/wiki/opensource:dokuwiki:plugin:doodle:demo|here]]. ===== Release Notes ===== * 2009-02-05 : - Fix options can support special character Exp. & (Jonas noticed the bug) - Add submit datetime function over the Okay Icon * {{http://www.ichiayi.com/wiki/_media/opensource/dokuwiki/plugin/doodle_20090205.png}} * 2009-08-10 : - Fix the bug when using HTML tag as a part of fullname string, table will be broken. * {{http://www.ichiayi.com/wiki/_media/opensource/dokuwiki/plugin/doodle_20090810.png}} ===== Installation Notes ===== When the [[blog]] plugin is also installed, you need to turn ''$conf['plugin']['blog']['useifmodifiedsince']'' off. I will make sure this incompatibility is still exist or not. ===== Languages ===== The "Submit" Button needs to be translated to other languages. Currently only Catalan (ca), German (de), English (en), Spanish (es), French (fr), Hungarian (hu), Italian (it), Dutch (nl), Swedish (sv), Simplified Chinese (zh-cn), Traditional Chinese (zh-tw), Euskera (eu), Luxembourgish (lb) and Valencian (val) are available. [[tryweb@ichiayi.com|Send us]] your translation or put below! ==== English ==== ==== Esperanto ==== ==== Catalan ==== */ $lang['btn_submit'] = 'Envia'; //Setup VIM: ex: et ts=4 enc=utf-8 : ?> ==== German ==== ==== Simplified Chinese ==== ==== Traditional Chinese ==== ==== Swedish ==== ==== Danish ==== ==== Dutch ==== ==== French ==== ==== Italian ==== ==== Japanese ==== ==== Luxembourgish ==== ==== Spanish ==== ==== Hungarian ==== ==== Euskera ==== ==== Valencian ==== ==== Icelandic ==== ==== Czech ==== ===== Further Resources ===== * [[https://svn.ichiayi.com/opensvn/opentrysoft/dokuwiki/plugin/doodle/|SVN Repository]] * Click here to download the [[https://svn.ichiayi.com/opensvn/opentrysoft/dokuwiki/plugin/doodle/syntax.php|syntax.php]] file ===== Discussion ===== ==== export to csv ==== Sometimes voting results have to be further processed in other software. An option similar to disable like "export" would be helpful to export the voting. --- 2010/06/26 11:23 ==== Delete Lines ==== Hi, great job! :-) But I have a problem. How I can delete lines in an existing doodle? E.g. if somebody did a joke by writing nonsense in the name. Thanks, Christian > You can uncheck all choices of the line, it will not show on doodle. (It's not Really delete lines, but can meet your requirement) --- //[[tryweb@ichiayi.com|Jonathan Tsai]] 2008-03-03 21:55// ==== Retain scroll position ==== I just set up a questionnaire with a dozen doodles on one page. It is very unfortunate that you have to scroll up after each vote submission - a true showstopper for a questionnaire. (The wiki I'm using has an older version of the plugin installed, and a have no access to that. I apologize if this has been fixed in the meantime.) ==== Configuration ==== How hard would it be to configure **doodle** plugin to have this functionality: * Show VoteCount if Configuration Parameter (such as conf['doodle_show_vote_count']) is TRUE. * Show VoteDate beneath the Yes GreenIcon if Configuration Parameter (such as conf['doodle_show_vote_date']) is TRUE. This plugin would become very useful to my team if each person would be tagged with the date of the vote and if the count wouldn't show up (since we're aiming at using it as a Go-No-Go tool). --- //[[jose.monteiro@dowedo-it.com|José Carlos Monteiro]] 2006-04-21 21:03// ==== Options ==== Is there any chance of incorporating Jonathan Tsai's changes into the plugin (rather than forking it) to ensure future changes are included and details are recorded on this page, particularly as his site is not written in English. The single/disable/login options are really useful. Also, the ability to delete (erroneous) rows would be useful (ref Christian's request) in a similar way to [[plugin:btable|btable]]. This could be limited to an administrator or logged in user. Thanks, Bob (28 Nov 2007) > Bob, > Last month I got a mail from Chi, ... and now I am being the doodle plugin maintainer.. :-P > --- //[[tryweb@ichiayi.com|Jonathan Tsai]] 2008-03-03 21:55// ==== Yes / No / Ifneedbe -polls ==== Great plugin! It would be nice to have a "maybe" or "if nothing else works"-option, like in [[http://doodle.ch/participation.html?pollId=qgp2cy79u72xm9p9|the "powerdoodle"]] of doodle.ch. Oh, and I added Swedish translation to the submit-button. - //[[erik@vindar.se|Erik H]] 2008-03-12 13:45// I'd like to see this option too - //[[id2ndr at crocobox org|Id2ndR]] 2008-03-12 13:45// Sure this could be a good idea, but keep your design which is way nicer than powerdoodle :) - // fr32c 2008-09-10 10:49// > Added by Martasdx > I edit my doodle code and add this option. To use it, download it here: [[http://files.use-it.cz/free/doodle.zip]]. Added ifneed option to other 3 options. > > Questions to > > Included: > * Syntax.php > * style.css > * EN and CS lang files > > Edit 14.3.2012 - Added support for editing more doodles one same page ==== If title string with dot, it cannot work ==== **The issue is fixed on 2008-05-20** --- //[[tryweb@ichiayi.com|Jonathan Tsai]] 2008/05/20 05:55// \\ Siegfried Schnapka report that :\\ I get no answerline; results... \\ Working with DokuWiki current release 2008-05-05. \\ After "submit" the choice is lost, and it happens nothing more \\ >I will try to fix it soon. --- //[[tryweb@ichiayi.com|Jonathan Tsai]] 2008/05/14 04:19// >> After tracing the source code, I found the issue is from title string with dot. In your case, the title string is \\ "Testanfrage: Palmenfest in der Karibik am 16.06 bis 29.08". It will be transformed to \\ "Testanfrage:_Palmenfest_in_der_Karibik_am_16_06_bis_29_08"; however, \\ "Testanfrage:_Palmenfest_in_der_Karibik_am_16.06_bis_29.08" should be right.\\ >>The issue is fixed on doodle-2008-05-20 version(Use md5 encoding to solve it). Old meta_doodle files are also renamed automatically to meet the new version. \\ --- //[[tryweb@ichiayi.com|Jonathan Tsai]] 2008/05/20 05:55// ==== Where is the ''$conf['plugin']['blog']['useifmodifiedsince']'' ==== :?: I have searched in the blog plugin and in the doodle plugin, but I don't found the ''$conf['plugin']['blog']['useifmodifiedsince']'' anywhere. :?: ==== Multi-line text in headers ==== What about to enable more lines in headers? Doodle results with more words in header ( especially time&date ) would be more readable. //Example:// ^Name^ 08-01-01\\ 9:00 ^ 08-01-01\\ 12:00 ^ 08-01-02\\ 9:00 ^ 08-01-02\\ 12:00 ^ |Name1| y | n | n | n | |Name2| n | n | y | y | //Quick patch: // Replace line 124 in ''syntax.php '': $renderer->doc .= $renderer->_xmlEntities($options[$i]); by: $renderer->doc .= str_replace('\\\\','
'.DOKU_LF,$renderer->_xmlEntities($options[$i])); I'm not familiar with PHP at all, this is only dirty code "that works". Also centering multiline text in header would be nice.\\ --- //Martin 2008/09/25 13:40// ==== Muti Vote Please ==== FIXME **Hi I need a Multivote like this, can this be done?? Voting 2times is not intuitive enough for users. Thanks** ^ Name ^ Mo ^ Tu ^ Wed 08-01-02 ^ Thu ^ | Name1 | y | y | n | n | | Name2 | n | n | y | y | ^ Name ^ 08-01-01\\ 9:00 ^ 08-01-01\\ 12:00 ^ 08-01-02\\ 9:00 ^ 08-01-02\\ 12:00 ^ | Name1 | y | n | n | n | | Name2 | n | n | y | y | ==== Alternate Syntax Suggestion ==== To be more consistent with a another plugin I have installed on my wiki([[plugin:userpoll]]), it'd be nice if this doodle plugin supported the following alternate syntax: * [option] * [option] * ... This also seems to be more consistent with a list of choices. ==== Require Login by Default ==== Perhaps as an option on the config page, it'd be nice if the **[login]** option was able to be set as always on. My wiki is on an intranet so everybody who would be responding has an account. ==== Loginname instead of realname ==== It would be nice to have the loginname instead of the realname when the [login] option is used. How can I achieve that? Could this be made an option? --//Rolf 2009/01/03 14:46// >I made some big changes to the doodle plugin, like using loginname(pseudo) instead of realname. I will post my diff as soon as I have a bit of time --//JRD 2009/03/26 14:35// ==== Email address ==== It would be nice to have a option for a second input field for emailadress, which should be hidden after send for non registered users. --//Björn 2009/02/05 15:26// ==== Multi-Vote, sorting, implicit group member fill and admin edit ==== I needed the following features: * allow to sign up more than one person for the scheduled date * sort signed-up list of users by last name * auto-fill the vote list with members of a certain group * for normal users limit signup capability to self * for advanced users (group member...) allow signing up other users or overriding their entries Disclaimer: I hacked doodle to do what I need. It works for me, but may not be right for you. Please note that this is the first time I ever touched PHP code, so this might be not the best nor most efficient solution. I found no built-in way to determine if a user is a member of a certain DokuWiki group, so this code was handcrafted as well. Only use this code in restricted environments, I am pretty sure there are security issues (even when limiting the doodle via 'login' it is possible to override the user by changing the hidden param; cross site scripting is very likely possible as well). New options: autogroup=GROUP If this is set, the doodle is pre-filled with all members of Dokuwik group GROUP. admingroup=GROUP Only makes sense if option 'login' is also set. Normal users may only change their own values, members of group GROUP can change entries for any doodle entry as if 'login' option was not given. multi=NUMBER Display drop-down box instead of checkbox allowing to select at most NUMBER participants for the doodle entry. Summary on the bottom of the doodle will reflect correct total number. Option 'single' must not be set when using multi. Example: ^ 08:00-12:00 ^ 13:30-17:30 ^ 20:00-23:00 ^ Deficiencies: * currently there is no way to delete a single doodle user entry Diff against version 2009-08-10: --- a/syntax.php +++ b/syntax.php @@ -53,12 +53,28 @@ class syntax_plugin_doodle extends DokuWiki_Syntax_Plugin { $disable = ""; $single = ""; $login = ""; + $autogroup = ""; + $admingroup = ""; + $multi= false; } else { $title = $rightstr; $disable = strpos($leftstr, "disable"); $single = strpos($leftstr, "single"); $login = strpos($leftstr, "login"); + $autogroup = false; + $admingroup = false; + $multi = false; + + if (preg_match('/group=(\w+)/', $leftstr, $arg)) { + $autogroup = $arg[1]; + } + if (preg_match('/admin=(\w+)/', $leftstr, $arg)) { + $admingroup = $arg[1]; + } + if (preg_match('/multi=(\d+)/', $leftstr, $arg)) { + $multi = $arg[1]; + } } if (!$options){ $options = $title; @@ -71,15 +87,27 @@ class syntax_plugin_doodle extends DokuWiki_Syntax_Plugin { $options[$i] = trim($options[$i]); } - return array(trim($title), $options, $disable, $single, $login); + return array(trim($title), $options, $disable, $single, $login, $autogroup, $admingroup, $multi); } /** * Create output */ function render($mode, &$renderer, $data) { + if (! function_exists("sortByLastName")) { + function sortByLastName($a, $b) { + $a = preg_match('/\w+$/', $a, $a_n); + $b = preg_match('/\w+$/', $b, $b_n); + if (($a != 0) && ($b != 0)) { + return strcasecmp($a_n[0], $b_n[0]); + } else { + return strcasecmp($a, $b); + } + } + } if ($mode == 'xhtml'){ global $lang; + global $auth; $options = $data[1]; $c = count($options)-1; @@ -87,6 +115,9 @@ class syntax_plugin_doodle extends DokuWiki_Syntax_Plugin { $disable = $renderer->_xmlEntities($data[2]); $single = $renderer->_xmlEntities($data[3]); $login = $renderer->_xmlEntities($data[4]); + $autogroup = $renderer->_xmlEntities($data[5]); + $admingroup = $renderer->_xmlEntities($data[6]); + $multi = $renderer->_xmlEntities($data[7]); $dID = md5($title); // prevent caching to ensure the poll results are fresh @@ -100,12 +131,36 @@ class syntax_plugin_doodle extends DokuWiki_Syntax_Plugin { rename($old_dfile, $dfile); } $doodle = unserialize(@file_get_contents($dfile)); - if ($c == 0){ // no options given: reset the doodle $doodle = NULL; } - + #$renderer->doc .= var_dump($doodle); + if ($autogroup) { + # TAG ADDGROUP + if (! is_array ($doodle)) { + $doodle = array(); + } + /* add users not yet contained in the array */ + # TAG GROUP + $filter['grps'] = $autogroup; + $getuser = $auth->retrieveUsers(0, -1, $filter); + foreach ($getuser as $entry) { + $fullname = $entry["name"]; + for ($i = 1; $i < $c; $i++){ + $opt = md5($options[$i]); + if (! isset($doodle[$fullname][$opt])) { + $doodle[$fullname][$opt] = false; + } + } + $doodle[$fullname]['show'] = true; + } + } + + if (is_array($doodle)) { + uksort($doodle, "sortByLastName"); + } + // output the doodle $renderer->table_open(); if ($title){ @@ -138,24 +193,29 @@ class syntax_plugin_doodle extends DokuWiki_Syntax_Plugin { if (isset($doodle[$user][$opt_old])) { $doodle[$user][$opt_old] = false; } - if ($_REQUEST[$dID.'-option'.$i]){ - $doodle[$user][$opt] = true; + if (! $multi) { + if ($_REQUEST[$dID.'-option'.$i]){ + $doodle[$user][$opt] = true; + } else { + $doodle[$user][$opt] = false; + } } else { - $doodle[$user][$opt] = false; + $doodle[$user][$opt] = $_REQUEST[$dID.'-option'.$i]; } } $doodle[$user]['time']=time(); } + uksort($doodle, "sortByLastName"); $fh = fopen($dfile, 'w'); fwrite($fh, serialize($doodle)); fclose($fh); } // display results - if (is_array($doodle)) $renderer->doc .= $this->_doodleResults($doodle, $options); + if (is_array($doodle)) $renderer->doc .= $this->_doodleResults($doodle, $options, $multi); // display entry form if ($disable=="") { - $renderer->doc .= $this->_doodleForm($c, $dID, $doodle, $options, $login, $single); + $renderer->doc .= $this->_doodleForm($c, $dID, $doodle, $options, $login, $single, $autogroup, $admingroup, $multi); } $renderer->table_close(); return true; @@ -164,36 +224,63 @@ class syntax_plugin_doodle extends DokuWiki_Syntax_Plugin { return false; } - function _doodleResults($doodle, $options){ + function _doodleResults($doodle, $options, $multi){ + global $INFO; $cuser = count($doodle); if ($cuser < 1) return ''; $copt = count($options)-1; $users = array_keys($doodle); $ret = ''; $count = array(); - + $logged_in_user = ($_SERVER['REMOTE_USER'] ? $INFO['userinfo']['name'] : ''); + // table okay / not okay for ($i = 0; $i < $cuser; $i++){ $isChecked = 0; + if ($doodle[$user]['show']) { + $isChecked = 1; + } $user = $users[$i]; + $highlighted_user=$user; + if (strpos($user, $logged_in_user) !== false) { + $highlighted_user="$user"; + } $updTime = isset($doodle[$user]['time'])?date('Y-m-d H:i:s', $doodle[$user]['time']):'Okey'; - $retTmp = ''.$user.''; + $retTmp = ''.$highlighted_user.''; for ($j = 1; $j < $copt; $j++){ $option = md5($options[$j]); $option_old = $options[$j]; - if ($doodle[$user][$option] || $doodle[$user][$option_old]){ - $class = 'okay'; - $title = ''.$updTime.''; - $count[$option] += 1; - $isChecked = 1; - } elseif (!isset($doodle[$user][$option]) && !isset($doodle[$user][$option_old])){ - $class = 'centeralign'; - $title = ' '; + $value = $doodle[$user][$option]; + if (! isset($value)) { + $value = $doodle[$user][$option_old]; + } + if (! $multi) { + if ($value){ + $class = 'okay'; + $title = ''.$updTime.''; + $count[$option] += 1; + $isChecked = 1; + } elseif (!isset($doodle[$user][$option]) && !isset($doodle[$user][$option_old])){ + $class = 'centeralign'; + $title = ' '; + } else { + $class = 'notokay'; + $title = ' '; + } } else { - $class = 'notokay'; - $title = ' '; + $class = 'centeralign'; + if (strpos($user, $logged_in_user) !== false) { + if ($value > 0) { + $class = 'okay'; + } else { + $class = 'notokay'; + } + } + $title = $value; + $count[$option] += $value; + $isChecked = 1; } $retTmp .= ''.$title.''; } @@ -212,10 +299,11 @@ class syntax_plugin_doodle extends DokuWiki_Syntax_Plugin { return $ret; } - function _doodleForm($n, $dID, $doodle, $options, $login, $single){ + function _doodleForm($n, $dID, $doodle, $options, $login, $single, $autogroup, $admingroup, $multi){ global $lang; global $ID; global $INFO; + global $auth; $user = ($_SERVER['REMOTE_USER'] ? $INFO['userinfo']['name'] : ''); $count = array(); @@ -224,6 +312,21 @@ class syntax_plugin_doodle extends DokuWiki_Syntax_Plugin { '" accept-charset="'.$lang['encoding'].'">'. ''. ''; + + if ($admingroup) { + $filter = array(); + $filter['name'] = $user; + $getuser = $auth->retrieveUsers(0, -1, $filter); + #$ret .= var_dump($getuser); + foreach ($getuser as $key => $value) { + if ($getuser[$key]['name'] == $user) { + $usergroups = $getuser[$key]['grps']; + if (count(preg_grep("/^$admingroup$/", $usergroups)) > 0) { + $login = ""; + } + } + } + } if ($login=="") { $ret .= ''; } @@ -235,13 +338,19 @@ class syntax_plugin_doodle extends DokuWiki_Syntax_Plugin { } $i = 1; while ($i < $n){ + $selected = ""; if (is_array($doodle)){ $option = md5($options[$i]); $option_old = $options[$j]; - if ($doodle[$user][$option] || $doodle[$user][$option_old]){ + + $checked = ' '; + if ($doodle[$user][$option_old]) { + $selected = $doodle[$user][$option_old]; + $checked = 'checked="checked" '; + } + if ($doodle[$user][$option]) { + $selected = $doodle[$user][$option]; $checked = 'checked="checked" '; - } else { - $checked = ' '; } } else { $checked = ' '; @@ -256,8 +365,21 @@ class syntax_plugin_doodle extends DokuWiki_Syntax_Plugin { } $onclickstr .= '"'; } - $ret.= ''; + } else { + $ret.= ''; + } $i++; } $ret .= ''. --//Martin 2009-09-01 15:00 CEST// ==== more confortable edit function ==== I just patched your plugin to allow a more comfortable way to edit existing entries. Just click the name (it's a link now) and the input fields will be initialised with the saved values. See my demo: http://strukturpunkt.de/doodle/demo Here is the source: http://strukturpunkt.de/doodle/start If you like it, it will be great if you integrate my changes in your official plugin. -- //Klaus Franken 2010-07-28 // ===== Doodle Poll Plugin V2.0 ===== I merged the [[plugin:doodle]], [[plugin:vote]] and [[plugin:userpoll]] plugins into one with all their features. Have a look at [[plugin:doodle2]]. I already asked the author of this plugin. We see the doodle2 as the new version. --- //Doogie - September 2010//