2 rcs_id('$Id: editpage.php,v 1.44 2002-02-23 05:53:14 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(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."),
246 "<<<<<<< ". _("Your version"),
247 ">>>>>>> . _("Other version"));
249 $message = HTML::p(_("Please check it through before saving."));
253 /*$steps = HTML::ol(HTML::li(_("Copy your changes to the clipboard or to another temporary place (e.g. text editor).")),
254 HTML::li(fmt("%s of the page. You should now see the most current version of the page. Your changes are no longer there.",
256 HTML::li(_("Make changes to the file again. Paste your additions from the clipboard (or text editor).")),
257 HTML::li(_("Save your updated changes.")));
259 return HTML(HTML::h2(_("Conflicting Edits!")),
260 HTML::p(_("In the time since you started editing this page, another user has saved a new version of it.")),
261 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.")),
266 function getTextArea () {
267 $request = &$this->request;
269 // wrap=virtual is not HTML4, but without it NS4 doesn't wrap long lines
270 $readonly = $this->canEdit(); // || $this->isConcurrentUpdate();
272 return HTML::textarea(array('class' => 'wikiedit',
273 'name' => 'edit[content]',
274 'rows' => $request->getPref('editHeight'),
275 'cols' => $request->getPref('editWidth'),
276 'readonly' => (bool) $readonly,
277 'wrap' => 'virtual'),
281 function getFormElements () {
282 $request = &$this->request;
283 $page = &$this->page;
286 $h = array('action' => 'edit',
287 'pagename' => $page->getName(),
288 'version' => $this->version,
289 'edit[current_version]' => $this->_currentVersion);
291 $el['HIDDEN_INPUTS'] = HiddenInputs($h);
294 $el['EDIT_TEXTAREA'] = $this->getTextArea();
297 = HTML::input(array('type' => 'text',
298 'class' => 'wikitext',
299 'name' => 'edit[summary]',
302 'value' => $this->meta['summary']));
304 = HTML::input(array('type' => 'checkbox',
305 'name' => 'edit[minor_edit]',
306 'checked' => (bool) $this->meta['is_minor_edit']));
308 = HTML::input(array('type' => 'checkbox',
309 'name' => 'edit[markup]',
311 'checked' => $this->meta['markup'] >= 2.0));
314 = HTML::input(array('type' => 'checkbox',
315 'name' => 'edit[locked]',
316 'disabled' => (bool) !$this->user->isadmin(),
317 'checked' => (bool) $this->meta['locked']));
319 $el['PREVIEW_B'] = Button('submit:edit[preview]', _("Preview"), 'wikiaction');
321 //if (!$this->isConcurrentUpdate() && !$this->canEdit())
322 $el['SAVE_B'] = Button('submit:edit[save]', _("Save"), 'wikiaction');
324 $el['IS_CURRENT'] = $this->version == $this->current->getVersion();
330 function _restoreState () {
331 $request = &$this->request;
333 $posted = $request->getArg('edit');
334 $request->setArg('edit', false);
336 if (!$posted || !$request->isPost() || $request->getArg('action') != 'edit')
339 if (!isset($posted['content']) || !is_string($posted['content']))
341 $this->_content = preg_replace('/[ \t\r]+\n/', "\n",
342 rtrim($posted['content']));
344 $this->_currentVersion = (int) $posted['current_version'];
346 if ($this->_currentVersion < 0)
348 if ($this->_currentVersion > $this->current->getVersion())
349 return false; // FIXME: some kind of warning?
351 $is_new_markup = !empty($posted['markup']) && $posted['markup'] == 'new';
352 $meta['markup'] = $is_new_markup ? 2.0: false;
353 $meta['summary'] = trim(substr($posted['summary'], 0, 256));
354 $meta['locked'] = !empty($posted['locked']);
355 $meta['is_minor_edit'] = !empty($posted['minor_edit']);
357 $this->meta = array_merge($this->meta, $meta);
359 if (!empty($posted['preview']))
360 $this->editaction = 'preview';
361 elseif (!empty($posted['save']))
362 $this->editaction = 'save';
364 $this->editaction = 'edit';
369 function _initializeState () {
370 $request = &$this->request;
371 $current = &$this->current;
372 $selected = &$this->selected;
373 $user = &$this->user;
376 NoSuchRevision($request, $this->page, $this->version); // noreturn
378 $this->_currentVersion = $current->getVersion();
379 $this->_content = $selected->getPackedContent();
381 $this->meta['summary'] = '';
382 $this->meta['locked'] = $this->page->get('locked');
384 // If author same as previous author, default minor_edit to on.
385 $age = time() - $current->get('mtime');
386 $this->meta['is_minor_edit'] = ( $age < MINOR_EDIT_TIMEOUT
387 && $current->get('author') == $user->getId()
390 // Default for new pages is new-style markup.
391 if ($selected->hasDefaultContents())
392 $is_new_markup = true;
394 $is_new_markup = $selected->get('markup') >= 2.0;
396 $this->meta['markup'] = $is_new_markup ? 2.0: false;
397 $this->editaction = 'edit';
405 // c-hanging-comment-ender-p: nil
406 // indent-tabs-mode: nil