2 rcs_id('$Id: editpage.php,v 1.47 2002-03-21 21:24:50 lakka 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);
39 header("Last-Modified: ".Rfc2822DateTime($this->selected->get('mtime')));
42 function editPage () {
46 if ($this->canEdit()) {
47 if ($this->isInitialEdit())
48 return $this->viewSource();
49 $tokens['PAGE_LOCKED_MESSAGE'] = $this->getLockedMessage();
51 elseif ($this->editaction == 'save') {
52 if ($this->savePage())
53 return true; // Page saved.
57 if ($saveFailed || $this->isConcurrentUpdate())
59 // Get the text of the original page, and the two conflicting edits
60 // The diff3 class takes arrays as input. So retrieve content as
61 // an array, or convert it as necesary.
62 $orig = $this->page->getRevision($this->_currentVersion);
63 $orig_content = $orig->getContent();
64 $this_content = explode("\n", $this->_content);
65 $other_content = $this->current->getContent();
66 include_once("lib/diff3.php");
67 $diff = new diff3($orig_content, $this_content, $other_content);
68 $output = $diff->merged_output(_("Your version"), _("Other version"));
69 // Set the content of the textarea to the merged diff output, and update the version
70 $this->_content = implode ("\n", $output);
71 $this->_currentVersion = $this->current->getVersion();
72 $this->version = $this->_currentVersion;
73 $unresolved = $diff->ConflictingBlocks;
74 $tokens['CONCURRENT_UPDATE_MESSAGE'] = $this->getConflictMessage($unresolved);
77 if ($this->editaction == 'preview')
78 $tokens['PREVIEW_CONTENT'] = $this->getPreview(); // FIXME: convert to _MESSAGE?
80 // FIXME: NOT_CURRENT_MESSAGE?
82 $tokens = array_merge($tokens, $this->getFormElements());
84 return $this->output('editpage', _("Edit: %s"), $tokens);
87 function output ($template, $title_fs, $tokens) {
88 $selected = &$this->selected;
89 $current = &$this->current;
91 if ($selected && $selected->getVersion() != $current->getVersion()) {
93 $pagelink = WikiLink($selected);
97 $pagelink = WikiLink($this->page);
101 $title = new FormattedText ($title_fs, $pagelink);
102 $template = Template($template, $tokens);
104 GeneratePage($template, $title, $rev);
109 function viewSource ($tokens = false) {
110 assert($this->isInitialEdit());
111 assert($this->selected);
113 $tokens['PAGE_SOURCE'] = $this->_content;
115 return $this->output('viewsource', _("View Source: %s"), $tokens);
118 function setPageLockChanged($isadmin, $lock, &$page) {
120 if (! $page->get('locked') == $lock) {
121 $request = &$this->request;
122 $request->setArg('lockchanged', true); //is it safe to add new args to $request like this?
124 $page->set('locked', $lock);
128 function savePage () {
129 $request = &$this->request;
131 if ($this->isUnchanged()) {
132 // Allow admin lock/unlock even if
133 // no text changes were made.
134 if ($isadmin = $this->user->isadmin()) {
135 $page = &$this->page;
136 $lock = $this->meta['locked'];
137 $this->setPageLockChanged($isadmin, $lock, $page);
139 // Save failed. No changes made.
140 include_once('lib/display.php');
141 // force browse of current version:
142 $request->setArg('version', false);
143 displayPage($request, 'nochanges');
147 $page = &$this->page;
148 $lock = $this->meta['locked'];
149 $this->meta['locked'] = ''; // hackish
152 $newrevision = $page->createRevision($this->_currentVersion + 1,
155 ExtractWikiPageLinks($this->_content));
156 if (!is_object($newrevision)) {
157 // Save failed. (Concurrent updates).
160 // New contents successfully saved...
161 if ($isadmin = $this->user->isadmin())
162 $this->setPageLockChanged($isadmin, $lock, $page);
164 // Clean out archived versions of this page.
165 include_once('lib/ArchiveCleaner.php');
166 $cleaner = new ArchiveCleaner($GLOBALS['ExpireParams']);
167 $cleaner->cleanPageRevisions($page);
169 $dbi = $request->getDbh();
170 $warnings = $dbi->GenericWarnings();
173 if (empty($warnings) && ! $Theme->getImageURL('signature')) {
174 // Do redirect to browse page if no signature has
175 // been defined. In this case, the user will most
176 // likely not see the rest of the HTML we generate
178 $request->redirect(WikiURL($page, false, 'absolute_url'));
181 // Force browse of current page version.
182 $request->setArg('version', false);
184 require_once('lib/PageType.php');
185 $transformedText = PageType($newrevision);
186 $template = Template('savepage',
187 array('CONTENT' => $transformedText));
188 //include_once('lib/BlockParser.php');
189 //$template = Template('savepage',
190 // array('CONTENT' => TransformText($newrevision)));
191 if (!empty($warnings))
192 $template->replace('WARNINGS', $warnings);
194 $pagelink = WikiLink($page);
196 GeneratePage($template, fmt("Saved: %s", $pagelink), $newrevision);
200 function isConcurrentUpdate () {
201 assert($this->current->getVersion() >= $this->_currentVersion);
202 return $this->current->getVersion() != $this->_currentVersion;
205 function canEdit () {
206 return $this->page->get('locked') && !$this->user->isAdmin();
209 function isInitialEdit () {
210 return $this->_initialEdit;
213 function isUnchanged () {
214 $current = &$this->current;
216 if ($this->meta['markup'] != $current->get('markup'))
219 return $this->_content == $current->getPackedContent();
222 function getPreview () {
223 require_once('lib/PageType.php');
224 return PageType($this->_content, $this->page->getName(), $this->meta['markup']);
226 //include_once('lib/BlockParser.php');
227 //return TransformText($this->_content, $this->meta['markup']);
230 function getLockedMessage () {
232 HTML(HTML::h2(_("Page Locked")),
233 HTML::p(_("This page has been locked by the administrator so your changes can not be saved.")),
234 HTML::p(_("(Copy your changes to the clipboard. You can try editing a different page or save your text in a text editor.)")),
235 HTML::p(_("Sorry for the inconvenience.")));
238 function getConflictMessage ($unresolved = false) {
240 xgettext only knows about c/c++ line-continuation strings
241 it does not know about php's dot operator.
242 We want to translate this entire paragraph as one string, of course.
245 //$re_edit_link = Button('edit', _("Edit the new version"), $this->page);
248 $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.",
249 "<<<<<<< ". _("Your version"),
250 ">>>>>>> ". _("Other version")));
252 $message = HTML::p(_("Please check it through before saving."));
256 /*$steps = HTML::ol(HTML::li(_("Copy your changes to the clipboard or to another temporary place (e.g. text editor).")),
257 HTML::li(fmt("%s of the page. You should now see the most current version of the page. Your changes are no longer there.",
259 HTML::li(_("Make changes to the file again. Paste your additions from the clipboard (or text editor).")),
260 HTML::li(_("Save your updated changes.")));
262 return HTML(HTML::h2(_("Conflicting Edits!")),
263 HTML::p(_("In the time since you started editing this page, another user has saved a new version of it.")),
264 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.")),
269 function getTextArea () {
270 $request = &$this->request;
272 // wrap=virtual is not HTML4, but without it NS4 doesn't wrap long lines
273 $readonly = $this->canEdit(); // || $this->isConcurrentUpdate();
275 return HTML::textarea(array('class' => 'wikiedit',
276 'name' => 'edit[content]',
277 'rows' => $request->getPref('editHeight'),
278 'cols' => $request->getPref('editWidth'),
279 'readonly' => (bool) $readonly,
280 'wrap' => 'virtual'),
284 function getFormElements () {
285 $request = &$this->request;
286 $page = &$this->page;
289 $h = array('action' => 'edit',
290 'pagename' => $page->getName(),
291 'version' => $this->version,
292 'edit[current_version]' => $this->_currentVersion);
294 $el['HIDDEN_INPUTS'] = HiddenInputs($h);
297 $el['EDIT_TEXTAREA'] = $this->getTextArea();
300 = HTML::input(array('type' => 'text',
301 'class' => 'wikitext',
302 'name' => 'edit[summary]',
305 'value' => $this->meta['summary']));
307 = HTML::input(array('type' => 'checkbox',
308 'name' => 'edit[minor_edit]',
309 'checked' => (bool) $this->meta['is_minor_edit']));
311 = HTML::input(array('type' => 'checkbox',
312 'name' => 'edit[markup]',
314 'checked' => $this->meta['markup'] >= 2.0));
317 = HTML::input(array('type' => 'checkbox',
318 'name' => 'edit[locked]',
319 'disabled' => (bool) !$this->user->isadmin(),
320 'checked' => (bool) $this->meta['locked']));
322 $el['PREVIEW_B'] = Button('submit:edit[preview]', _("Preview"), 'wikiaction');
324 //if (!$this->isConcurrentUpdate() && !$this->canEdit())
325 $el['SAVE_B'] = Button('submit:edit[save]', _("Save"), 'wikiaction');
327 $el['IS_CURRENT'] = $this->version == $this->current->getVersion();
333 function _restoreState () {
334 $request = &$this->request;
336 $posted = $request->getArg('edit');
337 $request->setArg('edit', false);
339 if (!$posted || !$request->isPost() || $request->getArg('action') != 'edit')
342 if (!isset($posted['content']) || !is_string($posted['content']))
344 $this->_content = preg_replace('/[ \t\r]+\n/', "\n",
345 rtrim($posted['content']));
347 $this->_currentVersion = (int) $posted['current_version'];
349 if ($this->_currentVersion < 0)
351 if ($this->_currentVersion > $this->current->getVersion())
352 return false; // FIXME: some kind of warning?
354 $is_new_markup = !empty($posted['markup']) && $posted['markup'] == 'new';
355 $meta['markup'] = $is_new_markup ? 2.0: false;
356 $meta['summary'] = trim(substr($posted['summary'], 0, 256));
357 $meta['locked'] = !empty($posted['locked']);
358 $meta['is_minor_edit'] = !empty($posted['minor_edit']);
360 $this->meta = array_merge($this->meta, $meta);
362 if (!empty($posted['preview']))
363 $this->editaction = 'preview';
364 elseif (!empty($posted['save']))
365 $this->editaction = 'save';
367 $this->editaction = 'edit';
372 function _initializeState () {
373 $request = &$this->request;
374 $current = &$this->current;
375 $selected = &$this->selected;
376 $user = &$this->user;
379 NoSuchRevision($request, $this->page, $this->version); // noreturn
381 $this->_currentVersion = $current->getVersion();
382 $this->_content = $selected->getPackedContent();
384 $this->meta['summary'] = '';
385 $this->meta['locked'] = $this->page->get('locked');
387 // If author same as previous author, default minor_edit to on.
388 $age = time() - $current->get('mtime');
389 $this->meta['is_minor_edit'] = ( $age < MINOR_EDIT_TIMEOUT
390 && $current->get('author') == $user->getId()
393 // Default for new pages is new-style markup.
394 if ($selected->hasDefaultContents())
395 $is_new_markup = true;
397 $is_new_markup = $selected->get('markup') >= 2.0;
399 $this->meta['markup'] = $is_new_markup ? 2.0: false;
400 $this->editaction = 'edit';
408 // c-hanging-comment-ender-p: nil
409 // indent-tabs-mode: nil