request = &$request; $this->user = $request->getUser(); $this->page = $request->getPage(); $this->current = $this->page->getCurrentRevision(); $this->meta = array('author' => $this->user->getId(), 'locked' => $this->page->get('locked'), 'author_id' => $this->user->getAuthenticatedId()); $version = $request->getArg('version'); if ($version !== false) { $this->selected = $this->page->getRevision($version); $this->version = $version; } else { $this->selected = $this->current; $this->version = $this->current->getVersion(); } if ($this->_restoreState()) { $this->_initialEdit = false; } else { $this->_initializeState(); $this->_initialEdit = true; } } function editPage () { $saveFailed = false; $tokens = array(); if ($this->canEdit()) { if ($this->isInitialEdit()) return $this->viewSource(); $tokens['PAGE_LOCKED_MESSAGE'] = $this->getLockedMessage(); } elseif ($this->editaction == 'save') { if ($this->savePage()) return true; // Page saved. $saveFailed = true; } if ($saveFailed || $this->isConcurrentUpdate()) { // Get the text of the original page, and the two conflicting edits // The diff3 class takes arrays as input. So retrieve content as // an array, or convert it as necesary. $orig = $this->page->getRevision($this->_currentVersion); $orig_content = $orig->getContent(); $this_content = explode("\n", $this->_content); $other_content = $this->current->getContent(); include_once("lib/diff3.php"); $diff = new diff3($orig_content, $this_content, $other_content); $output = $diff->merged_output(_("Your version"), _("Other version")); // Set the content of the textarea to the merged diff output, and update the version $this->_content = implode ("\n", $output); $this->_currentVersion = $this->current->getVersion(); $this->version = $this->_currentVersion; $unresolved = $diff->ConflictingBlocks; $tokens['CONCURRENT_UPDATE_MESSAGE'] = $this->getConflictMessage($unresolved); } if ($this->editaction == 'preview') $tokens['PREVIEW_CONTENT'] = $this->getPreview(); // FIXME: convert to _MESSAGE? // FIXME: NOT_CURRENT_MESSAGE? $tokens = array_merge($tokens, $this->getFormElements()); return $this->output('editpage', _("Edit: %s"), $tokens); } function output ($template, $title_fs, $tokens) { $selected = &$this->selected; $current = &$this->current; if ($selected && $selected->getVersion() != $current->getVersion()) { $rev = $selected; $pagelink = WikiLink($selected); } else { $rev = $current; $pagelink = WikiLink($this->page); } $title = new FormattedText ($title_fs, $pagelink); $template = Template($template, $tokens); GeneratePage($template, $title, $rev); return true; } function viewSource ($tokens = false) { assert($this->isInitialEdit()); assert($this->selected); $tokens['PAGE_SOURCE'] = $this->_content; return $this->output('viewsource', _("View Source: %s"), $tokens); } function setPageLockChanged($isadmin, $lock, &$page) { if ($isadmin) { if (! $page->get('locked') == $lock) { $request = &$this->request; $request->setArg('lockchanged', true); //is it safe to add new args to $request like this? } $page->set('locked', $lock); } } function savePage () { $request = &$this->request; if ($this->isUnchanged()) { // Allow admin lock/unlock even if // no text changes were made. if ($isadmin = $this->user->isadmin()) { $page = &$this->page; $lock = $this->meta['locked']; $this->setPageLockChanged($isadmin, $lock, &$page); } // Save failed. No changes made. include_once('lib/display.php'); // force browse of current version: $request->setArg('version', false); displayPage($request, 'nochanges'); return true; } $page = &$this->page; $lock = $this->meta['locked']; $this->meta['locked'] = ''; // hackish // Save new revision $newrevision = $page->createRevision($this->_currentVersion + 1, $this->_content, $this->meta, ExtractWikiPageLinks($this->_content)); if (!is_object($newrevision)) { // Save failed. (Concurrent updates). return false; } // New contents successfully saved... if ($isadmin = $this->user->isadmin()) $this->setPageLockChanged($isadmin, $lock, &$page); // Clean out archived versions of this page. include_once('lib/ArchiveCleaner.php'); $cleaner = new ArchiveCleaner($GLOBALS['ExpireParams']); $cleaner->cleanPageRevisions($page); $dbi = $request->getDbh(); $warnings = $dbi->GenericWarnings(); global $Theme; if (empty($warnings) && ! $Theme->getImageURL('signature')) { // Do redirect to browse page if no signature has // been defined. In this case, the user will most // likely not see the rest of the HTML we generate // (below). $request->redirect(WikiURL($page, false, 'absolute_url')); } // Force browse of current page version. $request->setArg('version', false); include_once('lib/BlockParser.php'); $template = Template('savepage', array('CONTENT' => TransformText($newrevision))); if (!empty($warnings)) $template->replace('WARNINGS', $warnings); $pagelink = WikiLink($page); GeneratePage($template, fmt("Saved: %s", $pagelink), $newrevision); return true; } function isConcurrentUpdate () { assert($this->current->getVersion() >= $this->_currentVersion); return $this->current->getVersion() != $this->_currentVersion; } function canEdit () { return $this->page->get('locked') && !$this->user->isAdmin(); } function isInitialEdit () { return $this->_initialEdit; } function isUnchanged () { $current = &$this->current; if ($this->meta['markup'] != $current->get('markup')) return false; return $this->_content == $current->getPackedContent(); } function getPreview () { include_once('lib/BlockParser.php'); return TransformText($this->_content, $this->meta['markup']); } function getLockedMessage () { return HTML(HTML::h2(_("Page Locked")), HTML::p(_("This page has been locked by the administrator so your changes can not be saved.")), HTML::p(_("(Copy your changes to the clipboard. You can try editing a different page or save your text in a text editor.)")), HTML::p(_("Sorry for the inconvenience."))); } function getConflictMessage ($unresolved = false) { /* xgettext only knows about c/c++ line-continuation strings it does not know about php's dot operator. We want to translate this entire paragraph as one string, of course. */ // $re_edit_link = Button('edit', _("Edit the new version"), $this->page); if ($unresolved ) $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")); else $message = HTML::p(_("Please check it through and click Save to save it.")); /* $steps = HTML::ol(HTML::li(_("Copy your changes to the clipboard or to another temporary place (e.g. text editor).")), HTML::li(fmt("%s of the page. You should now see the most current version of the page. Your changes are no longer there.", $re_edit_link)), HTML::li(_("Make changes to the file again. Paste your additions from the clipboard (or text editor).")), HTML::li(_("Save your updated changes."))); */ return HTML(HTML::h2(_("Conflicting Edits!")), 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.")), HTML::p(_("So, your changes and those of the other author have been combined. The result is shown below")), $message); } function getTextArea () { $request = &$this->request; // wrap=virtual is not HTML4, but without it NS4 doesn't wrap long lines $readonly = $this->canEdit(); // || $this->isConcurrentUpdate(); return HTML::textarea(array('class' => 'wikiedit', 'name' => 'edit[content]', 'rows' => $request->getPref('editHeight'), 'cols' => $request->getPref('editWidth'), 'readonly' => (bool) $readonly, 'wrap' => 'virtual'), $this->_content); } function getFormElements () { $request = &$this->request; $page = &$this->page; $h = array('action' => 'edit', 'pagename' => $page->getName(), 'version' => $this->version, 'edit[current_version]' => $this->_currentVersion); $el['HIDDEN_INPUTS'] = HiddenInputs($h); $el['EDIT_TEXTAREA'] = $this->getTextArea(); $el['SUMMARY_INPUT'] = HTML::input(array('type' => 'text', 'class' => 'wikitext', 'name' => 'edit[summary]', 'size' => 50, 'maxlength' => 256, 'value' => $this->meta['summary'])); $el['MINOR_EDIT_CB'] = HTML::input(array('type' => 'checkbox', 'name' => 'edit[minor_edit]', 'checked' => (bool) $this->meta['is_minor_edit'])); $el['NEW_MARKUP_CB'] = HTML::input(array('type' => 'checkbox', 'name' => 'edit[markup]', 'value' => 'new', 'checked' => $this->meta['markup'] >= 2.0)); $el['LOCKED_CB'] = HTML::input(array('type' => 'checkbox', 'name' => 'edit[locked]', 'disabled' => (bool) !$this->user->isadmin(), 'checked' => (bool) $this->meta['locked'])); $el['PREVIEW_B'] = Button('submit:edit[preview]', _("Preview"), 'wikiaction'); // if (!$this->isConcurrentUpdate() && !$this->canEdit()) $el['SAVE_B'] = Button('submit:edit[save]', _("Save"), 'wikiaction'); $el['IS_CURRENT'] = $this->version == $this->current->getVersion(); return $el; } function _restoreState () { $request = &$this->request; $posted = $request->getArg('edit'); $request->setArg('edit', false); if (!$posted || !$request->isPost() || $request->getArg('action') != 'edit') return false; if (!isset($posted['content']) || !is_string($posted['content'])) return false; $this->_content = preg_replace('/[ \t\r]+\n/', "\n", rtrim($posted['content'])); $this->_currentVersion = (int) $posted['current_version']; if ($this->_currentVersion < 0) return false; if ($this->_currentVersion > $this->current->getVersion()) return false; // FIXME: some kind of warning? $is_new_markup = !empty($posted['markup']) && $posted['markup'] == 'new'; $meta['markup'] = $is_new_markup ? 2.0: false; $meta['summary'] = trim(substr($posted['summary'], 0, 256)); $meta['locked'] = !empty($posted['locked']); $meta['is_minor_edit'] = !empty($posted['minor_edit']); $this->meta = array_merge($this->meta, $meta); if (!empty($posted['preview'])) $this->editaction = 'preview'; elseif (!empty($posted['save'])) $this->editaction = 'save'; else $this->editaction = 'edit'; return true; } function _initializeState () { $request = &$this->request; $current = &$this->current; $selected = &$this->selected; $user = &$this->user; if (!$selected) NoSuchRevision($request, $this->page, $this->version); // noreturn $this->_currentVersion = $current->getVersion(); $this->_content = $selected->getPackedContent(); $this->meta['summary'] = ''; $this->meta['locked'] = $this->page->get('locked'); // If author same as previous author, default minor_edit to on. $age = time() - $current->get('mtime'); $this->meta['is_minor_edit'] = ( $age < MINOR_EDIT_TIMEOUT && $current->get('author') == $user->getId() ); // Default for new pages is new-style markup. if ($selected->hasDefaultContents()) $is_new_markup = true; else $is_new_markup = $selected->get('markup') >= 2.0; $this->meta['markup'] = $is_new_markup ? 2.0: false; $this->editaction = 'edit'; } } // Local Variables: // mode: php // tab-width: 8 // c-basic-offset: 4 // c-hanging-comment-ender-p: nil // indent-tabs-mode: nil // End: ?>