line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package HTML::PopupTreeSelect; |
2
|
1
|
|
|
1
|
|
24797
|
use 5.006; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
47
|
|
3
|
1
|
|
|
1
|
|
6
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
41
|
|
4
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
30
|
|
5
|
|
|
|
|
|
|
|
6
|
1
|
|
|
1
|
|
5
|
use Carp qw(croak); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
84
|
|
7
|
1
|
|
|
1
|
|
1673
|
use HTML::Template 2.6; |
|
1
|
|
|
|
|
18169
|
|
|
1
|
|
|
|
|
1181
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
our $VERSION = "1.6"; |
10
|
|
|
|
|
|
|
our $TEMPLATE_SRC; |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
=head1 NAME |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
HTML::PopupTreeSelect - HTML popup tree widget |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
=head1 SYNOPSIS |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
use HTML::PopupTreeSelect; |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
# setup your tree as a hash structure. This one sets up a tree like: |
21
|
|
|
|
|
|
|
# |
22
|
|
|
|
|
|
|
# - Root |
23
|
|
|
|
|
|
|
# - Top Category 1 |
24
|
|
|
|
|
|
|
# - Sub Category 1 |
25
|
|
|
|
|
|
|
# - Sub Category 2 |
26
|
|
|
|
|
|
|
# - Top Category 2 |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
my $data = { label => "Root", |
29
|
|
|
|
|
|
|
value => 0, |
30
|
|
|
|
|
|
|
children => [ |
31
|
|
|
|
|
|
|
{ label => "Top Category 1", |
32
|
|
|
|
|
|
|
value => 1, |
33
|
|
|
|
|
|
|
children => [ |
34
|
|
|
|
|
|
|
{ label => "Sub Category 1", |
35
|
|
|
|
|
|
|
value => 2 |
36
|
|
|
|
|
|
|
}, |
37
|
|
|
|
|
|
|
{ label => "Sub Category 2", |
38
|
|
|
|
|
|
|
value => 3 |
39
|
|
|
|
|
|
|
}, |
40
|
|
|
|
|
|
|
], |
41
|
|
|
|
|
|
|
}, |
42
|
|
|
|
|
|
|
{ label => "Top Category 2", |
43
|
|
|
|
|
|
|
value => 4 |
44
|
|
|
|
|
|
|
}, |
45
|
|
|
|
|
|
|
] |
46
|
|
|
|
|
|
|
}; |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
# create your HTML tree select widget. This one will call a |
50
|
|
|
|
|
|
|
# javascript function 'select_category(value)' when the user selects |
51
|
|
|
|
|
|
|
# a category. |
52
|
|
|
|
|
|
|
my $select = HTML::PopupTreeSelect->new(name => 'category', |
53
|
|
|
|
|
|
|
data => $data, |
54
|
|
|
|
|
|
|
title => 'Select a Category', |
55
|
|
|
|
|
|
|
button_label => 'Choose', |
56
|
|
|
|
|
|
|
onselect => 'select_category'); |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
# include it in your HTML page, for example using HTML::Template: |
59
|
|
|
|
|
|
|
$template->param(category_select => $select->output); |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
=head1 DESCRIPTION |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
This module creates an HTML popup tree selector. The HTML and |
64
|
|
|
|
|
|
|
Javascript produced will work in Mozilla 1+ (Netscape 6+) on all |
65
|
|
|
|
|
|
|
operating systems, Microsoft IE 5+ and Safari 1.0. For an example, |
66
|
|
|
|
|
|
|
visit this page: |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
http://sam.tregar.com/html-popuptreeselect/example.html |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
I based the design for this widget on the xTree widget from WebFX. |
71
|
|
|
|
|
|
|
You can find it here: |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
http://webfx.eae.net/dhtml/xtree/ |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
This module is used to provide the category chooser in Krang, an open |
76
|
|
|
|
|
|
|
source content management system. You can find out more about Krang |
77
|
|
|
|
|
|
|
here: |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
http://krang.sf.net |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
=head1 INSTALLATION |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
To use this module you'll need to copy the contents of the images/ |
84
|
|
|
|
|
|
|
directory in the module distribution into a place where your webserver |
85
|
|
|
|
|
|
|
can serve them. If that's not the same place your CGI will run from |
86
|
|
|
|
|
|
|
then you need to set the image_path parameter when you call new(). |
87
|
|
|
|
|
|
|
See below for details. |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
=head1 INTERFACE |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
=head2 new() |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
new(), is used to build a new HTML selector. You call it with a |
94
|
|
|
|
|
|
|
description of the tree to display and get back an object. Call it |
95
|
|
|
|
|
|
|
with following parameters: |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
=over |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
=item name |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
A unique name for the tree selector. You can have multiple tree |
102
|
|
|
|
|
|
|
selectors on a page, but they must have unique names. Must be |
103
|
|
|
|
|
|
|
alpha-numeric and begin with a letter. |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
=item data |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
This must be a hash reference (or an array reference of these hash |
108
|
|
|
|
|
|
|
references, if there are multiple "root" categories) containing |
109
|
|
|
|
|
|
|
the following keys: |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
=over |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
=item label (required) |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
The textual label for this node. |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
=item value (required) |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
The value passed to the onselect handler or set in the form_field when |
120
|
|
|
|
|
|
|
the user selects this node. |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
=item open (optional) |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
If set to 1 this node will start open (showing its children). By |
125
|
|
|
|
|
|
|
default all nodes start closed. |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
=item inactive (optional) |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
If set to 1 this node will not be selectable. It will not appear as a |
130
|
|
|
|
|
|
|
link in the widget and clicking on the label will have no effect. |
131
|
|
|
|
|
|
|
However, if it has children they will still be accessible. |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
=item children (optional) |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
The 'children' key may point to an array of hashes with the same keys. |
136
|
|
|
|
|
|
|
This is the tree structure which will be displayed in the tree |
137
|
|
|
|
|
|
|
selector. |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
=back |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
See SYNOPSIS above for an example of a valid data structure. |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
=item title |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
The title of the window which pops up. |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
=item button_label (optional) |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
The widget pops up when the user presses a button. This field gives |
150
|
|
|
|
|
|
|
the label for the button. Defaults to "Choose". |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
=item onselect (optional) |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
Specifies a Javascript function that will be called when an item in |
155
|
|
|
|
|
|
|
the tree is selected. Recieves the value of the item as a single |
156
|
|
|
|
|
|
|
argument. The default is for nothing to happen. |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
=item form_field (optional) |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
Specifies a form field to recieve the value of the selected item. |
161
|
|
|
|
|
|
|
This provides a no-javascript means to use this widget (although the |
162
|
|
|
|
|
|
|
widget itself, of course, uses great gobs of javascript). |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
=item form_field_form (optional) |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
Specifies the form in which to find the C specified. If |
167
|
|
|
|
|
|
|
not included the first form on the page will be used. |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
=item include_css (optional) |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
Set this to 0 and the default CSS will not be included in the widget |
172
|
|
|
|
|
|
|
output. This allows you to include your own CSS which will be used by |
173
|
|
|
|
|
|
|
your widget. Modifying the CSS will allow you to control the fonts, |
174
|
|
|
|
|
|
|
colors and spacing in the output widget. |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
If you run the widget with include_css set to 1 then you can use that |
177
|
|
|
|
|
|
|
output as a base on which to make changes. |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
=item resizable (optional) |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
Set this to 1 and the default widget output will not be resizable. If |
182
|
|
|
|
|
|
|
you run the widget with resizable set to 1 then default output will |
183
|
|
|
|
|
|
|
have a bar at the bottom which allows it to be resized by dragging. |
184
|
|
|
|
|
|
|
Defaults to 0. |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
=item image_path (optional) |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
Set this to the URL to the images for the widget. These files should |
189
|
|
|
|
|
|
|
be copied from the images directory in the module distribution into a |
190
|
|
|
|
|
|
|
place where your webserver can reach them. By default this is empty |
191
|
|
|
|
|
|
|
and the widget expects to find images in the current directory. |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
=item width (optional) |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
Set this to the width of the popup window. Defaults to 200. |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
=item height (optional) |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
Set this to the height of the tree box inside the window. This |
200
|
|
|
|
|
|
|
defaults to 0 which allows the chooser to grow as the tree expands. |
201
|
|
|
|
|
|
|
If you set this option you'll probably want to set the |
202
|
|
|
|
|
|
|
C option as well. |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
=item scrollbars (optional) |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
If set to 1 the chooser will have a fixed size (specified by width and |
207
|
|
|
|
|
|
|
height) and show scrollbars inside the tree area. |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
=item hide_selects (optional) |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
This option will cause the chooser to dynamically hide select boxes on |
212
|
|
|
|
|
|
|
the page when the chooser opens. This is necessary in order to avoid |
213
|
|
|
|
|
|
|
the select boxes showing through the chooser under Windows in both IE |
214
|
|
|
|
|
|
|
and Mozilla (to a lesser extent). This defaults to 1. For a detailed |
215
|
|
|
|
|
|
|
explanation of the problem, see this page: |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
http://www.webreference.com/dhtml/diner/seethru/ |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
=item hide_textareas (optional) |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
This option will cause the chooser to dynamically hide textareas on |
222
|
|
|
|
|
|
|
the page when the chooser opens. This is necessary to workaround a |
223
|
|
|
|
|
|
|
bug in Netscape 6.0 through 7.0 in which buttons hovering over |
224
|
|
|
|
|
|
|
textareas are not clickable. This defect is fixed in version 7.1 and |
225
|
|
|
|
|
|
|
later. This option defaults to 0, since this problem only affects |
226
|
|
|
|
|
|
|
older browsers. |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
=item parent_var (optional) |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
This option includes a 'parent' loop in the template data used to |
231
|
|
|
|
|
|
|
construct the widget's HTML. It's not used by the default template, |
232
|
|
|
|
|
|
|
so it defaults to 0. Set to 1 to use this variable in your own |
233
|
|
|
|
|
|
|
template via sub-classing. |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
=back |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
=head1 output() |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
Call output() to get HTML from the widget object to include in your |
240
|
|
|
|
|
|
|
page. |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
=cut |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
=head1 SUBCLASSING |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
HTML::PopupTreeSelect can be subclassed, for the purposes of -- for |
247
|
|
|
|
|
|
|
example -- using a different template engine to generate the HTML. |
248
|
|
|
|
|
|
|
Here's one brief example, using the Template engine: |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
package My::PopupTreeSelect; |
251
|
|
|
|
|
|
|
use Template; |
252
|
|
|
|
|
|
|
use base 'HTML::PopupTreeSelect'; |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
sub output { |
255
|
|
|
|
|
|
|
my($self) = @_; |
256
|
|
|
|
|
|
|
return $self->SUPER::output(Template->new); |
257
|
|
|
|
|
|
|
} |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
sub _output_generate { |
260
|
|
|
|
|
|
|
my($self, $template, $param) = @_; |
261
|
|
|
|
|
|
|
my $output; |
262
|
|
|
|
|
|
|
$template->process(\$MY_TEMPLATE_SRC, $param, \$output); |
263
|
|
|
|
|
|
|
return $output; |
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
Of course, $MY_TEMPLATE_SRC will need to be provided, too. |
267
|
|
|
|
|
|
|
$HTML::PopupTreeSelect::TEMPLATE_SRC is a global variable, |
268
|
|
|
|
|
|
|
so it may be modified to your liking, or your own template |
269
|
|
|
|
|
|
|
data can be provided to your own template generator method. |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
=head1 CAVEATS |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
=over 4 |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
=item * |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
The javascript used to implement the widget needs control over the |
278
|
|
|
|
|
|
|
global document.onmousedown, document.onmousemove and |
279
|
|
|
|
|
|
|
document.onmouseup handlers. This means that it's unlikely to play |
280
|
|
|
|
|
|
|
nice with other DHTML on the same page. |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
=back |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
=head1 TODO |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
Here are some possible directions for future development. Send me a |
287
|
|
|
|
|
|
|
patch for one of these and you're guaranteed a place in F. |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
=over |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
=item * |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
Allow each node to specify its own icon. Right now every node uses |
294
|
|
|
|
|
|
|
C and C. |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
=back |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
=head1 BUGS |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
I know of no bugs in this module. If you find one, please file a bug |
301
|
|
|
|
|
|
|
report at: |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
http://rt.cpan.org |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
Alternately you can email me directly at C. Please |
306
|
|
|
|
|
|
|
include the version of the module and a complete test case that |
307
|
|
|
|
|
|
|
demonstrates the bug. |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
Copyright (C) 2003, 2004 Sam Tregar |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify |
314
|
|
|
|
|
|
|
it under the same terms as Perl 5 itself. |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
=head1 AUTHOR |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
Sam Tregar |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
=cut |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
sub new { |
323
|
2
|
|
|
2
|
1
|
5462
|
my $pkg = shift; |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
# setup defaults and get parameters |
326
|
2
|
|
|
|
|
33
|
my $self = bless({ button_label => 'Choose', |
327
|
|
|
|
|
|
|
height => 0, |
328
|
|
|
|
|
|
|
width => 300, |
329
|
|
|
|
|
|
|
scrollbars => 0, |
330
|
|
|
|
|
|
|
hide_selects => 1, |
331
|
|
|
|
|
|
|
hide_textareas=> 0, |
332
|
|
|
|
|
|
|
indent_width => 25, |
333
|
|
|
|
|
|
|
include_css => 1, |
334
|
|
|
|
|
|
|
resizable => 0, |
335
|
|
|
|
|
|
|
image_path => ".", |
336
|
|
|
|
|
|
|
parent_var => 0, |
337
|
|
|
|
|
|
|
@_, |
338
|
|
|
|
|
|
|
}, $pkg); |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
# fix up image_path to always end in a / |
341
|
2
|
50
|
|
|
|
19
|
$self->{image_path} .= "/" unless $self->{image_path} =~ m!/$!; |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
# check required params |
344
|
2
|
|
|
|
|
5
|
foreach my $req (qw(name data title)) { |
345
|
6
|
50
|
|
|
|
19
|
croak("Missing required parameter '$req'") unless exists $self->{$req}; |
346
|
|
|
|
|
|
|
} |
347
|
|
|
|
|
|
|
|
348
|
2
|
|
|
|
|
6
|
return $self; |
349
|
|
|
|
|
|
|
} |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
sub output { |
352
|
2
|
|
|
2
|
0
|
661
|
my($self, $template) = @_; |
353
|
2
|
|
33
|
|
|
23
|
$template ||= HTML::Template->new(scalarref => \$TEMPLATE_SRC, |
354
|
|
|
|
|
|
|
die_on_bad_params => 0, |
355
|
|
|
|
|
|
|
global_vars => 1, |
356
|
|
|
|
|
|
|
); |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
# build node loop |
359
|
2
|
|
|
|
|
17410
|
my @loop; |
360
|
2
|
|
|
|
|
14
|
$self->_output_node(node => $self->{data}, |
361
|
|
|
|
|
|
|
loop => \@loop, |
362
|
|
|
|
|
|
|
); |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
# setup template parameters |
365
|
32
|
|
|
|
|
90
|
my %param = (loop => \@loop, |
366
|
2
|
|
|
|
|
8
|
map { ($_, $self->{$_}) } qw(name height width |
367
|
|
|
|
|
|
|
indent_width onselect |
368
|
|
|
|
|
|
|
form_field form_field_form |
369
|
|
|
|
|
|
|
button_label |
370
|
|
|
|
|
|
|
button_image title |
371
|
|
|
|
|
|
|
include_css resizable |
372
|
|
|
|
|
|
|
image_path scrollbars |
373
|
|
|
|
|
|
|
hide_selects hide_textareas |
374
|
|
|
|
|
|
|
)); |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
# get output for the widget |
377
|
2
|
|
|
|
|
8
|
my $output; |
378
|
2
|
50
|
|
|
|
28
|
if ($self->can('_output_generate')) { |
379
|
0
|
|
|
|
|
0
|
$output = $self->_output_generate($template, \%param); |
380
|
|
|
|
|
|
|
} else { |
381
|
2
|
|
|
|
|
17
|
$template->param(%param); |
382
|
2
|
|
|
|
|
433
|
$output = $template->output; |
383
|
|
|
|
|
|
|
} |
384
|
|
|
|
|
|
|
|
385
|
2
|
|
|
|
|
16697
|
return $output; |
386
|
|
|
|
|
|
|
} |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
# recursively add nodes to the output loop |
389
|
|
|
|
|
|
|
sub _output_node { |
390
|
11
|
|
|
11
|
|
146
|
my ($self, %arg) = @_; |
391
|
|
|
|
|
|
|
|
392
|
11
|
|
|
|
|
13
|
my @nodes; |
393
|
11
|
100
|
|
|
|
33
|
if (ref $arg{node} eq 'ARRAY') { |
394
|
1
|
|
|
|
|
2
|
@nodes = @{$arg{node}}; |
|
1
|
|
|
|
|
3
|
|
395
|
|
|
|
|
|
|
} else { |
396
|
10
|
|
|
|
|
22
|
@nodes = ($arg{node}); |
397
|
|
|
|
|
|
|
} |
398
|
|
|
|
|
|
|
|
399
|
11
|
|
|
|
|
17
|
for my $node (@nodes) { |
400
|
12
|
|
|
|
|
23
|
my $id = next_id(); |
401
|
|
|
|
|
|
|
|
402
|
12
|
50
|
66
|
|
|
14
|
push @{$arg{loop}}, { label => $node->{label}, |
|
12
|
50
|
|
|
|
117
|
|
|
|
100
|
|
|
|
|
|
403
|
|
|
|
|
|
|
value => $node->{value}, |
404
|
|
|
|
|
|
|
id => $id, |
405
|
|
|
|
|
|
|
open => $node->{open} ? 1 : 0, |
406
|
|
|
|
|
|
|
inactive => $node->{inactive} ? 1 : 0, |
407
|
|
|
|
|
|
|
($self->{parent_var} ? |
408
|
|
|
|
|
|
|
(parent => [ $arg{parent} || () ]) : |
409
|
|
|
|
|
|
|
()), |
410
|
|
|
|
|
|
|
}; |
411
|
|
|
|
|
|
|
|
412
|
12
|
100
|
66
|
|
|
67
|
if ($node->{children} and @{$node->{children}}) { |
|
5
|
|
|
|
|
24
|
|
413
|
5
|
|
|
|
|
12
|
$arg{loop}[-1]{has_children} = 1; |
414
|
5
|
|
|
|
|
6
|
for my $child (@{$node->{children}}) { |
|
5
|
|
|
|
|
12
|
|
415
|
9
|
|
|
|
|
36
|
$self->_output_node(node => $child, |
416
|
|
|
|
|
|
|
parent => $node, |
417
|
|
|
|
|
|
|
loop => $arg{loop}, |
418
|
|
|
|
|
|
|
); |
419
|
|
|
|
|
|
|
} |
420
|
5
|
|
|
|
|
9
|
push @{$arg{loop}}, { end_block => 1 }; |
|
5
|
|
|
|
|
26
|
|
421
|
|
|
|
|
|
|
} |
422
|
|
|
|
|
|
|
} |
423
|
|
|
|
|
|
|
} |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
{ |
426
|
|
|
|
|
|
|
my $id = 1; |
427
|
12
|
|
|
12
|
0
|
22
|
sub next_id { $id++ } |
428
|
|
|
|
|
|
|
} |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
$TEMPLATE_SRC = <
|
431
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
|
765
|
|
|
|
|
|
|
|
766
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
|
768
|
|
|
|
|
|
|
|
769
|
|
|
|
|
|
|
|
770
|
|
|
|
|
|
|
|
771
|
|
|
|
|
|
|
|
772
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
ondblclick="_toggle_expand()" onclick="_toggle_select(, '')"> |
774
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
onclick="_toggle_select(, '')"> |
776
|
|
|
|
|
|
|
|
777
|
|
|
|
|
|
|
|
778
|
|
|
|
|
|
|
|
779
|
|
|
|
|
|
|
|
780
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
|
782
|
|
|
|
|
|
|
|
783
|
|
|
|
|
|
|
|
784
|
|
|
|
|
|
|
|
785
|
|
|
|
|
|
|
|
786
|
|
|
|
|
|
|
|
787
|
|
|
|
|
|
|
|
788
|
|
|
|
|
|
|
|
789
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
|
791
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
|
793
|
|
|
|
|
|
|
|
794
|
|
|
|
|
|
|
|
795
|
|
|
|
|
|
|
|
796
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
END |
798
|
|
|
|
|
|
|
|
799
|
|
|
|
|
|
|
1; |