2 rcs_id('$Id: editpage.php,v 1.42 2002-02-18 08:48:18 carstenklapp Exp $');
4 require_once('lib/Template.php');
8 function PageEditor (&$request) {
9 $this->request = &$request;
11 $this->user = $request->getUser();
12 $this->page = $request->getPage();
14 $this->current = $this->page->getCurrentRevision();
16 $this->meta = array('author' => $this->user->getId(),
17 'locked' => $this->page->get('locked'),
18 'author_id' => $this->user->getAuthenticatedId());
20 $version = $request->getArg('version');
21 if ($version !== false) {
22 $this->selected = $this->page->getRevision($version);
23 $this->version = $version;
26 $this->selected = $this->current;
27 $this->version = $this->current->getVersion();
30 if ($this->_restoreState()) {
31 $this->_initialEdit = false;
34 $this->_initializeState();
35 $this->_initialEdit = true;
39 function editPage () {
43 if ($this->canEdit()) {
44 if ($this->isInitialEdit())
45 return $this->viewSource();
46 $tokens['PAGE_LOCKED_MESSAGE'] = $this->getLockedMessage();
48 elseif ($this->editaction == 'save') {
49 if ($this->savePage())
50 return true; // Page saved.
54 if ($saveFailed || $this->isConcurrentUpdate())
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);
74 if ($this->editaction == 'preview')
75 $tokens['PREVIEW_CONTENT'] = $this->getPreview(); // FIXME: convert to _MESSAGE?
77 // FIXME: NOT_CURRENT_MESSAGE?
79 $tokens = array_merge($tokens, $this->getFormElements());
81 return $this->output('editpage', _("Edit: %s"), $tokens);
84 function output ($template, $title_fs, $tokens) {
85 $selected = &$this->selected;
86 $current = &$this->current;
88 if ($selected && $selected->getVersion() != $current->getVersion()) {
90 $pagelink = WikiLink($selected);
94 $pagelink = WikiLink($this->page);
98 $title = new FormattedText ($title_fs, $pagelink);
99 $template = Template($template, $tokens);
101 GeneratePage($template, $title, $rev);
106 function viewSource ($tokens = false) {
107 assert($this->isInitialEdit());
108 assert($this->selected);
110 $tokens['PAGE_SOURCE'] = $this->_content;
112 return $this->output('viewsource', _("View Source: %s"), $tokens);
115 function setPageLockChanged($isadmin, $lock, &$page) {
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?
121 $page->set('locked', $lock);
125 function savePage () {
126 $request = &$this->request;
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);
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');
144 $page = &$this->page;
145 $lock = $this->meta['locked'];
146 $this->meta['locked'] = ''; // hackish
149 $newrevision = $page->createRevision($this->_currentVersion + 1,
152 ExtractWikiPageLinks($this->_content));
153 if (!is_object($newrevision)) {
154 // Save failed. (Concurrent updates).
157 // New contents successfully saved...
158 if ($isadmin = $this->user->isadmin())
159 $this->setPageLockChanged($isadmin, $lock, &$page);
161 // Clean out archived versions of this page.
162 include_once('lib/ArchiveCleaner.php');
163 $cleaner = new ArchiveCleaner($GLOBALS['ExpireParams']);
164 $cleaner->cleanPageRevisions($page);
166 $dbi = $request->getDbh();
167 $warnings = $dbi->GenericWarnings();
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
175 $request->redirect(WikiURL($page, false, 'absolute_url'));
178 // Force browse of current page version.
179 $request->setArg('version', false);
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);
191 $pagelink = WikiLink($page);
193 GeneratePage($template, fmt("Saved: %s", $pagelink), $newrevision);
197 function isConcurrentUpdate () {
198 assert($this->current->getVersion() >= $this->_currentVersion);
199 return $this->current->getVersion() != $this->_currentVersion;
202 function canEdit () {
203 return $this->page->get('locked') && !$this->user->isAdmin();
206 function isInitialEdit () {
207 return $this->_initialEdit;
210 function isUnchanged () {
211 $current = &$this->current;
213 if ($this->meta['markup'] != $current->get('markup'))
216 return $this->_content == $current->getPackedContent();
219 function getPreview () {
220 require_once('lib/PageType.php');
221 return PageType($this->_content, $this->page->getName(), $this->meta['markup']);
223 // include_once('lib/BlockParser.php');
224 // return TransformText($this->_content, $this->meta['markup']);
227 function getLockedMessage () {
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.")));
235 function getConflictMessage ($unresolved = false) {
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.
242 // $re_edit_link = Button('edit', _("Edit the new version"), $this->page);
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 the click Save"));
247 $message = HTML::p(_("Please check it through and click Save to save it."));
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.",
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.")));
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")),
264 function getTextArea () {
265 $request = &$this->request;
267 // wrap=virtual is not HTML4, but without it NS4 doesn't wrap long lines
268 $readonly = $this->canEdit(); // || $this->isConcurrentUpdate();
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'),
279 function getFormElements () {
280 $request = &$this->request;
281 $page = &$this->page;
284 $h = array('action' => 'edit',
285 'pagename' => $page->getName(),
286 'version' => $this->version,
287 'edit[current_version]' => $this->_currentVersion);
289 $el['HIDDEN_INPUTS'] = HiddenInputs($h);
292 $el['EDIT_TEXTAREA'] = $this->getTextArea();
295 = HTML::input(array('type' => 'text',
296 'class' => 'wikitext',
297 'name' => 'edit[summary]',
300 'value' => $this->meta['summary']));
302 = HTML::input(array('type' => 'checkbox',
303 'name' => 'edit[minor_edit]',
304 'checked' => (bool) $this->meta['is_minor_edit']));
306 = HTML::input(array('type' => 'checkbox',
307 'name' => 'edit[markup]',
309 'checked' => $this->meta['markup'] >= 2.0));
312 = HTML::input(array('type' => 'checkbox',
313 'name' => 'edit[locked]',
314 'disabled' => (bool) !$this->user->isadmin(),
315 'checked' => (bool) $this->meta['locked']));
317 $el['PREVIEW_B'] = Button('submit:edit[preview]', _("Preview"), 'wikiaction');
319 // if (!$this->isConcurrentUpdate() && !$this->canEdit())
320 $el['SAVE_B'] = Button('submit:edit[save]', _("Save"), 'wikiaction');
322 $el['IS_CURRENT'] = $this->version == $this->current->getVersion();
328 function _restoreState () {
329 $request = &$this->request;
331 $posted = $request->getArg('edit');
332 $request->setArg('edit', false);
334 if (!$posted || !$request->isPost() || $request->getArg('action') != 'edit')
337 if (!isset($posted['content']) || !is_string($posted['content']))
339 $this->_content = preg_replace('/[ \t\r]+\n/', "\n",
340 rtrim($posted['content']));
342 $this->_currentVersion = (int) $posted['current_version'];
344 if ($this->_currentVersion < 0)
346 if ($this->_currentVersion > $this->current->getVersion())
347 return false; // FIXME: some kind of warning?
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']);
355 $this->meta = array_merge($this->meta, $meta);
357 if (!empty($posted['preview']))
358 $this->editaction = 'preview';
359 elseif (!empty($posted['save']))
360 $this->editaction = 'save';
362 $this->editaction = 'edit';
367 function _initializeState () {
368 $request = &$this->request;
369 $current = &$this->current;
370 $selected = &$this->selected;
371 $user = &$this->user;
374 NoSuchRevision($request, $this->page, $this->version); // noreturn
376 $this->_currentVersion = $current->getVersion();
377 $this->_content = $selected->getPackedContent();
379 $this->meta['summary'] = '';
380 $this->meta['locked'] = $this->page->get('locked');
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()
388 // Default for new pages is new-style markup.
389 if ($selected->hasDefaultContents())
390 $is_new_markup = true;
392 $is_new_markup = $selected->get('markup') >= 2.0;
394 $this->meta['markup'] = $is_new_markup ? 2.0: false;
395 $this->editaction = 'edit';
403 // c-hanging-comment-ender-p: nil
404 // indent-tabs-mode: nil