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