Signed-off-by: Francois Gouget fgouget@codeweavers.com --- testbot/lib/ObjectModel/CGI/Page.pm | 7 +++++++ testbot/lib/WineTestBot/CGI/PageBase.pm | 11 +++++++++++ 2 files changed, 18 insertions(+)
diff --git a/testbot/lib/ObjectModel/CGI/Page.pm b/testbot/lib/ObjectModel/CGI/Page.pm index d7463b5a8..406ca4ff8 100644 --- a/testbot/lib/ObjectModel/CGI/Page.pm +++ b/testbot/lib/ObjectModel/CGI/Page.pm @@ -369,6 +369,13 @@ sub GetTitle($) return undef; }
+sub GenerateImportJS($$) +{ + my ($self, $Filename) = @_; + + $self->{PageBase}->GenerateImportJS($Filename); +} + sub GenerateHttpHeaders($) { my ($self) = @_; diff --git a/testbot/lib/WineTestBot/CGI/PageBase.pm b/testbot/lib/WineTestBot/CGI/PageBase.pm index 477a2ff15..0dacbf6dd 100644 --- a/testbot/lib/WineTestBot/CGI/PageBase.pm +++ b/testbot/lib/WineTestBot/CGI/PageBase.pm @@ -397,6 +397,17 @@ sub GetPageTitle($$) return $Title; }
+sub GenerateImportJS($$) +{ + my ($self, $Filename) = @_; + + if (!$self->{js}->{$Filename}) + { + print "<script type='text/javascript' src='$Filename'></script>\n"; + $self->{js}->{$Filename} = 1; + } +} + sub GenerateHttpHeaders($) { my ($self) = @_;
Signed-off-by: Francois Gouget fgouget@codeweavers.com --- testbot/lib/ObjectModel/CGI/Table.pm | 84 ++++++++++++++++++++++++++++ testbot/web/Submit.pl | 26 ++------- testbot/web/js/table.js | 26 +++++++++ 3 files changed, 116 insertions(+), 20 deletions(-) create mode 100644 testbot/lib/ObjectModel/CGI/Table.pm create mode 100644 testbot/web/js/table.js
diff --git a/testbot/lib/ObjectModel/CGI/Table.pm b/testbot/lib/ObjectModel/CGI/Table.pm new file mode 100644 index 000000000..b55fa4157 --- /dev/null +++ b/testbot/lib/ObjectModel/CGI/Table.pm @@ -0,0 +1,84 @@ +# -*- Mode: Perl; perl-indent-level: 2; indent-tabs-mode: nil -*- +# Provides a wrapper for the table JavaScript code. +# +# Copyright 2022 Francois Gouget +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +use strict; + +package ObjectModel::CGI::Table; + +use Exporter 'import'; +our @EXPORT = qw(GetTableJSFile GenerateMasterCheckbox); + + +=pod +=over 12 + +=item C<GetTableJSFile()> + +Returns the path to the file containing the table JavaScript code. + +=back +=cut + +sub GetTableJSFile() +{ + return "/js/table.js"; +} + + +=pod +=over 12 + +=item C<GenerateMasterCheckbox()> + +Generates a master checkbox that changes all the checkboxes with the specified +'cbgroup' value. + +=over + +=item CbGroup +A string identifying this group of checkboxes. + +=item Checked +True if the initial state should be checked. + +=item Attrs +A string containing extra attributes to be inserted in this master checkbox +tag. It should not contain the type, checked and onchange attributes. + +=back +=back +=cut + +sub GenerateMasterCheckbox($;$$) +{ + my ($CbGroup, $Checked, $Attrs) = @_; + + $Attrs ||= ""; + $Checked = $Checked ? " checked" : ""; + print <<EOF; +<script type='text/javascript'> +<!-- +// Only add the master checkbox if JavaScript is enabled +document.write("<input$Attrs type='checkbox' onchange='SetCheckboxes(this, "$CbGroup");'$Checked>"); +//--> +</script> +EOF +} + +1; diff --git a/testbot/web/Submit.pl b/testbot/web/Submit.pl index 8a1cc3c1d..cf00ed53d 100644 --- a/testbot/web/Submit.pl +++ b/testbot/web/Submit.pl @@ -30,6 +30,8 @@ use POSIX qw(:fcntl_h); # For SEEK_XXX
use ObjectModel::BasicPropertyDescriptor; use ObjectModel::EnumPropertyDescriptor; +use ObjectModel::CGI::Table; + use WineTestBot::Branches; use WineTestBot::Config; use WineTestBot::Engine::Notify; @@ -773,11 +775,12 @@ sub GenerateFields($) if ($self->{Page} == 2 or $self->{Page} == 4) { $self->_GenerateStateField("ShowAll"); + $self->GenerateImportJS(GetTableJSFile()); print "<div class='CollectionBlock'><table>\n"; print "<thead><tr><th class='Record'>";
# Check which VMs are selected and set the master default - my $MasterChecked = " checked"; + my $MasterChecked = 1; foreach my $VMRow (@{$self->{VMRows}}) { next if ($VMRow->{Incompatible}); @@ -793,27 +796,10 @@ sub GenerateFields($) { $VMRow->{Checked} = 1; } - $MasterChecked = "" if (!$VMRow->{Checked}); + $MasterChecked = 0 if (!$VMRow->{Checked}); }
- # Add a "Toggle All" pseudo action - print <<EOF; -<script type='text/javascript'> -<!-- -function SetAllVMCBs(master) -{ - var vmcbs = document.getElementsByClassName("vmcb"); - for (var i = 0; i < vmcbs.length; i++) - { - vmcbs[i].checked = master.checked; - } -} - -// Only put the JavaScript checkbox if JavaScript is enabled -document.write("<input type='checkbox' onchange='SetAllVMCBs(this);'$MasterChecked/>"); -//--> -</script> -EOF + GenerateMasterCheckbox("vmcb", $MasterChecked); print "</th>\n"; print "<th class='Record'>VM Name</th>\n"; print "<th class='Record'>Options</th>\n"; diff --git a/testbot/web/js/table.js b/testbot/web/js/table.js new file mode 100644 index 000000000..350dd8453 --- /dev/null +++ b/testbot/web/js/table.js @@ -0,0 +1,26 @@ +/* Copyright 2022 Francois Gouget + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +"use strict"; + +function SetCheckboxes(master, group) +{ + var cbs = document.getElementsByClassName(group); + for (var i = 0; i < cbs.length; i++) + { + cbs[i].checked = master.checked; + } +}
The master checkbox is automatically checked / unchecked when the other checkboxes are. This also removes the need to figure out what the initial state of the master checkbox should be. And it simplifies the master checkbox HTML code.
Signed-off-by: Francois Gouget fgouget@codeweavers.com --- testbot/lib/ObjectModel/CGI/Table.pm | 22 ++++--------- testbot/web/Submit.pl | 6 ++-- testbot/web/js/table.js | 49 ++++++++++++++++++++++++---- 3 files changed, 52 insertions(+), 25 deletions(-)
diff --git a/testbot/lib/ObjectModel/CGI/Table.pm b/testbot/lib/ObjectModel/CGI/Table.pm index b55fa4157..1e33d7879 100644 --- a/testbot/lib/ObjectModel/CGI/Table.pm +++ b/testbot/lib/ObjectModel/CGI/Table.pm @@ -52,33 +52,25 @@ Generates a master checkbox that changes all the checkboxes with the specified =over
=item CbGroup -A string identifying this group of checkboxes. +A string identifying this group of checkboxes. The 'cbgroup' attribute of all +checkboxes in this group must be set to this value:
-=item Checked -True if the initial state should be checked. + <input type='checkbox' cbgroup='$CbGroup' name='...'>
=item Attrs A string containing extra attributes to be inserted in this master checkbox -tag. It should not contain the type, checked and onchange attributes. +tag. It should not contain the type and hidden attributes.
=back =back =cut
-sub GenerateMasterCheckbox($;$$) +sub GenerateMasterCheckbox($;$) { - my ($CbGroup, $Checked, $Attrs) = @_; + my ($CbGroup, $Attrs) = @_;
$Attrs ||= ""; - $Checked = $Checked ? " checked" : ""; - print <<EOF; -<script type='text/javascript'> -<!-- -// Only add the master checkbox if JavaScript is enabled -document.write("<input$Attrs type='checkbox' onchange='SetCheckboxes(this, "$CbGroup");'$Checked>"); -//--> -</script> -EOF + print "<input$Attrs type='checkbox' hidden='true' mcbgroup='$CbGroup'>\n"; }
1; diff --git a/testbot/web/Submit.pl b/testbot/web/Submit.pl index cf00ed53d..9292d387b 100644 --- a/testbot/web/Submit.pl +++ b/testbot/web/Submit.pl @@ -780,7 +780,6 @@ sub GenerateFields($) print "<thead><tr><th class='Record'>";
# Check which VMs are selected and set the master default - my $MasterChecked = 1; foreach my $VMRow (@{$self->{VMRows}}) { next if ($VMRow->{Incompatible}); @@ -796,10 +795,9 @@ sub GenerateFields($) { $VMRow->{Checked} = 1; } - $MasterChecked = 0 if (!$VMRow->{Checked}); }
- GenerateMasterCheckbox("vmcb", $MasterChecked); + GenerateMasterCheckbox("vmcb"); print "</th>\n"; print "<th class='Record'>VM Name</th>\n"; print "<th class='Record'>Options</th>\n"; @@ -815,7 +813,7 @@ sub GenerateFields($) my $VM = $VMRow->{VM};
print "<tr class='", ($Even ? "even" : "odd"), - "'><td><input class='vmcb' name='$VMRow->{Field}' type='checkbox'"; + "'><td><input cbgroup='vmcb' name='$VMRow->{Field}' type='checkbox'"; $Even = !$Even; print " checked='checked'" if ($VMRow->{Checked}); print "/></td>\n"; diff --git a/testbot/web/js/table.js b/testbot/web/js/table.js index 350dd8453..f617912c5 100644 --- a/testbot/web/js/table.js +++ b/testbot/web/js/table.js @@ -16,11 +16,48 @@ */ "use strict";
-function SetCheckboxes(master, group) +var mcb_count; +var mcb_checked; + +function SetCheckboxes(e) +{ + const master = e.target.closest("input"); + const group = master.getAttribute("mcbgroup"); + const selector = 'input[cbgroup="' + group + '"]'; + document.querySelectorAll(selector).forEach(cb => { + cb.checked = master.checked; + }); + mcb_checked[group] = master.checked ? mcb_count[group] : 0; +} + +function UpdateMasterCb(e) +{ + const cb = e.target.closest("input"); + const group = cb.getAttribute("cbgroup"); + mcb_checked[group] += cb.checked ? 1 : -1; + + const master = document.querySelector('input[mcbgroup="' + group + '"]'); + master.checked = (mcb_count[group] == mcb_checked[group]); +} + + +function InitMasterCbs() { - var cbs = document.getElementsByClassName(group); - for (var i = 0; i < cbs.length; i++) - { - cbs[i].checked = master.checked; - } + mcb_count = {}; + mcb_checked = {}; + document.querySelectorAll("input[mcbgroup]").forEach(master => { + const group = master.getAttribute("mcbgroup"); + mcb_count[group] = mcb_checked[group] = 0; + const selector = 'input[cbgroup="' + group + '"]'; + document.querySelectorAll(selector).forEach(cb => { + mcb_count[group]++; + if (cb.checked) mcb_checked[group]++; + cb.addEventListener('click', UpdateMasterCb); + }); + master.checked = (mcb_count[group] == mcb_checked[group]); + master.addEventListener('click', SetCheckboxes); + master.hidden = false; + }); } + +window.addEventListener('load', InitMasterCbs);
This brings the collection blocks in line with the Submit page.
Signed-off-by: Francois Gouget fgouget@codeweavers.com --- This can be tested on the Users, VMs and Branches administrator pages. --- .../lib/ObjectModel/CGI/CollectionBlock.pm | 36 +++++++------------ 1 file changed, 13 insertions(+), 23 deletions(-)
diff --git a/testbot/lib/ObjectModel/CGI/CollectionBlock.pm b/testbot/lib/ObjectModel/CGI/CollectionBlock.pm index 36f1b0188..3e3ee2952 100644 --- a/testbot/lib/ObjectModel/CGI/CollectionBlock.pm +++ b/testbot/lib/ObjectModel/CGI/CollectionBlock.pm @@ -47,9 +47,12 @@ our @EXPORT = qw(new); use POSIX qw(strftime); use URI::Escape;
+use ObjectModel::CGI::Table; use ObjectModel::CGI::ValueFormatter;
+my $Unique; + =pod =over 12
@@ -82,6 +85,7 @@ sub new($$$@) my $self = {Collection => $Collection, EnclosingPage => $EnclosingPage, RW => 1, + Unique => $Unique++, }; $self = bless $self, $class; $self->_initialize(@_); @@ -331,9 +335,12 @@ sub GenerateHeaderRow($$$) my ($self, $Row) = @_;
print "<tr>\n"; - if (@{$Row->{ItemActions}}) + if (@{$Row->{ItemActions}} and $Row->{Rows}) { - print "<th> </th>\n"; + $self->{EnclosingPage}->GenerateImportJS(GetTableJSFile()); + print "<th>"; + GenerateMasterCheckbox("block$self->{Unique}"); + print "</th>\n"; } foreach my $PropertyDescriptor (@{$Row->{PropertyDescriptors}}) { @@ -377,7 +384,7 @@ sub GenerateDataRow($$) if (@{$Row->{ItemActions}}) { print "<td><input name='", $self->SelName($Row->{Item}->GetKey()), - "' type='checkbox' /></td>\n"; + "' type='checkbox' cbgroup='block$self->{Unique}'/></td>\n"; } foreach my $PropertyDescriptor (@{$Row->{PropertyDescriptors}}) { @@ -442,6 +449,7 @@ EOF $self->GenerateFormStart(); $self->GenerateErrorDiv();
+ my $Items = $self->{Collection}->GetSortedItems(); print "<table border='0' cellpadding='5' cellspacing='0' summary='" . "Overview of " . $Collection->GetCollectionName() . "'>\n"; print "<thead>\n"; @@ -450,12 +458,12 @@ EOF DetailsPage => $self->GetDetailsPage(), ItemActions => $self->{RW} ? $self->GetItemActions() : [], Row => 0, # 0 for the header ---> 1 for the first line + Rows => scalar(@$Items), }; $self->GenerateHeaderRow($Row); print "</thead>\n";
print "<tbody>\n"; - my $Items = $self->{Collection}->GetSortedItems(); foreach my $Item (@$Items) { $Row->{Row}++; @@ -473,25 +481,7 @@ EOF
if (@{$Row->{ItemActions}} and @$Items) { - print <<EOF; -<div class='CollectionBlockActions'> -<script type='text/javascript'> -<!-- -function ToggleAll() -{ - for (var i = 0; i < document.forms[0].elements.length; i++) - { - if(document.forms[0].elements[i].type == 'checkbox') - document.forms[0].elements[i].checked = !(document.forms[0].elements[i].checked); - } -} - -// Only put javascript link in document if javascript is enabled -document.write("<a href='javascript:void(0)' onClick='ToggleAll();'>Toggle All<\\\/a> "); -//--> -</script> -EOF - print "For selected ", $self->{Collection}->GetCollectionName() . ":"; + print "<div class='CollectionBlockActions'>For selected ", $self->{Collection}->GetCollectionName() . ":"; foreach my $Action (@{$Row->{ItemActions}}) { print " <input type='submit' name='Action' value='" .