Filename | /var/www/foswiki11/lib/Foswiki/Form/FieldDefinition.pm |
Statements | Executed 7 statements in 1.27ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 16µs | 28µs | BEGIN@18 | Foswiki::Form::FieldDefinition::
1 | 1 | 1 | 11µs | 16µs | BEGIN@19 | Foswiki::Form::FieldDefinition::
1 | 1 | 1 | 10µs | 23µs | BEGIN@20 | Foswiki::Form::FieldDefinition::
0 | 0 | 0 | 0s | 0s | cssClasses | Foswiki::Form::FieldDefinition::
0 | 0 | 0 | 0s | 0s | finish | Foswiki::Form::FieldDefinition::
0 | 0 | 0 | 0s | 0s | getDefaultValue | Foswiki::Form::FieldDefinition::
0 | 0 | 0 | 0s | 0s | isEditable | Foswiki::Form::FieldDefinition::
0 | 0 | 0 | 0s | 0s | isMandatory | Foswiki::Form::FieldDefinition::
0 | 0 | 0 | 0s | 0s | isMultiValued | Foswiki::Form::FieldDefinition::
0 | 0 | 0 | 0s | 0s | isTextMergeable | Foswiki::Form::FieldDefinition::
0 | 0 | 0 | 0s | 0s | new | Foswiki::Form::FieldDefinition::
0 | 0 | 0 | 0s | 0s | populateMetaFromQueryData | Foswiki::Form::FieldDefinition::
0 | 0 | 0 | 0s | 0s | renderForDisplay | Foswiki::Form::FieldDefinition::
0 | 0 | 0 | 0s | 0s | renderForEdit | Foswiki::Form::FieldDefinition::
0 | 0 | 0 | 0s | 0s | renderHidden | Foswiki::Form::FieldDefinition::
0 | 0 | 0 | 0s | 0s | stringify | Foswiki::Form::FieldDefinition::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | # See bottom of file for license and copyright information | ||||
2 | # base class for all form field types | ||||
3 | |||||
4 | =begin TML | ||||
5 | |||||
6 | ---+ package Foswiki::Form::FieldDefinition | ||||
7 | |||||
8 | Base class of all field definition classes. | ||||
9 | |||||
10 | Type-specific classes are derived from this class to define specific | ||||
11 | per-type behaviours. This class also provides default behaviours for when | ||||
12 | a specific type cannot be loaded. | ||||
13 | |||||
14 | =cut | ||||
15 | |||||
16 | package Foswiki::Form::FieldDefinition; | ||||
17 | |||||
18 | 2 | 31µs | 2 | 41µs | # spent 28µs (16+13) within Foswiki::Form::FieldDefinition::BEGIN@18 which was called:
# once (16µs+13µs) by Foswiki::Form::BEGIN@42 at line 18 # spent 28µs making 1 call to Foswiki::Form::FieldDefinition::BEGIN@18
# spent 12µs making 1 call to strict::import |
19 | 2 | 24µs | 2 | 22µs | # spent 16µs (11+5) within Foswiki::Form::FieldDefinition::BEGIN@19 which was called:
# once (11µs+5µs) by Foswiki::Form::BEGIN@42 at line 19 # spent 16µs making 1 call to Foswiki::Form::FieldDefinition::BEGIN@19
# spent 5µs making 1 call to warnings::import |
20 | 2 | 1.21ms | 2 | 36µs | # spent 23µs (10+13) within Foswiki::Form::FieldDefinition::BEGIN@20 which was called:
# once (10µs+13µs) by Foswiki::Form::BEGIN@42 at line 20 # spent 23µs making 1 call to Foswiki::Form::FieldDefinition::BEGIN@20
# spent 13µs making 1 call to Assert::import |
21 | |||||
22 | =begin TML | ||||
23 | |||||
24 | ---++ ClassMethod new(%...) | ||||
25 | |||||
26 | Construct a new FieldDefinition. Parameters are passed in a hash. See | ||||
27 | Form.pm for how it is called. Subclasses should pass @_ on to this class. | ||||
28 | |||||
29 | =cut | ||||
30 | |||||
31 | sub new { | ||||
32 | my $class = shift; | ||||
33 | my %attrs = @_; | ||||
34 | ASSERT( $attrs{session} ) if DEBUG; | ||||
35 | |||||
36 | $attrs{name} ||= ''; | ||||
37 | $attrs{attributes} ||= ''; | ||||
38 | $attrs{type} ||= ''; # default | ||||
39 | $attrs{size} ||= ''; | ||||
40 | $attrs{size} =~ s/^\s*//; | ||||
41 | $attrs{size} =~ s/\s*$//; | ||||
42 | |||||
43 | return bless( \%attrs, $class ); | ||||
44 | } | ||||
45 | |||||
46 | =begin TML | ||||
47 | |||||
48 | ---++ ObjectMethod finish() | ||||
49 | Break circular references. | ||||
50 | |||||
51 | =cut | ||||
52 | |||||
53 | # Note to developers; please undef *all* fields in the object explicitly, | ||||
54 | # whether they are references or not. That way this method is "golden | ||||
55 | # documentation" of the live fields in the object. | ||||
56 | sub finish { | ||||
57 | my $this = shift; | ||||
58 | |||||
59 | undef $this->{name}; | ||||
60 | undef $this->{attributes}; | ||||
61 | undef $this->{type}; | ||||
62 | undef $this->{size}; | ||||
63 | undef $this->{session}; | ||||
64 | } | ||||
65 | |||||
66 | =begin TML | ||||
67 | |||||
68 | ---++ isEditable() -> $boolean | ||||
69 | |||||
70 | Is the field type editable? Labels aren't, for example. Subclasses may need | ||||
71 | to redefine this. | ||||
72 | |||||
73 | =cut | ||||
74 | |||||
75 | sub isEditable { 1 } | ||||
76 | |||||
77 | =begin TML | ||||
78 | |||||
79 | ---++ isMultiValued() -> $boolean | ||||
80 | |||||
81 | Is the field type multi-valued (i.e. does it store multiple values)? | ||||
82 | Subclasses may need to redefine this. | ||||
83 | |||||
84 | =cut | ||||
85 | |||||
86 | sub isMultiValued { 0 } | ||||
87 | |||||
88 | =begin TML | ||||
89 | |||||
90 | ---++ isTextMergeable() -> $boolean | ||||
91 | |||||
92 | Is this field type mergeable using a conventional text merge? | ||||
93 | |||||
94 | =cut | ||||
95 | |||||
96 | # can't merge multi-valued fields (select+multi, checkbox) | ||||
97 | sub isTextMergeable { return !shift->isMultiValued() } | ||||
98 | |||||
99 | =begin TML | ||||
100 | |||||
101 | ---++ isMandatory() -> $boolean | ||||
102 | |||||
103 | Is this field mandatory (required)? | ||||
104 | |||||
105 | =cut | ||||
106 | |||||
107 | sub isMandatory { return shift->{attributes} =~ /M/ } | ||||
108 | |||||
109 | =begin TML | ||||
110 | |||||
111 | ---++ renderForEdit( $topicObject, $value ) -> ($col0html, $col1html) | ||||
112 | =$topicObject= - the topic being edited | ||||
113 | Render the field for editing. Returns two chunks of HTML; the | ||||
114 | =$col0html= is appended to the HTML for the first column in the | ||||
115 | form table, and the =$col1html= is used as the content of the second column. | ||||
116 | |||||
117 | =cut | ||||
118 | |||||
119 | sub renderForEdit { | ||||
120 | my ( $this, $topicObject, $value ) = @_; | ||||
121 | |||||
122 | # Treat like text, make it reasonably long, add a warning | ||||
123 | return ( | ||||
124 | '<br /><span class="foswikiAlert">MISSING TYPE ' | ||||
125 | . $this->{type} | ||||
126 | . '</span>', | ||||
127 | CGI::textfield( | ||||
128 | -class => $this->cssClasses('foswikiAlert foswikiInputField'), | ||||
129 | -name => $this->{name}, | ||||
130 | -size => 80, | ||||
131 | -value => $value | ||||
132 | ) | ||||
133 | ); | ||||
134 | } | ||||
135 | |||||
136 | =begin TML | ||||
137 | |||||
138 | ---++ cssClasses(@classes) -> $classes | ||||
139 | Construct a list of the CSS classes for the form field. Adds additional | ||||
140 | class specifiers related to the attributes of the field e.g mandatory. | ||||
141 | Pass it a list of the other classnames you want on the field. | ||||
142 | |||||
143 | =cut | ||||
144 | |||||
145 | sub cssClasses { | ||||
146 | my $this = shift; | ||||
147 | if ( $this->isMandatory() ) { | ||||
148 | push( @_, 'foswikiMandatory' ); | ||||
149 | } | ||||
150 | return join( ' ', @_ ); | ||||
151 | } | ||||
152 | |||||
153 | =begin TML | ||||
154 | |||||
155 | ---++ getDefaultValue() -> $value | ||||
156 | Try and get a sensible default value for the field from the | ||||
157 | values stored in the form definition. The result should be | ||||
158 | a value string. | ||||
159 | |||||
160 | Some subclasses may not support the definition of defaults in | ||||
161 | the form definition. In that case this method should return =undef=. | ||||
162 | |||||
163 | =cut | ||||
164 | |||||
165 | sub getDefaultValue { | ||||
166 | my $this = shift; | ||||
167 | |||||
168 | my $value = $this->{value}; | ||||
169 | $value = '' unless defined $value; # allow 0 values | ||||
170 | |||||
171 | return $value; | ||||
172 | } | ||||
173 | |||||
174 | =begin TML | ||||
175 | |||||
176 | ---++ renderHidden($meta) -> $html | ||||
177 | Render the form in =$meta= as a set of hidden fields. | ||||
178 | |||||
179 | =cut | ||||
180 | |||||
181 | sub renderHidden { | ||||
182 | my ( $this, $meta ) = @_; | ||||
183 | |||||
184 | my $value; | ||||
185 | if ( $this->{name} ) { | ||||
186 | my $field = $meta->get( 'FIELD', $this->{name} ); | ||||
187 | $value = $field->{value}; | ||||
188 | } | ||||
189 | |||||
190 | my @values; | ||||
191 | |||||
192 | if ( defined($value) ) { | ||||
193 | if ( $this->isMultiValued() ) { | ||||
194 | push( @values, split( /\s*,\s*/, $value ) ); | ||||
195 | } | ||||
196 | else { | ||||
197 | push( @values, $value ); | ||||
198 | } | ||||
199 | } | ||||
200 | else { | ||||
201 | $value = $this->getDefaultValue(); | ||||
202 | push( @values, $this->getDefaultValue() ) if $value; | ||||
203 | } | ||||
204 | |||||
205 | return '' unless scalar(@values); | ||||
206 | |||||
207 | return CGI::hidden( -name => $this->{name}, -default => \@values ); | ||||
208 | } | ||||
209 | |||||
210 | =begin TML | ||||
211 | |||||
212 | ---++ populateMetaDataFromQuery( $query, $meta, $old ) -> ($bValid, $bPresent) | ||||
213 | |||||
214 | Given a CGI =$query=, a =$meta= object, and an array of =$old= field entries, | ||||
215 | then populate the $meta with a row for this field definition, taking the | ||||
216 | content from the query if it's there, otherwise from $old or failing that, | ||||
217 | from the default defined for the type. Refuses to update mandatory fields | ||||
218 | that have an empty value. | ||||
219 | |||||
220 | Return $bValid true if the value in $meta was updated (either from the | ||||
221 | query or from a default in the form. | ||||
222 | Return $bPresent true if a value was present in the query (even it was undef) | ||||
223 | |||||
224 | =cut | ||||
225 | |||||
226 | sub populateMetaFromQueryData { | ||||
227 | my ( $this, $query, $meta, $old ) = @_; | ||||
228 | my $value; | ||||
229 | my $bPresent = 0; | ||||
230 | |||||
231 | return unless $this->{name}; | ||||
232 | |||||
233 | my %names = map { $_ => 1 } $query->param; | ||||
234 | |||||
235 | if ( $names{ $this->{name} } ) { | ||||
236 | |||||
237 | # Field is present in the request | ||||
238 | $bPresent = 1; | ||||
239 | if ( $this->isMultiValued() ) { | ||||
240 | my @values = $query->param( $this->{name} ); | ||||
241 | |||||
242 | if ( scalar(@values) == 1 && defined $values[0] ) { | ||||
243 | @values = split( /,|%2C/, $values[0] ); | ||||
244 | } | ||||
245 | my %vset = (); | ||||
246 | foreach my $val (@values) { | ||||
247 | $val ||= ''; | ||||
248 | $val =~ s/^\s*//o; | ||||
249 | $val =~ s/\s*$//o; | ||||
250 | |||||
251 | # skip empty values | ||||
252 | $vset{$val} = ( defined $val && $val =~ /\S/ ); | ||||
253 | } | ||||
254 | $value = ''; | ||||
255 | my $isValues = ( $this->{type} =~ /\+values/ ); | ||||
256 | |||||
257 | foreach my $option ( @{ $this->getOptions() } ) { | ||||
258 | $option =~ s/^.*?[^\\]=(.*)$/$1/ if $isValues; | ||||
259 | |||||
260 | # Maintain order of definition | ||||
261 | if ( $vset{$option} ) { | ||||
262 | $value .= ', ' if length($value); | ||||
263 | $value .= $option; | ||||
264 | } | ||||
265 | } | ||||
266 | } | ||||
267 | else { | ||||
268 | |||||
269 | # Default the value to the empty string (undef would result | ||||
270 | # in the old value being restored) | ||||
271 | # Note: we test for 'defined' because value can also be 0 (zero) | ||||
272 | $value = $query->param( $this->{name} ); | ||||
273 | $value = '' unless defined $value; | ||||
274 | if ( $this->{session}->inContext('edit') ) { | ||||
275 | $value = Foswiki::expandStandardEscapes($value); | ||||
276 | } | ||||
277 | } | ||||
278 | } | ||||
279 | |||||
280 | # Find the old value of this field | ||||
281 | my $preDef; | ||||
282 | foreach my $item (@$old) { | ||||
283 | if ( $item->{name} eq $this->{name} ) { | ||||
284 | $preDef = $item; | ||||
285 | last; | ||||
286 | } | ||||
287 | } | ||||
288 | my $def; | ||||
289 | |||||
290 | if ( defined($value) ) { | ||||
291 | |||||
292 | # mandatory fields must have length > 0 | ||||
293 | if ( $this->isMandatory() && length($value) == 0 ) { | ||||
294 | return ( 0, $bPresent ); | ||||
295 | } | ||||
296 | |||||
297 | # NOTE: title and name are stored in the topic so that it can be | ||||
298 | # viewed without reading in the form definition | ||||
299 | my $title = $this->{title}; | ||||
300 | if ( $this->{definingTopic} ) { | ||||
301 | $title = '[[' . $this->{definingTopic} . '][' . $title . ']]'; | ||||
302 | } | ||||
303 | $def = { | ||||
304 | name => $this->{name}, | ||||
305 | title => $title, | ||||
306 | value => $value, | ||||
307 | attributes => $this->{attributes}, | ||||
308 | }; | ||||
309 | } | ||||
310 | elsif ($preDef) { | ||||
311 | $def = $preDef; | ||||
312 | } | ||||
313 | else { | ||||
314 | return ( 0, $bPresent ); | ||||
315 | } | ||||
316 | |||||
317 | $meta->putKeyed( 'FIELD', $def ) if $def; | ||||
318 | |||||
319 | return ( 1, $bPresent ); | ||||
320 | } | ||||
321 | |||||
322 | =begin TML | ||||
323 | |||||
324 | ---++ ObjectMethod renderForDisplay($format, $attrs) -> $html | ||||
325 | |||||
326 | Render the field for display, under the control of $attrs. | ||||
327 | |||||
328 | The following vars in $format are expanded: | ||||
329 | $title - title of the form field | ||||
330 | $value - expanded to the *protected* value of the form field | ||||
331 | |||||
332 | The value is protected by Foswiki::Render::protectFormFieldValue. | ||||
333 | |||||
334 | =cut | ||||
335 | |||||
336 | sub renderForDisplay { | ||||
337 | my ( $this, $format, $value, $attrs ) = @_; | ||||
338 | |||||
339 | if ( !$attrs->{showhidden} ) { | ||||
340 | my $fa = $this->{attributes} || ''; | ||||
341 | if ( $fa =~ /H/ ) { | ||||
342 | return ''; | ||||
343 | } | ||||
344 | } | ||||
345 | |||||
346 | require Foswiki::Render; | ||||
347 | $value = Foswiki::Render::protectFormFieldValue( $value, $attrs ); | ||||
348 | |||||
349 | $format =~ s/\$title/$this->{title}/g; | ||||
350 | $format =~ s/\$value/$value/g; | ||||
351 | $format =~ s/\$name/$this->{name}/g; | ||||
352 | $format =~ s/\$attributes/$this->{attributes}/g; | ||||
353 | $format =~ s/\$type/$this->{type}/g; | ||||
354 | $format =~ s/\$size/$this->{size}/g; | ||||
355 | my $definingTopic = $this->{definingTopic} || 'FIELD'; | ||||
356 | $format =~ s/\$definingTopic/$definingTopic/g; | ||||
357 | |||||
358 | return $format; | ||||
359 | } | ||||
360 | |||||
361 | # Debug | ||||
362 | sub stringify { | ||||
363 | my $this = shift; | ||||
364 | my $s = '| ' | ||||
365 | . $this->{name} . ' | ' | ||||
366 | . $this->{type} . ' | ' | ||||
367 | . $this->{size} . ' | ' | ||||
368 | . $this->{attributes} . " |\n"; | ||||
369 | return $s; | ||||
370 | } | ||||
371 | |||||
372 | 1 | 2µs | 1; | ||
373 | __END__ |