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