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