← Index
NYTProf Performance Profile   « block view • line view • sub view »
For /usr/local/src/github.com/foswiki/core/bin/view
  Run on Sun Dec 4 17:17:59 2011
Reported on Sun Dec 4 17:26:36 2011

Filename/usr/local/src/github.com/foswiki/core/lib/Foswiki/Form.pm
StatementsExecuted 1762 statements in 16.2ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
28117.03ms15.5msFoswiki::Form::::createFieldFoswiki::Form::createField
1114.94ms1.34sFoswiki::Form::::_parseFormDefinitionFoswiki::Form::_parseFormDefinition
1112.23ms2.35msFoswiki::Form::::BEGIN@42Foswiki::Form::BEGIN@42
4551611.62ms1.62msFoswiki::Form::::CORE:substFoswiki::Form::CORE:subst (opcode)
111894µs10.4msFoswiki::Form::::renderForDisplayFoswiki::Form::renderForDisplay
111876µs1.02msFoswiki::Form::::BEGIN@43Foswiki::Form::BEGIN@43
2811634µs792µsFoswiki::Form::::fieldTitle2FieldNameFoswiki::Form::fieldTitle2FieldName
2811438µs526µsFoswiki::Form::::__ANON__[:302]Foswiki::Form::__ANON__[:302]
111436µs1.25msFoswiki::Form::::finishFoswiki::Form::finish
12841309µs309µsFoswiki::Form::::CORE:matchFoswiki::Form::CORE:match (opcode)
111133µs1.34sFoswiki::Form::::newFoswiki::Form::new
11129µs37µsFoswiki::Form::::BEGIN@32Foswiki::Form::BEGIN@32
11124µs540µsFoswiki::Form::::BEGIN@39Foswiki::Form::BEGIN@39
11122µs47µsFoswiki::Form::::BEGIN@33Foswiki::Form::BEGIN@33
31119µs19µsFoswiki::Form::::CORE:substcontFoswiki::Form::CORE:substcont (opcode)
11118µs68µsFoswiki::Form::::BEGIN@38Foswiki::Form::BEGIN@38
11111µs11µsFoswiki::Form::::BEGIN@44Foswiki::Form::BEGIN@44
11110µs10µsFoswiki::Form::::BEGIN@41Foswiki::Form::BEGIN@41
11110µs10µsFoswiki::Form::::BEGIN@35Foswiki::Form::BEGIN@35
1119µs9µsFoswiki::Form::::BEGIN@45Foswiki::Form::BEGIN@45
0000s0sFoswiki::Form::::_extractPseudoFieldDefsFoswiki::Form::_extractPseudoFieldDefs
0000s0sFoswiki::Form::::_linkFoswiki::Form::_link
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::::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;
32249µs246µs
# spent 37µs (29+8) within Foswiki::Form::BEGIN@32 which was called: # once (29µs+8µs) by Foswiki::Meta::renderFormForDisplay at line 32
use strict;
# spent 37µs making 1 call to Foswiki::Form::BEGIN@32 # spent 8µs making 1 call to strict::import
33253µs272µs
# spent 47µs (22+25) within Foswiki::Form::BEGIN@33 which was called: # once (22µs+25µs) by Foswiki::Meta::renderFormForDisplay at line 33
use warnings;
# spent 47µs making 1 call to Foswiki::Form::BEGIN@33 # spent 25µs making 1 call to warnings::import
34
35275µs110µs
# spent 10µs within Foswiki::Form::BEGIN@35 which was called: # once (10µs+0s) by Foswiki::Meta::renderFormForDisplay at line 35
use Foswiki::Meta ();
# spent 10µs making 1 call to Foswiki::Form::BEGIN@35
36111µsour @ISA = ('Foswiki::Meta');
37
38250µs2117µs
# spent 68µs (18+49) within Foswiki::Form::BEGIN@38 which was called: # once (18µs+49µs) by Foswiki::Meta::renderFormForDisplay at line 38
use Assert;
# spent 68µs making 1 call to Foswiki::Form::BEGIN@38 # spent 49µs making 1 call to Assert::import
39259µs21.05ms
# spent 540µs (24+515) within Foswiki::Form::BEGIN@39 which was called: # once (24µs+515µs) by Foswiki::Meta::renderFormForDisplay at line 39
use Error qw( :try );
# spent 540µs making 1 call to Foswiki::Form::BEGIN@39 # spent 515µs making 1 call to Error::import
40
41240µs110µs
# spent 10µs within Foswiki::Form::BEGIN@41 which was called: # once (10µs+0s) by Foswiki::Meta::renderFormForDisplay at line 41
use Foswiki::Sandbox ();
# spent 10µs making 1 call to Foswiki::Form::BEGIN@41
422165µs12.35ms
# spent 2.35ms (2.23+123µs) within Foswiki::Form::BEGIN@42 which was called: # once (2.23ms+123µs) by Foswiki::Meta::renderFormForDisplay at line 42
use Foswiki::Form::FieldDefinition ();
# spent 2.35ms making 1 call to Foswiki::Form::BEGIN@42
432159µs11.02ms
# spent 1.02ms (876µs+139µs) within Foswiki::Form::BEGIN@43 which was called: # once (876µs+139µs) by Foswiki::Meta::renderFormForDisplay at line 43
use Foswiki::Form::ListFieldDefinition ();
# spent 1.02ms making 1 call to Foswiki::Form::BEGIN@43
44240µs111µs
# spent 11µs within Foswiki::Form::BEGIN@44 which was called: # once (11µs+0s) by Foswiki::Meta::renderFormForDisplay at line 44
use Foswiki::AccessControlException ();
# spent 11µs making 1 call to Foswiki::Form::BEGIN@44
4523.95ms19µs
# spent 9µs within Foswiki::Form::BEGIN@45 which was called: # once (9µs+0s) by Foswiki::Meta::renderFormForDisplay at line 45
use Foswiki::OopsException ();
# spent 9µ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.
491865µ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
74
# spent 1.34s (133µs+1.34) within Foswiki::Form::new which was called: # once (133µs+1.34s) by Foswiki::Meta::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Meta.pm:1739] at line 1737 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Meta.pm
sub new {
7515108µs my ( $class, $session, $web, $form, $def ) = @_;
76
77 my $this = $session->{forms}->{"$web.$form"};
78 unless ($this) {
79
80 # A form name has to be a valid topic name after normalisation
81150µs my ( $vweb, $vtopic ) = $session->normalizeWebTopicName( $web, $form );
# spent 50µs making 1 call to Foswiki::normalizeWebTopicName
82195µs $vweb = Foswiki::Sandbox::untaint( $vweb,
# spent 95µs making 1 call to Foswiki::Sandbox::untaint
83 \&Foswiki::Sandbox::validateWebName );
84167µs $vtopic = Foswiki::Sandbox::untaint( $vtopic,
# spent 67µs making 1 call to Foswiki::Sandbox::untaint
85 \&Foswiki::Sandbox::validateTopicName );
86 unless ( $vweb && $vtopic ) {
87 throw Foswiki::OopsException(
88 'attention',
89 def => 'invalid_form_name',
90 web => $session->{webName},
91 topic => $session->{topicName},
92 params => [ $web, $form ]
93 );
94 }
95
96 # Got to have either a def or a topic
971200µs unless ( $def || $session->topicExists( $vweb, $vtopic ) ) {
# spent 200µs making 1 call to Foswiki::topicExists
98 throw Foswiki::OopsException(
99 'attention',
100 def => 'no_form_def',
101 web => $session->{webName},
102 topic => $session->{topicName},
103 params => [ $web, $form ]
104 );
105 }
106
107173µs $this = $class->SUPER::new( $session, $vweb, $vtopic );
# spent 73µs making 1 call to Foswiki::Meta::new
108 $session->{forms}->{"$web.$form"} = $this;
109
11013.17ms unless ( $def || $this->haveAccess('VIEW') ) {
# spent 3.17ms making 1 call to Foswiki::Meta::haveAccess
111 throw Foswiki::AccessControlException( 'VIEW', $session->{user},
112 $web, $form, $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 $session->{forms}->{"$web.$form"} = $this;
120 }
121
122 unless ($def) {
12311.34s $this->{fields} = $this->_parseFormDefinition();
# spent 1.34s making 1 call to Foswiki::Form::_parseFormDefinition
124 }
125 elsif ( ref($def) eq 'ARRAY' ) {
126 $this->{fields} = $def;
127 }
128 else {
129
130 # Foswiki::Meta object
131 $this->{fields} = $this->_extractPseudoFieldDefs($def);
132 }
133 }
134
135 return $this;
136}
137
138=begin TML
139
140---++ ObjectMethod finish()
141Break circular references.
142
143=cut
144
145# Note to developers; please undef *all* fields in the object explicitly,
146# whether they are references or not. That way this method is "golden
147# documentation" of the live fields in the object.
148
# spent 1.25ms (436µs+810µs) within Foswiki::Form::finish which was called: # once (436µs+810µs) by Foswiki::finish at line 2091 of /usr/local/src/github.com/foswiki/core/lib/Foswiki.pm
sub finish {
14933400µs my $this = shift;
150 foreach ( @{ $this->{fields} } ) {
15128680µs $_->finish();
# spent 295µs making 20 calls to Foswiki::Form::FieldDefinition::finish, avg 15µs/call # spent 227µs making 4 calls to Foswiki::Form::Select::finish, avg 57µs/call # spent 158µs making 4 calls to Foswiki::Form::ListFieldDefinition::finish, avg 40µs/call
152 }
153 undef $this->{fields};
1541131µs $this->SUPER::finish();
# spent 131µs making 1 call to Foswiki::Meta::finish
155}
156
157=begin TML
158
159---++ StaticMethod getAvailableForms( $metaObject ) -> @forms
160
161Get a list of the names of forms that are available for use in the
162given topic. $metaObject can be a topic or a web.
163
164=cut
165
166sub getAvailableForms {
167 my $metaObject = shift;
168 if ( defined $metaObject->topic ) {
169 $metaObject =
170 Foswiki::Meta->new( $metaObject->session, $metaObject->web );
171 }
172 my $legalForms = $metaObject->getPreference('WEBFORMS') || '';
173 $legalForms =~ s/^\s+//;
174 $legalForms =~ s/\s+$//;
175 my @forms = split( /[,\s]+/, $legalForms );
176
177 # This is where we could %SEARCH for *Form topics
178 return @forms;
179}
180
181=begin TML
182
183---++ StaticMethod fieldTitle2FieldName($title) -> $name
184Chop out all except A-Za-z0-9_. from a field name to create a
185valid "name" for storing in meta-data
186
187=cut
188
189
# spent 792µs (634+158) within Foswiki::Form::fieldTitle2FieldName which was called 28 times, avg 28µs/call: # 28 times (634µs+158µs) by Foswiki::Form::_parseFormDefinition at line 257, avg 28µs/call
sub fieldTitle2FieldName {
190168805µs my ($text) = @_;
191 return '' unless defined($text);
1922851µs $text =~ s/!//g;
# spent 51µs making 28 calls to Foswiki::Form::CORE:subst, avg 2µs/call
1932842µs $text =~ s/<nop>//g; # support <nop> character in title
# spent 42µs making 28 calls to Foswiki::Form::CORE:subst, avg 1µs/call
1942865µs $text =~ s/[^A-Za-z0-9_\.]//g;
# spent 65µs making 28 calls to Foswiki::Form::CORE:subst, avg 2µs/call
195 return $text;
196}
197
198# Get definition from supplied topic text
199# Returns array of arrays
200# 1st - list fields
201# 2nd - name, title, type, size, vals, tooltip, attributes
202# Possible attributes are "M" (mandatory field)
203
# spent 1.34s (4.94ms+1.33) within Foswiki::Form::_parseFormDefinition which was called: # once (4.94ms+1.33s) by Foswiki::Form::new at line 123
sub _parseFormDefinition {
20410866.36ms my $this = shift;
205
206 my @fields = ();
207 my $inBlock = 0;
208128µs my $text = $this->text();
# spent 28µs making 1 call to Foswiki::Meta::text
209 $text = '' unless defined $text;
210
21116µs $text =~ s/\\\n//g; # remove trailing '\' and join continuation lines
# spent 6µs making 1 call to Foswiki::Form::CORE:subst
212
213# | *Name:* | *Type:* | *Size:* | *Value:* | *Tooltip message:* | *Attributes:* |
214# Tooltip and attributes are optional
215 foreach my $line ( split( /\n/, $text ) ) {
21658138µs if ( $line =~ /^\s*\|.*Name[^|]*\|.*Type[^|]*\|.*Size[^|]*\|/ ) {
# spent 138µs making 58 calls to Foswiki::Form::CORE:match, avg 2µs/call
217 $inBlock = 1;
218 next;
219 }
220
221 # Only insist on first field being present FIXME - use oops page instead?
22229167µs if ( $inBlock && $line =~ s/^\s*\|\s*// ) {
# spent 167µs making 29 calls to Foswiki::Form::CORE:subst, avg 6µs/call
2232856µs $line =~ s/\\\|/\007/g; # protect \| from split
# spent 56µs making 28 calls to Foswiki::Form::CORE:subst, avg 2µs/call
224116205µs my ( $title, $type, $size, $vals, $tooltip, $attributes ) =
# spent 205µs making 116 calls to Foswiki::Form::CORE:subst, avg 2µs/call
225 map { s/\007/|/g; $_ } split( /\s*\|\s*/, $line );
226
227 $title ||= '';
228
229 $type ||= '';
230 $type = lc($type);
23128130µs $type =~ s/^\s*//go;
# spent 130µs making 28 calls to Foswiki::Form::CORE:subst, avg 5µs/call
23228160µs $type =~ s/\s*$//go;
# spent 160µs making 28 calls to Foswiki::Form::CORE:subst, avg 6µs/call
233 $type = 'text' if ( !$type );
234
235 $size ||= '';
236
237 $vals ||= '';
238280s $vals = $this->expandMacros($vals);
# spent 1.32s making 28 calls to Foswiki::Meta::expandMacros, avg 47.0ms/call, recursion: max depth 1, sum of overlapping time 1.32s
23928155µs $vals =~ s/<\/?(!|nop|noautolink)\/?>//go;
# spent 155µs making 28 calls to Foswiki::Form::CORE:subst, avg 6µs/call
2402871µs $vals =~ s/^\s+//g;
# spent 71µs making 28 calls to Foswiki::Form::CORE:subst, avg 3µs/call
24128292µs $vals =~ s/\s+$//g;
# spent 292µs making 28 calls to Foswiki::Form::CORE:subst, avg 10µs/call
242
243 $tooltip ||= '';
244
245 $attributes ||= '';
24628115µs $attributes =~ s/\s*//go;
# spent 115µs making 28 calls to Foswiki::Form::CORE:subst, avg 4µs/call
247 $attributes = '' if ( !$attributes );
248
249 my $definingTopic = "";
2502858µs if ( $title =~ /\[\[(.+)\]\[(.+)\]\]/ ) {
# spent 58µs making 28 calls to Foswiki::Form::CORE:match, avg 2µs/call
251
252 # use common defining topics with different field titles
253 $definingTopic = fieldTitle2FieldName($1);
254 $title = $2;
255 }
256
25728792µs my $name = fieldTitle2FieldName($title);
# spent 792µs making 28 calls to Foswiki::Form::fieldTitle2FieldName, avg 28µs/call
258
259 # Rename fields with reserved names
260 if ( $reservedFieldNames{$name} ) {
261 $name .= '_';
262 }
2638415.9ms my $fieldDef = $this->createField(
# spent 15.5ms making 28 calls to Foswiki::Form::createField, avg 552µs/call # spent 220µs making 28 calls to Foswiki::Meta::web, avg 8µs/call # spent 195µs making 28 calls to Foswiki::Meta::topic, avg 7µs/call
264 $type,
265 name => $name,
266 title => $title,
267 size => $size,
268 value => $vals,
269 tooltip => $tooltip,
270 attributes => $attributes,
271 definingTopic => $definingTopic,
272 web => $this->web(),
273 topic => $this->topic()
274 );
275 push( @fields, $fieldDef );
276
277226µs $this->{mandatoryFieldsPresent} ||= $fieldDef->isMandatory();
# spent 26µs making 2 calls to Foswiki::Form::FieldDefinition::isMandatory, avg 13µs/call
278 }
279 else {
280 $inBlock = 0;
281 }
282 }
283
284 return \@fields;
285}
286
287# PROTECTED
288# Create a field object. Done like this so that this method can be
289# overridden by subclasses to extend the range of field types.
290
# spent 15.5ms (7.03+8.43) within Foswiki::Form::createField which was called 28 times, avg 552µs/call: # 28 times (7.03ms+8.43ms) by Foswiki::Form::_parseFormDefinition at line 263, avg 552µs/call
sub createField {
2911682.22ms my $this = shift;
292 my $type = shift;
293
294 # The untaint is required for the validation *and* the ucfirst, which
295 # retaints when use locale is in force
296 my $class = Foswiki::Sandbox::untaint(
297 $type,
298
# spent 526µs (438+88) within Foswiki::Form::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Form.pm:302] which was called 28 times, avg 19µs/call: # 28 times (438µs+88µs) by Foswiki::Sandbox::untaint at line 133 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Sandbox.pm, avg 19µs/call
sub {
29984563µs my $class = shift;
3002888µs $class =~ /^(\w*)/; # cut off +buttons etc
# spent 88µs making 28 calls to Foswiki::Form::CORE:match, avg 3µs/call
301 return 'Foswiki::Form::' . ucfirst($1);
302 }
303281.53ms );
# spent 1.53ms making 28 calls to Foswiki::Sandbox::untaint, avg 55µs/call
304 eval 'require ' . $class;
# spent 191µs executing statements in 14 string evals (merged) # spent 152µs executing statements in 4 string evals (merged) # spent 142µs executing statements in string eval # spent 120µs executing statements in 6 string evals (merged) # spent 116µs executing statements in 2 string evals (merged) # spent 113µs executing statements in string eval
305 if ($@) {
306
307 # Type not available; use base type
308 require Foswiki::Form::FieldDefinition;
309 $class = 'Foswiki::Form::FieldDefinition';
310 }
311566.15ms return $class->new( session => $this->session(), type => $type, @_ );
# spent 3.83ms making 2 calls to Foswiki::Form::Textboxlist::new, avg 1.92ms/call # spent 862µs making 14 calls to Foswiki::Form::FieldDefinition::new, avg 62µs/call # spent 575µs making 6 calls to Foswiki::Form::Text::new, avg 96µs/call # spent 428µs making 4 calls to Foswiki::Form::Select::new, avg 107µs/call # spent 169µs making 28 calls to Foswiki::Meta::session, avg 6µs/call # spent 164µs making 1 call to Foswiki::Form::Checkbox::new # spent 118µs making 1 call to Foswiki::Form::Radio::new
312}
313
314# Generate a link to the given topic, so we can bring up details in a
315# separate window.
316sub _link {
317 my ( $this, $string, $tooltip, $topic ) = @_;
318
319 $string =~ s/[\[\]]//go;
320
321 $topic ||= $string;
322 my $defaultToolTip =
323 $this->session->i18n->maketext('Details in separate window');
324 $tooltip ||= $defaultToolTip;
325
326 ( my $web, $topic ) =
327 $this->session->normalizeWebTopicName( $this->{web}, $topic );
328
329 $web =
330 Foswiki::Sandbox::untaint( $web, \&Foswiki::Sandbox::validateWebName );
331
332 $topic = Foswiki::Sandbox::untaint( $topic,
333 \&Foswiki::Sandbox::validateTopicName );
334
335 my $link;
336
337 if ( $this->session->topicExists( $web, $topic ) ) {
338 $link = CGI::a(
339 {
340 target => $topic,
341 title => $tooltip,
342 href => $this->session->getScriptUrl( 0, 'view', $web, $topic ),
343 rel => 'nofollow'
344 },
345 $string
346 );
347 }
348 else {
349 my $that =
350 Foswiki::Meta->new( $this->session, $web,
351 $topic || $Foswiki::cfg{HomeTopicName} );
352 my $expanded = $that->expandMacros($string);
353 if ( $tooltip ne $defaultToolTip ) {
354 $link = CGI::span( { title => $tooltip }, $expanded );
355 }
356 else {
357 $link = $expanded;
358 }
359 }
360
361 return $link;
362}
363
364sub stringify {
365 my $this = shift;
366 my $fs = "| *Name* | *Type* | *Size* | *Attributes* |\n";
367 foreach my $fieldDef ( @{ $this->{fields} } ) {
368 $fs .= $fieldDef->stringify();
369 }
370 return $fs;
371}
372
373=begin TML
374
375---++ ObjectMethod renderForEdit( $topicObject ) -> $html
376
377 * =$topicObject= the topic being rendered
378
379Render the form fields for entry during an edit session, using data values
380from $meta
381
382=cut
383
384sub renderForEdit {
385 my ( $this, $topicObject ) = @_;
386 ASSERT( $topicObject->isa('Foswiki::Meta') ) if DEBUG;
387 require CGI;
388 my $session = $this->session;
389
390 if ( $this->{mandatoryFieldsPresent} ) {
391 $session->enterContext('mandatoryfields');
392 }
393 my $tmpl = $session->templates->readTemplate('form');
394 $tmpl = $topicObject->expandMacros($tmpl);
395
396 $tmpl =~ s/%FORMTITLE%/$this->_link( $this->web.'.'.$this->topic )/ge;
397 my ( $text, $repeatTitledText, $repeatUntitledText, $afterText ) =
398 split( /%REPEAT%/, $tmpl );
399
400 foreach my $fieldDef ( @{ $this->{fields} } ) {
401
402 my $value;
403 my $tooltip = $fieldDef->{tooltip};
404 my $definingTopic = $fieldDef->{definingTopic};
405 my $title = $fieldDef->{title};
406 my $tmp = '';
407 if ( !$title && !$fieldDef->isEditable() ) {
408
409 # Special handling for untitled labels.
410 # SMELL: Assumes that uneditable fields are not multi-valued
411 $tmp = $repeatUntitledText;
412 $value =
413 $topicObject->renderTML(
414 $topicObject->expandMacros( $fieldDef->{value} ) );
415 }
416 else {
417 $tmp = $repeatTitledText;
418
419 if ( defined( $fieldDef->{name} ) ) {
420 my $field = $topicObject->get( 'FIELD', $fieldDef->{name} );
421 $value = $field->{value};
422 }
423 my $extra = ''; # extras on col 0
424
425 unless ( defined($value) ) {
426 my $dv = $fieldDef->getDefaultValue($value);
427 if ( defined($dv) ) {
428 $dv = $topicObject->expandMacros($dv);
429 $value = Foswiki::expandStandardEscapes($dv); # Item2837
430 }
431 }
432
433 # Give plugin field types a chance first (but no chance to add to
434 # col 0 :-(
435 # SMELL: assumes that the field value is a string
436 my $output = $session->{plugins}->dispatch(
437 'renderFormFieldForEditHandler', $fieldDef->{name},
438 $fieldDef->{type}, $fieldDef->{size},
439 $value, $fieldDef->{attributes},
440 $fieldDef->{value}
441 );
442
443 if ($output) {
444 $value = $output;
445 }
446 else {
447 ( $extra, $value ) =
448 $fieldDef->renderForEdit( $topicObject, $value );
449 }
450
451 if ( $fieldDef->isMandatory() ) {
452 $extra .= CGI::span( { class => 'foswikiAlert' }, ' *' );
453 }
454
455 $tmp =~ s/%ROWTITLE%/
456 $this->_link( $title, $tooltip, $definingTopic )/ge;
457 $tmp =~ s/%ROWEXTRA%/$extra/g;
458 }
459 $tmp =~ s/%ROWVALUE%/$value/g;
460 $text .= $tmp;
461 }
462
463 $text .= $afterText;
464 return $text;
465}
466
467=begin TML
468
469---++ ObjectMethod renderHidden( $topicObject ) -> $html
470
471Render form fields found in the meta as hidden inputs, so they pass
472through edits untouched.
473
474=cut
475
476sub renderHidden {
477 my ( $this, $topicObject ) = @_;
478 ASSERT( $topicObject->isa('Foswiki::Meta') ) if DEBUG;
479
480 my $text = '';
481
482 foreach my $field ( @{ $this->{fields} } ) {
483 $text .= $field->renderHidden($topicObject);
484 }
485
486 return $text;
487}
488
489=begin TML
490
491---++ ObjectMethod getFieldValuesFromQuery($query, $topicObject) -> ( $seen, \@missing )
492
493Extract new values for form fields from a query.
494
495 * =$query= - the query
496 * =$topicObject= - the meta object that is storing the form values
497
498For each field, if there is a value in the query, use it.
499Otherwise if there is already entry for the field in the meta, keep it.
500
501Returns the number of fields which had values provided by the query,
502and a references to an array of the names of mandatory fields that were
503missing from the query.
504
505=cut
506
507sub getFieldValuesFromQuery {
508 my ( $this, $query, $topicObject ) = @_;
509 ASSERT( $topicObject->isa('Foswiki::Meta') ) if DEBUG;
510 my @missing;
511 my $seen = 0;
512
513 # Remove the old defs so we apply the
514 # order in the form definition, and not the
515 # order in the previous meta object. See Item1982.
516 my @old = $topicObject->find('FIELD');
517 $topicObject->remove('FIELD');
518 foreach my $fieldDef ( @{ $this->{fields} } ) {
519 my ( $set, $present ) =
520 $fieldDef->populateMetaFromQueryData( $query, $topicObject, \@old );
521 if ($present) {
522 $seen++;
523 }
524 if ( !$set && $fieldDef->isMandatory() ) {
525
526 # Remember missing mandatory fields
527 push( @missing, $fieldDef->{title} || "unnamed field" );
528 }
529 }
530 return ( $seen, \@missing );
531}
532
533=begin TML
534
535---++ ObjectMethod isTextMergeable( $name ) -> $boolean
536
537 * =$name= - name of a form field (value of the =name= attribute)
538
539Returns true if the type of the named field allows it to be text-merged.
540
541If the form does not define the field, it is assumed to be mergeable.
542
543=cut
544
545sub isTextMergeable {
546 my ( $this, $name ) = @_;
547
548 my $fieldDef = $this->getField($name);
549 if ($fieldDef) {
550 return $fieldDef->isTextMergeable();
551 }
552
553 # Field not found - assume it is mergeable
554 return 1;
555}
556
557=begin TML
558
559---++ ObjectMethod getField( $name ) -> $fieldDefinition
560
561 * =$name= - name of a form field (value of the =name= attribute)
562
563Returns a =Foswiki::Form::FieldDefinition=, or undef if the form does not
564define the field.
565
566=cut
567
568sub getField {
569 my ( $this, $name ) = @_;
570 foreach my $fieldDef ( @{ $this->{fields} } ) {
571 return $fieldDef if ( $fieldDef->{name} && $fieldDef->{name} eq $name );
572 }
573 return;
574}
575
576=begin TML
577
578---++ ObjectMethod getFields() -> \@fields
579
580Return a list containing references to field name/value pairs.
581Each entry in the list has a {name} field and a {value} field. It may
582have other fields as well, which caller should ignore. The
583returned list should be treated as *read only* (must not be written to).
584
585=cut
586
587sub getFields {
588 my $this = shift;
589 return $this->{fields};
590}
591
592
# spent 10.4ms (894µs+9.53) within Foswiki::Form::renderForDisplay which was called: # once (894µs+9.53ms) by Foswiki::Meta::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Meta.pm:1739] at line 1738 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Meta.pm
sub renderForDisplay {
593168989µs my ( $this, $topicObject ) = @_;
594
595217µs my $templates = $this->session->templates;
# spent 13µs making 1 call to Foswiki::templates # spent 4µs making 1 call to Foswiki::Meta::session
59614.85ms $templates->readTemplate('formtables');
# spent 4.85ms making 1 call to Foswiki::Templates::readTemplate
597
59811.30ms my $text = $templates->expandTemplate('FORM:display:header');
# spent 1.30ms making 1 call to Foswiki::Templates::expandTemplate
599
6001220µs my $rowTemplate = $templates->expandTemplate('FORM:display:row');
# spent 220µs making 1 call to Foswiki::Templates::expandTemplate
601 my $hasAllFieldsHidden = 1;
602 foreach my $fieldDef ( @{ $this->{fields} } ) {
60328988µs my $fm = $topicObject->get( 'FIELD', $fieldDef->{name} );
# spent 988µs making 28 calls to Foswiki::Meta::get, avg 35µs/call
604 next unless $fm;
605 my $fa = $fm->{attributes} || '';
6061425µs unless ( $fa =~ /H/ ) {
# spent 25µs making 14 calls to Foswiki::Form::CORE:match, avg 2µs/call
607 $hasAllFieldsHidden = 0;
608 my $row = $rowTemplate;
609
610 # Legacy; was %A_TITLE% before it was $title
6111459µs $row =~ s/%A_TITLE%/\$title/g;
# spent 59µs making 14 calls to Foswiki::Form::CORE:subst, avg 4µs/call
6121442µs $row =~ s/%A_VALUE%/\$value/g; # Legacy
# spent 42µs making 14 calls to Foswiki::Form::CORE:subst, avg 3µs/call
613141.75ms $text .= $fieldDef->renderForDisplay( $row, $fm->{value} );
# spent 1.75ms making 14 calls to Foswiki::Form::FieldDefinition::renderForDisplay, avg 125µs/call
614 }
615 }
616 return '' if $hasAllFieldsHidden;
617
6181231µs $text .= $templates->expandTemplate('FORM:display:footer');
# spent 231µs making 1 call to Foswiki::Templates::expandTemplate
619
620 # substitute remaining placeholders in footer and header
621648µs $text =~ s/%A_TITLE%/$this->getPath()/ge;
# spent 25µs making 2 calls to Foswiki::Meta::getPath, avg 12µs/call # spent 19µs making 3 calls to Foswiki::Form::CORE:substcont, avg 6µs/call # spent 4µs making 1 call to Foswiki::Form::CORE:subst
622
623 return $text;
624}
625
626# extractPseudoFieldDefs( $meta ) -> $fieldDefs
627# Examine the FIELDs in $meta and reverse-engineer a set of field
628# definitions that can be used to construct a new "pseudo-form". This
629# fake form can be used to support editing of topics that have an attached
630# form that has no definition topic.
631sub _extractPseudoFieldDefs {
632 my ( $this, $meta ) = @_;
633 my @fields = $meta->find('FIELD');
634 my @fieldDefs;
635 require Foswiki::Form::FieldDefinition;
636 foreach my $field (@fields) {
637
638 # Fields are name, value, title, but there is no other type
639 # information so we have to treat them all as "text" :-(
640 my $fieldDef = new Foswiki::Form::FieldDefinition(
641 session => $this->session,
642 name => $field->{name},
643 title => $field->{title} || $field->{name},
644 attributes => $field->{attributes} || ''
645 );
646 push( @fieldDefs, $fieldDef );
647 }
648 return \@fieldDefs;
649}
650
651110µs1;
652__END__
 
# spent 309µs within Foswiki::Form::CORE:match which was called 128 times, avg 2µs/call: # 58 times (138µs+0s) by Foswiki::Form::_parseFormDefinition at line 216, avg 2µs/call # 28 times (88µs+0s) by Foswiki::Form::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Form.pm:302] at line 300, avg 3µs/call # 28 times (58µs+0s) by Foswiki::Form::_parseFormDefinition at line 250, avg 2µs/call # 14 times (25µs+0s) by Foswiki::Form::renderForDisplay at line 606, avg 2µs/call
sub Foswiki::Form::CORE:match; # opcode
# spent 1.62ms within Foswiki::Form::CORE:subst which was called 455 times, avg 4µs/call: # 116 times (205µs+0s) by Foswiki::Form::_parseFormDefinition at line 224, avg 2µs/call # 29 times (167µs+0s) by Foswiki::Form::_parseFormDefinition at line 222, avg 6µs/call # 28 times (292µs+0s) by Foswiki::Form::_parseFormDefinition at line 241, avg 10µs/call # 28 times (160µs+0s) by Foswiki::Form::_parseFormDefinition at line 232, avg 6µs/call # 28 times (155µs+0s) by Foswiki::Form::_parseFormDefinition at line 239, avg 6µs/call # 28 times (130µs+0s) by Foswiki::Form::_parseFormDefinition at line 231, avg 5µs/call # 28 times (115µs+0s) by Foswiki::Form::_parseFormDefinition at line 246, avg 4µs/call # 28 times (71µs+0s) by Foswiki::Form::_parseFormDefinition at line 240, avg 3µs/call # 28 times (65µs+0s) by Foswiki::Form::fieldTitle2FieldName at line 194, avg 2µs/call # 28 times (56µs+0s) by Foswiki::Form::_parseFormDefinition at line 223, avg 2µs/call # 28 times (51µs+0s) by Foswiki::Form::fieldTitle2FieldName at line 192, avg 2µs/call # 28 times (42µs+0s) by Foswiki::Form::fieldTitle2FieldName at line 193, avg 1µs/call # 14 times (59µs+0s) by Foswiki::Form::renderForDisplay at line 611, avg 4µs/call # 14 times (42µs+0s) by Foswiki::Form::renderForDisplay at line 612, avg 3µs/call # once (6µs+0s) by Foswiki::Form::_parseFormDefinition at line 211 # once (4µs+0s) by Foswiki::Form::renderForDisplay at line 621
sub Foswiki::Form::CORE:subst; # opcode
# spent 19µs within Foswiki::Form::CORE:substcont which was called 3 times, avg 6µs/call: # 3 times (19µs+0s) by Foswiki::Form::renderForDisplay at line 621, avg 6µs/call
sub Foswiki::Form::CORE:substcont; # opcode