]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/editpage.php
Fixed SF bug #528567 (I think) - two or three functions were called with arguments
[SourceForge/phpwiki.git] / lib / editpage.php
1 <?php
2 rcs_id('$Id: editpage.php,v 1.47 2002-03-21 21:24:50 lakka Exp $');
3
4 require_once('lib/Template.php');
5
6 class PageEditor
7 {
8     function PageEditor (&$request) {
9         $this->request = &$request;
10
11         $this->user = $request->getUser();
12         $this->page = $request->getPage();
13
14         $this->current = $this->page->getCurrentRevision();
15
16         $this->meta = array('author' => $this->user->getId(),
17                             'locked' => $this->page->get('locked'),
18                             'author_id' => $this->user->getAuthenticatedId());
19
20         $version = $request->getArg('version');
21         if ($version !== false) {
22             $this->selected = $this->page->getRevision($version);
23             $this->version = $version;
24         }
25         else {
26             $this->selected = $this->current;
27             $this->version = $this->current->getVersion();
28         }
29
30         if ($this->_restoreState()) {
31             $this->_initialEdit = false;
32         }
33         else {
34             $this->_initializeState();
35             $this->_initialEdit = true;
36         }
37
38         header("Content-Type: text/html; charset=" . CHARSET);
39         header("Last-Modified: ".Rfc2822DateTime($this->selected->get('mtime')));
40     }
41
42     function editPage () {
43         $saveFailed = false;
44         $tokens = array();
45
46         if ($this->canEdit()) {
47             if ($this->isInitialEdit())
48                 return $this->viewSource();
49             $tokens['PAGE_LOCKED_MESSAGE'] = $this->getLockedMessage();
50         }
51         elseif ($this->editaction == 'save') {
52             if ($this->savePage())
53                 return true;    // Page saved.
54             $saveFailed = true;
55         }
56
57         if ($saveFailed || $this->isConcurrentUpdate())
58         {
59             // Get the text of the original page, and the two conflicting edits
60             // The diff3 class takes arrays as input.  So retrieve content as
61             // an array, or convert it as necesary.
62             $orig = $this->page->getRevision($this->_currentVersion);
63             $orig_content = $orig->getContent();
64             $this_content = explode("\n", $this->_content);
65             $other_content = $this->current->getContent();
66             include_once("lib/diff3.php");
67             $diff = new diff3($orig_content, $this_content, $other_content);
68             $output = $diff->merged_output(_("Your version"), _("Other version"));
69             // Set the content of the textarea to the merged diff output, and update the version
70             $this->_content = implode ("\n", $output);
71             $this->_currentVersion = $this->current->getVersion();
72             $this->version = $this->_currentVersion;
73             $unresolved = $diff->ConflictingBlocks;
74             $tokens['CONCURRENT_UPDATE_MESSAGE'] = $this->getConflictMessage($unresolved);
75         }
76
77         if ($this->editaction == 'preview')
78             $tokens['PREVIEW_CONTENT'] = $this->getPreview(); // FIXME: convert to _MESSAGE?
79
80         // FIXME: NOT_CURRENT_MESSAGE?
81
82         $tokens = array_merge($tokens, $this->getFormElements());
83
84         return $this->output('editpage', _("Edit: %s"), $tokens);
85     }
86
87     function output ($template, $title_fs, $tokens) {
88         $selected = &$this->selected;
89         $current = &$this->current;
90
91         if ($selected && $selected->getVersion() != $current->getVersion()) {
92             $rev = $selected;
93             $pagelink = WikiLink($selected);
94         }
95         else {
96             $rev = $current;
97             $pagelink = WikiLink($this->page);
98         }
99
100
101         $title = new FormattedText ($title_fs, $pagelink);
102         $template = Template($template, $tokens);
103
104         GeneratePage($template, $title, $rev);
105         return true;
106     }
107
108
109     function viewSource ($tokens = false) {
110         assert($this->isInitialEdit());
111         assert($this->selected);
112
113         $tokens['PAGE_SOURCE'] = $this->_content;
114
115         return $this->output('viewsource', _("View Source: %s"), $tokens);
116     }
117
118     function setPageLockChanged($isadmin, $lock, &$page) {
119         if ($isadmin) {
120             if (! $page->get('locked') == $lock) {
121                 $request = &$this->request;
122                 $request->setArg('lockchanged', true); //is it safe to add new args to $request like this?
123             }
124             $page->set('locked', $lock);
125         }
126     }
127
128     function savePage () {
129         $request = &$this->request;
130
131         if ($this->isUnchanged()) {
132             // Allow admin lock/unlock even if
133             // no text changes were made.
134             if ($isadmin = $this->user->isadmin()) {
135                 $page = &$this->page;
136                 $lock = $this->meta['locked'];
137                 $this->setPageLockChanged($isadmin, $lock, $page);
138             }
139             // Save failed. No changes made.
140             include_once('lib/display.php');
141             // force browse of current version:
142             $request->setArg('version', false);
143             displayPage($request, 'nochanges');
144             return true;
145         }
146
147         $page = &$this->page;
148         $lock = $this->meta['locked'];
149         $this->meta['locked'] = ''; // hackish
150
151         // Save new revision
152         $newrevision = $page->createRevision($this->_currentVersion + 1,
153                                              $this->_content,
154                                              $this->meta,
155                                              ExtractWikiPageLinks($this->_content));
156         if (!is_object($newrevision)) {
157             // Save failed.  (Concurrent updates).
158             return false;
159         }
160         // New contents successfully saved...
161         if ($isadmin = $this->user->isadmin())
162             $this->setPageLockChanged($isadmin, $lock, $page);
163
164         // Clean out archived versions of this page.
165         include_once('lib/ArchiveCleaner.php');
166         $cleaner = new ArchiveCleaner($GLOBALS['ExpireParams']);
167         $cleaner->cleanPageRevisions($page);
168
169         $dbi = $request->getDbh();
170         $warnings = $dbi->GenericWarnings();
171
172         global $Theme;
173         if (empty($warnings) && ! $Theme->getImageURL('signature')) {
174             // Do redirect to browse page if no signature has
175             // been defined.  In this case, the user will most
176             // likely not see the rest of the HTML we generate
177             // (below).
178             $request->redirect(WikiURL($page, false, 'absolute_url'));
179         }
180
181         // Force browse of current page version.
182         $request->setArg('version', false);
183
184         require_once('lib/PageType.php');
185         $transformedText = PageType($newrevision);
186         $template = Template('savepage',
187                              array('CONTENT' => $transformedText));
188         //include_once('lib/BlockParser.php');
189         //$template = Template('savepage',
190         //                     array('CONTENT' => TransformText($newrevision)));
191         if (!empty($warnings))
192             $template->replace('WARNINGS', $warnings);
193
194         $pagelink = WikiLink($page);
195
196         GeneratePage($template, fmt("Saved: %s", $pagelink), $newrevision);
197         return true;
198     }
199
200     function isConcurrentUpdate () {
201         assert($this->current->getVersion() >= $this->_currentVersion);
202         return $this->current->getVersion() != $this->_currentVersion;
203     }
204
205     function canEdit () {
206         return $this->page->get('locked') && !$this->user->isAdmin();
207     }
208
209     function isInitialEdit () {
210         return $this->_initialEdit;
211     }
212
213     function isUnchanged () {
214         $current = &$this->current;
215
216         if ($this->meta['markup'] !=  $current->get('markup'))
217             return false;
218
219         return $this->_content == $current->getPackedContent();
220     }
221
222     function getPreview () {
223         require_once('lib/PageType.php');
224         return PageType($this->_content, $this->page->getName(), $this->meta['markup']);
225
226         //include_once('lib/BlockParser.php');
227         //return TransformText($this->_content, $this->meta['markup']);
228     }
229
230     function getLockedMessage () {
231         return
232         HTML(HTML::h2(_("Page Locked")),
233              HTML::p(_("This page has been locked by the administrator so your changes can not be saved.")),
234              HTML::p(_("(Copy your changes to the clipboard. You can try editing a different page or save your text in a text editor.)")),
235              HTML::p(_("Sorry for the inconvenience.")));
236     }
237
238     function getConflictMessage ($unresolved = false) {
239         /*
240          xgettext only knows about c/c++ line-continuation strings
241          it does not know about php's dot operator.
242          We want to translate this entire paragraph as one string, of course.
243          */
244
245         //$re_edit_link = Button('edit', _("Edit the new version"), $this->page);
246
247         if ($unresolved)
248             $message =  HTML::p(fmt("Some of the changes could not automatically be combined.  Please look for sections beginning with '%s', and ending with '%s'.  You will need to edit those sections by hand before you click Save.",
249                                 "<<<<<<< ". _("Your version"),
250                                 ">>>>>>> ". _("Other version")));
251         else
252             $message = HTML::p(_("Please check it through before saving."));
253
254
255
256         /*$steps = HTML::ol(HTML::li(_("Copy your changes to the clipboard or to another temporary place (e.g. text editor).")),
257           HTML::li(fmt("%s of the page. You should now see the most current version of the page. Your changes are no longer there.",
258                        $re_edit_link)),
259           HTML::li(_("Make changes to the file again. Paste your additions from the clipboard (or text editor).")),
260           HTML::li(_("Save your updated changes.")));
261         */
262         return HTML(HTML::h2(_("Conflicting Edits!")),
263                     HTML::p(_("In the time since you started editing this page, another user has saved a new version of it.")),
264                     HTML::p(_("Your changes can not be saved as they are, since doing so would overwrite the other author's changes. So, your changes and those of the other author have been combined. The result is shown below.")),
265                     $message);
266     }
267
268
269     function getTextArea () {
270         $request = &$this->request;
271
272         // wrap=virtual is not HTML4, but without it NS4 doesn't wrap long lines
273         $readonly = $this->canEdit(); // || $this->isConcurrentUpdate();
274
275         return HTML::textarea(array('class'    => 'wikiedit',
276                                     'name'     => 'edit[content]',
277                                     'rows'     => $request->getPref('editHeight'),
278                                     'cols'     => $request->getPref('editWidth'),
279                                     'readonly' => (bool) $readonly,
280                                     'wrap'     => 'virtual'),
281                               $this->_content);
282     }
283
284     function getFormElements () {
285         $request = &$this->request;
286         $page = &$this->page;
287
288
289         $h = array('action'   => 'edit',
290                    'pagename' => $page->getName(),
291                    'version'  => $this->version,
292                    'edit[current_version]' => $this->_currentVersion);
293
294         $el['HIDDEN_INPUTS'] = HiddenInputs($h);
295
296
297         $el['EDIT_TEXTAREA'] = $this->getTextArea();
298
299         $el['SUMMARY_INPUT']
300             = HTML::input(array('type'  => 'text',
301                                 'class' => 'wikitext',
302                                 'name'  => 'edit[summary]',
303                                 'size'  => 50,
304                                 'maxlength' => 256,
305                                 'value' => $this->meta['summary']));
306         $el['MINOR_EDIT_CB']
307             = HTML::input(array('type' => 'checkbox',
308                                 'name'  => 'edit[minor_edit]',
309                                 'checked' => (bool) $this->meta['is_minor_edit']));
310         $el['NEW_MARKUP_CB']
311             = HTML::input(array('type' => 'checkbox',
312                                 'name' => 'edit[markup]',
313                                 'value' => 'new',
314                                 'checked' => $this->meta['markup'] >= 2.0));
315
316         $el['LOCKED_CB']
317             = HTML::input(array('type' => 'checkbox',
318                                 'name' => 'edit[locked]',
319                                 'disabled' => (bool) !$this->user->isadmin(),
320                                 'checked'  => (bool) $this->meta['locked']));
321
322         $el['PREVIEW_B'] = Button('submit:edit[preview]', _("Preview"), 'wikiaction');
323
324         //if (!$this->isConcurrentUpdate() && !$this->canEdit())
325         $el['SAVE_B'] = Button('submit:edit[save]', _("Save"), 'wikiaction');
326
327         $el['IS_CURRENT'] = $this->version == $this->current->getVersion();
328
329         return $el;
330     }
331
332
333     function _restoreState () {
334         $request = &$this->request;
335
336         $posted = $request->getArg('edit');
337         $request->setArg('edit', false);
338
339         if (!$posted || !$request->isPost() || $request->getArg('action') != 'edit')
340             return false;
341
342         if (!isset($posted['content']) || !is_string($posted['content']))
343             return false;
344         $this->_content = preg_replace('/[ \t\r]+\n/', "\n",
345                                         rtrim($posted['content']));
346
347         $this->_currentVersion = (int) $posted['current_version'];
348
349         if ($this->_currentVersion < 0)
350             return false;
351         if ($this->_currentVersion > $this->current->getVersion())
352             return false;       // FIXME: some kind of warning?
353
354         $is_new_markup = !empty($posted['markup']) && $posted['markup'] == 'new';
355         $meta['markup'] = $is_new_markup ? 2.0: false;
356         $meta['summary'] = trim(substr($posted['summary'], 0, 256));
357         $meta['locked'] = !empty($posted['locked']);
358         $meta['is_minor_edit'] = !empty($posted['minor_edit']);
359
360         $this->meta = array_merge($this->meta, $meta);
361
362         if (!empty($posted['preview']))
363             $this->editaction = 'preview';
364         elseif (!empty($posted['save']))
365             $this->editaction = 'save';
366         else
367             $this->editaction = 'edit';
368
369         return true;
370     }
371
372     function _initializeState () {
373         $request = &$this->request;
374         $current = &$this->current;
375         $selected = &$this->selected;
376         $user = &$this->user;
377
378         if (!$selected)
379             NoSuchRevision($request, $this->page, $this->version); // noreturn
380
381         $this->_currentVersion = $current->getVersion();
382         $this->_content = $selected->getPackedContent();
383
384         $this->meta['summary'] = '';
385         $this->meta['locked'] = $this->page->get('locked');
386
387         // If author same as previous author, default minor_edit to on.
388         $age = time() - $current->get('mtime');
389         $this->meta['is_minor_edit'] = ( $age < MINOR_EDIT_TIMEOUT
390                                          && $current->get('author') == $user->getId()
391                                          );
392
393         // Default for new pages is new-style markup.
394         if ($selected->hasDefaultContents())
395             $is_new_markup = true;
396         else
397             $is_new_markup = $selected->get('markup') >= 2.0;
398
399         $this->meta['markup'] = $is_new_markup ? 2.0: false;
400         $this->editaction = 'edit';
401     }
402 }
403
404 // Local Variables:
405 // mode: php
406 // tab-width: 8
407 // c-basic-offset: 4
408 // c-hanging-comment-ender-p: nil
409 // indent-tabs-mode: nil
410 // End:
411 ?>