blob: 90966a5099260bc0da76ae666cb0c417d8a5e1a9 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
<%doc>
A tristate checkbox (with three values: true, false, and null).
Internally, this creates a checkbox, coupled via javascript to a hidden
field that actually contains the value. For now, the only values these
can have are 1, -1, and empty. Clicking the checkbox cycles between them.
For compatibility with regular checkboxes, empty is the false state and
-1 is the indeterminate state.
Displaying these is a problem. "indeterminate" is a standard HTML5 attribute
but some browsers display it in unhelpful ways (e.g. Firefox slightly grays
the checkbox, approximately #dddddd), and checkboxes ignore nearly all CSS
styling.
</%doc>
<%shared>
my $init = 0;
</%shared>
% if ( !$init ) {
% $init = 1;
<STYLE>
input.partial {
position: absolute;
opacity: 0;
z-index: 1;
}
input.partial + label::before {
position: relative;
content: "\2610";
}
input.partial:checked + label::before {
content: "\2611";
}
input.partial:indeterminate + label::before {
content: "\2612";
}
</STYLE>
<SCRIPT TYPE="text/javascript">
function tristate_onclick() {
var checkbox = this;
var input = checkbox.input;
if ( input.value == "" ) { // false -> true
input.value = "1";
checkbox.checked = true;
checkbox.indeterminate = false;
} else if ( input.value == "1" ) { // true -> indeterminate
input.value = "-1";
checkbox.checked = false;
checkbox.indeterminate = true;
} else if ( input.value == "-1" ) { // indeterminate -> false
input.value = "";
checkbox.checked = false;
checkbox.indeterminate = false;
}
}
var tristates = [];
var tristate_boxes = [];
window.onload = function() { // don't do this until all of the checkboxes exist
%# tristates = document.getElementsByClassName('tristate'); # curse you, IE8
var all_inputs = document.getElementsByTagName('input');
for (var i=0; i < all_inputs.length; i++) {
if ( all_inputs[i].className == 'tristate' ) {
tristates.push(all_inputs[i]);
}
}
for (var i=0; i < tristates.length; i++) {
tristate_boxes[i] =
document.getElementById('checkbox_' + tristates[i].name);
// make sure they can find each other
tristate_boxes[i].input = tristates[i];
tristates[i].checkbox = tristate_boxes[i];
// set event handler
tristate_boxes[i].onclick = tristate_onclick;
// set initial value
if ( tristates[i].value == "-1" ) {
tristate_boxes[i].indeterminate = true
}
if ( tristates[i].value == "1" ) {
tristate_boxes[i].checked = true;
}
}
};
</SCRIPT>
% } # end of $init
<INPUT TYPE="hidden" NAME="<% $opt{field} %>"
ID="<% $opt{id} %>"
VALUE="<% $curr_value %>"
CLASS="tristate">
<INPUT TYPE="checkbox" ID="checkbox_<%$opt{field}%>" CLASS="partial">
<LABEL />
<%init>
my %opt = @_;
# might be useful but I'm not implementing it yet
#my $onchange = $opt{'onchange'}
# ? 'onChange="'. $opt{'onchange'}. '(this)"'
# : '';
$opt{'id'} ||= 'hidden_'.$opt{'field'};
my $curr_value = '-1';
if (exists $opt{curr_value}) {
$curr_value = $opt{curr_value};
$curr_value = '' unless $curr_value eq '-1' or $curr_value eq '1';
}
</%init>
|