← Index
NYTProf Performance Profile   « line view »
For ./view
  Run on Fri Jul 31 18:42:36 2015
Reported on Fri Jul 31 18:48:14 2015

Filename/var/www/foswikidev/core/lib/Foswiki/Plugins/WysiwygPlugin.pm
StatementsExecuted 251 statements in 2.35ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
2213.41ms4.76msFoswiki::Plugins::WysiwygPlugin::::addXMLTagFoswiki::Plugins::WysiwygPlugin::addXMLTag
10011486µs627µsFoswiki::Plugins::WysiwygPlugin::::beforeCommonTagsHandlerFoswiki::Plugins::WysiwygPlugin::beforeCommonTagsHandler
11163µs175µsFoswiki::Plugins::WysiwygPlugin::::initPluginFoswiki::Plugins::WysiwygPlugin::initPlugin
51119µs19µsFoswiki::Plugins::WysiwygPlugin::::postRenderingHandlerFoswiki::Plugins::WysiwygPlugin::postRenderingHandler
11115µs37µsFoswiki::Plugins::WysiwygPlugin::::modifyHeaderHandlerFoswiki::Plugins::WysiwygPlugin::modifyHeaderHandler
11114µs27µsFoswiki::Plugins::WysiwygPlugin::::BEGIN@25Foswiki::Plugins::WysiwygPlugin::BEGIN@25
11110µs37µsFoswiki::Plugins::WysiwygPlugin::::BEGIN@28Foswiki::Plugins::WysiwygPlugin::BEGIN@28
11110µs24µsFoswiki::Plugins::WysiwygPlugin::::BEGIN@156Foswiki::Plugins::WysiwygPlugin::BEGIN@156
11110µs14µsFoswiki::Plugins::WysiwygPlugin::::BEGIN@26Foswiki::Plugins::WysiwygPlugin::BEGIN@26
11110µs40µsFoswiki::Plugins::WysiwygPlugin::::BEGIN@45Foswiki::Plugins::WysiwygPlugin::BEGIN@45
1119µs18µsFoswiki::Plugins::WysiwygPlugin::::BEGIN@158Foswiki::Plugins::WysiwygPlugin::BEGIN@158
0000s0sFoswiki::Plugins::WysiwygPlugin::::__ANON__[:72]Foswiki::Plugins::WysiwygPlugin::__ANON__[:72]
0000s0sFoswiki::Plugins::WysiwygPlugin::::__ANON__[:74]Foswiki::Plugins::WysiwygPlugin::__ANON__[:74]
0000s0sFoswiki::Plugins::WysiwygPlugin::::__ANON__[:76]Foswiki::Plugins::WysiwygPlugin::__ANON__[:76]
0000s0sFoswiki::Plugins::WysiwygPlugin::::__ANON__[:78]Foswiki::Plugins::WysiwygPlugin::__ANON__[:78]
0000s0sFoswiki::Plugins::WysiwygPlugin::::__ANON__[:80]Foswiki::Plugins::WysiwygPlugin::__ANON__[:80]
0000s0sFoswiki::Plugins::WysiwygPlugin::::__ANON__[:91]Foswiki::Plugins::WysiwygPlugin::__ANON__[:91]
0000s0sFoswiki::Plugins::WysiwygPlugin::::__ANON__[:93]Foswiki::Plugins::WysiwygPlugin::__ANON__[:93]
0000s0sFoswiki::Plugins::WysiwygPlugin::::__ANON__[:95]Foswiki::Plugins::WysiwygPlugin::__ANON__[:95]
0000s0sFoswiki::Plugins::WysiwygPlugin::::_executeFoswiki::Plugins::WysiwygPlugin::_execute
0000s0sFoswiki::Plugins::WysiwygPlugin::::afterEditHandlerFoswiki::Plugins::WysiwygPlugin::afterEditHandler
0000s0sFoswiki::Plugins::WysiwygPlugin::::beforeEditHandlerFoswiki::Plugins::WysiwygPlugin::beforeEditHandler
0000s0sFoswiki::Plugins::WysiwygPlugin::::beforeMergeHandlerFoswiki::Plugins::WysiwygPlugin::beforeMergeHandler
0000s0sFoswiki::Plugins::WysiwygPlugin::::beforeSaveHandlerFoswiki::Plugins::WysiwygPlugin::beforeSaveHandler
0000s0sFoswiki::Plugins::WysiwygPlugin::::getBrowserNameFoswiki::Plugins::WysiwygPlugin::getBrowserName
0000s0sFoswiki::Plugins::WysiwygPlugin::::notWysiwygEditableFoswiki::Plugins::WysiwygPlugin::notWysiwygEditable
0000s0sFoswiki::Plugins::WysiwygPlugin::::postConvertURLFoswiki::Plugins::WysiwygPlugin::postConvertURL
0000s0sFoswiki::Plugins::WysiwygPlugin::::startRenderingHandlerFoswiki::Plugins::WysiwygPlugin::startRenderingHandler
0000s0sFoswiki::Plugins::WysiwygPlugin::::wysiwygEditingDisabledForThisContentFoswiki::Plugins::WysiwygPlugin::wysiwygEditingDisabledForThisContent
0000s0sFoswiki::Plugins::WysiwygPlugin::::wysiwygEditingNotPossibleForThisContentFoswiki::Plugins::WysiwygPlugin::wysiwygEditingNotPossibleForThisContent
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 WysiwygPlugin
6
7This plugin is responsible for translating TML to HTML before an edit starts
8and translating the resultant HTML back into TML.
9
10Note: In the case of a new topic, you might expect to see the "create topic"
11screen in the editor when it goes back to Foswiki for the topic content. This
12doesn't happen because the earliest possible handler is called on the topic
13content and not the template. The template is effectively ignored and a blank
14document is sent to the editor.
15
16Attachment uploads can be handled by URL requests from the editor to the rest
17handler in this plugin. This avoids the need to add any scripts to the bin dir.
18You will have to use a form, though, as XmlHttpRequest does not support file
19uploads.
20
21=cut
22
23package Foswiki::Plugins::WysiwygPlugin;
24
25228µs241µs
# spent 27µs (14+14) within Foswiki::Plugins::WysiwygPlugin::BEGIN@25 which was called: # once (14µs+14µs) by Foswiki::Plugin::BEGIN@2.42 at line 25
use strict;
# spent 27µs making 1 call to Foswiki::Plugins::WysiwygPlugin::BEGIN@25 # spent 14µs making 1 call to strict::import
26230µs218µs
# spent 14µs (10+4) within Foswiki::Plugins::WysiwygPlugin::BEGIN@26 which was called: # once (10µs+4µs) by Foswiki::Plugin::BEGIN@2.42 at line 26
use warnings;
# spent 14µs making 1 call to Foswiki::Plugins::WysiwygPlugin::BEGIN@26 # spent 4µs making 1 call to warnings::import
27
282101µs264µs
# spent 37µs (10+27) within Foswiki::Plugins::WysiwygPlugin::BEGIN@28 which was called: # once (10µs+27µs) by Foswiki::Plugin::BEGIN@2.42 at line 28
use Assert;
# spent 37µs making 1 call to Foswiki::Plugins::WysiwygPlugin::BEGIN@28 # spent 27µs making 1 call to Exporter::import
29
301500nsour $SHORTDESCRIPTION = 'Translator framework for WYSIWYG editors';
311200nsour $NO_PREFS_IN_TOPIC = 1;
32
331200nsour $VERSION = '1.31';
341300nsour $RELEASE = '14 Jun 2015';
35
361200nsour %xmltag;
37
38# The following are all used in Handlers, but declared here so we can
39# check them without loading the handlers module
4010sour $tml2html;
4110sour $recursionBlock;
4210sour %FoswikiCompatibility;
43
44# Set to 1 for reasons for rejection
452596µs270µs
# spent 40µs (10+30) within Foswiki::Plugins::WysiwygPlugin::BEGIN@45 which was called: # once (10µs+30µs) by Foswiki::Plugin::BEGIN@2.42 at line 45
use constant WHY => 0;
# spent 40µs making 1 call to Foswiki::Plugins::WysiwygPlugin::BEGIN@45 # spent 30µs making 1 call to constant::import
46
47#simple Browser detection.
4815µsour %defaultINIT_BROWSER = (
49 MSIE => '',
50 OPERA => '',
51 GECKO => '"gecko_spellcheck" : true',
52 SAFARI => '',
53 CHROME => '',
54 UNKNOWN => '',
55);
561200nsmy $query;
57
58# Info about browser type
591100nsmy %browserInfo;
6010smy $browser;
61
62
# spent 175µs (63+112) within Foswiki::Plugins::WysiwygPlugin::initPlugin which was called: # once (63µs+112µs) by Foswiki::Plugin::__ANON__[/var/www/foswikidev/core/lib/Foswiki/Plugin.pm:257] at line 250 of /var/www/foswikidev/core/lib/Foswiki/Plugin.pm
sub initPlugin {
6312µs my ( $topic, $web, $user, $installWeb ) = @_;
64
65 # %OWEB%.%OTOPIC% is the topic where the initial content should be
66 # grabbed from, as defined in templates/edit.skin.tmpl
67 # Note; rather than declaring the handlers in this module, we use
68 # the _execute function to hand off execution to
69 # Foswiki::Plugins::WysiwygPlugin::Handlers. The goal is to keep this
70 # module small and light so it loads fast.
71 Foswiki::Func::registerTagHandler( 'OWEB',
7214µs116µs sub { _execute( '_OWEBTAG', @_ ) } );
# spent 16µs making 1 call to Foswiki::Func::registerTagHandler
73 Foswiki::Func::registerTagHandler( 'OTOPIC',
7414µs112µs sub { _execute( '_OTOPICTAG', @_ ) } );
# spent 12µs making 1 call to Foswiki::Func::registerTagHandler
75 Foswiki::Func::registerTagHandler( 'WYSIWYG_TEXT',
7614µs111µs sub { _execute( '_WYSIWYG_TEXT', @_ ) } );
# spent 11µs making 1 call to Foswiki::Func::registerTagHandler
77 Foswiki::Func::registerTagHandler( 'JAVASCRIPT_TEXT',
7814µs114µs sub { _execute( '_JAVASCRIPT_TEXT', @_ ) } );
# spent 14µs making 1 call to Foswiki::Func::registerTagHandler
79 Foswiki::Func::registerTagHandler( 'WYSIWYG_SECRET_ID',
8014µs111µs sub { _execute( '_SECRET_ID', @_ ) } );
# spent 11µs making 1 call to Foswiki::Func::registerTagHandler
81
82 # The WYSIWYG REST handlers all check for appropriate access.
83 # Core does not need to enforce access or validation.
8413µs my %opts = (
85 authenticate => 0,
86 validate => 0,
87 http_allow => 'GET,POST',
88 );
89
90 Foswiki::Func::registerRESTHandler( 'tml2html',
9115µs118µs sub { _execute( 'REST_TML2HTML', @_ ) }, %opts );
# spent 18µs making 1 call to Foswiki::Func::registerRESTHandler
92 Foswiki::Func::registerRESTHandler( 'html2tml',
9318µs115µs sub { _execute( 'REST_HTML2TML', @_ ) }, %opts );
# spent 15µs making 1 call to Foswiki::Func::registerRESTHandler
94 Foswiki::Func::registerRESTHandler( 'attachments',
9515µs114µs sub { _execute( 'REST_attachments', @_ ) }, %opts );
# spent 14µs making 1 call to Foswiki::Func::registerRESTHandler
96
97 # Plugin correctly initialized
9817µs return 1;
99}
100
101sub getBrowserName {
102 return $browser if ( defined($browser) );
103
104 $query = Foswiki::Func::getCgiQuery();
105 return unless ($query);
106
107 # Identify the browser from the user agent string
108 my $ua = $query->user_agent();
109 if ($ua) {
110 $browserInfo{isMSIE} = $ua =~ m/MSIE/;
111 $browserInfo{isMSIE5} = $browserInfo{isMSIE} && ( $ua =~ m/MSIE 5/ );
112 $browserInfo{isMSIE5_0} =
113 $browserInfo{isMSIE} && ( $ua =~ m/MSIE 5.0/ );
114 $browserInfo{isMSIE6} = $browserInfo{isMSIE} && $ua =~ m/MSIE 6/;
115 $browserInfo{isMSIE7} = $browserInfo{isMSIE} && $ua =~ m/MSIE 7/;
116 $browserInfo{isMSIE8} = $browserInfo{isMSIE} && $ua =~ m/MSIE 8/;
117 $browserInfo{isGecko} = $ua =~ m/Gecko/; # Will also be true on Safari
118 $browserInfo{isSafari} = $ua =~ m/Safari/; # Will also be true on Chrome
119 $browserInfo{isOpera} = $ua =~ m/Opera/;
120 $browserInfo{isChrome} = $ua =~ m/Chrome/;
121 $browserInfo{isMac} = $ua =~ m/Mac/;
122 $browserInfo{isNS7} = $ua =~ m/Netscape\/7/;
123 $browserInfo{isNS71} = $ua =~ m/Netscape\/7.1/;
124 }
125
126 # The order of these conditions is important, because browsers
127 # spoof eachother
128 if ( $browserInfo{isChrome} ) {
129 $browser = 'CHROME';
130 }
131 elsif ( $browserInfo{isSafari} ) {
132 $browser = 'SAFARI';
133 }
134 elsif ( $browserInfo{isOpera} ) {
135 $browser = 'OPERA';
136 }
137 elsif ( $browserInfo{isGecko} ) {
138 $browser = 'GECKO';
139 }
140 elsif ( $browserInfo{isMSIE} ) {
141 $browser = 'MSIE';
142 }
143 else {
144 $browser = 'UNKNOWN';
145 }
146
147 return ( $browser, $defaultINIT_BROWSER{$browser} );
148}
149
150sub _execute {
151 my $fn = shift;
152
153 eval "require Foswiki::Plugins::WysiwygPlugin::Handlers";
154 ASSERT( !$@, $@ ) if DEBUG;
155 $fn = 'Foswiki::Plugins::WysiwygPlugin::Handlers::' . $fn;
156240µs239µs
# spent 24µs (10+14) within Foswiki::Plugins::WysiwygPlugin::BEGIN@156 which was called: # once (10µs+14µs) by Foswiki::Plugin::BEGIN@2.42 at line 156
no strict 'refs';
# spent 24µs making 1 call to Foswiki::Plugins::WysiwygPlugin::BEGIN@156 # spent 14µs making 1 call to strict::unimport
157 return &$fn(@_);
15821.08ms227µs
# spent 18µs (9+9) within Foswiki::Plugins::WysiwygPlugin::BEGIN@158 which was called: # once (9µs+9µs) by Foswiki::Plugin::BEGIN@2.42 at line 158
use strict 'refs';
# spent 18µs making 1 call to Foswiki::Plugins::WysiwygPlugin::BEGIN@158 # spent 9µs making 1 call to strict::import
159}
160
161=begin TML
162
163---++ StaticMethod notWysiwygEditable($text) -> $boolean
164Determine if the given =$text= is WYSIWYG editable, based on the topic content
165and the value of the Foswiki preferences WYSIWYG_EXCLUDE and
166WYSIWYG_EDITABLE_CALLS. Returns a descriptive string if the text is not
167editable, 0 otherwise.
168
169=cut
170
171sub notWysiwygEditable {
172
173 #my ($text, $exclusions) = @_;
174 my $disabled = wysiwygEditingDisabledForThisContent( $_[0], $_[1] );
175 return $disabled if $disabled;
176
177 # Check that the topic text can be converted to HTML. This is an
178 # *expensive* process, to be avoided if possible (hence all the
179 # earlier checks)
180 my $impossible = wysiwygEditingNotPossibleForThisContent( $_[0] );
181 return $impossible if $impossible;
182
183 return 0;
184}
185
186sub wysiwygEditingDisabledForThisContent {
187
188 #my ($text, $exclusions) = @_;
189
190 my $exclusions = $_[1];
191 unless ( defined($exclusions) ) {
192 $exclusions = Foswiki::Func::getPreferencesValue('WYSIWYG_EXCLUDE')
193 || '';
194 }
195
196 # Check for explicit exclusions before generic, non-configurable
197 # purely content-related reasons for exclusion
198 if ($exclusions) {
199 my $calls_ok =
200 Foswiki::Func::getPreferencesValue('WYSIWYG_EDITABLE_CALLS')
201 || '---';
202 $calls_ok =~ s/\s//g;
203
204 my $ok = 1;
205 if ( $exclusions =~ m/calls/
206 && $_[0] =~ m/%((?!($calls_ok){)[A-Z_]+{.*?})%/s )
207 {
208 print STDERR "WYSIWYG_DEBUG: has calls $1 (not in $calls_ok)\n"
209 if (WHY);
210 return "Text contains calls";
211 }
212 if ( $exclusions =~ m/(macros|variables)/ && $_[0] =~ m/%([A-Z_]+)%/s )
213 {
214 print STDERR "$exclusions WYSIWYG_DEBUG: has macros $1\n"
215 if (WHY);
216 return "Text contains macros";
217 }
218 if ( $exclusions =~ m/html/
219 && $_[0] =~ m/<\/?((?!literal|verbatim|noautolink|nop|br)\w+)/i )
220 {
221 print STDERR "WYSIWYG_DEBUG: has html: $1\n"
222 if (WHY);
223 return "Text contains HTML";
224 }
225 if ( $exclusions =~ m/comments/ && $_[0] =~ m/<[!]--/ ) {
226 print STDERR "WYSIWYG_DEBUG: has comments\n"
227 if (WHY);
228 return "Text contains comments";
229 }
230 if ( $exclusions =~ m/pre/ && $_[0] =~ m/<pre\w/i ) {
231 print STDERR "WYSIWYG_DEBUG: has pre\n"
232 if (WHY);
233 return "Text contains PRE";
234 }
235 if ( $exclusions =~ m/script/ && $_[0] =~ m/<script\W/i ) {
236 print STDERR "WYSIWYG_DEBUG: has script\n"
237 if (WHY);
238 return "Text contains script";
239 }
240 if ( $exclusions =~ m/style/ && $_[0] =~ m/<style\W/i ) {
241 print STDERR "WYSIWYG_DEBUG: has style\n"
242 if (WHY);
243 return "Text contains style";
244 }
245 if ( $exclusions =~ m/table/ && $_[0] =~ m/<table\W/i ) {
246 print STDERR "WYSIWYG_DEBUG: has table\n"
247 if (WHY);
248 return "Text contains table";
249 }
250 }
251
252 # Copy the content.
253 # Then crunch verbatim blocks, because verbatim blocks may
254 # contain *anything*.
255 my $text = $_[0];
256
257 # Look for combinations of sticky and other markup that cause
258 # problems together
259 for my $tag ('literal') {
260 while ( $text =~ m/<$tag\b[^>]*>(.*?)<\/$tag>/gsi ) {
261 my $inner = $1;
262 if ( $inner =~ m/<sticky\b[^>]*>/i ) {
263 print STDERR "WYSIWYG_DEBUG: <sticky> inside <$tag>\n"
264 if (WHY);
265 return "&lt;sticky&gt; inside &lt;$tag&gt;";
266 }
267 }
268 }
269
270 my $wasAVerbatimTag = "\000verbatim\001";
271 while ( $text =~ s/<verbatim\b[^>]*>(.*?)<\/verbatim>/$wasAVerbatimTag/i ) {
272
273 #my $content = $1;
274 # If there is any content that breaks conversion if it is inside
275 # a verbatim block, check for it here:
276 }
277
278 # Look for combinations of verbatim and other markup that cause
279 # problems together
280 for my $tag ('literal') {
281 while ( $text =~ m/<$tag\b[^>]*>(.*?)<\/$tag>/gsi ) {
282 my $inner = $1;
283 if ( $inner =~ m/$wasAVerbatimTag/i ) {
284 print STDERR "WYSIWYG_DEBUG: <verbatim> inside <$tag>\n"
285 if (WHY);
286 return "&lt;verbatim&gt; inside &lt;$tag&gt;";
287 }
288 }
289 }
290
291 return 0;
292}
293
294sub wysiwygEditingNotPossibleForThisContent {
295 eval {
296 require Foswiki::Plugins::WysiwygPlugin::Handlers;
297 Foswiki::Plugins::WysiwygPlugin::Handlers::TranslateTML2HTML(
298 $_[0],
299 web => 'Fakewebname',
300 topic => 'FakeTopicName',
301 dieOnError => 1
302 );
303 };
304 if ($@) {
305 Foswiki::Func::writeDebug(
306 "WYSIWYG_DEBUG: TML2HTML conversion threw an exception: $@")
307 if (WHY);
308 return "TML2HTML conversion fails";
309 }
310
311 return 0;
312}
313
314
# spent 4.76ms (3.41+1.35) within Foswiki::Plugins::WysiwygPlugin::addXMLTag which was called 2 times, avg 2.38ms/call: # once (3.40ms+1.34ms) by Foswiki::Plugins::DirectedGraphPlugin::initPlugin at line 305 of /var/www/foswikidev/core/lib/Foswiki/Plugins/DirectedGraphPlugin.pm # once (4µs+7µs) by Foswiki::Plugins::DirectedGraphPlugin::initPlugin at line 308 of /var/www/foswikidev/core/lib/Foswiki/Plugins/DirectedGraphPlugin.pm
sub addXMLTag {
315275µs require Foswiki::Plugins::WysiwygPlugin::Handlers;
31629µs218µs Foswiki::Plugins::WysiwygPlugin::Handlers::addXMLTag(@_);
# spent 18µs making 2 calls to Foswiki::Plugins::WysiwygPlugin::Handlers::addXMLTag, avg 9µs/call
317}
318
319sub postConvertURL {
320 require Foswiki::Plugins::WysiwygPlugin::Handlers;
321 Foswiki::Plugins::WysiwygPlugin::Handlers::postConvertURL(@_);
322}
323
324sub beforeEditHandler {
325 _execute( 'beforeEditHandler', @_ );
326}
327
328sub beforeSaveHandler {
329 _execute( 'beforeSaveHandler', @_ );
330}
331
332sub beforeMergeHandler {
333 _execute( 'beforeMergeHandler', @_ );
334}
335
336sub afterEditHandler {
337 _execute( 'afterEditHandler', @_ );
338}
339
340# The next few handlers have to be executed on topic views, so have to
341# avoid lazy-loading the handlers unless absolutely necessary.
342
3431700ns$FoswikiCompatibility{startRenderingHandler} = 2.1;
344
345sub startRenderingHandler {
346 $_[0] =~ s#</?sticky>##g;
347}
348
349
# spent 627µs (486+141) within Foswiki::Plugins::WysiwygPlugin::beforeCommonTagsHandler which was called 100 times, avg 6µs/call: # 100 times (486µs+141µs) by Foswiki::Plugin::invoke at line 310 of /var/www/foswikidev/core/lib/Foswiki/Plugin.pm, avg 6µs/call
sub beforeCommonTagsHandler {
35010020µs return if $recursionBlock;
351100285µs100120µs return unless Foswiki::Func::getContext()->{body_text};
# spent 120µs making 100 calls to Foswiki::Func::getContext, avg 1µs/call
352
35312µs14µs my $query = Foswiki::Func::getCgiQuery();
# spent 4µs making 1 call to Foswiki::Func::getCgiQuery
354
3551300ns return unless $query;
356
35713µs117µs return unless defined( $query->param('wysiwyg_edit') );
# spent 17µs making 1 call to Foswiki::Request::param
358 _execute( 'beforeCommonTagsHandler', @_ );
359}
360
361
# spent 19µs within Foswiki::Plugins::WysiwygPlugin::postRenderingHandler which was called 5 times, avg 4µs/call: # 5 times (19µs+0s) by Foswiki::Plugin::invoke at line 310 of /var/www/foswikidev/core/lib/Foswiki/Plugin.pm, avg 4µs/call
sub postRenderingHandler {
362516µs return if ( $recursionBlock || !$tml2html );
363 _execute( 'postRenderingHandler', @_ );
364}
365
366
# spent 37µs (15+22) within Foswiki::Plugins::WysiwygPlugin::modifyHeaderHandler which was called: # once (15µs+22µs) by Foswiki::Plugin::invoke at line 310 of /var/www/foswikidev/core/lib/Foswiki/Plugin.pm
sub modifyHeaderHandler {
36711µs my ( $headers, $query ) = @_;
368
36916µs122µs if ( $query->param('wysiwyg_edit') ) {
# spent 22µs making 1 call to Foswiki::Request::param
370 _execute( 'modifyHeaderHandler', @_ );
371 }
372}
373
37417µs1;
375__END__