DokuWiki

It's better when it's simple

User Tools

Site Tools


plugin:doodle

Doodle Plugin

Compatible with DokuWiki

  • 2013-12-08 "Binky" unknown
  • 2013-05-10 "Weatherwax" yes
  • 2012-10-13 "Adora Belle" yes
  • 2012-01-25 "Angua" yes

plugin Helps to schedule meetings or making other decisions in a team. (previous authors: Esther Brunner)

Last updated on
2009-08-10
Provides
Syntax
Conflicts with
doodle2

Similar to btable, doodle2

Tagged with calculation, calendar, doodle, form, poll, tables, todo

The idea is stolen from Doodle by Michael Näf.

Syntax

This plugin can help your team to schedule meetings or making other decisions in a team. The syntax looks like this:

<doodle [id]>
^ [choice] ^ [choice] ^ ... ^
</doodle>

That means, you can simply put <doodle> tags around regular table header to get a check box table with different choices.

[id] the ID of the doodle; must be unique1); 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…

<doodle [disable] [single] [login]| [id]>
^ [choice] ^ [choice] ^ ... ^
</doodle>
[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 here.

Release Notes

  • 2009-02-05 :
    1. Fix options can support special character Exp. & (Jonas noticed the bug)
    2. Add submit datetime function over the Okay Icon
  • 2009-08-10 :
    1. Fix the bug when using HTML tag as a part of fullname string, table will be broken.

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. Send us your translation or put below!

English

<?php
 
$lang['btn_submit'] = 'Submit';
 
//Setup VIM: ex: et ts=4 enc=utf-8 :
?>

Esperanto

<?php
 
$lang['btn_submit'] = 'Konservi';
 
//Setup VIM: ex: et ts=4 enc=utf-8 :
?>

Catalan

<?php
/**
 * translation by Raimon  <gwindor@auna.com>
 */
 
$lang['btn_submit'] = 'Envia';
 
//Setup VIM: ex: et ts=4 enc=utf-8 :
?>

German

<?php
 
$lang['btn_submit'] = 'Abschicken';
 
//Setup VIM: ex: et ts=4 enc=utf-8 :
?>

Simplified Chinese

<?php
 
$lang['btn_submit'] = '提交';
 
//Setup VIM: ex: et ts=4 enc=utf-8 :
?>

Traditional Chinese

<?php
 
$lang['btn_submit'] = '送出';
 
//Setup VIM: ex: et ts=4 enc=utf-8 :
?>

Swedish

<?php
 
$lang['btn_submit'] = 'Skicka';
 
//Setup VIM: ex: et ts=4 enc=utf-8 :
?>

Danish

<?php
 
$lang['btn_submit'] = 'Send';
 
//Setup VIM: ex: et ts=4 enc=utf-8 :
?>

Dutch

<?php
 
$lang['btn_submit'] = 'Verstuur';
 
//Setup VIM: ex: et ts=4 enc=utf-8 :
?>

French

<?php
 
$lang['btn_submit'] = 'Envoyer';
 
?>

Italian

<?php
 
  $lang['btn_submit'] = 'Invia';
 
?>

Japanese

<?php
 
  $lang['btn_submit'] = '提出';
 
?>

Luxembourgish

<?php
 
  $lang['btn_submit'] = 'Aschécken';
 
?>

Spanish

<?php
 
  $lang['btn_submit'] = 'Enviar';
 
?>

Hungarian

<?php
 
  $lang['btn_submit'] = 'Szavazok';
 
?>

Euskera

<?php
 
  $lang['btn_submit'] = 'Bidali';
 
?>

Valencian

<?php
 
  $lang['btn_submit'] = 'Enviar';
 
?>

Icelandic

<?php
 
  $lang['btn_submit'] = 'Senda';
 
?>

Czech

<?php
 
  $lang['btn_submit'] = 'Odeslat';
 
?>

Further Resources

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) — 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). — 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 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
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 the "powerdoodle" of doodle.ch. Oh, and I added Swedish translation to the submit-button. - Erik H 2008-03-12 13:45

