]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/editpage.php
Transform API cleanup.
[SourceForge/phpwiki.git] / lib / editpage.php
1 <?php
2 rcs_id('$Id: editpage.php,v 1.38 2002-02-08 03:01:11 dairiki 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' => TransformText($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         include_once('lib/BlockParser.php');
199         return TransformText($this->_content, $this->meta['markup']);
200     }
201
202     function getLockedMessage () {
203         return
204         HTML(HTML::h2(_("Page Locked")),
205              HTML::p(_("This page has been locked by the administrator so your changes can not be saved.")),
206              HTML::p(_("(Copy your changes to the clipboard. You can try editing a different page or save your text in a text editor.)")),
207              HTML::p(_("Sorry for the inconvenience.")));
208     }
209
210     function getConflictMessage () {
211         /*
212          xgettext only knows about c/c++ line-continuation strings
213          it does not know about php's dot operator.
214          We want to translate this entire paragraph as one string, of course.
215          */
216
217         $re_edit_link = Button('edit', _("Edit the new version"), $this->page);
218
219         $steps = HTML::ol(HTML::li(_("Copy your changes to the clipboard or to another temporary place (e.g. text editor).")),
220                           HTML::li(fmt("%s of the page. You should now see the most current version of the page. Your changes are no longer there.",
221                                        $re_edit_link)),
222                           HTML::li(_("Make changes to the file again. Paste your additions from the clipboard (or text editor).")),
223                           HTML::li(_("Save your updated changes.")));
224
225         return HTML(HTML::h2(_("Conflicting Edits!")),
226                     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.")),
227                     HTML::p(_("In order to recover from this situation, follow these steps:")),
228                     $steps,
229                     HTML::p(_("Sorry for the inconvenience.")));
230     }
231
232
233     function getTextArea () {
234         $request = &$this->request;
235
236         // wrap=virtual is not HTML4, but without it NS4 doesn't wrap long lines
237         $readonly = $this->canEdit() || $this->isConcurrentUpdate();
238
239         return HTML::textarea(array('class'    => 'wikiedit',
240                                     'name'     => 'edit[content]',
241                                     'rows'     => $request->getPref('editHeight'),
242                                     'cols'     => $request->getPref('editWidth'),
243                                     'readonly' => (bool) $readonly,
244                                     'wrap'     => 'virtual'),
245                               $this->_content);
246     }
247
248     function getFormElements () {
249         $request = &$this->request;
250         $page = &$this->page;
251
252
253         $h = array('action'   => 'edit',
254                    'pagename' => $page->getName(),
255                    'version'  => $this->version,
256                    'edit[current_version]' => $this->_currentVersion);
257
258         $el['HIDDEN_INPUTS'] = HiddenInputs($h);
259
260
261         $el['EDIT_TEXTAREA'] = $this->getTextArea();
262
263         $el['SUMMARY_INPUT']
264             = HTML::input(array('type'  => 'text',
265                                 'class' => 'wikitext',
266                                 'name'  => 'edit[summary]',
267                                 'size'  => 50,
268                                 'maxlength' => 256,
269                                 'value' => $this->meta['summary']));
270         $el['MINOR_EDIT_CB']
271             = HTML::input(array('type' => 'checkbox',
272                                 'name'  => 'edit[minor_edit]',
273                                 'checked' => (bool) $this->meta['is_minor_edit']));
274         $el['NEW_MARKUP_CB']
275             = HTML::input(array('type' => 'checkbox',
276                                 'name' => 'edit[markup]',
277                                 'value' => 'new',
278                                 'checked' => $this->meta['markup'] >= 2.0));
279
280         $el['LOCKED_CB']
281             = HTML::input(array('type' => 'checkbox',
282                                 'name' => 'edit[locked]',
283                                 'disabled' => (bool) !$this->user->isadmin(),
284                                 'checked'  => (bool) $this->meta['locked']));
285
286         $el['PREVIEW_B'] = Button('submit:edit[preview]', _("Preview"));
287
288         if (!$this->isConcurrentUpdate() && !$this->canEdit())
289             $el['SAVE_B'] = Button('submit:edit[save]', _("Save"));
290
291         $el['IS_CURRENT'] = $this->version == $this->current->getVersion();
292
293         return $el;
294     }
295
296
297     function _restoreState () {
298         $request = &$this->request;
299
300         $posted = $request->getArg('edit');
301         $request->setArg('edit', false);
302
303         if (!$posted || !$request->isPost() || $request->getArg('action') != 'edit')
304             return false;
305
306         if (!isset($posted['content']) || !is_string($posted['content']))
307             return false;
308         $this->_content = preg_replace('/[ \t\r]+\n/', "\n",
309                                        rtrim($posted['content']));
310
311         $this->_currentVersion = (int) $posted['current_version'];
312
313         if ($this->_currentVersion < 0)
314             return false;
315         if ($this->_currentVersion > $this->current->getVersion())
316             return false;       // FIXME: some kind of warning?
317
318         $is_new_markup = !empty($posted['markup']) && $posted['markup'] == 'new';
319         $meta['markup'] = $is_new_markup ? 2.0: false;
320         $meta['summary'] = trim(substr($posted['summary'], 0, 256));
321         $meta['locked'] = !empty($posted['locked']);
322         $meta['is_minor_edit'] = !empty($posted['minor_edit']);
323
324         $this->meta = array_merge($this->meta, $meta);
325
326         if (!empty($posted['preview']))
327             $this->editaction = 'preview';
328         elseif (!empty($posted['save']))
329             $this->editaction = 'save';
330         else
331             $this->editaction = 'edit';
332
333         return true;
334     }
335
336     function _initializeState () {
337         $request = &$this->request;
338         $current = &$this->current;
339         $selected = &$this->selected;
340         $user = &$this->user;
341
342         if (!$selected)
343             NoSuchRevision($request, $this->page, $this->version); // noreturn
344
345         $this->_currentVersion = $current->getVersion();
346         $this->_content = $selected->getPackedContent();
347
348         $this->meta['summary'] = '';
349         $this->meta['locked'] = $this->page->get('locked');
350
351         // If author same as previous author, default minor_edit to on.
352         $age = time() - $current->get('mtime');
353         $this->meta['is_minor_edit'] = ( $age < MINOR_EDIT_TIMEOUT
354                                          && $current->get('author') == $user->getId()
355                                          );
356
357         // Default for new pages is new-style markup.
358         if ($selected->hasDefaultContents())
359             $is_new_markup = true;
360         else
361             $is_new_markup = $selected->get('markup') >= 2.0;
362
363         $this->meta['markup'] = $is_new_markup ? 2.0: false;
364         $this->editaction = 'edit';
365     }
366 }
367
368 // Local Variables:
369 // mode: php
370 // tab-width: 8
371 // c-basic-offset: 4
372 // c-hanging-comment-ender-p: nil
373 // indent-tabs-mode: nil
374 // End:
375 ?>