← Index
NYTProf Performance Profile   « line view »
For ./view
  Run on Fri Jul 31 19:05:14 2015
Reported on Fri Jul 31 19:08:11 2015

Filename/var/www/foswiki11/lib/Foswiki/Form.pm
StatementsExecuted 23 statements in 2.66ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
1111.33ms1.39msFoswiki::Form::::BEGIN@42Foswiki::Form::BEGIN@42
111527µs599µsFoswiki::Form::::BEGIN@43Foswiki::Form::BEGIN@43
11119µs46µsFoswiki::Form::::BEGIN@32Foswiki::Form::BEGIN@32
11116µs30µsFoswiki::Form::::BEGIN@33Foswiki::Form::BEGIN@33
11114µs206µsFoswiki::Form::::BEGIN@39Foswiki::Form::BEGIN@39
11113µs38µsFoswiki::Form::::BEGIN@38Foswiki::Form::BEGIN@38
1116µs6µsFoswiki::Form::::BEGIN@44Foswiki::Form::BEGIN@44
1115µs5µsFoswiki::Form::::BEGIN@35Foswiki::Form::BEGIN@35
1115µs5µsFoswiki::Form::::BEGIN@41Foswiki::Form::BEGIN@41
1114µs4µsFoswiki::Form::::BEGIN@45Foswiki::Form::BEGIN@45
0000s0sFoswiki::Form::::__ANON__[:305]Foswiki::Form::__ANON__[:305]
0000s0sFoswiki::Form::::_extractPseudoFieldDefsFoswiki::Form::_extractPseudoFieldDefs
0000s0sFoswiki::Form::::_linkFoswiki::Form::_link
0000s0sFoswiki::Form::::_parseFormDefinitionFoswiki::Form::_parseFormDefinition
0000s0sFoswiki::Form::::createFieldFoswiki::Form::createField
0000s0sFoswiki::Form::::fieldTitle2FieldNameFoswiki::Form::fieldTitle2FieldName
0000s0sFoswiki::Form::::finishFoswiki::Form::finish
0000s0sFoswiki::Form::::getAvailableFormsFoswiki::Form::getAvailableForms
0000s0sFoswiki::Form::::getFieldFoswiki::Form::getField
0000s0sFoswiki::Form::::getFieldValuesFromQueryFoswiki::Form::getFieldValuesFromQuery
0000s0sFoswiki::Form::::getFieldsFoswiki::Form::getFields
0000s0sFoswiki::Form::::isTextMergeableFoswiki::Form::isTextMergeable
0000s0sFoswiki::Form::::newFoswiki::Form::new
0000s0sFoswiki::Form::::renderForDisplayFoswiki::Form::renderForDisplay
0000s0sFoswiki::Form::::renderForEditFoswiki::Form::renderForEdit
0000s0sFoswiki::Form::::renderHiddenFoswiki::Form::renderHidden
0000s0sFoswiki::Form::::stringifyFoswiki::Form::stringify
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1# See bottom of file for license and copyright information
2
3=begin TML
4
5---+ package Foswiki::Form
6
7Object representing a single form definition.
8
9Form definitions are mainly used to control rendering of a form for
10editing, though there is some application login there that handles
11transferring values between edits and saves.
12
13A form definition consists of a Foswiki::Form object, which has a list
14of field definitions. Each field definition is an object of a type
15derived from Foswiki::Form::FieldDefinition. These objects are responsible
16for the actual syntax and semantics of the field type. Form definitions
17are parsed from Foswiki tables, and the types are mapped by name to a
18class declared in Foswiki::Form::* - for example, the =text= type is mapped
19to =Foswiki::Form::Text= and the =checkbox= type to =Foswiki::Form::Checkbox=.
20
21The =Foswiki::Form::FieldDefinition= class declares default behaviours for
22types that accept a single value in their definitions. The
23=Foswiki::Form::ListFieldDefinition= extends this for types that have lists
24of possible values.
25
26=cut
27
28# The bulk of this object is a parser for form definitions. All the
29# intelligence is in the individual field types.
30
31package Foswiki::Form;
32241µs272µs
# spent 46µs (19+26) within Foswiki::Form::BEGIN@32 which was called: # once (19µs+26µs) by Foswiki::Meta::renderFormForDisplay at line 32
use strict;
# spent 46µs making 1 call to Foswiki::Form::BEGIN@32 # spent 26µs making 1 call to strict::import
33233µs244µs
# spent 30µs (16+14) within Foswiki::Form::BEGIN@33 which was called: # once (16µs+14µs) by Foswiki::Meta::renderFormForDisplay at line 33
use warnings;
# spent 30µs making 1 call to Foswiki::Form::BEGIN@33 # spent 14µs making 1 call to warnings::import
34
35246µs15µs
# spent 5µs within Foswiki::Form::BEGIN@35 which was called: # once (5µs+0s) by Foswiki::Meta::renderFormForDisplay at line 35
use Foswiki::Meta ();
# spent 5µs making 1 call to Foswiki::Form::BEGIN@35
3618µsour @ISA = ('Foswiki::Meta');
37
38235µs263µs
# spent 38µs (13+25) within Foswiki::Form::BEGIN@38 which was called: # once (13µs+25µs) by Foswiki::Meta::renderFormForDisplay at line 38
use Assert;
# spent 38µs making 1 call to Foswiki::Form::BEGIN@38 # spent 25µs making 1 call to Assert::import
39235µs2397µs
# spent 206µs (14+191) within Foswiki::Form::BEGIN@39 which was called: # once (14µs+191µs) by Foswiki::Meta::renderFormForDisplay at line 39
use Error qw( :try );
# spent 206µs making 1 call to Foswiki::Form::BEGIN@39 # spent 191µs making 1 call to Error::import
40
41220µs15µs
# spent 5µs within Foswiki::Form::BEGIN@41 which was called: # once (5µs+0s) by Foswiki::Meta::renderFormForDisplay at line 41
use Foswiki::Sandbox ();
# spent 5µs making 1 call to Foswiki::Form::BEGIN@41
422106µs11.39ms
# spent 1.39ms (1.33+67µs) within Foswiki::Form::BEGIN@42 which was called: # once (1.33ms+67µs) by Foswiki::Meta::renderFormForDisplay at line 42
use Foswiki::Form::FieldDefinition ();
# spent 1.39ms making 1 call to Foswiki::Form::BEGIN@42
43299µs1599µs
# spent 599µs (527+72) within Foswiki::Form::BEGIN@43 which was called: # once (527µs+72µs) by Foswiki::Meta::renderFormForDisplay at line 43
use Foswiki::Form::ListFieldDefinition ();
# spent 599µs making 1 call to Foswiki::Form::BEGIN@43
44221µs16µs
# spent 6µs within Foswiki::Form::BEGIN@44 which was called: # once (6µs+0s) by Foswiki::Meta::renderFormForDisplay at line 44
use Foswiki::AccessControlException ();
# spent 6µs making 1 call to Foswiki::Form::BEGIN@44
4522.20ms14µs
# spent 4µs within Foswiki::Form::BEGIN@45 which was called: # once (4µs+0s) by Foswiki::Meta::renderFormForDisplay at line 45
use Foswiki::OopsException ();
# spent 4µs making 1 call to Foswiki::Form::BEGIN@45
46
47# The following are reserved as URL parameters to scripts and may not be
48# used as field names in forms.
49116µsmy %reservedFieldNames = map { $_ => 1 }
50 qw( action breaklock contenttype cover dontnotify editaction
51 forcenewrevision formtemplate onlynewtopic onlywikiname
52 originalrev skin templatetopic text topic topicparent user );
53
54=begin TML
55
56---++ ClassMethod new ( $session, $web, $topic, \@def )
57
58Looks up a form in the session object or, if it hasn't been read yet,
59reads it from the form definition topic on disc.
60 * =$web= - default web to recover form from, if =$form= doesn't
61 specify a web
62 * =$topic= - name of the topic that contains the form definition
63 * =\@def= - optional. A reference to a list of field definitions.
64 If present, these definitions will be used, rather than any read from
65 the form definition topic.
66
67May throw Foswiki::OopsException if the web and form are not valid for use as a
68form name, or if \@def is not given and the form does not exist in the
69database. May throw Foswiki::AccessControlException if the form schema
70in the database is protected against view.
71
72=cut
73
74sub new {
75 my ( $class, $session, $web, $form, $def ) = @_;
76
77 my ( $vweb, $vtopic ) = $session->normalizeWebTopicName( $web, $form );
78 my $this = $session->{forms}->{"$vweb.$vtopic"};
79
80 unless ($this) {
81
82 # A form name has to be a valid topic name after normalisation
83 $vweb = Foswiki::Sandbox::untaint( $vweb,
84 \&Foswiki::Sandbox::validateWebName );
85 $vtopic = Foswiki::Sandbox::untaint( $vtopic,
86 \&Foswiki::Sandbox::validateTopicName );
87 unless ( $vweb && $vtopic ) {
88 throw Foswiki::OopsException(
89 'attention',
90 def => 'invalid_form_name',
91 web => $session->{webName},
92 topic => $session->{topicName},
93 params => [ $web, $form ]
94 );
95 }
96
97 # Got to have either a def or a topic
98 unless ( $def || $session->topicExists( $vweb, $vtopic ) ) {
99 throw Foswiki::OopsException(
100 'attention',
101 def => 'no_form_def',
102 web => $session->{webName},
103 topic => $session->{topicName},
104 params => [ $vweb, $vtopic ]
105 );
106 }
107
108 $this = $class->SUPER::new( $session, $vweb, $vtopic );
109
110 unless ( $def || $this->haveAccess('VIEW') ) {
111 throw Foswiki::AccessControlException( 'VIEW', $session->{user},
112 $vweb, $vtopic, $Foswiki::Meta::reason );
113 }
114
115 if ( ref($this) ne 'Foswiki::Form' ) {
116
117 #recast if we have to - allowing the cache to work its magic
118 $this = bless( $this, 'Foswiki::Form' );
119 }
120
121 # cache the object before we've parsed it to prevent recursion
122 #when there are SEARCH / INCLUDE macros in the form definition
123 $session->{forms}->{"$vweb.$vtopic"} = $this;
124
125 unless ($def) {
126 $this->{fields} = $this->_parseFormDefinition();
127 }
128 elsif ( ref($def) eq 'ARRAY' ) {
129 $this->{fields} = $def;
130 }
131 else {
132
133 # Foswiki::Meta object
134 $this->{fields} = $this->_extractPseudoFieldDefs($def);
135 }
136 }
137
138 return $this;
139}
140
141=begin TML
142
143---++ ObjectMethod finish()
144Break circular references.
145
146=cut
147
148# Note to developers; please undef *all* fields in the object explicitly,
149# whether they are references or not. That way this method is "golden
150# documentation" of the live fields in the object.
151sub finish {
152 my $this = shift;
153 foreach ( @{ $this->{fields} } ) {
154 $_->finish();
155 }
156 undef $this->{fields};
157 $this->SUPER::finish();
158}
159
160=begin TML
161
162---++ StaticMethod getAvailableForms( $metaObject ) -> @forms
163
164Get a list of the names of forms that are available for use in the
165given topic. $metaObject can be a topic or a web.
166
167=cut
168
169sub getAvailableForms {
170 my $metaObject = shift;
171 if ( defined $metaObject->topic ) {
172 $metaObject =
173 Foswiki::Meta->new( $metaObject->session, $metaObject->web );
174 }
175 my $legalForms = $metaObject->getPreference('WEBFORMS') || '';
176 $legalForms =~ s/^\s+//;
177 $legalForms =~ s/\s+$//;
178 my @forms = split( /[,\s]+/, $legalForms );
179
180 # This is where we could %SEARCH for *Form topics
181 return @forms;
182}
183
184=begin TML
185
186---++ StaticMethod fieldTitle2FieldName($title) -> $name
187Chop out all except A-Za-z0-9_. from a field name to create a
188valid "name" for storing in meta-data
189
190=cut
191
192sub fieldTitle2FieldName {
193 my ($text) = @_;
194 return '' unless defined($text);
195 $text =~ s/!//g;
196 $text =~ s/<nop>//g; # support <nop> character in title
197 $text =~ s/[^A-Za-z0-9_\.]//g;
198 return $text;
199}
200
201# Get definition from supplied topic text
202# Returns array of arrays
203# 1st - list fields
204# 2nd - name, title, type, size, vals, tooltip, attributes
205# Possible attributes are "M" (mandatory field)
206sub _parseFormDefinition {
207 my $this = shift;
208
209 my @fields = ();
210 my $inBlock = 0;
211 my $text = $this->text();
212 $text = '' unless defined $text;
213
214 $text =~ s/\\\n//g; # remove trailing '\' and join continuation lines
215
216# | *Name:* | *Type:* | *Size:* | *Value:* | *Tooltip message:* | *Attributes:* |
217# Tooltip and attributes are optional
218 foreach my $line ( split( /\n/, $text ) ) {
219 if ( $line =~ /^\s*\|.*Name[^|]*\|.*Type[^|]*\|.*Size[^|]*\|/ ) {
220 $inBlock = 1;
221 next;
222 }
223
224 # Only insist on first field being present FIXME - use oops page instead?
225 if ( $inBlock && $line =~ s/^\s*\|\s*// ) {
226 $line =~ s/\\\|/\007/g; # protect \| from split
227 my ( $title, $type, $size, $vals, $tooltip, $attributes ) =
228 map { s/\007/|/g; $_ } split( /\s*\|\s*/, $line );
229
230 $title ||= '';
231
232 $type ||= '';
233 $type = lc($type);
234 $type =~ s/^\s*//go;
235 $type =~ s/\s*$//go;
236 $type = 'text' if ( !$type );
237
238 $size ||= '';
239
240 $vals ||= '';
241 $vals = $this->expandMacros($vals);
242 $vals =~ s/<\/?(!|nop|noautolink)\/?>//go;
243 $vals =~ s/^\s+//g;
244 $vals =~ s/\s+$//g;
245
246 $tooltip ||= '';
247
248 $attributes ||= '';
249 $attributes =~ s/\s*//go;
250 $attributes = '' if ( !$attributes );
251
252 my $definingTopic = "";
253 if ( $title =~ /\[\[(.+)\]\[(.+)\]\]/ ) {
254
255 # use common defining topics with different field titles
256 $definingTopic = fieldTitle2FieldName($1);
257 $title = $2;
258 }
259
260 my $name = fieldTitle2FieldName($title);
261
262 # Rename fields with reserved names
263 if ( $reservedFieldNames{$name} ) {
264 $name .= '_';
265 }
266 my $fieldDef = $this->createField(
267 $type,
268 name => $name,
269 title => $title,
270 size => $size,
271 value => $vals,
272 tooltip => $tooltip,
273 attributes => $attributes,
274 definingTopic => $definingTopic,
275 web => $this->web(),
276 topic => $this->topic()
277 );
278 push( @fields, $fieldDef );
279
280 $this->{mandatoryFieldsPresent} ||= $fieldDef->isMandatory();
281 }
282 else {
283 $inBlock = 0;
284 }
285 }
286
287 return \@fields;
288}
289
290# PROTECTED
291# Create a field object. Done like this so that this method can be
292# overridden by subclasses to extend the range of field types.
293sub createField {
294 my $this = shift;
295 my $type = shift;
296
297 # The untaint is required for the validation *and* the ucfirst, which
298 # retaints when use locale is in force
299 my $class = Foswiki::Sandbox::untaint(
300 $type,
301 sub {
302 my $class = shift;
303 $class =~ /^(\w*)/; # cut off +buttons etc
304 return 'Foswiki::Form::' . ucfirst($1);
305 }
306 );
307 eval 'require ' . $class;
308 if ($@) {
309 $this->session->logger->log( 'error',
310 "error compiling class $class: $@" );
311
312 # Type not available; use base type
313 require Foswiki::Form::FieldDefinition;
314 $class = 'Foswiki::Form::FieldDefinition';
315 }
316 return $class->new( session => $this->session(), type => $type, @_ );
317}
318
319# Generate a link to the given topic, so we can bring up details in a
320# separate window.
321sub _link {
322 my ( $this, $string, $tooltip, $topic ) = @_;
323
324 $string =~ s/[\[\]]//go;
325
326 $topic ||= $string;
327 my $defaultToolTip =
328 $this->session->i18n->maketext('Details in separate window');
329 $tooltip ||= $defaultToolTip;
330
331 ( my $web, $topic ) =
332 $this->session->normalizeWebTopicName( $this->{web}, $topic );
333
334 $web =
335 Foswiki::Sandbox::untaint( $web, \&Foswiki::Sandbox::validateWebName );
336
337 $topic = Foswiki::Sandbox::untaint( $topic,
338 \&Foswiki::Sandbox::validateTopicName );
339
340 my $link;
341
342 if ( $this->session->topicExists( $web, $topic ) ) {
343 $link = CGI::a(
344 {
345 target => $topic,
346 title => $tooltip,
347 href => $this->session->getScriptUrl( 0, 'view', $web, $topic ),
348 rel => 'nofollow'
349 },
350 $string
351 );
352 }
353 else {
354 my $that =
355 Foswiki::Meta->new( $this->session, $web,
356 $topic || $Foswiki::cfg{HomeTopicName} );
357 my $expanded = $that->expandMacros($string);
358 if ( $tooltip ne $defaultToolTip ) {
359 $link = CGI::span( { title => $tooltip }, $expanded );
360 }
361 else {
362 $link = $expanded;
363 }
364 }
365
366 return $link;
367}
368
369sub stringify {
370 my $this = shift;
371 my $fs = "| *Name* | *Type* | *Size* | *Attributes* |\n";
372 foreach my $fieldDef ( @{ $this->{fields} } ) {
373 $fs .= $fieldDef->stringify();
374 }
375 return $fs;
376}
377
378=begin TML
379
380---++ ObjectMethod renderForEdit( $topicObject ) -> $html
381
382 * =$topicObject= the topic being rendered
383
384Render the form fields for entry during an edit session, using data values
385from $meta
386
387=cut
388
389sub renderForEdit {
390 my ( $this, $topicObject ) = @_;
391 ASSERT( $topicObject->isa('Foswiki::Meta') ) if DEBUG;
392 require CGI;
393 my $session = $this->session;
394
395 if ( $this->{mandatoryFieldsPresent} ) {
396 $session->enterContext('mandatoryfields');
397 }
398 my $tmpl = $session->templates->readTemplate('form');
399 $tmpl = $topicObject->expandMacros($tmpl);
400
401 $tmpl =~ s/%FORMTITLE%/$this->_link( $this->web.'.'.$this->topic )/ge;
402 my ( $text, $repeatTitledText, $repeatUntitledText, $afterText ) =
403 split( /%REPEAT%/, $tmpl );
404
405 foreach my $fieldDef ( @{ $this->{fields} } ) {
406
407 my $value;
408 my $tooltip = $fieldDef->{tooltip};
409 my $definingTopic = $fieldDef->{definingTopic};
410 my $title = $fieldDef->{title};
411 my $tmp = '';
412 if ( !$title && !$fieldDef->isEditable() ) {
413
414 # Special handling for untitled labels.
415 # SMELL: Assumes that uneditable fields are not multi-valued
416 $tmp = $repeatUntitledText;
417 $value =
418 $topicObject->renderTML(
419 $topicObject->expandMacros( $fieldDef->{value} ) );
420 }
421 else {
422 $tmp = $repeatTitledText;
423
424 if ( defined( $fieldDef->{name} ) ) {
425 my $field = $topicObject->get( 'FIELD', $fieldDef->{name} );
426 $value = $field->{value};
427 }
428 my $extra = ''; # extras on col 0
429
430 unless ( defined($value) ) {
431 my $dv = $fieldDef->getDefaultValue($value);
432 if ( defined($dv) ) {
433 $dv = $topicObject->expandMacros($dv);
434 $value = Foswiki::expandStandardEscapes($dv); # Item2837
435 }
436 }
437
438 # Give plugin field types a chance first (but no chance to add to
439 # col 0 :-(
440 # SMELL: assumes that the field value is a string
441 my $output = $session->{plugins}->dispatch(
442 'renderFormFieldForEditHandler', $fieldDef->{name},
443 $fieldDef->{type}, $fieldDef->{size},
444 $value, $fieldDef->{attributes},
445 $fieldDef->{value}
446 );
447
448 if ($output) {
449 $value = $output;
450 }
451 else {
452 ( $extra, $value ) =
453 $fieldDef->renderForEdit( $topicObject, $value );
454 }
455
456 if ( $fieldDef->isMandatory() ) {
457 $extra .= CGI::span( { class => 'foswikiAlert' }, ' *' );
458 }
459
460 $tmp =~ s/%ROWTITLE%/
461 $this->_link( $title, $tooltip, $definingTopic )/ge;
462 $tmp =~ s/%ROWEXTRA%/$extra/g;
463 }
464 $tmp =~ s/%ROWVALUE%/$value/g;
465 $text .= $tmp;
466 }
467
468 $text .= $afterText;
469 return $text;
470}
471
472=begin TML
473
474---++ ObjectMethod renderHidden( $topicObject ) -> $html
475
476Render form fields found in the meta as hidden inputs, so they pass
477through edits untouched.
478
479=cut
480
481sub renderHidden {
482 my ( $this, $topicObject ) = @_;
483 ASSERT( $topicObject->isa('Foswiki::Meta') ) if DEBUG;
484
485 my $text = '';
486
487 foreach my $field ( @{ $this->{fields} } ) {
488 $text .= $field->renderHidden($topicObject);
489 }
490
491 return $text;
492}
493
494=begin TML
495
496---++ ObjectMethod getFieldValuesFromQuery($query, $topicObject) -> ( $seen, \@missing )
497
498Extract new values for form fields from a query.
499
500 * =$query= - the query
501 * =$topicObject= - the meta object that is storing the form values
502
503For each field, if there is a value in the query, use it.
504Otherwise if there is already entry for the field in the meta, keep it.
505
506Returns the number of fields which had values provided by the query,
507and a references to an array of the names of mandatory fields that were
508missing from the query.
509
510=cut
511
512sub getFieldValuesFromQuery {
513 my ( $this, $query, $topicObject ) = @_;
514 ASSERT( $topicObject->isa('Foswiki::Meta') ) if DEBUG;
515 my @missing;
516 my $seen = 0;
517
518 # Remove the old defs so we apply the
519 # order in the form definition, and not the
520 # order in the previous meta object. See Item1982.
521 my @old = $topicObject->find('FIELD');
522 $topicObject->remove('FIELD');
523 foreach my $fieldDef ( @{ $this->{fields} } ) {
524 my ( $set, $present ) =
525 $fieldDef->populateMetaFromQueryData( $query, $topicObject, \@old );
526 if ($present) {
527 $seen++;
528 }
529 if ( !$set && $fieldDef->isMandatory() ) {
530
531 # Remember missing mandatory fields
532 push( @missing, $fieldDef->{title} || "unnamed field" );
533 }
534 }
535 return ( $seen, \@missing );
536}
537
538=begin TML
539
540---++ ObjectMethod isTextMergeable( $name ) -> $boolean
541
542 * =$name= - name of a form field (value of the =name= attribute)
543
544Returns true if the type of the named field allows it to be text-merged.
545
546If the form does not define the field, it is assumed to be mergeable.
547
548=cut
549
550sub isTextMergeable {
551 my ( $this, $name ) = @_;
552
553 my $fieldDef = $this->getField($name);
554 if ($fieldDef) {
555 return $fieldDef->isTextMergeable();
556 }
557
558 # Field not found - assume it is mergeable
559 return 1;
560}
561
562=begin TML
563
564---++ ObjectMethod getField( $name ) -> $fieldDefinition
565
566 * =$name= - name of a form field (value of the =name= attribute)
567
568Returns a =Foswiki::Form::FieldDefinition=, or undef if the form does not
569define the field.
570
571=cut
572
573sub getField {
574 my ( $this, $name ) = @_;
575 foreach my $fieldDef ( @{ $this->{fields} } ) {
576 return $fieldDef if ( $fieldDef->{name} && $fieldDef->{name} eq $name );
577 }
578 return;
579}
580
581=begin TML
582
583---++ ObjectMethod getFields() -> \@fields
584
585Return a list containing references to field name/value pairs.
586Each entry in the list has a {name} field and a {value} field. It may
587have other fields as well, which caller should ignore. The
588returned list should be treated as *read only* (must not be written to).
589
590=cut
591
592sub getFields {
593 my $this = shift;
594 return $this->{fields};
595}
596
597sub renderForDisplay {
598 my ( $this, $topicObject ) = @_;
599
600 my $templates = $this->session->templates;
601 $templates->readTemplate('formtables');
602
603 my $text = $templates->expandTemplate('FORM:display:header');
604
605 my $rowTemplate = $templates->expandTemplate('FORM:display:row');
606 my $hasAllFieldsHidden = 1;
607 foreach my $fieldDef ( @{ $this->{fields} } ) {
608 my $fm = $topicObject->get( 'FIELD', $fieldDef->{name} );
609 next unless $fm;
610 my $fa = $fm->{attributes} || '';
611 unless ( $fa =~ /H/ ) {
612 $hasAllFieldsHidden = 0;
613 my $row = $rowTemplate;
614
615 # Legacy; was %A_TITLE% before it was $title
616 $row =~ s/%A_TITLE%/\$title/g;
617 $row =~ s/%A_VALUE%/\$value/g; # Legacy
618
619 # display => 1 gets mapped values (rather than raw)
620 $text .=
621 $fieldDef->renderForDisplay( $row, $fm->{value},
622 { display => 1 } );
623 }
624 }
625 return '' if $hasAllFieldsHidden;
626
627 $text .= $templates->expandTemplate('FORM:display:footer');
628
629 # substitute remaining placeholders in footer and header
630 $text =~ s/%A_TITLE%/$this->getPath()/ge;
631
632 return $text;
633}
634
635# extractPseudoFieldDefs( $meta ) -> $fieldDefs
636# Examine the FIELDs in $meta and reverse-engineer a set of field
637# definitions that can be used to construct a new "pseudo-form". This
638# fake form can be used to support editing of topics that have an attached
639# form that has no definition topic.
640sub _extractPseudoFieldDefs {
641 my ( $this, $meta ) = @_;
642 my @fields = $meta->find('FIELD');
643 my @fieldDefs;
644 require Foswiki::Form::FieldDefinition;
645 foreach my $field (@fields) {
646
647 # Fields are name, value, title, but there is no other type
648 # information so we have to treat them all as "text" :-(
649 my $fieldDef = new Foswiki::Form::FieldDefinition(
650 session => $this->session,
651 name => $field->{name},
652 title => $field->{title} || $field->{name},
653 attributes => $field->{attributes} || ''
654 );
655 push( @fieldDefs, $fieldDef );
656 }
657 return \@fieldDefs;
658}
659
66016µs1;
661__END__