| 1 | # Copyright (C) 2007-2012 Michael Daum http://michaeldaumconsulting.com |
|---|
| 2 | # |
|---|
| 3 | # This program is free software; you can redistribute it and/or |
|---|
| 4 | # modify it under the terms of the GNU General Public License |
|---|
| 5 | # as published by the Free Software Foundation; either version 2 |
|---|
| 6 | # of the License, or (at your option) any later version. For |
|---|
| 7 | # more details read LICENSE in the root of this distribution. |
|---|
| 8 | # |
|---|
| 9 | # This program is distributed in the hope that it will be useful, |
|---|
| 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|---|
| 12 | |
|---|
| 13 | package Foswiki::Plugins::NatEditPlugin; |
|---|
| 14 | |
|---|
| 15 | use strict; |
|---|
| 16 | use Foswiki::Func; |
|---|
| 17 | |
|---|
| 18 | |
|---|
| 19 | use vars qw( |
|---|
| 20 | $VERSION $RELEASE $SHORTDESCRIPTION $NO_PREFS_IN_TOPIC |
|---|
| 21 | $baseWeb $baseTopic |
|---|
| 22 | ); |
|---|
| 23 | |
|---|
| 24 | $VERSION = '$Rev$'; |
|---|
| 25 | $RELEASE = '5.20'; |
|---|
| 26 | |
|---|
| 27 | $NO_PREFS_IN_TOPIC = 1; |
|---|
| 28 | $SHORTDESCRIPTION = 'A Wikiwyg Editor'; |
|---|
| 29 | |
|---|
| 30 | use constant DEBUG => 0; # toggle me |
|---|
| 31 | use Foswiki::Func (); |
|---|
| 32 | use Foswiki::Plugins::JQueryPlugin (); |
|---|
| 33 | |
|---|
| 34 | ############################################################################### |
|---|
| 35 | sub writeDebug { |
|---|
| 36 | return unless DEBUG; |
|---|
| 37 | print STDERR "- NatEditPlugin - " . $_[0] . "\n"; |
|---|
| 38 | #Foswiki::Func::writeDebug("- NatEditPlugin - $_[0]"); |
|---|
| 39 | } |
|---|
| 40 | |
|---|
| 41 | |
|---|
| 42 | ############################################################################### |
|---|
| 43 | sub initPlugin { |
|---|
| 44 | ($baseTopic, $baseWeb) = @_; |
|---|
| 45 | |
|---|
| 46 | Foswiki::Func::registerTagHandler('FORMBUTTON', \&handleFORMBUTTON); |
|---|
| 47 | Foswiki::Func::registerTagHandler('NATFORMLIST', \&handleNATFORMLIST); |
|---|
| 48 | |
|---|
| 49 | # register the natedit jquery plugin |
|---|
| 50 | Foswiki::Plugins::JQueryPlugin::registerPlugin("NatEdit", |
|---|
| 51 | 'Foswiki::Plugins::NatEditPlugin::NATEDIT'); |
|---|
| 52 | |
|---|
| 53 | return 1; |
|---|
| 54 | } |
|---|
| 55 | |
|---|
| 56 | ############################################################################### |
|---|
| 57 | # render a button to add/change the form while editing |
|---|
| 58 | # returns |
|---|
| 59 | # * the empty string if there's no WEBFORM |
|---|
| 60 | # * or "Add form" if there is no form attached to a topic yet |
|---|
| 61 | # * or "Change form" otherwise |
|---|
| 62 | # |
|---|
| 63 | # there are no native means besides the "addform" template being used |
|---|
| 64 | # to render the FORMFIELDS. but this is not what we need here at all. infact |
|---|
| 65 | # we need an empty addform.nat.tmp to switch off this feature of FORMFIELDS |
|---|
| 66 | sub handleFORMBUTTON { |
|---|
| 67 | my ($session, $params, $theTopic, $theWeb) = @_; |
|---|
| 68 | |
|---|
| 69 | Foswiki::Plugins::JQueryPlugin::createPlugin("natedit"); |
|---|
| 70 | |
|---|
| 71 | my $saveCmd = ''; |
|---|
| 72 | my $request = Foswiki::Func::getCgiQuery(); |
|---|
| 73 | $saveCmd = $request->param('cmd') || '' if $request; |
|---|
| 74 | return '' if $saveCmd eq 'repRev'; |
|---|
| 75 | |
|---|
| 76 | my $form = $request->param('formtemplate') || ''; |
|---|
| 77 | |
|---|
| 78 | unless ($form) { |
|---|
| 79 | my ($meta, $dumy) = Foswiki::Func::readTopic($theWeb, $theTopic); |
|---|
| 80 | my $formMeta = $meta->get('FORM'); |
|---|
| 81 | $form = $formMeta->{"name"} if $formMeta; |
|---|
| 82 | } |
|---|
| 83 | |
|---|
| 84 | $form = '' if $form eq 'none'; |
|---|
| 85 | |
|---|
| 86 | my $action; |
|---|
| 87 | my $actionTitle; |
|---|
| 88 | my $actionText; |
|---|
| 89 | |
|---|
| 90 | if ($form) { |
|---|
| 91 | $action = 'replaceform'; |
|---|
| 92 | } else { |
|---|
| 93 | $action = 'addform'; |
|---|
| 94 | } |
|---|
| 95 | |
|---|
| 96 | if ($form) { |
|---|
| 97 | $actionText = $session->{i18n}->maketext("Change form"); |
|---|
| 98 | $actionTitle = $session->{i18n}->maketext("Change the current form of <nop>[_1]", "$theWeb.$theTopic"); |
|---|
| 99 | } elsif (Foswiki::Func::getPreferencesValue('WEBFORMS', $theWeb)) { |
|---|
| 100 | $actionText = $session->{i18n}->maketext("Add form"); |
|---|
| 101 | $actionTitle = $session->{i18n}->maketext("Add a new form to <nop>[_1]", "$theWeb.$theTopic"); |
|---|
| 102 | } else { |
|---|
| 103 | return ''; |
|---|
| 104 | } |
|---|
| 105 | $actionText =~ s/&&/\&/g; |
|---|
| 106 | $actionTitle =~ s/&&/\&/g; |
|---|
| 107 | |
|---|
| 108 | my $theFormat = $params->{_DEFAULT} || $params->{format} || '$link'; |
|---|
| 109 | $theFormat =~ s/\$link/<a href='\$url' accesskey='f' title='\$title'><span>\$acton<\/span><\/a>/g; |
|---|
| 110 | $theFormat =~ s/\$url/javascript:\$script/g; |
|---|
| 111 | $theFormat =~ s/\$script/submitEditForm('save', '$action');/g; |
|---|
| 112 | $theFormat =~ s/\$title/$actionTitle/g; |
|---|
| 113 | $theFormat =~ s/\$action/$actionText/g; |
|---|
| 114 | $theFormat =~ s/\$id/$action/g; |
|---|
| 115 | $theFormat = Foswiki::Func::expandCommonVariables($theFormat, $theTopic, $theWeb) |
|---|
| 116 | if escapeParameter($theFormat); |
|---|
| 117 | |
|---|
| 118 | return $theFormat; |
|---|
| 119 | } |
|---|
| 120 | |
|---|
| 121 | ############################################################################### |
|---|
| 122 | # This function will store the TopicTitle in a preference variable if it isn't |
|---|
| 123 | # part of the DataForm of this topic. In a way, we do the reverse of |
|---|
| 124 | # WebDB::onReload() where the TopicTitle is extracted and put into the cache. |
|---|
| 125 | sub beforeSaveHandler { |
|---|
| 126 | my ($text, $topic, $web, $meta) = @_; |
|---|
| 127 | |
|---|
| 128 | writeDebug("called beforeSaveHandler"); |
|---|
| 129 | # find out if we received a TopicTitle |
|---|
| 130 | my $request = Foswiki::Func::getCgiQuery(); |
|---|
| 131 | my $topicTitle = $request->param('TopicTitle'); |
|---|
| 132 | |
|---|
| 133 | unless (defined $topicTitle) { |
|---|
| 134 | writeDebug("didn't get a TopicTitle, nothing do here"); |
|---|
| 135 | return; |
|---|
| 136 | } |
|---|
| 137 | |
|---|
| 138 | my $fieldTopicTitle = $meta->get('FIELD', 'TopicTitle'); |
|---|
| 139 | writeDebug("topic=$web.$topic, topicTitle=$topicTitle"); |
|---|
| 140 | |
|---|
| 141 | if ($topicTitle eq $topic) { |
|---|
| 142 | writeDebug("same as topic name ... nulling"); |
|---|
| 143 | $request->param("TopicTitle", ""); |
|---|
| 144 | $topicTitle = ''; |
|---|
| 145 | if (defined $fieldTopicTitle) { |
|---|
| 146 | $fieldTopicTitle->{value} = ""; |
|---|
| 147 | } |
|---|
| 148 | } |
|---|
| 149 | |
|---|
| 150 | # find out if this topic can store the TopicTitle in its metadata |
|---|
| 151 | if (defined $fieldTopicTitle) { |
|---|
| 152 | writeDebug("can deal with TopicTitles by itself"); |
|---|
| 153 | |
|---|
| 154 | # however, check if we've got a TOPICTITLE preference setting |
|---|
| 155 | # if so remove it. this happens if we stored a topic title but |
|---|
| 156 | # then added a form that now takes the topic title instead |
|---|
| 157 | if (defined $meta->get('PREFERENCE', 'TOPICTITLE')) { |
|---|
| 158 | writeDebug("removing redundant TopicTitles in preferences"); |
|---|
| 159 | $meta->remove('PREFERENCE', 'TOPICTITLE'); |
|---|
| 160 | } |
|---|
| 161 | return; |
|---|
| 162 | } |
|---|
| 163 | |
|---|
| 164 | writeDebug("we need to store the TopicTitle in the preferences"); |
|---|
| 165 | |
|---|
| 166 | |
|---|
| 167 | # if it is a topic setting, override it. |
|---|
| 168 | my $topicTitleHash = $meta->get('PREFERENCE', 'TOPICTITLE'); |
|---|
| 169 | if (defined $topicTitleHash) { |
|---|
| 170 | writeDebug("found old TopicTitle in preference settings: $topicTitleHash->{value}"); |
|---|
| 171 | if ($topicTitle) { |
|---|
| 172 | # set the new value |
|---|
| 173 | $topicTitleHash->{value} = $topicTitle; |
|---|
| 174 | } else { |
|---|
| 175 | # remove the value if the new TopicTitle is an empty string |
|---|
| 176 | $meta->remove('PREFERENCE', 'TOPICTITLE'); |
|---|
| 177 | } |
|---|
| 178 | return; |
|---|
| 179 | } |
|---|
| 180 | |
|---|
| 181 | writeDebug("no TopicTitle in preference settings"); |
|---|
| 182 | |
|---|
| 183 | # if it is a bullet setting, replace it. |
|---|
| 184 | if ($text =~ s/((?:^|[\n\r])(?:\t| )+\*\s+(?:Set|Local)\s+TOPICTITLE\s*=\s*)(.*)((?:$|[\r\n]))/$1$topicTitle$3/o) { |
|---|
| 185 | writeDebug("found old TopicTitle defined as a bullet setting: $2"); |
|---|
| 186 | $_[0] = $text; |
|---|
| 187 | return; |
|---|
| 188 | } |
|---|
| 189 | |
|---|
| 190 | writeDebug("no TopicTitle stored anywhere. creating a new preference setting"); |
|---|
| 191 | |
|---|
| 192 | if ($topicTitle) { # but only if we don't set it to the empty string |
|---|
| 193 | $meta->putKeyed('PREFERENCE', { |
|---|
| 194 | name=>'TOPICTITLE', |
|---|
| 195 | title=>'TOPICTITLE', |
|---|
| 196 | type=>'Local', |
|---|
| 197 | value=>$topicTitle |
|---|
| 198 | }); |
|---|
| 199 | } |
|---|
| 200 | } |
|---|
| 201 | |
|---|
| 202 | ############################################################################### |
|---|
| 203 | # taken from Foswiki::UI::ChangeForm and leveraged to normal formatting standards |
|---|
| 204 | sub handleNATFORMLIST { |
|---|
| 205 | my ($session, $params, $theTopic, $theWeb) = @_; |
|---|
| 206 | |
|---|
| 207 | my $theFormat = $params->{_DEFAULT} || $params->{format} |
|---|
| 208 | || '<label><input type="radio" name="formtemplate" id="formtemplateelem$index" $checked value="$name">'. |
|---|
| 209 | ' $formTopic</input></label>'; |
|---|
| 210 | |
|---|
| 211 | $theWeb = $params->{web} if defined $params->{web}; |
|---|
| 212 | $theTopic = $params->{topic} if defined $params->{topic}; |
|---|
| 213 | my $theSeparator = $params->{separator}; |
|---|
| 214 | my $theHeader = $params->{header} || ''; |
|---|
| 215 | my $theFooter = $params->{footer} || ''; |
|---|
| 216 | my $theSelected = $params->{selected}; |
|---|
| 217 | |
|---|
| 218 | my $request = Foswiki::Func::getCgiQuery(); |
|---|
| 219 | $theSelected = $request->param('formtemplate') unless defined $theSelected; |
|---|
| 220 | $theSeparator = '<br />' unless defined $theSeparator; |
|---|
| 221 | |
|---|
| 222 | unless ($theSelected) { |
|---|
| 223 | my ($meta) = Foswiki::Func::readTopic($theWeb, $theTopic); |
|---|
| 224 | my $form = $meta->get( 'FORM' ); |
|---|
| 225 | $theSelected = $form->{name} if $form; |
|---|
| 226 | } |
|---|
| 227 | $theSelected = 'none' unless $theSelected; |
|---|
| 228 | |
|---|
| 229 | my $legalForms = Foswiki::Func::getPreferencesValue('WEBFORMS', $theWeb); |
|---|
| 230 | $legalForms =~ s/^\s*//; |
|---|
| 231 | $legalForms =~ s/\s*$//; |
|---|
| 232 | my %forms = map {$_ => 1} split( /[,\s]+/, $legalForms ); |
|---|
| 233 | my @forms = sort keys %forms; |
|---|
| 234 | push @forms, 'none'; |
|---|
| 235 | |
|---|
| 236 | my @formList = ''; |
|---|
| 237 | my $index = 0; |
|---|
| 238 | foreach my $form (@forms) { |
|---|
| 239 | $index++; |
|---|
| 240 | my $text = $theFormat; |
|---|
| 241 | my $checked = ''; |
|---|
| 242 | $checked = 'checked' if $form eq $theSelected; |
|---|
| 243 | my ($formWeb, $formTopic) = $session->normalizeWebTopicName($theWeb, $form); |
|---|
| 244 | |
|---|
| 245 | $text =~ s/\$index/$index/g; |
|---|
| 246 | $text =~ s/\$checked/$checked/g; |
|---|
| 247 | $text =~ s/\$name/$form/g; |
|---|
| 248 | $text =~ s/\$formWeb/$formWeb/g; |
|---|
| 249 | $text =~ s/\$formTopic/$formTopic/g; |
|---|
| 250 | |
|---|
| 251 | push @formList, $text; |
|---|
| 252 | } |
|---|
| 253 | my $result = $theHeader.join($theSeparator, @formList).$theFooter; |
|---|
| 254 | $result =~ s/\$count/$index/g; |
|---|
| 255 | $result =~ s/\$web/$theWeb/g; |
|---|
| 256 | $result =~ s/\$topic/$theTopic/g; |
|---|
| 257 | $result = Foswiki::Func::expandCommonVariables($result, $theTopic, $theWeb) |
|---|
| 258 | if escapeParameter($result); |
|---|
| 259 | |
|---|
| 260 | return $result; |
|---|
| 261 | } |
|---|
| 262 | |
|---|
| 263 | ############################################################################### |
|---|
| 264 | sub escapeParameter { |
|---|
| 265 | |
|---|
| 266 | return 0 unless $_[0]; |
|---|
| 267 | |
|---|
| 268 | my $found = 0; |
|---|
| 269 | |
|---|
| 270 | $found = 1 if $_[0] =~ s/\$percnt/%/g; |
|---|
| 271 | $found = 1 if $_[0] =~ s/\$nop//g; |
|---|
| 272 | $found = 1 if $_[0] =~ s/\\n/\n/g; |
|---|
| 273 | $found = 1 if $_[0] =~ s/\$n/\n/g; |
|---|
| 274 | $found = 1 if $_[0] =~ s/\\%/%/g; |
|---|
| 275 | $found = 1 if $_[0] =~ s/\\"/"/g; |
|---|
| 276 | $found = 1 if $_[0] =~ s/\$dollar/\$/g; |
|---|
| 277 | |
|---|
| 278 | return $found; |
|---|
| 279 | } |
|---|
| 280 | |
|---|
| 281 | 1; |
|---|