response
[ikiwiki] / doc / todo / progressbar_plugin.mdwn
1 I would like to add next plugin to Ikiwiki. It's `progressbar` or simply `progress`.
2 I'm not sure what plugin name better is, probably that shorter ;) I know that
3 [DokuWiki](http://wiki.splitbrain.org/plugin:progressbar) has similar plugin,
4 so I think it can be useful also for Ikiwiki users.
5
6 Here is proposition of the plugin syntax:
7
8     \[[!progress done=50]]
9
10 Of course, `done` argument is integer from 0 to 100. 
11
12 A here is its HTML result:
13
14     <div class="progress">
15       <div class="progress-done" style="width: 50%">50%</div>
16     </div>
17
18 Note: I was trying with `<span>` tags too, but that tag is inline, so I can't
19 set `width` property for it.
20
21 > In the poll plugin, I ended up using a `<hr>` for the progress-like
22 > thing. One reason I did so is because it actually works in text-mode
23 > browsers (w3m, lynx), that do not support css or colorized
24 > divs. Since the hr is an element they display, just setting its width can
25 > make a basic progress-type display. The style then makes it display
26 > better in more capable browsers.
27
28 > The other advantage to that approach is that the htmlscrubber lets
29 > through the `class` and `width` fields, that are all that are needed for
30 > it to work. No need to work around htmlscrubber.
31
32 > So I suggest adapting this to use similar html. --[[Joey]]
33
34 >> I just had a brief play with this.  It seems there are some trade-offs involved.
35 >> The `width` attribute of an `<hr>` tag is deprecated, but that's not the big one.
36 >> I can't see how to place text next to an `<hr>` tag.  I note that in the
37 >> [[plugins/poll]] plugin there is text above and below the 'graph line', but none
38 >> on the same line as the graph.  I prefer the way the current code renders,
39 >> with the percentage complete appearing as text inside the graph.
40 >>
41 >> So, if we use `hr` we get:
42 >>
43 >> - Graph line on text / non-css browsers
44 >> - No percentage complete text on the same line as the graph line
45 >> - Deprecated HTML
46 >>
47 >> If we use `div` we get:
48 >>
49 >> - Need to clean up after HTMLScrubber (which is not hard - already implemented)
50 >> - Get the percentage written as text on text / non-css browsers
51 >> - Get the percentage on the same line as the graph in css browsers
52 >>
53 >> I'm strongly in favour of having the percentage text label on the graph, and on
54 >> text based browsers I think having the text label is enough -- the lack of the line
55 >> in that case doesn't bother me.
56 >> So, given the choice between the two suggested techniques, I'd take the second and
57 >> stay with div... unless you know how to get text next to (or within) an `<hr>` tag. -- [[Will]]
58
59 Default CSS styles for the plugin can be like below:
60
61     div.progress {
62             border: 1px solid #ddd;
63             /* border: 2px solid #ddd; */
64             width: 200px;
65             background: #fff;
66             padding: 2px;
67             /* padding: 0px; */
68             border: 2px solid #aaa;
69             background: #eee;
70     }
71     div.progress-done {
72             height: 14px;
73             background: #ff6600;
74             font-size: 12px;
75             text-align: center;
76             vertical-align: middle;
77     }
78
79 You can use alternative, commented CSS code for `div.progress` if you dislike
80 padding around done strip.
81
82 Any comments? --[[Paweł|ptecza]]
83
84 > Please make sure to always set a foreground color if a background color is
85 > set, and use '!important' so the foreground color can be overridden. (CSS
86 > best practices) --[[Joey]]
87
88 >> Below is the CSS I've been using -- [[Will]]
89
90     div.progress {
91         margin-top: 1ex;
92         margin-bottom: 1ex;
93         border: 1px solid #888;
94         width: 400px;
95         background: #eee;
96         color: black !important;
97         padding: 1px;
98     }
99     div.progress-done {
100         background: #ea6 !important;
101         color: black !important;
102         text-align: center;
103         padding: 1px;
104     }
105
106 > This looks like a nice idea.  If I could add one further suggestion: Allow your
107 > ratio to be a pair of pagespecs.  Then you could have something like:
108
109     \[[!progress totalpages="bugs/* and backlink(milestoneB)" donepages="bugs/* and backlink(milestoneB) and !link(bugs/done)"]]
110
111 > to have a progress bar marking how many bugs were compete for a
112 > particular milestone.  -- [[Will]]
113
114 >> Thanks a lot for your comment, Will! It seems very interesting for me.
115 >> I need to think more about improving that plugin. --[[Paweł|ptecza]]
116
117 >> Attached is a [[patch]] (well, source) for this.  You also need to add the proposed CSS above to `style.css`.
118 >> At the moment this plugin interacts poorly with the [[plugins/htmlscrubber]] plugin.
119 >> HTMLScrubber plugin removes the `style` attribute from the `progress-done` `div` tag, and so it defaults
120 >> to a width of 100%. -- [[Will]]
121
122 >>> Thank you for the code! I know how to fix that problem, because I had
123 >>> the same issue while writing [[todo/color_plugin]] :) --[[Paweł|ptecza]]
124
125 >>>> Ahh - good idea.  Patch updated to work with HTMLScrubber. --[[Will]]
126
127 >>>>> I like it, but I think that Joey should take a look at that patch too :)
128 >>>>> --[[Paweł|ptecza]]
129
130     #!/usr/bin/perl
131     package IkiWiki::Plugin::progress;
132     
133     use warnings;
134     use strict;
135     use IkiWiki 2.00;
136     
137     my $percentage_pattern = qr/[0-9]+\%/; # pattern to validate percentages
138     
139     sub import { #{{{
140         hook(type => "getsetup", id => "progress", call => \&getsetup);
141         hook(type => "preprocess", id => "progress", call => \&preprocess);
142         hook(type => "format",     id => "progress", call => \&format);
143     } # }}}
144     
145     sub getsetup () { #{{{
146         return 
147                 plugin => {
148                         safe => 1,
149                         rebuild => undef,
150                 },
151     } #}}}
152     
153     sub preprocess (@) { #{{{
154         my %params=@_;
155         
156         my $fill;
157         
158         if (defined $params{percent}) {
159                 $fill = $params{percent};
160                 ($fill) = $fill =~ m/($percentage_pattern)/; # fill is untainted now
161         }
162         elsif (defined $params{totalpages} and defined $params{donepages}) {
163                 add_depends($params{page}, $params{totalpages});
164                 add_depends($params{page}, $params{donepages});
165     
166                 my @pages=keys %pagesources;
167                 my $totalcount=0;
168                 my $donecount=0;
169                 foreach my $page (@pages) {
170                         $totalcount++ if pagespec_match($page, $params{totalpages}, location => $params{page});
171                         $donecount++ if pagespec_match($page, $params{donepages}, location => $params{page});
172                 }
173                 
174                 if ($totalcount == 0) {
175                         $fill = "100%";
176                 } else {
177                         my $number = $donecount/$totalcount*100;
178                         $fill = sprintf("%u%%", $number);
179                 }
180         }
181         else {
182                 error("Missing parameters to progress plugin.  Need either `percent` or `totalpages` and `donepages` parameters.");
183         }
184     
185         return <<EODIV
186     <div class="progress">
187       <div class="progress-done" style="width: $fill">$fill</div>
188     </div>
189     EODIV
190     
191     } # }}}
192     
193     sub format(@) { #{{{
194         my %params = @_;
195     
196         # If HTMLScrubber has removed the style attribute, then bring it back
197     
198         $params{content} =~ s!<div class="progress-done">($percentage_pattern)</div>!<div class="progress-done" style="width: $1">$1</div>!g;
199     
200         return $params{content};    
201     } #}}}
202     
203     1
204
205 Here is a potential documentation page:
206
207 -----
208
209 [[!template id=plugin name=progress author="[[Will]]"]]
210 [[!tag type/meta]]
211
212 Provides a \\[[!progress ]] [[ikiwiki/PreProcessorDirective]] that is
213 replaced with a progress bar.
214
215 There are two possible parameter sets.  The first is a single parameter
216 `percent` which holds a percentage figure for how complete the progress bar is.
217
218 The second possible set of parameters is a pair of [[ikiwiki/PageSpec]]s,
219 `totalpages` and `donepages`.  The progress plugin counts the number of
220 pages in each pagespec and shows the percentage of the total pages that are
221 done.
222
223 This plugin is included in ikiwiki, but is not enabled by default.
224
225 If it is turned on it can show what percentage of pages have discussion pages:
226
227         \[[!progress totalpages="* and !*/Discussion" donepages="*/Discussion"]]