I'd like to see this option too - 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 polivma2 [at] fit [dot] cvut [dot] cz

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-20Jonathan 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. — 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.
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('\\\\','<br/>'.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 n 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(userpoll), it'd be nice if this doodle plugin supported the following alternate syntax:

<doodle [id]>
  * [option]
  * [option]
  * ...
</doodle>

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:

<doodle login group=normalusers admin=powerusers multi=9 | My cool activity >
^ 08:00-12:00 ^ 13:30-17:30 ^ 20:00-23:00 ^
</doodle>

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="<strong>$user</strong>";
+               }
                $updTime = isset($doodle[$user]['time'])?date('Y-m-d H:i:s', $doodle[$user]['time']):'Okey';
-               $retTmp = '<tr><td class="rightalign">'.$user.'</td>';
+               $retTmp = '<tr><td class="rightalign">'.$highlighted_user.'</td>';
                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 = '<img src="'.DOKU_BASE.'lib/images/success.png" title="'.
-                                 $updTime.'" alt="'.$updTime.'" '.
-                                 'width="16" height="16" />';
-                               $count[$option] += 1;
-                               $isChecked = 1;
-                       } elseif (!isset($doodle[$user][$option]) && !isset($doodle[$user][$option_old])){
-                               $class = 'centeralign';
-                               $title = '&nbsp;';
+                       $value = $doodle[$user][$option];
+                       if (! isset($value)) {
+                               $value = $doodle[$user][$option_old];
+                       }
+                       if (! $multi) {
+                               if ($value){
+                                       $class = 'okay';
+                                       $title = '<img src="'.DOKU_BASE.'lib/images/success.png" title="'.
+                                       $updTime.'" alt="'.$updTime.'" '.
+                                       'width="16" height="16" />';
+                                       $count[$option] += 1;
+                                       $isChecked = 1;
+                               } elseif (!isset($doodle[$user][$option]) && !isset($doodle[$user][$option_old])){
+                                       $class = 'centeralign';
+                                       $title = '&nbsp;';
+                               } else {
+                                       $class = 'notokay';
+                                       $title = '&nbsp;';
+                               }
                        } else {
-                               $class = 'notokay';
-                               $title = '&nbsp;';
+                               $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 .= '<td class="'.$class.'">'.$title.'</td>';
                }
@@ -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'].'"><tr>'.
                '<input type="hidden" name="do" value="show" />'.
                '<input type="hidden" name="id" value="'.$ID.'" />';
+
+       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 .= '<td class="rightalign"><input type="text" name="fullname" '.'value="'.$user.'" /></td>';
        }
@@ -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.= '<td class="centeralign"><input type="checkbox" '.
+               if (! $multi) {
+                       $ret.= '<td class="centeralign"><input type="checkbox" '.
                        'name="'.$dID.'-option'.$i.'" value="1" '.$checked.' '.$onclickstr.'/></td>';
+               } else {
+                       $ret.= '<td class="centeralign"><select size="1" '.
+                       'name="' . $dID . '-option' . $i . '"' . $onclickstr.'>';
+                       for ($k = 0; $k <= $multi; $k++) {
+                               $selected_string = "";
+                               if ($selected == $k) {
+                                       $selected_string = " selected";
+                               }
+                               $ret .= "<option" . $selected_string . ">$k</option>";
+                       }
+                       $ret .= '</select></td>';
+               }
                $i++;
        }
        $ret .= '</tr><tr><td class="centeralign" colspan="'.($n).'">'.

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 doodle, vote and userpoll plugins into one with all their features. Have a look at doodle2. I already asked the author of this plugin. We see the doodle2 as the new version. — Doogie - September 2010

1) 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.
plugin/doodle.txt · Last modified: 2013/05/29 20:14 by 111.240.74.61