1# See bottom of file for license and copyright information 2 3package Foswiki::UI::Preview; 4 5use strict; 6use warnings; 7use Error qw( :try ); 8 9use Foswiki (); 10use Foswiki::UI::Save (); 11use Foswiki::OopsException (); 12 13use Assert; 14 15BEGIN { 16 if ( $Foswiki::cfg{UseLocale} ) { 17 require locale; 18 import locale(); 19 } 20} 21 22sub preview { 23 my $session = shift; 24 25 my $query = $session->{request}; 26 my $web = $session->{webName}; 27 my $topic = $session->{topicName}; 28 my $user = $session->{user}; 29 30 if ( $session->{invalidTopic} ) { 31 throw Foswiki::OopsException( 32 'accessdenied', 33 status => 404, 34 def => 'invalid_topic_name', 35 web => $web, 36 topic => $topic, 37 params => [ $session->{invalidTopic} ] 38 ); 39 } 40 41 # SMELL: it's probably not good to do this here, because a preview may 42 # give enough time for a new topic with the same name to be created. 43 # It would be better to do it only on an actual save. 44 45 $topic = Foswiki::UI::Save::expandAUTOINC( $session, $web, $topic ); 46 47 my $topicObject = Foswiki::Meta->new( $session, $web, $topic ); 48 49 my ( $saveOpts, $merged ) = 50 Foswiki::UI::Save::buildNewTopic( $session, $topicObject, 'preview' ); 51 52 # Note: param(formtemplate) has already been decoded by buildNewTopic 53 # so the $meta entry reflects if it was used. 54 # get form fields to pass on 55 my $formFields = ''; 56 my $form = $topicObject->get('FORM') || ''; 57 my $formName; 58 if ($form) { 59 $formName = $form->{name}; # used later on as well 60 require Foswiki::Form; 61 my $formDef = new Foswiki::Form( $session, $web, $formName ); 62 unless ($formDef) { 63 throw Foswiki::OopsException( 64 'attention', 65 def => 'no_form_def', 66 web => $session->{webName}, 67 topic => $session->{topicName}, 68 params => [ $web, $formName ] 69 ); 70 } 71 $formFields = $formDef->renderHidden( $topicObject, 0 ); 72 } 73 74 my $text = $topicObject->text() || ''; 75 $session->{plugins} 76 ->dispatch( 'afterEditHandler', $text, $topic, $web, $topicObject ); 77 78 # Load the template for the view 79 my $content = $text; 80 my $template = $session->{prefs}->getPreference('VIEW_TEMPLATE'); 81 if ($template) { 82 my $vt = $session->templates->readTemplate( $template, no_oops => 1 ); 83 if ($vt) { 84 85 # We can't just use a VIEW_TEMPLATE directly because it 86 # describes an entire HTML page. But the bit we 87 # need is defined by the %TMPL:DEF{"content"}% within it, so 88 # we can just pull it out and instantiate that small bit. 89 90 $content = $session->templates->expandTemplate('content'); 91 $content =~ s/%TEXT%/$text/g; 92 } 93 } 94 95 my $tmpl = $session->templates->readTemplate('preview'); 96 97 if ( $saveOpts->{minor} ) { 98 $tmpl =~ s/%DONTNOTIFYCHECKBOX%/checked="checked"/g; 99 } 100 else { 101 $tmpl =~ s/%DONTNOTIFYCHECKBOX%//g; 102 } 103 if ( $saveOpts->{forcenewrevision} ) { 104 $tmpl =~ s/%FORCENEWREVISIONCHECKBOX%/checked="checked"/g; 105 } 106 else { 107 $tmpl =~ s/%FORCENEWREVISIONCHECKBOX%//g; 108 } 109 my $saveCmd = Foswiki::entityEncode( $query->param('cmd') || '' ); 110 $tmpl =~ s/%CMD%/$saveCmd/g; 111 112 my $redirectTo = Foswiki::entityEncode( $query->param('redirectto') || '' ); 113 $tmpl =~ s/%REDIRECTTO%/$redirectTo/g; 114 115 $formName ||= ''; 116 $tmpl =~ s/%FORMTEMPLATE%/$formName/g; 117 118 my $parent = $topicObject->get('TOPICPARENT'); 119 $parent = $parent->{name} if ($parent); 120 $parent ||= ''; 121 $tmpl =~ s/%TOPICPARENT%/$parent/g; 122 123 my $displayText = $content; 124 $displayText = $topicObject->expandMacros($displayText); 125 $displayText = $topicObject->renderTML($displayText); 126 127 # Disable links and inputs in the text 128 # SMELL: This will break on <a name="blah /> 129 # XXX - Use a real HTML parser like HTML::Parser 130 $displayText =~ s#(<a\s[^>]*>)(.*?)(</a>)#_disableLink($1, $2, $3)#gies 131 ; # Disables base relative links 132 $displayText =~ s#(<a\s[^>]*>)(.*?)(</a>)#_reTargetLink($1, $2, $3)#gies 133 ; # Retargets remaining links 134 $displayText =~ s/<(input|button|textarea) /<$1 disabled="disabled" /gis; 135 $displayText =~ s(</?form(|\s.*?)>)()gis; 136 $displayText =~ s/(<[^>]*\bon[A-Za-z]+=)('[^']*'|"[^"]*")/$1''/gis; 137 138 # let templates know the context so they can act on it 139 $session->enterContext( 'preview', 1 ); 140 141 # note: preventing linkage in rendered form can only happen in templates 142 # see formtables.tmpl 143 144 my $originalrev = 145 Foswiki::entityEncode( $query->param('originalrev') || '' ) 146 ; # rev edit started on 147 148 #ASSERT($originalrev ne '%ORIGINALREV%') if DEBUG; 149 $tmpl =~ s/%ORIGINALREV%/$originalrev/g; 150 151 my $templatetopic = 152 Foswiki::entityEncode( $query->param('templatetopic') || '' ); 153 154 #ASSERT($templatetopic ne '%TEMPLATETOPIC%') if DEBUG; 155 $tmpl =~ s/%TEMPLATETOPIC%/$templatetopic/g; 156 157 #this one's worrying, its special, and not set much at all 158 #$tmpl =~ s/%SETTINGSTOPIC%/$settingstopic/g; 159 my $newtopic = Foswiki::entityEncode( $query->param('newtopic') || '' ); 160 161 #ASSERT($newtopic ne '%NEWTOPIC%') if DEBUG; 162 $tmpl =~ s/%NEWTOPIC%/$newtopic/g; 163 164# CAUTION: Once expandMacros executes, any template tokens that are expanded 165# inside a %ENCODE will be corrupted. So do token substitution before this point. 166 $tmpl = $topicObject->expandMacros($tmpl); 167 $tmpl = $topicObject->renderTML($tmpl); 168 $tmpl =~ s/%TEXT%/$displayText/g; 169 170 # write the hidden form fields 171 $tmpl =~ s/%FORMFIELDS%/$formFields/g; 172 173 # SMELL: this should be done using CGI::hidden 174 $text = Foswiki::entityEncode( $text, "\n" ); 175 176 $tmpl =~ s/%HIDDENTEXT%/$text/g; 177 178 $tmpl =~ s/<\/?(nop|noautolink)\/?>//gis; 179 180### 181 $session->writeCompletePage($tmpl); 182} 183 184sub _reTargetLink { 185 my ( $one, $two, $three ) = @_; 186 187 unless ( $one =~ m/foswikiEmulatedLink/ ) { 188 if ( $one =~ m/\btarget=/i ) { 189 $one =~ 190s/\btarget=(?:(?: \'[^\']*\' | \"[^\"]*\" | [^\'\"\s]+ )+)(.*?>)/target="_blank"$1/xi; 191 } 192 else { 193 $one =~ s/\bhref=/target="_blank" href=/; 194 } 195 } 196 return $one . $two . $three; 197} 198 199sub _disableLink { 200 my ( $one, $two, $three ) = @_; 201 202 if ( $one =~ m/\bhref=['"][#?]/i ) { #Anchors or relative links 203 $one = "<span class=\"foswikiEmulatedLink\">"; 204 $three = "</span>"; 205 } 206 return $one . $two . $three; 207} 208 2091; 210__END__ 211Foswiki - The Free and Open Source Wiki, http://foswiki.org/ 212 213Copyright (C) 2008-2010 Foswiki Contributors. Foswiki Contributors 214are listed in the AUTHORS file in the root of this distribution. 215NOTE: Please extend that file, not this notice. 216 217Additional copyrights apply to some or all of the code in this 218file as follows: 219 220Copyright (C) 1999-2007 Peter Thoeny, peter@thoeny.org 221and TWiki Contributors. All Rights Reserved. TWiki Contributors 222are listed in the AUTHORS file in the root of this distribution. 223 224This program is free software; you can redistribute it and/or 225modify it under the terms of the GNU General Public License 226as published by the Free Software Foundation; either version 2 227of the License, or (at your option) any later version. For 228more details read LICENSE in the root of this distribution. 229 230This program is distributed in the hope that it will be useful, 231but WITHOUT ANY WARRANTY; without even the implied warranty of 232MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 233 234As per the GPL, removal of this notice is prohibited. 235