Filename | /var/www/foswikidev/core/lib/Foswiki/UI/View.pm |
Statements | Executed 163 statements in 4.02ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 2.15ms | 3.71ms | BEGIN@25 | Foswiki::UI::View::
3 | 3 | 1 | 934µs | 137s | _prepare | Foswiki::UI::View::
1 | 1 | 1 | 800µs | 4.22ms | BEGIN@23 | Foswiki::UI::View::
1 | 1 | 1 | 590µs | 137s | view | Foswiki::UI::View::
1 | 1 | 1 | 160µs | 163µs | BEGIN@15 | Foswiki::UI::View::
1 | 1 | 1 | 95µs | 4.44ms | revisionsAround | Foswiki::UI::View::
1 | 1 | 1 | 13µs | 27µs | BEGIN@13 | Foswiki::UI::View::
1 | 1 | 1 | 9µs | 14µs | BEGIN@14 | Foswiki::UI::View::
1 | 1 | 1 | 8µs | 34µs | BEGIN@17 | Foswiki::UI::View::
1 | 1 | 1 | 5µs | 5µs | BEGIN@27 | Foswiki::UI::View::
1 | 1 | 1 | 5µs | 5µs | BEGIN@24 | Foswiki::UI::View::
1 | 1 | 1 | 4µs | 4µs | BEGIN@16 | Foswiki::UI::View::
1 | 1 | 1 | 4µs | 4µs | BEGIN@19 | Foswiki::UI::View::
1 | 1 | 1 | 3µs | 3µs | BEGIN@21 | Foswiki::UI::View::
1 | 1 | 1 | 3µs | 3µs | BEGIN@20 | Foswiki::UI::View::
1 | 1 | 1 | 3µs | 3µs | BEGIN@22 | Foswiki::UI::View::
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::UI::View | ||||
6 | |||||
7 | UI delegate for view function | ||||
8 | |||||
9 | =cut | ||||
10 | |||||
11 | package Foswiki::UI::View; | ||||
12 | |||||
13 | 2 | 31µs | 2 | 41µs | # spent 27µs (13+14) within Foswiki::UI::View::BEGIN@13 which was called:
# once (13µs+14µs) by Foswiki::UI::BEGIN@2 at line 13 # spent 27µs making 1 call to Foswiki::UI::View::BEGIN@13
# spent 14µs making 1 call to strict::import |
14 | 2 | 22µs | 2 | 18µs | # spent 14µs (9+5) within Foswiki::UI::View::BEGIN@14 which was called:
# once (9µs+5µs) by Foswiki::UI::BEGIN@2 at line 14 # spent 14µs making 1 call to Foswiki::UI::View::BEGIN@14
# spent 5µs making 1 call to warnings::import |
15 | 2 | 174µs | 2 | 165µs | # spent 163µs (160+3) within Foswiki::UI::View::BEGIN@15 which was called:
# once (160µs+3µs) by Foswiki::UI::BEGIN@2 at line 15 # spent 163µs making 1 call to Foswiki::UI::View::BEGIN@15
# spent 2µs making 1 call to integer::import |
16 | 2 | 20µs | 1 | 4µs | # spent 4µs within Foswiki::UI::View::BEGIN@16 which was called:
# once (4µs+0s) by Foswiki::UI::BEGIN@2 at line 16 # spent 4µs making 1 call to Foswiki::UI::View::BEGIN@16 |
17 | 2 | 24µs | 2 | 60µs | # spent 34µs (8+26) within Foswiki::UI::View::BEGIN@17 which was called:
# once (8µs+26µs) by Foswiki::UI::BEGIN@2 at line 17 # spent 34µs making 1 call to Foswiki::UI::View::BEGIN@17
# spent 26µs making 1 call to Exporter::import |
18 | |||||
19 | 2 | 19µs | 1 | 4µs | # spent 4µs within Foswiki::UI::View::BEGIN@19 which was called:
# once (4µs+0s) by Foswiki::UI::BEGIN@2 at line 19 # spent 4µs making 1 call to Foswiki::UI::View::BEGIN@19 |
20 | 2 | 18µs | 1 | 3µs | # spent 3µs within Foswiki::UI::View::BEGIN@20 which was called:
# once (3µs+0s) by Foswiki::UI::BEGIN@2 at line 20 # spent 3µs making 1 call to Foswiki::UI::View::BEGIN@20 |
21 | 2 | 18µs | 1 | 3µs | # spent 3µs within Foswiki::UI::View::BEGIN@21 which was called:
# once (3µs+0s) by Foswiki::UI::BEGIN@2 at line 21 # spent 3µs making 1 call to Foswiki::UI::View::BEGIN@21 |
22 | 2 | 17µs | 1 | 3µs | # spent 3µs within Foswiki::UI::View::BEGIN@22 which was called:
# once (3µs+0s) by Foswiki::UI::BEGIN@2 at line 22 # spent 3µs making 1 call to Foswiki::UI::View::BEGIN@22 |
23 | 2 | 114µs | 1 | 4.22ms | # spent 4.22ms (800µs+3.42) within Foswiki::UI::View::BEGIN@23 which was called:
# once (800µs+3.42ms) by Foswiki::UI::BEGIN@2 at line 23 # spent 4.22ms making 1 call to Foswiki::UI::View::BEGIN@23 |
24 | 2 | 20µs | 1 | 5µs | # spent 5µs within Foswiki::UI::View::BEGIN@24 which was called:
# once (5µs+0s) by Foswiki::UI::BEGIN@2 at line 24 # spent 5µs making 1 call to Foswiki::UI::View::BEGIN@24 |
25 | 2 | 125µs | 1 | 3.71ms | # spent 3.71ms (2.15+1.56) within Foswiki::UI::View::BEGIN@25 which was called:
# once (2.15ms+1.56ms) by Foswiki::UI::BEGIN@2 at line 25 # spent 3.71ms making 1 call to Foswiki::UI::View::BEGIN@25 |
26 | |||||
27 | # spent 5µs within Foswiki::UI::View::BEGIN@27 which was called:
# once (5µs+0s) by Foswiki::UI::BEGIN@2 at line 32 | ||||
28 | 1 | 5µs | if ( $Foswiki::cfg{UseLocale} ) { | ||
29 | require locale; | ||||
30 | import locale(); | ||||
31 | } | ||||
32 | 1 | 1.89ms | 1 | 5µs | } # spent 5µs making 1 call to Foswiki::UI::View::BEGIN@27 |
33 | |||||
34 | =begin TML | ||||
35 | |||||
36 | ---++ StaticMethod view( $session ) | ||||
37 | |||||
38 | =view= command handler. | ||||
39 | This method is designed to be | ||||
40 | invoked via the =UI::run= method. | ||||
41 | |||||
42 | Generate a complete HTML page that represents the viewed topics. | ||||
43 | The view is controlled by CGI parameters as follows: | ||||
44 | |||||
45 | | =rev= | topic revision to view | | ||||
46 | | =section= | restrict view to a named section | | ||||
47 | | =raw= | no format body text if set | | ||||
48 | | =skin= | comma-separated list of skin(s) to use | | ||||
49 | | =contenttype= | Allows you to specify an alternate content type | | ||||
50 | | =release_lock= | Set to non-blank to release any edit locks held by the current user. | | ||||
51 | |||||
52 | =cut | ||||
53 | |||||
54 | # spent 137s (590µs+137) within Foswiki::UI::View::view which was called:
# once (590µs+137s) by Foswiki::UI::__ANON__[/var/www/foswikidev/core/lib/Foswiki/UI.pm:376] at line 374 of /var/www/foswikidev/core/lib/Foswiki/UI.pm | ||||
55 | 1 | 800ns | my $session = shift; | ||
56 | |||||
57 | 1 | 900ns | my $query = $session->{request}; | ||
58 | 1 | 1µs | my $web = $session->{webName}; | ||
59 | 1 | 1µs | my $topic = $session->{topicName}; | ||
60 | 1 | 800ns | my $user = $session->{user}; | ||
61 | 1 | 700ns | my $users = $session->{users}; | ||
62 | |||||
63 | 1 | 800ns | if ( $session->{invalidTopic} ) { | ||
64 | throw Foswiki::OopsException( | ||||
65 | 'accessdenied', | ||||
66 | status => 404, | ||||
67 | def => 'invalid_topic_name', | ||||
68 | web => $web, | ||||
69 | topic => $topic, | ||||
70 | params => [ $session->{invalidTopic} ] | ||||
71 | ); | ||||
72 | } | ||||
73 | 1 | 2µs | 1 | 19µs | if ( defined $query->param('release_lock') # spent 19µs making 1 call to Foswiki::Request::param |
74 | && $query->param('release_lock') ne '' ) | ||||
75 | { | ||||
76 | $query->delete('release_lock'); | ||||
77 | my $topicObject = Foswiki::Meta->new( $session, $web, $topic ); | ||||
78 | |||||
79 | my $lease = $topicObject->getLease(); | ||||
80 | if ( $lease && $lease->{user} eq $session->{user} ) { | ||||
81 | $topicObject->clearLease(); | ||||
82 | } | ||||
83 | $topicObject->finish(); | ||||
84 | } | ||||
85 | |||||
86 | 1 | 4µs | 1 | 5µs | return if $session->satisfiedByCache( 'view', $web, $topic ); # spent 5µs making 1 call to Foswiki::satisfiedByCache |
87 | |||||
88 | Foswiki::Func::writeDebug("computing page for $web.$topic") | ||||
89 | if Foswiki::PageCache::TRACE(); | ||||
90 | |||||
91 | 1 | 900ns | my $response = $session->{response}; | ||
92 | 1 | 3µs | 1 | 3µs | my $method = $session->{request}->method || ''; # spent 3µs making 1 call to Foswiki::Request::method |
93 | 1 | 2µs | 1 | 13µs | my $raw = $query->param('raw') || ''; # spent 13µs making 1 call to Foswiki::Request::param |
94 | 1 | 2µs | 1 | 12µs | my $requestedRev = $query->param('rev'); # spent 12µs making 1 call to Foswiki::Request::param |
95 | |||||
96 | 1 | 2µs | 1 | 12µs | my $contentType = $query->param('contenttype'); # spent 12µs making 1 call to Foswiki::Request::param |
97 | |||||
98 | 1 | 300ns | my $logEntry = ''; | ||
99 | |||||
100 | # is this view indexable by search engines? Default yes. | ||||
101 | 1 | 200ns | my $indexableView = 1; | ||
102 | 1 | 300ns | my $viewTemplate; | ||
103 | |||||
104 | 1 | 4µs | 1 | 90µs | Foswiki::UI::checkWebExists( $session, $web, 'view' ); # spent 90µs making 1 call to Foswiki::UI::checkWebExists |
105 | |||||
106 | 1 | 300ns | if ( defined $requestedRev ) { | ||
107 | $requestedRev = Foswiki::Store::cleanUpRevID($requestedRev); | ||||
108 | unless ($requestedRev) { | ||||
109 | |||||
110 | # Invalid request, remove it from the query. | ||||
111 | $requestedRev = undef; | ||||
112 | $query->delete('rev'); | ||||
113 | } | ||||
114 | } | ||||
115 | |||||
116 | 1 | 800ns | my $showLatest = !$requestedRev; | ||
117 | 1 | 200ns | my $showRev; | ||
118 | |||||
119 | 1 | 200ns | my $topicObject; # the stub of the topic we are to display | ||
120 | 1 | 100ns | my $text; # the text to display, *not* necessarily | ||
121 | # the same as $topicObject->text | ||||
122 | 1 | 500ns | my $revIt; # Iterator over the range of available revs | ||
123 | 1 | 200ns | my $maxRev; | ||
124 | |||||
125 | 1 | 4µs | 1 | 59µs | if ( $session->topicExists( $web, $topic ) ) { # spent 59µs making 1 call to Foswiki::topicExists |
126 | |||||
127 | # Load the most recent rev. This *should* be maxRev, but may | ||||
128 | # not say it is because the TOPICINFO could be up the spout | ||||
129 | 1 | 4µs | 1 | 565µs | $topicObject = Foswiki::Meta->load( $session, $web, $topic ); # spent 565µs making 1 call to Foswiki::Meta::load |
130 | 1 | 4µs | 1 | 37µs | Foswiki::UI::checkAccess( $session, 'VIEW', $topicObject ); # spent 37µs making 1 call to Foswiki::UI::checkAccess |
131 | |||||
132 | # If we are applying control to the raw view: | ||||
133 | 1 | 400ns | if ( $raw | ||
134 | && defined $Foswiki::cfg{FeatureAccess}{AllowRaw} | ||||
135 | && $Foswiki::cfg{FeatureAccess}{AllowRaw} ne 'all' ) | ||||
136 | { | ||||
137 | |||||
138 | if ( $Foswiki::cfg{FeatureAccess}{AllowRaw} eq 'authenticated' ) { | ||||
139 | throw Foswiki::AccessControlException( 'authenticated', | ||||
140 | $session->{user}, $web, $topic, $Foswiki::Meta::reason ) | ||||
141 | unless $session->inContext("authenticated"); | ||||
142 | } | ||||
143 | else { | ||||
144 | Foswiki::UI::checkAccess( $session, 'RAW', $topicObject ) | ||||
145 | unless $topicObject->haveAccess('CHANGE'); | ||||
146 | } | ||||
147 | } | ||||
148 | |||||
149 | # If we are applying control to the revisions: | ||||
150 | 1 | 400ns | if ( $requestedRev | ||
151 | && defined $Foswiki::cfg{FeatureAccess}{AllowHistory} | ||||
152 | && $Foswiki::cfg{FeatureAccess}{AllowHistory} ne 'all' ) | ||||
153 | { | ||||
154 | |||||
155 | if ( $Foswiki::cfg{FeatureAccess}{AllowHistory} eq 'authenticated' ) | ||||
156 | { | ||||
157 | throw Foswiki::AccessControlException( 'authenticated', | ||||
158 | $session->{user}, $web, $topic, $Foswiki::Meta::reason ) | ||||
159 | unless $session->inContext("authenticated"); | ||||
160 | } | ||||
161 | else { | ||||
162 | Foswiki::UI::checkAccess( $session, 'HISTORY', $topicObject ); | ||||
163 | } | ||||
164 | } | ||||
165 | |||||
166 | 1 | 3µs | 1 | 408µs | $revIt = $topicObject->getRevisionHistory(); # spent 408µs making 1 call to Foswiki::Meta::getRevisionHistory |
167 | |||||
168 | # The topic exists; it must have at least one rev | ||||
169 | ASSERT( $revIt->hasNext() ) if DEBUG; | ||||
170 | 1 | 3µs | 1 | 4µs | $maxRev = $revIt->next(); # spent 4µs making 1 call to Foswiki::Iterator::NumberRangeIterator::next |
171 | |||||
172 | 1 | 1µs | if ( defined $requestedRev ) { | ||
173 | |||||
174 | # Is the requested rev id known? | ||||
175 | $revIt->reset(); | ||||
176 | while ( $revIt->hasNext() ) { | ||||
177 | if ( $requestedRev eq $revIt->next() ) { | ||||
178 | $showRev = $requestedRev; | ||||
179 | last; | ||||
180 | } | ||||
181 | } | ||||
182 | |||||
183 | # if rev was not found; show max rev | ||||
184 | $showRev = $maxRev unless ( defined $showRev ); | ||||
185 | |||||
186 | if ( $showRev ne $maxRev ) { | ||||
187 | |||||
188 | # Load the old revision instead | ||||
189 | $topicObject = | ||||
190 | Foswiki::Meta->load( $session, $web, $topic, $showRev ); | ||||
191 | if ( !$topicObject->haveAccess('VIEW') ) { | ||||
192 | throw Foswiki::AccessControlException( 'VIEW', | ||||
193 | $session->{user}, $web, $topic, | ||||
194 | $Foswiki::Meta::reason ); | ||||
195 | } | ||||
196 | $logEntry .= 'r' . $requestedRev; | ||||
197 | } | ||||
198 | } | ||||
199 | else { | ||||
200 | 1 | 400ns | $showRev = $maxRev; | ||
201 | } | ||||
202 | |||||
203 | 1 | 3µs | 1 | 17µs | if ( my $section = $query->param('section') ) { # spent 17µs making 1 call to Foswiki::Request::param |
204 | |||||
205 | # Apply the 'section' selection (and maybe others in the | ||||
206 | # future as well). $text is cleared unless a named section | ||||
207 | # matching the 'section' URL parameter is found. | ||||
208 | my ( $ntext, $sections ) = | ||||
209 | Foswiki::parseSections( $topicObject->text() ); | ||||
210 | $text = ''; # in the beginning, there was ... NO section | ||||
211 | FINDSECTION: | ||||
212 | for my $s (@$sections) { | ||||
213 | if ( $s->{type} eq 'section' && $s->{name} eq $section ) { | ||||
214 | $text = | ||||
215 | substr( $ntext, $s->{start}, $s->{end} - $s->{start} ); | ||||
216 | last FINDSECTION; | ||||
217 | } | ||||
218 | } | ||||
219 | } | ||||
220 | else { | ||||
221 | |||||
222 | # Otherwise take the full topic text | ||||
223 | 1 | 2µs | 1 | 4µs | $text = $topicObject->text(); # spent 4µs making 1 call to Foswiki::Meta::text |
224 | } | ||||
225 | } | ||||
226 | else { # Topic does not exist yet | ||||
227 | $topicObject = Foswiki::Meta->new( $session, $web, $topic ); | ||||
228 | |||||
229 | # If user would not be able to access the topic, don't reveal that | ||||
230 | # it does not exist | ||||
231 | Foswiki::UI::checkAccess( $session, 'VIEW', $topicObject ); | ||||
232 | |||||
233 | $indexableView = 0; | ||||
234 | $session->enterContext('new_topic'); | ||||
235 | $response->status(404); | ||||
236 | $showRev = 1; | ||||
237 | $maxRev = 0; | ||||
238 | $viewTemplate = 'TopicDoesNotExistView'; | ||||
239 | $logEntry .= ' (not exist)'; | ||||
240 | $raw = ''; # There is no raw view of a topic that doesn't exist | ||||
241 | $revIt = new Foswiki::ListIterator( [1] ); | ||||
242 | } | ||||
243 | |||||
244 | 1 | 500ns | if ($raw) { | ||
245 | $indexableView = 0; | ||||
246 | $logEntry .= ' raw=' . $raw; | ||||
247 | if ( $raw eq 'debug' || $raw eq 'all' ) { | ||||
248 | |||||
249 | # We want to see the embedded store form | ||||
250 | $text = Foswiki::Serialise::serialise( $topicObject, 'Embedded' ); | ||||
251 | } | ||||
252 | } | ||||
253 | |||||
254 | 1 | 300ns | $text = '' unless defined $text; | ||
255 | |||||
256 | 1 | 12µs | 4 | 4.97ms | $session->logger->log( # spent 4.47ms making 1 call to Foswiki::logger
# spent 496µs making 1 call to Foswiki::Logger::PlainFile::log
# spent 2µs making 1 call to Foswiki::Meta::web
# spent 2µs making 1 call to Foswiki::Meta::topic |
257 | { | ||||
258 | level => 'info', | ||||
259 | action => 'view', | ||||
260 | webTopic => $topicObject->web . '.' . $topicObject->topic, | ||||
261 | extra => $logEntry . " ($method)" | ||||
262 | } | ||||
263 | ); | ||||
264 | |||||
265 | 1 | 1µs | if ( $method && $method eq 'HEAD' ) { | ||
266 | return $session->writeCompletePage( '', 'view', 'text/plain' ); | ||||
267 | } | ||||
268 | |||||
269 | # Note; must enter all contexts before the template is read, as | ||||
270 | # TMPL:P is expanded on the fly in the template reader. :-( | ||||
271 | 1 | 1µs | my ( $revTitle, $revArg ) = ( '', '' ); | ||
272 | 1 | 3µs | 1 | 3µs | $revIt->reset(); # spent 3µs making 1 call to Foswiki::Iterator::NumberRangeIterator::reset |
273 | 1 | 2µs | 1 | 2µs | if ( $showRev && $showRev != $revIt->next() ) { # spent 2µs making 1 call to Foswiki::Iterator::NumberRangeIterator::next |
274 | $session->enterContext('inactive'); | ||||
275 | |||||
276 | # disable edit of previous revisions | ||||
277 | $revTitle = '(r' . $showRev . ')'; | ||||
278 | $revArg = '&rev=' . $showRev; | ||||
279 | } | ||||
280 | |||||
281 | 1 | 6µs | 2 | 38µs | my $template = # spent 20µs making 1 call to Foswiki::Prefs::getPreference
# spent 18µs making 1 call to Foswiki::Request::param |
282 | $viewTemplate | ||||
283 | || $query->param('template') | ||||
284 | || $session->{prefs}->getPreference('VIEW_TEMPLATE') | ||||
285 | || 'view'; | ||||
286 | |||||
287 | # Always use default view template for raw=debug, raw=all and raw=on | ||||
288 | 1 | 600ns | if ( $raw =~ m/^(debug|all|on)$/ ) { | ||
289 | $template = 'view'; | ||||
290 | } | ||||
291 | |||||
292 | 1 | 9µs | 2 | 35.0ms | my $tmpl = $session->templates->readTemplate( $template, no_oops => 1 ); # spent 35.0ms making 1 call to Foswiki::Templates::readTemplate
# spent 2µs making 1 call to Foswiki::templates |
293 | |||||
294 | # If the VIEW_TEMPLATE (or other) doesn't exist, default to view. | ||||
295 | 1 | 1µs | $tmpl = $session->templates->readTemplate('view') unless defined($tmpl); | ||
296 | |||||
297 | 1 | 20µs | $tmpl =~ s/%REVTITLE%/$revTitle/g; | ||
298 | 1 | 20µs | $tmpl =~ s/%REVARG%/$revArg/g; | ||
299 | |||||
300 | 1 | 4µs | 1 | 15µs | if ( $indexableView # spent 15µs making 1 call to Foswiki::Request::param |
301 | && $Foswiki::cfg{AntiSpam}{RobotsAreWelcome} | ||||
302 | && !$query->param() ) | ||||
303 | { | ||||
304 | |||||
305 | # it's an indexable view type, there are no parameters | ||||
306 | # on the url, and robots are welcome. Remove the NOINDEX meta tag | ||||
307 | $tmpl =~ s/<meta name="robots"[^>]*>//gi; | ||||
308 | } | ||||
309 | |||||
310 | # Show revisions around the one being displayed. | ||||
311 | 1 | 33µs | 1 | 4.44ms | $tmpl =~ s/%REVISIONS%/ # spent 4.44ms making 1 call to Foswiki::UI::View::revisionsAround |
312 | revisionsAround( | ||||
313 | $session, $topicObject, $requestedRev, $showRev, $maxRev)/e; | ||||
314 | |||||
315 | ## SMELL: This is also used in Foswiki::_TOC. Could insert a tag in | ||||
316 | ## TOC and remove all those here, finding the parameters only once | ||||
317 | 1 | 900ns | my @qparams = (); | ||
318 | 1 | 3µs | 1 | 14µs | foreach my $name ( $query->param ) { # spent 14µs making 1 call to Foswiki::Request::param |
319 | 2 | 700ns | next if ( $name eq 'keywords' ); | ||
320 | 2 | 700ns | next if ( $name eq 'topic' ); | ||
321 | |||||
322 | # SMELL if multi-value is allowed here, this isn't correct, | ||||
323 | # but calling multi_param doesn't seem correct either. | ||||
324 | 1 | 2µs | 1 | 15µs | push @qparams, $name => scalar( $query->param($name) ); # spent 15µs making 1 call to Foswiki::Request::param |
325 | } | ||||
326 | |||||
327 | # SMELL: %QUERYPARAMSTRING% isn't a documented macro, and is | ||||
328 | # no longer used in core or core extensions. Maintained for | ||||
329 | # legacy only. | ||||
330 | 1 | 7µs | if ( $tmpl =~ m/%QUERYPARAMSTRING%/ ) { | ||
331 | my $qps = Foswiki::make_params(@qparams); | ||||
332 | $qps =~ s/^.*\?/;/; # remove any anchor (there should be none) and the ? | ||||
333 | $tmpl =~ s/%QUERYPARAMSTRING%/$qps/g; | ||||
334 | } | ||||
335 | |||||
336 | # extract header and footer from the template, if there is a | ||||
337 | # %TEXT% tag marking the split point. The topic text is inserted | ||||
338 | # in place of the %TEXT% tag. The text before this tag is inserted | ||||
339 | # as header, the text after is inserted as footer. If there is a | ||||
340 | # %STARTTEXT% tag present, the header text between %STARTTEXT% and | ||||
341 | # %TEXT is rendered together, as is the footer text between %TEXT% | ||||
342 | # and %ENDTEXT%, if present. This allows correct handling of Foswiki | ||||
343 | # markup in header or footer if those do require examination of the | ||||
344 | # topic text to work correctly (e.g., %TOC%). | ||||
345 | # Note: This feature is experimental and may be replaced by an | ||||
346 | # alternative solution not requiring additional tags. | ||||
347 | 1 | 900ns | my ( $start, $end ); | ||
348 | |||||
349 | # SMELL: unchecked implicit untaint of data that *may* be coming from | ||||
350 | # a topic (topics can be templates) | ||||
351 | 1 | 169µs | if ( $tmpl =~ m/^(.*)%TEXT%(.*)$/s ) { | ||
352 | 1 | 16µs | my @starts = split( /%STARTTEXT%/, $1 ); | ||
353 | 1 | 1µs | if ( $#starts > 0 ) { | ||
354 | |||||
355 | # we know that there is something before %STARTTEXT% | ||||
356 | $start = $starts[0]; | ||||
357 | $text = $starts[1] . $text; | ||||
358 | } | ||||
359 | else { | ||||
360 | 1 | 2µs | $start = $1; | ||
361 | } | ||||
362 | 1 | 10µs | my @ends = split( /%ENDTEXT%/, $2 ); | ||
363 | 1 | 1µs | if ( $#ends > 0 ) { | ||
364 | |||||
365 | # we know that there is something after %ENDTEXT% | ||||
366 | $text .= $ends[0]; | ||||
367 | $end = $ends[1]; | ||||
368 | } | ||||
369 | else { | ||||
370 | 1 | 1µs | $end = $2; | ||
371 | } | ||||
372 | } | ||||
373 | else { | ||||
374 | my @starts = split( /%STARTTEXT%/, $tmpl ); | ||||
375 | if ( $#starts > 0 ) { | ||||
376 | |||||
377 | # we know that there is something before %STARTTEXT% | ||||
378 | $start = $starts[0]; | ||||
379 | $text = $starts[1]; | ||||
380 | } | ||||
381 | else { | ||||
382 | $start = $tmpl; | ||||
383 | $text = ''; | ||||
384 | } | ||||
385 | $end = ''; | ||||
386 | } | ||||
387 | |||||
388 | # If minimalist is set, images and anchors will be stripped from text | ||||
389 | 1 | 600ns | my $minimalist = 0; | ||
390 | 1 | 7µs | 2 | 117µs | if ($contentType) { # spent 117µs making 2 calls to Foswiki::getSkin, avg 59µs/call |
391 | $minimalist = ( $session->getSkin() =~ m/\brss/ ); | ||||
392 | } | ||||
393 | elsif ( $session->getSkin() =~ m/\brss/ ) { | ||||
394 | $contentType = 'text/xml'; | ||||
395 | $minimalist = 1; | ||||
396 | } | ||||
397 | elsif ( $session->getSkin() =~ m/\bxml/ ) { | ||||
398 | $contentType = 'text/xml'; | ||||
399 | $minimalist = 1; | ||||
400 | } | ||||
401 | elsif ( $raw eq 'text' || $raw eq 'all' ) { | ||||
402 | $contentType = 'text/plain'; | ||||
403 | } | ||||
404 | else { | ||||
405 | 1 | 600ns | $contentType = 'text/html'; | ||
406 | } | ||||
407 | 1 | 3µs | 1 | 70µs | $session->{prefs}->setSessionPreferences( # spent 70µs making 1 call to Foswiki::Prefs::setSessionPreferences |
408 | MAXREV => $maxRev, | ||||
409 | CURRREV => $showRev | ||||
410 | ); | ||||
411 | |||||
412 | # Set page generation mode to RSS if using an RSS skin | ||||
413 | 1 | 6µs | 1 | 59µs | if ( $session->getSkin() =~ m/\brss/ ) { # spent 59µs making 1 call to Foswiki::getSkin |
414 | $session->enterContext('rss'); | ||||
415 | $session->enterContext('absolute_urls'); | ||||
416 | } | ||||
417 | |||||
418 | 1 | 500ns | my $page; | ||
419 | |||||
420 | # Legacy: If the _only_ skin is 'text' it is used like this: | ||||
421 | # http://.../view/Codev/MyTopic?skin=text&contenttype=text/plain&raw=on | ||||
422 | # which shows the topic as plain text; useful for those who want | ||||
423 | # to download plain text for the topic. So when the skin is 'text' | ||||
424 | # we do _not_ want to create a textarea. | ||||
425 | # raw=on&skin=text is deprecated; use raw=text instead. | ||||
426 | 1 | 2µs | 1 | 1µs | Monitor::MARK('Ready to render'); # spent 1µs making 1 call to Monitor::__ANON__[/var/www/foswikidev/core/lib/Monitor.pm:119] |
427 | 1 | 2µs | if ( $raw eq 'text' | ||
428 | || $raw eq 'all' | ||||
429 | || ( $raw && $session->getSkin() eq 'text' ) ) | ||||
430 | { | ||||
431 | |||||
432 | # use raw text | ||||
433 | $page = $text; | ||||
434 | } | ||||
435 | else { | ||||
436 | 1 | 1µs | my @args = ( $topicObject, $minimalist ); | ||
437 | |||||
438 | 1 | 2µs | 1 | 3µs | $session->enterContext('header_text'); # spent 3µs making 1 call to Foswiki::enterContext |
439 | 1 | 3µs | 1 | 207ms | $page = _prepare( $start, @args ); # spent 207ms making 1 call to Foswiki::UI::View::_prepare |
440 | 1 | 3µs | 1 | 6µs | $session->leaveContext('header_text'); # spent 6µs making 1 call to Foswiki::leaveContext |
441 | 1 | 3µs | 1 | 3µs | Monitor::MARK('Rendered header'); # spent 3µs making 1 call to Monitor::__ANON__[/var/www/foswikidev/core/lib/Monitor.pm:119] |
442 | |||||
443 | 1 | 2µs | if ($raw) { | ||
444 | if ($text) { | ||||
445 | my $p = $session->{prefs}; | ||||
446 | $page .= CGI::textarea( | ||||
447 | -readonly => 'readonly', | ||||
448 | -rows => $p->getPreference('EDITBOXHEIGHT'), | ||||
449 | -cols => $p->getPreference('EDITBOXWIDTH'), | ||||
450 | -style => $p->getPreference('EDITBOXSTYLE'), | ||||
451 | -class => 'foswikiTextarea foswikiTextareaRawView', | ||||
452 | -id => 'topic', | ||||
453 | -default => $text | ||||
454 | ); | ||||
455 | } | ||||
456 | } | ||||
457 | else { | ||||
458 | 1 | 2µs | 1 | 4µs | $session->enterContext('body_text'); # spent 4µs making 1 call to Foswiki::enterContext |
459 | 1 | 15µs | 1 | 137s | $page .= _prepare( $text, @args ); # spent 137s making 1 call to Foswiki::UI::View::_prepare |
460 | 1 | 5µs | 1 | 10µs | $session->leaveContext('body_text'); # spent 10µs making 1 call to Foswiki::leaveContext |
461 | } | ||||
462 | |||||
463 | 1 | 5µs | 1 | 5µs | Monitor::MARK('Rendered body'); # spent 5µs making 1 call to Monitor::__ANON__[/var/www/foswikidev/core/lib/Monitor.pm:119] |
464 | 1 | 2µs | 1 | 6µs | $session->enterContext('footer_text'); # spent 6µs making 1 call to Foswiki::enterContext |
465 | 1 | 15µs | 1 | 165ms | $page .= _prepare( $end, @args ); # spent 165ms making 1 call to Foswiki::UI::View::_prepare |
466 | 1 | 4µs | 1 | 6µs | $session->leaveContext('footer_text'); # spent 6µs making 1 call to Foswiki::leaveContext |
467 | 1 | 6µs | 1 | 3µs | Monitor::MARK('Rendered footer'); # spent 3µs making 1 call to Monitor::__ANON__[/var/www/foswikidev/core/lib/Monitor.pm:119] |
468 | } | ||||
469 | |||||
470 | # Output has to be done in one go, because if we generate the header and | ||||
471 | # then redirect because of some later constraint, some browsers fall over | ||||
472 | 1 | 6µs | 1 | 23.4ms | $session->writeCompletePage( $page, 'view', $contentType ); # spent 23.4ms making 1 call to Foswiki::writeCompletePage |
473 | 1 | 30µs | 1 | 2µs | Monitor::MARK('Wrote HTML'); # spent 2µs making 1 call to Monitor::__ANON__[/var/www/foswikidev/core/lib/Monitor.pm:119] |
474 | } | ||||
475 | |||||
476 | sub _prepare { | ||||
477 | 3 | 7µs | my ( $text, $topicObject, $minimalist ) = @_; | ||
478 | |||||
479 | 3 | 11µs | 3 | 137s | $text = $topicObject->expandMacros($text); # spent 137s making 3 calls to Foswiki::Meta::expandMacros, avg 45.7s/call |
480 | 3 | 11µs | 3 | 44.3ms | $text = $topicObject->renderTML($text); # spent 44.3ms making 3 calls to Foswiki::Meta::renderTML, avg 14.8ms/call |
481 | 3 | 884µs | $text =~ s/( ?) *<\/?(nop|noautolink)\/?>\n?/$1/gis; | ||
482 | |||||
483 | 3 | 2µs | if ($minimalist) { | ||
484 | $text =~ s/<img [^>]*>//gi; # remove image tags | ||||
485 | $text =~ s/<a [^>]*>//gi; # remove anchor tags | ||||
486 | $text =~ s/<\/a>//gi; # remove anchor tags | ||||
487 | } | ||||
488 | |||||
489 | 3 | 23µs | return $text; | ||
490 | } | ||||
491 | |||||
492 | =begin TML | ||||
493 | |||||
494 | ---++ StaticMethod revisionsAround($session, $topicObject, $requestedRev, $showRev, $maxRev) -> $output | ||||
495 | |||||
496 | Calculate the revisions spanning the current one for display in the bottom | ||||
497 | bar. | ||||
498 | |||||
499 | =cut | ||||
500 | |||||
501 | # spent 4.44ms (95µs+4.35) within Foswiki::UI::View::revisionsAround which was called:
# once (95µs+4.35ms) by Foswiki::UI::View::view at line 311 | ||||
502 | 1 | 2µs | my ( $session, $topicObject, $requestedRev, $showRev, $maxRev ) = @_; | ||
503 | |||||
504 | 1 | 2µs | my $revsToShow = $Foswiki::cfg{NumberOfRevisions} + 1; | ||
505 | |||||
506 | # Soak up the revision iterator | ||||
507 | 1 | 2µs | 1 | 339µs | my $revIt = $topicObject->getRevisionHistory(); # spent 339µs making 1 call to Foswiki::Meta::getRevisionHistory |
508 | 1 | 6µs | 1 | 42µs | my @revs = $revIt->all(); # spent 42µs making 1 call to Foswiki::Iterator::all |
509 | 1 | 300ns | my $maxRevDisjoint = 0; | ||
510 | |||||
511 | 1 | 1µs | if ( $Foswiki::cfg{NumberOfRevisions} ) { | ||
512 | |||||
513 | # Locate the preferred rev in the array | ||||
514 | 1 | 600ns | my $showIndex = $#revs; | ||
515 | 1 | 400ns | my $left = 0; | ||
516 | 1 | 700ns | my $right = $Foswiki::cfg{NumberOfRevisions}; | ||
517 | 1 | 400ns | if ($requestedRev) { | ||
518 | while ( $showIndex && $revs[$showIndex] != $showRev ) { | ||||
519 | $showIndex--; | ||||
520 | } | ||||
521 | $right = $showIndex + $Foswiki::cfg{NumberOfRevisions} - 1; | ||||
522 | $right = scalar(@revs) if $right > scalar(@revs); | ||||
523 | $left = $right - $Foswiki::cfg{NumberOfRevisions}; | ||||
524 | if ( $left < 0 ) { | ||||
525 | $left = 0; | ||||
526 | $right = $Foswiki::cfg{NumberOfRevisions}; | ||||
527 | } | ||||
528 | } | ||||
529 | 1 | 600ns | splice( @revs, $right ) if ( $right < scalar(@revs) ); | ||
530 | 1 | 1µs | splice( @revs, 0, $left ); | ||
531 | 1 | 500ns | if ( $left > 0 ) { | ||
532 | |||||
533 | # Put the max rev back in at the front, and flag | ||||
534 | # special treatment | ||||
535 | $maxRevDisjoint = 1; | ||||
536 | unshift( @revs, $maxRev ); | ||||
537 | } | ||||
538 | } | ||||
539 | |||||
540 | 1 | 600ns | my $output = ''; | ||
541 | 1 | 300ns | my $r = 0; | ||
542 | 1 | 800ns | while ( $r < scalar(@revs) ) { | ||
543 | 3 | 5µs | if ( $revs[$r] == $showRev ) { | ||
544 | $output .= 'r' . $showRev; | ||||
545 | } | ||||
546 | else { | ||||
547 | 2 | 15µs | 8 | 180µs | $output .= CGI::a( # spent 101µs making 2 calls to Foswiki::getScriptUrl, avg 51µs/call
# spent 72µs making 2 calls to CGI::a, avg 36µs/call
# spent 4µs making 2 calls to Foswiki::Meta::web, avg 2µs/call
# spent 3µs making 2 calls to Foswiki::Meta::topic, avg 2µs/call |
548 | { | ||||
549 | href => $session->getScriptUrl( | ||||
550 | 0, 'view', | ||||
551 | $topicObject->web, $topicObject->topic, | ||||
552 | rev => $revs[$r] | ||||
553 | ), | ||||
554 | rel => 'nofollow' | ||||
555 | }, | ||||
556 | 'r' . $revs[$r] | ||||
557 | ); | ||||
558 | } | ||||
559 | 3 | 25µs | 8 | 3.06ms | if ( $r == 0 && $maxRevDisjoint ) { # spent 2.87ms making 1 call to CGI::AUTOLOAD
# spent 157µs making 2 calls to Foswiki::getScriptUrl, avg 78µs/call
# spent 35µs making 1 call to CGI::a
# spent 4µs making 2 calls to Foswiki::Meta::web, avg 2µs/call
# spent 3µs making 2 calls to Foswiki::Meta::topic, avg 2µs/call |
560 | $output .= ' | '; | ||||
561 | } | ||||
562 | elsif ( $r < $#revs ) { | ||||
563 | $output .= ' ' | ||||
564 | . CGI::a( | ||||
565 | { | ||||
566 | href => $session->getScriptUrl( | ||||
567 | 0, 'rdiff', $topicObject->web, $topicObject->topic, | ||||
568 | rev1 => $revs[ $r + 1 ], | ||||
569 | rev2 => $revs[$r] | ||||
570 | ), | ||||
571 | rel => 'nofollow' | ||||
572 | }, | ||||
573 | '<' | ||||
574 | ) . ' '; | ||||
575 | } | ||||
576 | 3 | 2µs | $r++; | ||
577 | } | ||||
578 | 1 | 7µs | return $output; | ||
579 | } | ||||
580 | |||||
581 | 1 | 2µs | 1; | ||
582 | __END__ |