source: branches/Release01x01/WysiwygPlugin/lib/Foswiki/Plugins/WysiwygPlugin.pm @ 14524

Revision 14524, 10.0 KB checked in by GeorgeClark, 14 months ago (diff)

Item11312: Also WYSIWYG_EXCLUDE html table

Native HTML tables with embedded newlines don't survive the conversion
of the topic from TML to HTML. This is a temporary fix to avoid the
issue.

  • Property svn:keywords set to Revision Date
Line 
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
25use strict;
26use warnings;
27
28use Assert;
29
30our $SHORTDESCRIPTION  = 'Translator framework for WYSIWYG editors';
31our $NO_PREFS_IN_TOPIC = 1;
32our $VERSION           = '$Rev$';
33
34our $RELEASE = '1.1.5';
35
36our %xmltag;
37
38# The following are all used in Handlers, but declared here so we can
39# check them without loading the handlers module
40our $tml2html;
41our $recursionBlock;
42our %FoswikiCompatibility;
43
44# Set to 1 for reasons for rejection
45sub WHY { 0 }
46
47sub initPlugin {
48    my ( $topic, $web, $user, $installWeb ) = @_;
49
50    # %OWEB%.%OTOPIC% is the topic where the initial content should be
51    # grabbed from, as defined in templates/edit.skin.tmpl
52    # Note; rather than declaring the handlers in this module, we use
53    # the _execute function to hand off execution to
54    # Foswiki::Plugins::WysiwygPlugin::Handlers. The goal is to keep this
55    # module small and light so it loads fast.
56    Foswiki::Func::registerTagHandler( 'OWEB',
57        sub { _execute( '_OWEBTAG', @_ ) } );
58    Foswiki::Func::registerTagHandler( 'OTOPIC',
59        sub { _execute( '_OTOPICTAG', @_ ) } );
60    Foswiki::Func::registerTagHandler( 'WYSIWYG_TEXT',
61        sub { _execute( '_WYSIWYG_TEXT', @_ ) } );
62    Foswiki::Func::registerTagHandler( 'JAVASCRIPT_TEXT',
63        sub { _execute( '_JAVASCRIPT_TEXT', @_ ) } );
64    Foswiki::Func::registerTagHandler( 'WYSIWYG_SECRET_ID',
65        sub { _execute( '_SECRET_ID', @_ ) } );
66
67    Foswiki::Func::registerRESTHandler( 'tml2html',
68        sub { _execute( '_restTML2HTML', @_ ) } );
69    Foswiki::Func::registerRESTHandler( 'html2tml',
70        sub { _execute( '_restHTML2TML', @_ ) } );
71    Foswiki::Func::registerRESTHandler( 'upload',
72        sub { _execute( '_restUpload', @_ ) } );
73    Foswiki::Func::registerRESTHandler( 'attachments',
74        sub { _execute( '_restAttachments', @_ ) } );
75
76    # Plugin correctly initialized
77    return 1;
78}
79
80sub _execute {
81    my $fn = shift;
82
83    require Foswiki::Plugins::WysiwygPlugin::Handlers;
84    $fn = 'Foswiki::Plugins::WysiwygPlugin::Handlers::' . $fn;
85    no strict 'refs';
86    return &$fn(@_);
87    use strict 'refs';
88}
89
90=begin TML
91
92---++ StaticMethod notWysiwygEditable($text) -> $boolean
93Determine if the given =$text= is WYSIWYG editable, based on the topic content
94and the value of the Foswiki preferences WYSIWYG_EXCLUDE and
95WYSIWYG_EDITABLE_CALLS. Returns a descriptive string if the text is not
96editable, 0 otherwise.
97
98=cut
99
100sub notWysiwygEditable {
101
102    #my ($text, $exclusions) = @_;
103    my $disabled = wysiwygEditingDisabledForThisContent( $_[0], $_[1] );
104    return $disabled if $disabled;
105
106    # Check that the topic text can be converted to HTML. This is an
107    # *expensive* process, to be avoided if possible (hence all the
108    # earlier checks)
109    my $impossible = wysiwygEditingNotPossibleForThisContent( $_[0] );
110    return $impossible if $impossible;
111
112    return 0;
113}
114
115sub wysiwygEditingDisabledForThisContent {
116
117    #my ($text, $exclusions) = @_;
118
119    my $exclusions = $_[1];
120    unless ( defined($exclusions) ) {
121        $exclusions = Foswiki::Func::getPreferencesValue('WYSIWYG_EXCLUDE')
122          || 'script,style,table';
123    }
124   
125    # Check for explicit exclusions before generic, non-configurable
126    # purely content-related reasons for exclusion
127    if ($exclusions) {
128        my $calls_ok =
129          Foswiki::Func::getPreferencesValue('WYSIWYG_EDITABLE_CALLS')
130          || '---';
131        $calls_ok =~ s/\s//g;
132
133        my $ok = 1;
134        if (   $exclusions =~ /calls/
135            && $_[0] =~ /%((?!($calls_ok){)[A-Z_]+{.*?})%/s )
136        {
137            print STDERR "WYSIWYG_DEBUG: has calls $1 (not in $calls_ok)\n"
138              if (WHY);
139            return "Text contains calls";
140        }
141        if ( $exclusions =~ /(macros|variables)/ && $_[0] =~ /%([A-Z_]+)%/s ) {
142            print STDERR "$exclusions WYSIWYG_DEBUG: has macros $1\n"
143              if (WHY);
144            return "Text contains macros";
145        }
146        if (   $exclusions =~ /html/
147            && $_[0] =~ /<\/?((?!literal|verbatim|noautolink|nop|br)\w+)/i )
148        {
149            print STDERR "WYSIWYG_DEBUG: has html: $1\n"
150              if (WHY);
151            return "Text contains HTML";
152        }
153        if ( $exclusions =~ /comments/ && $_[0] =~ /<[!]--/ ) {
154            print STDERR "WYSIWYG_DEBUG: has comments\n"
155              if (WHY);
156            return "Text contains comments";
157        }
158        if ( $exclusions =~ /pre/ && $_[0] =~ /<pre\w/i ) {
159            print STDERR "WYSIWYG_DEBUG: has pre\n"
160              if (WHY);
161            return "Text contains PRE";
162        }
163        if ( $exclusions =~ /script/ && $_[0] =~ /<script\W/i ) {
164            print STDERR "WYSIWYG_DEBUG: has script\n"
165              if (WHY);
166            return "Text contains script";
167        }
168        if ( $exclusions =~ /style/ && $_[0] =~ /<style\W/i ) {
169            print STDERR "WYSIWYG_DEBUG: has style\n"
170              if (WHY);
171            return "Text contains style";
172        }
173        if ( $exclusions =~ /table/ && $_[0] =~ /<table\W/i ) {
174            print STDERR "WYSIWYG_DEBUG: has table\n"
175              if (WHY);
176            return "Text contains table";
177        }
178    }
179
180    # Copy the content.
181    # Then crunch verbatim blocks, because verbatim blocks may
182    # contain *anything*.
183    my $text = $_[0];
184
185    # Look for combinations of sticky and other markup that cause
186    # problems together
187    for my $tag ('literal') {
188        while ( $text =~ /<$tag\b[^>]*>(.*?)<\/$tag>/gsi ) {
189            my $inner = $1;
190            if ( $inner =~ /<sticky\b[^>]*>/i ) {
191                print STDERR "WYSIWYG_DEBUG: <sticky> inside <$tag>\n"
192                  if (WHY);
193                return "&lt;sticky&gt; inside &lt;$tag&gt;";
194            }
195        }
196    }
197
198    my $wasAVerbatimTag = "\000verbatim\001";
199    while ( $text =~ s/<verbatim\b[^>]*>(.*?)<\/verbatim>/$wasAVerbatimTag/i ) {
200
201        #my $content = $1;
202        # If there is any content that breaks conversion if it is inside
203        # a verbatim block, check for it here:
204    }
205
206    # Look for combinations of verbatim and other markup that cause
207    # problems together
208    for my $tag ('literal') {
209        while ( $text =~ /<$tag\b[^>]*>(.*?)<\/$tag>/gsi ) {
210            my $inner = $1;
211            if ( $inner =~ /$wasAVerbatimTag/i ) {
212                print STDERR "WYSIWYG_DEBUG: <verbatim> inside <$tag>\n"
213                  if (WHY);
214                return "&lt;verbatim&gt; inside &lt;$tag&gt;";
215            }
216        }
217    }
218
219    return 0;
220}
221
222sub wysiwygEditingNotPossibleForThisContent {
223    eval {
224        require Foswiki::Plugins::WysiwygPlugin::Handlers;
225        Foswiki::Plugins::WysiwygPlugin::Handlers::TranslateTML2HTML( $_[0],
226            'Fakewebname', 'FakeTopicName', dieOnError => 1 );
227    };
228    if ($@) {
229        print STDERR
230          "WYSIWYG_DEBUG: TML2HTML conversion threw an exception: $@\n"
231          if (WHY);
232        return "TML2HTML conversion fails";
233    }
234
235    return 0;
236}
237
238sub addXMLTag {
239    require Foswiki::Plugins::WysiwygPlugin::Handlers;
240    Foswiki::Plugins::WysiwygPlugin::Handlers::addXMLTag(@_);
241}
242
243sub postConvertURL {
244    require Foswiki::Plugins::WysiwygPlugin::Handlers;
245    Foswiki::Plugins::WysiwygPlugin::Handlers::postConvertURL(@_);
246}
247
248sub beforeEditHandler {
249    _execute( 'beforeEditHandler', @_ );
250}
251
252sub beforeSaveHandler {
253    _execute( 'beforeSaveHandler', @_ );
254}
255
256sub beforeMergeHandler {
257    _execute( 'beforeMergeHandler', @_ );
258}
259
260sub afterEditHandler {
261    _execute( 'afterEditHandler', @_ );
262}
263
264# The next few handlers have to be executed on topic views, so have to
265# avoid lazy-loading the handlers unless absolutely necessary.
266
267$FoswikiCompatibility{startRenderingHandler} = 2.1;
268
269sub startRenderingHandler {
270    $_[0] =~ s#</?sticky>##g;
271}
272
273sub beforeCommonTagsHandler {
274    return if $recursionBlock;
275    return unless Foswiki::Func::getContext()->{body_text};
276
277    my $query = Foswiki::Func::getCgiQuery();
278
279    return unless $query;
280
281    return unless defined( $query->param('wysiwyg_edit') );
282    _execute( 'beforeCommonTagsHandler', @_ );
283}
284
285sub postRenderingHandler {
286    return if ( $recursionBlock || !$tml2html );
287    _execute( 'postRenderingHandler', @_ );
288}
289
290sub modifyHeaderHandler {
291    my ( $headers, $query ) = @_;
292
293    if ( $query->param('wysiwyg_edit') ) {
294        _execute( 'modifyHeaderHandler', @_ );
295    }
296}
297
2981;
299__END__
300Module of Foswiki - The Free and Open Source Wiki, http://foswiki.org/
301
302Copyright (C) 2008-2012 Foswiki Contributors. Foswiki Contributors
303are listed in the AUTHORS file in the root of this distribution.
304NOTE: Please extend that file, not this notice.
305
306Additional copyrights apply to some or all of the code in this file:
307
308Copyright (C) 2005 ILOG http://www.ilog.fr
309and TWiki Contributors. All Rights Reserved. TWiki Contributors
310are listed in the AUTHORS file in the root of your Foswiki (or TWiki)
311distribution.
312
313This program is free software; you can redistribute it and/or
314modify it under the terms of the GNU General Public License
315as published by the Free Software Foundation; either version 2
316of the License, or (at your option) any later version. For
317more details read LICENSE in the root of the TWiki distribution.
318
319This program is distributed in the hope that it will be useful,
320but WITHOUT ANY WARRANTY; without even the implied warranty of
321MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
322
323As per the GPL, removal of this notice is prohibited.
Note: See TracBrowser for help on using the repository browser.