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