Skip Menu |

Preferred bug tracker

Please visit the preferred bug tracker to report your issue.

This queue is for tickets about the CGI CPAN distribution.

Report information
The Basics
Id: 30057
Status: rejected
Priority: 0/
Queue: CGI

People
Owner: MARKSTOS [...] cpan.org
Requestors: tom.luyten [...] verz.kbc.be
Cc: randomcoder1 [...] gmail.com
AdminCc:

Bug Information
Severity: Important
Broken in: (no value)
Fixed in: (no value)



Subject: CGI.pm popup_menu multiple selects
When you create a popup_menu with CGI.pm (ex: print my_popup_menu(- name=>'selection_serverlist',-default=>'' ,-multiple=>'true',- values=>\@ep, -labels=>\%serverlist);) and you use multiple=>'true' you can select multiple items in the list and post them. The problem in CGI.pm is that when you rebuild you page your selection is lost. The CGI.pm module doesn't work with the hash that's being returned. It only uses the first item in the has. As a quick-fix I changed the following: foreach (@values) { if (/<optgroup/) { foreach (split(/\n/)) { my $selectit = $XHTML ? 'selected="selected"' : 'selected'; s/(value="$selected")/$selectit $1/ if defined $selected; $result .= "$_\n"; } } else { my $temp_value = $_; for ( $self->param($name)) { if ($temp_value eq $_) { $selected = $_; } } my $attribs = $self->_set_attributes($_, $attributes); my($selectit) = defined($selected) ? $self->_selected ($selected eq $_) : ''; my($label) = $_; $label = $labels->{$_} if defined($labels) && defined($labels-> {$_}); my($value) = $self->escapeHTML($_); $label=$self->escapeHTML($label,1); $result .= "<option${attribs} ${selectit} value=\"$value\">$label</option>\n"; } } The first 6 lines of the else are mine. They fix my problem with the multiple select. Kind regards, Tom
On Wed Oct 17 09:08:47 2007, Wivern wrote: Show quoted text
> When you create a popup_menu with CGI.pm (ex: print my_popup_menu(- > name=>'selection_serverlist',-default=>'' ,-multiple=>'true',- > values=>\@ep, -labels=>\%serverlist);) and you use multiple=>'true' > you can select multiple items in the list and post them. > > The problem in CGI.pm is that when you rebuild you page your selection > is lost. > The CGI.pm module doesn't work with the hash that's being returned. > It only uses the first item in the has. > > As a quick-fix I changed the following: > > foreach (@values) { > if (/<optgroup/) { > foreach (split(/\n/)) { > my $selectit = $XHTML ? 'selected="selected"' : 'selected'; > s/(value="$selected")/$selectit $1/ if defined $selected; > $result .= "$_\n"; > } > } > else { > my $temp_value = $_; > for ( $self->param($name)) { > if ($temp_value eq $_) { > $selected = $_; > } > } > my $attribs = $self->_set_attributes($_, $attributes); > my($selectit) = defined($selected) ? $self->_selected > ($selected eq $_) : ''; > my($label) = $_; > $label = $labels->{$_} if defined($labels) && defined($labels-> > {$_}); > my($value) = $self->escapeHTML($_); > $label=$self->escapeHTML($label,1); > $result .= "<option${attribs} ${selectit} > value=\"$value\">$label</option>\n"; > } > } > > The first 6 lines of the else are mine. They fix my problem with the > multiple select.
Thanks for the report. If the issue still persists, could you prepare a Test::More style test case which illustrates it? I would also recommend considering using a templating system to generate the forms, and using HTML::FIllInForm to handle selecting values in the form. Mark
Hi, I've just fixed this bug. I have the code from github cloned I replaced only one line in CGI.pm and that will be my patch. Can I write here the patch. Also , as I understand , Somni on #perl on FreeNode argued that this isn't actually a bug-report but it is a feature because it wasn't mentioned in the initial specs for a popup_menu to support multiple selection. Do I just send the patch or also write a test for it ? Thank you, Stefan
Ok, patches rolled in. RFC please :)
1698c1698 < if ($DTD_PUBLIC_IDENTIFIER =~ /[^X]HTML (2\.0|3\.2|4\.01?)/i) { --- > if ($DTD_PUBLIC_IDENTIFIER =~ /[^X]HTML (2\.0|3\.2)/i) { 2538a2539 > $selectit = ' selected="selected" ' if $_ ~~ @{$self->{param}->{$name}} // ''; 4962,4963c4963 < If start_html()'s -dtd parameter specifies an HTML 2.0, < 3.2, 4.0 or 4.01 DTD, --- > If start_html()'s -dtd parameter specifies an HTML 2.0 or 3.2 DTD,
1c1 < #!perl --- > #!/usr/bin/perl 3c3,5 < use lib 't/lib'; --- > use lib './lib'; > use lib './t/lib'; > use CGI qw/:debug/; 5c7,8 < use CGI; --- > use feature 'say'; > use Data::Dumper; 7c10,12 < my $q = CGI->new; --- > push @ARGV,"selection=bbb;selection=ccc"; > > my $q = CGI->new(); 10c15 < '<select name="foo" > --- > '<select name="foo" > 14c19,46 < , 'popup_menu(): basic test, including 0 as a default value'); --- > , 'popup_menu(): basic test, including 0 as a default value'); > > > # test for popup_menu multiple selection that would have to last after submit button is > # pressed > my $q = CGI->new(); > > my $menu = $q->popup_menu( > -name=>'selection', > -default=>'' , > -multiple=>'true', > -values=>['aaa','bbb','ccc'], > -labels=>{ > 'aaa'=>'aaa', > 'bbb'=>'bbb', > 'ccc'=>'ccc', > } > ); > is($menu, > '<select name="selection" multiple="true"> > <option value="aaa">aaa</option> > <option selected="selected" value="bbb">bbb</option> > <option selected="selected" value="ccc">ccc</option> > </select>', > 'popup_menu(): test related to having multiple items selected and after select they should still be selected' > ); > >
On Sun Aug 16 16:43:51 2009, WSDOOKADR wrote: Show quoted text
> Ok, patches rolled in. > RFC please :)
Thanks for the patch! Here's the line you added: $selectit = ' selected="selected" ' if $_ ~~ @{$self->{param}->{$name}} // ''; For CGI.pm we would like compatibility with Perl 5.6. Could you rewrite it, avoiding "~~" and "//" ? You are also welcome to send me a pull request on github. Thanks! Mark
ok - replaced the ~~ with grep. - added some description of popup_menu to the POD. - added check for "-multiple" in order to not break other tests in ( if I don't check for "-multiple" some tests form.t:106 and no_tabindex.t:108)
2505a2506,2511 > # { > # sub deb { > # open my $debug_fh,">/tmp/debug_cgi.txt"; > # print $debug_fh $_[0] > # }; > # }; 2524a2531,2532 > # use Data::Dumper; > # deb Dumper \@_; 2538a2547,2556 > # Mark Stosberg suggestions -> using something that would be compatible for perl 5.6 > # for counting occurences inside an array ( instead of ~~ which was used before ) > # grep is a possibility > if( (grep /^-multiple$/, @_) > 0 && defined $self->{param}->{$name} && @{$self->{param}->{$name}} > 1) { > #this code will be run only if we have multiple selections > my $val = $_; # current > # we count in occ_val occurences of the current value attribute which is selected > my $occ_val = () = grep /^$val$/,@{ $self->{param}->{$name} }; > $selectit = ' selected="selected" ' if $occ_val > 0; > } 4962,4963c4980 < If start_html()'s -dtd parameter specifies an HTML 2.0, < 3.2, 4.0 or 4.01 DTD, --- > If start_html()'s -dtd parameter specifies an HTML 2.0 or 3.2 DTD, 6278a6296,6313 > -or- ( > multiple selection allows to have multiple items selected, > they will continue to be selected after you submit the form > ) > > print popup_menu( > -name=>'selection', > -default=>'' , > -multiple=>'true', > -values=>['aaa','bbb','ccc'], > -override=>1, > -labels=>{ > 'aaa'=>'aaa', > 'bbb'=>'bbb', > 'ccc'=>'ccc', > } > ) >
1c1 < #!perl --- > #!/usr/bin/perl 3c3,5 < use lib 't/lib'; --- > use lib './lib'; > use lib './t/lib'; > use CGI qw/:debug/; 5c7,8 < use CGI; --- > use feature 'say'; > use Data::Dumper; 7c10,12 < my $q = CGI->new; --- > push @ARGV,"selection=bbb;selection=ccc"; > > my $q = CGI->new(); 10c15 < '<select name="foo" > --- > '<select name="foo" > 14c19,47 < , 'popup_menu(): basic test, including 0 as a default value'); --- > , 'popup_menu(): basic test, including 0 as a default value'); > > > # test for popup_menu multiple selection that would have to last after submit button is > # pressed > $q = CGI->new(); > > my $menu = $q->popup_menu( > -name=>'selection', > -default=>'' , > -multiple=>'true', > -values=>['aaa','bbb','ccc'], > -override=>1, > -labels=>{ > 'aaa'=>'aaa', > 'bbb'=>'bbb', > 'ccc'=>'ccc', > } > ); > is($menu, > '<select name="selection" multiple="true"> > <option value="aaa">aaa</option> > <option selected="selected" value="bbb">bbb</option> > <option selected="selected" value="ccc">ccc</option> > </select>', > 'popup_menu(): test related to having multiple items selected and after select they should still be selected' > ); > >
Thanks! I'm about to leave for work now, but another helper watching the bug tracker should feel feel to peer-review this and apply it in their github branch if approved. Otherwise I should get to in the next 24 hours. Mark
Thanks. However, when I applied this patch and the new test, one of the tests failed: not ok 2 - popup_menu(): test related to having multiple items selected and after select they should still be selected # Failed test (t/popup_menu.t at line 37) # got: '<select name="selection" multiple="true"> <option value="aaa">aaa</option> <option value="bbb">bbb</option> <option value="ccc">ccc</option> </select>' # expected: '<select name="selection" multiple="true"> <option value="aaa">aaa</option> <option selected="selected" value="bbb">bbb</option> <option selected="selected" value="ccc">ccc</option> </select>' 1..2 ### If you submit a refined patch, there are a couple ways it could be cleaned up: - In the test it said "use feature 'say'", but it didn't seem to do anything. - In CGI.pm, there was commented out code related to "sub deb" and the call to Dumper can be removed, as can the comment about Perl 5.6 compatibility. Also, I didn't understand this idiom: my $occ_val = () = grep /^$val$/,@{ $self->{param}->{$name} }; What is the intent of assigning an empty list to a value, and then assigning the result to a variable? Mark
On Mon Aug 17 20:48:52 2009, MARKSTOS wrote: Show quoted text
> Also, I didn't understand this idiom: > > my $occ_val = () = grep /^$val$/,@{ $self->{param}->{$name} }; > > What is the intent of assigning an empty list to a value, and then > assigning the result to a variable? >
Sorry , here I intended my $occ_val = grep /^$val$/,@{ $self->{param}->{$name} };
Another tip: Use "diff -u" to generate the patches. This will include the file name and some more context in the file, making it easier to review the patch. You can also concatenate two of these diff files together to make one attachment which been reviewed and re-applied in one action.
On Mon Aug 17 21:23:54 2009, MARKSTOS wrote: Show quoted text
> Another tip: Use "diff -u" to generate the patches. This will include > the file name and some more context in the file, making it easier to > review the patch. You can also concatenate two of these diff files > together to make one attachment which been reviewed and re-applied in > one action.
Hi Mark, I've used git diff > popup_menu.patch I'm sending it now.
diff --git a/lib/CGI.pm b/lib/CGI.pm index 65fff24..855bb9e 100644 --- a/lib/CGI.pm +++ b/lib/CGI.pm @@ -2542,6 +2542,15 @@ sub popup_menu { else { my $attribs = $self->_set_attributes($_, $attributes); my($selectit) = $self->_selected($selected{$_}); + + if( (grep /^-multiple$/, @_) > 0 && defined $self->{param}->{$name} && @{$self->{param}->{$name}} > 1) { + #this code will be run only if we have multiple selections + my $val = $_; # current + # we count in occ_val occurences of the current value attribute which is selected + my $occ_val = grep /^$val$/,@{ $self->{param}->{$name} }; + $selectit = ' selected="selected" ' if $occ_val > 0; + } + my($label) = $_; $label = $labels->{$_} if defined($labels) && defined($labels->{$_}); my($value) = $self->escapeHTML($_); @@ -6284,6 +6293,24 @@ recognized. See textfield() for details. -default=>['meenie','minie'], -labels=>\%labels, -attributes=>\%attributes); + -or- ( + multiple selection allows to have multiple items selected, + they will continue to be selected after you submit the form + ) + + print popup_menu( + -name=>'selection', + -default=>'' , + -multiple=>'true', + -values=>['aaa','bbb','ccc'], + -override=>1, + -labels=>{ + 'aaa'=>'aaa', + 'bbb'=>'bbb', + 'ccc'=>'ccc', + } + ) + popup_menu() creates a menu. diff --git a/t/popup_menu.t b/t/popup_menu.t index 90c52a9..4c7a360 100644 --- a/t/popup_menu.t +++ b/t/popup_menu.t @@ -6,9 +6,34 @@ use CGI; my $q = CGI->new; is ( $q->popup_menu(-name=>"foo", - values=>[0,1], -default=>0), -'<select name="foo" > + '<select name="foo" > <option selected="selected" value="0">0</option> <option value="1">1</option> </select>' -, 'popup_menu(): basic test, including 0 as a default value'); + , 'popup_menu(): basic test, including 0 as a default value'); + + +push @ARGV,"selection=bbb;selection=ccc"; +$q = CGI->new(); + +my $menu = $q->popup_menu( + -name=>'selection', + -default=>'' , + -multiple=>'true', + -values=>['aaa','bbb','ccc'], + -override=>1, + -labels=>{ + 'aaa'=>'aaa', + 'bbb'=>'bbb', + 'ccc'=>'ccc', + } +); +is($menu, + '<select name="selection" multiple="true"> +<option value="aaa">aaa</option> +<option selected="selected" value="bbb">bbb</option> +<option selected="selected" value="ccc">ccc</option> +</select>', + 'popup_menu(): test related to having multiple items selected and after select they should still be selected' +);
On Thu Aug 20 10:43:57 2009, WSDOOKADR wrote: Show quoted text
> On Mon Aug 17 21:23:54 2009, MARKSTOS wrote:
> > Another tip: Use "diff -u" to generate the patches. This will include > > the file name and some more context in the file, making it easier to > > review the patch. You can also concatenate two of these diff files > > together to make one attachment which been reviewed and re-applied in > > one action.
> > Hi Mark, > > I've used git diff > popup_menu.patch
Thanks. One more suggestion for improvement: Instead of using the direct access to the param hash, it is preferable to respect the encapsulation and call the param() method instead. So calls like this: $self->{param}->{$name} should be: $self->param($name); This patch format was easier to deal with, but the test still fails for me in the same way...nothing becomes selected. This is on Perl 5.8.8. Let me ask this: Why have you not solved this just as it is in scrolling_list()? The code should be almost identical and I suspect that approach would get the test to pass for me.
On Thu Aug 20 22:07:09 2009, MARKSTOS wrote: Show quoted text
> On Thu Aug 20 10:43:57 2009, WSDOOKADR wrote:
> > On Mon Aug 17 21:23:54 2009, MARKSTOS wrote:
> > > Another tip: Use "diff -u" to generate the patches. This will
include Show quoted text
> > > the file name and some more context in the file, making it easier
to Show quoted text
> > > review the patch. You can also concatenate two of these diff files > > > together to make one attachment which been reviewed and re-
applied in Show quoted text
> > > one action.
> > > > Hi Mark, > > > > I've used git diff > popup_menu.patch
> > Thanks. One more suggestion for improvement: > > Instead of using the direct access to the param hash, it is preferable > to respect the encapsulation and call the param() method instead. > > So calls like this: $self->{param}->{$name} > should be: $self->param($name); > > This patch format was easier to deal with, but the test still fails
for Show quoted text
> me in the same way...nothing becomes selected. This is on Perl 5.8.8. > > Let me ask this: Why have you not solved this just as it is in > scrolling_list()? The code should be almost identical and I suspect
that Show quoted text
> approach would get the test to pass for me. >
I have tested all modifications on Perl 5.10.0 Please confirm that the bug is solved there and I will try to see if I get a 5.8.8 set up to test there as well.
Show quoted text
> I have tested all modifications on Perl 5.10.0 > Please confirm that the bug is solved there and I will try to see if I > get a 5.8.8 set up to test there as well.
I think the patch needs to be rewritten to be consistent with scrolling_list(). It ought to include "MULTIPLE" in the call to "rearrange()" and it makes sense that it should also make use of the "previous_or_default()" method. When a new patch is ready, I'll test it again on Perl 5.8.8.
Subject: Needs patch refinement: CGI.pm popup_menu multiple selects (use scrolling list instead)
On further consideration, I think there's been some confusion about popup_menu() and multiple selects (I became confused myself). I explain this here: https://rt.cpan.org/Ticket/Display.html?id=35376#txn-651534 I believe the correct "fix" here is to use scrolling_list() instead, which works basically exactly like popup_menu(), except it's designed for multi-selects. My proposal to Lincoln is to remove the multi-select feature to popup_menu() that was added somewhat recently. If he accepts my proposal, the change requested in this ticket will not go forward, so work on this ticket is stalled for now. Mark
On Fri Aug 21 21:55:23 2009, MARKSTOS wrote: Show quoted text
> On further consideration, I think there's been some confusion about > popup_menu() and multiple selects (I became confused myself). I
explain Show quoted text
> this here: > > https://rt.cpan.org/Ticket/Display.html?id=35376#txn-651534 > > I believe the correct "fix" here is to use scrolling_list() instead, > which works basically exactly like popup_menu(), except it's designed > for multi-selects. > > My proposal to Lincoln is to remove the multi-select feature to > popup_menu() that was added somewhat recently. If he accepts my > proposal, the change requested in this ticket will not go forward, so > work on this ticket is stalled for now. > > Mark
Ok
This issue has been copied to: https://github.com/leejo/CGI.pm/issues/50 please take all future correspondence there. This ticket will remain open but please do not reply here. This ticket will be closed when the github issue is dealt with.
I have updated the popup_menu method to IGNORE the -multiple argument if passed. Use scrolling_list instead. I am not accepting any feature requests / updates to HTML functions in CGI.pm unless they are of critical nature. Will go out in v4.03 Thanks, Lee.