2 rcs_id('$Id: editpage.php,v 1.51 2003-01-03 02:43:26 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;
38 header("Content-Type: text/html; charset=" . CHARSET);
41 function editPage () {
45 if ($this->canEdit()) {
46 if ($this->isInitialEdit())
47 return $this->viewSource();
48 $tokens['PAGE_LOCKED_MESSAGE'] = $this->getLockedMessage();
50 elseif ($this->editaction == 'save') {
51 if ($this->savePage())
52 return true; // Page saved.
56 if ($saveFailed || $this->isConcurrentUpdate())
58 // Get the text of the original page, and the two conflicting edits
59 // The diff3 class takes arrays as input. So retrieve content as
60 // an array, or convert it as necesary.
61 $orig = $this->page->getRevision($this->_currentVersion);
62 $orig_content = $orig->getContent();
63 $this_content = explode("\n", $this->_content);
64 $other_content = $this->current->getContent();
65 include_once("lib/diff3.php");
66 $diff = new diff3($orig_content, $this_content, $other_content);
67 $output = $diff->merged_output(_("Your version"), _("Other version"));
68 // Set the content of the textarea to the merged diff output, and update the version
69 $this->_content = implode ("\n", $output);
70 $this->_currentVersion = $this->current->getVersion();
71 $this->version = $this->_currentVersion;
72 $unresolved = $diff->ConflictingBlocks;
73 $tokens['CONCURRENT_UPDATE_MESSAGE'] = $this->getConflictMessage($unresolved);
76 if ($this->editaction == 'preview')
77 $tokens['PREVIEW_CONTENT'] = $this->getPreview(); // FIXME: convert to _MESSAGE?
79 // FIXME: NOT_CURRENT_MESSAGE?
81 $tokens = array_merge($tokens, $this->getFormElements());
83 return $this->output('editpage', _("Edit: %s"), $tokens);
86 function output ($template, $title_fs, $tokens) {
87 $selected = &$this->selected;
88 $current = &$this->current;
90 if ($selected && $selected->getVersion() != $current->getVersion()) {
92 $pagelink = WikiLink($selected);
96 $pagelink = WikiLink($this->page);
100 $title = new FormattedText ($title_fs, $pagelink);
101 $template = Template($template, $tokens);
103 GeneratePage($template, $title, $rev);
108 function viewSource ($tokens = false) {
109 assert($this->isInitialEdit());
110 assert($this->selected);
112 $tokens['PAGE_SOURCE'] = $this->_content;
114 return $this->output('viewsource', _("View Source: %s"), $tokens);
117 function setPageLockChanged($isadmin, $lock, &$page) {
119 if (! $page->get('locked') == $lock) {
120 $request = &$this->request;
121 $request->setArg('lockchanged', true); //is it safe to add new args to $request like this?
123 $page->set('locked', $lock);
127 function savePage () {
128 $request = &$this->request;
130 if ($this->isUnchanged()) {
131 // Allow admin lock/unlock even if
132 // no text changes were made.
133 if ($isadmin = $this->user->isadmin()) {
134 $page = &$this->page;
135 $lock = $this->meta['locked'];
136 $this->setPageLockChanged($isadmin, $lock, $page);
138 // Save failed. No changes made.
139 include_once('lib/display.php');
140 // force browse of current version:
141 $request->setArg('version', false);
142 displayPage($request, 'nochanges');
146 $page = &$this->page;
147 $lock = $this->meta['locked'];
148 $this->meta['locked'] = ''; // hackish
151 $newrevision = $page->createRevision($this->_currentVersion + 1,
154 ExtractWikiPageLinks($this->_content));
155 if (!is_object($newrevision)) {
156 // Save failed. (Concurrent updates).
159 // New contents successfully saved...
160 if ($isadmin = $this->user->isadmin())
161 $this->setPageLockChanged($isadmin, $lock, $page);
163 // Clean out archived versions of this page.
164 include_once('lib/ArchiveCleaner.php');
165 $cleaner = new ArchiveCleaner($GLOBALS['ExpireParams']);
166 $cleaner->cleanPageRevisions($page);
168 $dbi = $request->getDbh();
169 $warnings = $dbi->GenericWarnings();
172 if (empty($warnings) && ! $Theme->getImageURL('signature')) {
173 // Do redirect to browse page if no signature has
174 // been defined. In this case, the user will most
175 // likely not see the rest of the HTML we generate
177 $request->redirect(WikiURL($page, false, 'absolute_url'));
180 // Force browse of current page version.
181 $request->setArg('version', false);
183 require_once('lib/PageType.php');
184 $transformedText = PageType($newrevision);
185 $template = Template('savepage',
186 array('CONTENT' => $transformedText));
187 //include_once('lib/BlockParser.php');
188 //$template = Template('savepage',
189 // array('CONTENT' => TransformText($newrevision)));
190 if (!empty($warnings))
191 $template->replace('WARNINGS', $warnings);
193 $pagelink = WikiLink($page);
195 GeneratePage($template, fmt("Saved: %s", $pagelink), $newrevision);
199 function isConcurrentUpdate () {
200 assert($this->current->getVersion() >= $this->_currentVersion);
201 return $this->current->getVersion() != $this->_currentVersion;
204 function canEdit () {
205 return $this->page->get('locked') && !$this->user->isAdmin();
208 function isInitialEdit () {
209 return $this->_initialEdit;
212 function isUnchanged () {
213 $current = &$this->current;
215 if ($this->meta['markup'] != $current->get('markup'))
218 return $this->_content == $current->getPackedContent();
221 function getPreview () {
222 require_once('lib/PageType.php');
223 return PageType($this->_content, $this->page->getName(), $this->meta['markup']);
225 //include_once('lib/BlockParser.php');
226 //return TransformText($this->_content, $this->meta['markup']);
229 function getLockedMessage () {
231 HTML(HTML::h2(_("Page Locked")),
232 HTML::p(_("This page has been locked by the administrator so your changes can not be saved.")),
233 HTML::p(_("(Copy your changes to the clipboard. You can try editing a different page or save your text in a text editor.)")),
234 HTML::p(_("Sorry for the inconvenience.")));
237 function getConflictMessage ($unresolved = false) {
239 xgettext only knows about c/c++ line-continuation strings
240 it does not know about php's dot operator.
241 We want to translate this entire paragraph as one string, of course.
244 //$re_edit_link = Button('edit', _("Edit the new version"), $this->page);
247 $message = HTML::p(fmt("Some of the changes could not automatically be combined. Please look for sections beginning with '%s', and ending with '%s'. You will need to edit those sections by hand before you click Save.",
248 "<<<<<<< ". _("Your version"),
249 ">>>>>>> ". _("Other version")));
251 $message = HTML::p(_("Please check it through before saving."));
255 /*$steps = HTML::ol(HTML::li(_("Copy your changes to the clipboard or to another temporary place (e.g. text editor).")),
256 HTML::li(fmt("%s of the page. You should now see the most current version of the page. Your changes are no longer there.",
258 HTML::li(_("Make changes to the file again. Paste your additions from the clipboard (or text editor).")),
259 HTML::li(_("Save your updated changes.")));
261 return HTML(HTML::h2(_("Conflicting Edits!")),
262 HTML::p(_("In the time since you started editing this page, another user has saved a new version of it.")),
263 HTML::p(_("Your changes can not be saved as they are, since doing so would overwrite the other author's changes. So, your changes and those of the other author have been combined. The result is shown below.")),
268 function getTextArea () {
269 $request = &$this->request;
271 // wrap=virtual is not HTML4, but without it NS4 doesn't wrap long lines
272 $readonly = $this->canEdit(); // || $this->isConcurrentUpdate();
274 return HTML::textarea(array('class' => 'wikiedit',
275 'name' => 'edit[content]',
276 'rows' => $request->getPref('editHeight'),
277 'cols' => $request->getPref('editWidth'),
278 'readonly' => (bool) $readonly,
279 'wrap' => 'virtual'),
283 function getFormElements () {
284 $request = &$this->request;
285 $page = &$this->page;
288 $h = array('action' => 'edit',
289 'pagename' => $page->getName(),
290 'version' => $this->version,
291 'edit[current_version]' => $this->_currentVersion);
293 $el['HIDDEN_INPUTS'] = HiddenInputs($h);
296 $el['EDIT_TEXTAREA'] = $this->getTextArea();
299 = HTML::input(array('type' => 'text',
300 'class' => 'wikitext',
301 'name' => 'edit[summary]',
304 'value' => $this->meta['summary']));
306 = HTML::input(array('type' => 'checkbox',
307 'name' => 'edit[minor_edit]',
308 'checked' => (bool) $this->meta['is_minor_edit']));
310 = HTML::input(array('type' => 'checkbox',
311 'name' => 'edit[markup]',
313 'checked' => $this->meta['markup'] < 2.0,
314 'id' => 'useOldMarkup',
315 'onclick' => 'showOldMarkupRules(this.checked)'));
318 = HTML::input(array('type' => 'checkbox',
319 'name' => 'edit[locked]',
320 'disabled' => (bool) !$this->user->isadmin(),
321 'checked' => (bool) $this->meta['locked']));
323 $el['PREVIEW_B'] = Button('submit:edit[preview]', _("Preview"), 'wikiaction');
325 //if (!$this->isConcurrentUpdate() && !$this->canEdit())
326 $el['SAVE_B'] = Button('submit:edit[save]', _("Save"), 'wikiaction');
328 $el['IS_CURRENT'] = $this->version == $this->current->getVersion();
334 function _restoreState () {
335 $request = &$this->request;
337 $posted = $request->getArg('edit');
338 $request->setArg('edit', false);
340 if (!$posted || !$request->isPost() || $request->getArg('action') != 'edit')
343 if (!isset($posted['content']) || !is_string($posted['content']))
345 $this->_content = preg_replace('/[ \t\r]+\n/', "\n",
346 rtrim($posted['content']));
348 $this->_currentVersion = (int) $posted['current_version'];
350 if ($this->_currentVersion < 0)
352 if ($this->_currentVersion > $this->current->getVersion())
353 return false; // FIXME: some kind of warning?
355 $is_old_markup = !empty($posted['markup']) && $posted['markup'] == 'old';
356 $meta['markup'] = $is_old_markup ? false : 2.0;
357 $meta['summary'] = trim(substr($posted['summary'], 0, 256));
358 $meta['locked'] = !empty($posted['locked']);
359 $meta['is_minor_edit'] = !empty($posted['minor_edit']);
361 $this->meta = array_merge($this->meta, $meta);
363 if (!empty($posted['preview']))
364 $this->editaction = 'preview';
365 elseif (!empty($posted['save']))
366 $this->editaction = 'save';
368 $this->editaction = 'edit';
373 function _initializeState () {
374 $request = &$this->request;
375 $current = &$this->current;
376 $selected = &$this->selected;
377 $user = &$this->user;
380 NoSuchRevision($request, $this->page, $this->version); // noreturn
382 $this->_currentVersion = $current->getVersion();
383 $this->_content = $selected->getPackedContent();
385 $this->meta['summary'] = '';
386 $this->meta['locked'] = $this->page->get('locked');
388 // If author same as previous author, default minor_edit to on.
389 $age = time() - $current->get('mtime');
390 $this->meta['is_minor_edit'] = ( $age < MINOR_EDIT_TIMEOUT
391 && $current->get('author') == $user->getId()
394 // Default for new pages is new-style markup.
395 if ($selected->hasDefaultContents())
396 $is_new_markup = true;
398 $is_new_markup = $selected->get('markup') >= 2.0;
400 $this->meta['markup'] = $is_new_markup ? 2.0: false;
401 $this->editaction = 'edit';
405 class LoadFileConflictPageEditor
408 function editPage ($saveFailed = true) {
411 if ($this->canEdit()) {
412 if ($this->isInitialEdit())
413 return $this->viewSource();
414 $tokens['PAGE_LOCKED_MESSAGE'] = $this->getLockedMessage();
416 elseif ($this->editaction == 'save') {
417 if ($this->savePage())
418 return true; // Page saved.
422 if ($saveFailed || $this->isConcurrentUpdate())
424 // Get the text of the original page, and the two conflicting edits
425 // The diff class takes arrays as input. So retrieve content as
426 // an array, or convert it as necesary.
427 $orig = $this->page->getRevision($this->_currentVersion);
428 $this_content = explode("\n", $this->_content);
429 $other_content = $this->current->getContent();
430 include_once("lib/diff.php");
431 $diff2 = new Diff($other_content, $this_content);
432 $context_lines = max(4, count($other_content) + 1,
433 count($this_content) + 1);
434 $fmt = new BlockDiffFormatter($context_lines);
435 $this->_content = $fmt->format($diff2);
436 $this->_currentVersion = $this->current->getVersion();
437 $this->version = $this->_currentVersion;
438 $tokens['CONCURRENT_UPDATE_MESSAGE'] = $this->getConflictMessage();
441 if ($this->editaction == 'preview')
442 $tokens['PREVIEW_CONTENT'] = $this->getPreview(); // FIXME: convert to _MESSAGE?
444 // FIXME: NOT_CURRENT_MESSAGE?
446 $tokens = array_merge($tokens, $this->getFormElements());
448 return $this->output('editpage', _("Merge and Edit: %s"), $tokens); // FIXME: this doesn't display
451 function output ($template, $title_fs, $tokens) {
452 $selected = &$this->selected;
453 $current = &$this->current;
455 if ($selected && $selected->getVersion() != $current->getVersion()) {
457 $pagelink = WikiLink($selected);
461 $pagelink = WikiLink($this->page);
464 $title = new FormattedText ($title_fs, $pagelink);
465 $template = Template($template, $tokens);
467 //GeneratePage($template, $title, $rev);
471 function getConflictMessage () {
472 $message = HTML(HTML::p(fmt("Some of the changes could not automatically be combined. Please look for sections beginning with '%s', and ending with '%s'. You will need to edit those sections by hand before you click Save.",
475 HTML::p(_("Please check it through before saving."))));
481 $Log: not supported by cvs2svn $
488 // c-hanging-comment-ender-p: nil
489 // indent-tabs-mode: nil