2 rcs_id('$Id: editpage.php,v 1.38 2002-02-08 03:01:11 dairiki 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())
55 $tokens['CONCURRENT_UPDATE_MESSAGE'] = $this->getConflictMessage();
57 if ($this->editaction == 'preview')
58 $tokens['PREVIEW_CONTENT'] = $this->getPreview(); // FIXME: convert to _MESSAGE?
60 // FIXME: NOT_CURRENT_MESSAGE?
62 $tokens = array_merge($tokens, $this->getFormElements());
64 return $this->output('editpage', _("Edit: %s"), $tokens);
67 function output ($template, $title_fs, $tokens) {
68 $selected = &$this->selected;
69 $current = &$this->current;
71 if ($selected && $selected->getVersion() != $current->getVersion()) {
73 $pagelink = WikiLink($selected);
77 $pagelink = WikiLink($this->page);
81 $title = new FormattedText ($title_fs, $pagelink);
82 $template = Template($template, $tokens);
84 GeneratePage($template, $title, $rev);
89 function viewSource ($tokens = false) {
90 assert($this->isInitialEdit());
91 assert($this->selected);
93 $tokens['PAGE_SOURCE'] = $this->_content;
95 return $this->output('viewsource', _("View Source: %s"), $tokens);
98 function setPageLockChanged($isadmin, $lock, &$page) {
100 if (! $page->get('locked') == $lock) {
101 $request = &$this->request;
102 $request->setArg('lockchanged', true); //is it safe to add new args to $request like this?
104 $page->set('locked', $lock);
108 function savePage () {
109 $request = &$this->request;
111 if ($this->isUnchanged()) {
112 // Allow admin lock/unlock even if
113 // no text changes were made.
114 if ($isadmin = $this->user->isadmin()) {
115 $page = &$this->page;
116 $lock = $this->meta['locked'];
117 $this->setPageLockChanged($isadmin, $lock, &$page);
119 // Save failed. No changes made.
120 include_once('lib/display.php');
121 // force browse of current version:
122 $request->setArg('version', false);
123 displayPage($request, 'nochanges');
127 $page = &$this->page;
128 $lock = $this->meta['locked'];
129 $this->meta['locked'] = ''; // hackish
132 $newrevision = $page->createRevision($this->_currentVersion + 1,
135 ExtractWikiPageLinks($this->_content));
136 if (!is_object($newrevision)) {
137 // Save failed. (Concurrent updates).
140 // New contents successfully saved...
141 if ($isadmin = $this->user->isadmin())
142 $this->setPageLockChanged($isadmin, $lock, &$page);
144 // Clean out archived versions of this page.
145 include_once('lib/ArchiveCleaner.php');
146 $cleaner = new ArchiveCleaner($GLOBALS['ExpireParams']);
147 $cleaner->cleanPageRevisions($page);
149 $dbi = $request->getDbh();
150 $warnings = $dbi->GenericWarnings();
153 if (empty($warnings) && ! $Theme->getImageURL('signature')) {
154 // Do redirect to browse page if no signature has
155 // been defined. In this case, the user will most
156 // likely not see the rest of the HTML we generate
158 $request->redirect(WikiURL($page, false, 'absolute_url'));
161 // Force browse of current page version.
162 $request->setArg('version', false);
163 include_once('lib/BlockParser.php');
164 $template = Template('savepage',
165 array('CONTENT' => TransformText($newrevision)));
166 if (!empty($warnings))
167 $template->replace('WARNINGS', $warnings);
169 $pagelink = WikiLink($page);
171 GeneratePage($template, fmt("Saved: %s", $pagelink), $newrevision);
175 function isConcurrentUpdate () {
176 assert($this->current->getVersion() >= $this->_currentVersion);
177 return $this->current->getVersion() != $this->_currentVersion;
180 function canEdit () {
181 return $this->page->get('locked') && !$this->user->isAdmin();
184 function isInitialEdit () {
185 return $this->_initialEdit;
188 function isUnchanged () {
189 $current = &$this->current;
191 if ($this->meta['markup'] != $current->get('markup'))
194 return $this->_content == $current->getPackedContent();
197 function getPreview () {
198 include_once('lib/BlockParser.php');
199 return TransformText($this->_content, $this->meta['markup']);
202 function getLockedMessage () {
204 HTML(HTML::h2(_("Page Locked")),
205 HTML::p(_("This page has been locked by the administrator so your changes can not be saved.")),
206 HTML::p(_("(Copy your changes to the clipboard. You can try editing a different page or save your text in a text editor.)")),
207 HTML::p(_("Sorry for the inconvenience.")));
210 function getConflictMessage () {
212 xgettext only knows about c/c++ line-continuation strings
213 it does not know about php's dot operator.
214 We want to translate this entire paragraph as one string, of course.
217 $re_edit_link = Button('edit', _("Edit the new version"), $this->page);
219 $steps = HTML::ol(HTML::li(_("Copy your changes to the clipboard or to another temporary place (e.g. text editor).")),
220 HTML::li(fmt("%s of the page. You should now see the most current version of the page. Your changes are no longer there.",
222 HTML::li(_("Make changes to the file again. Paste your additions from the clipboard (or text editor).")),
223 HTML::li(_("Save your updated changes.")));
225 return HTML(HTML::h2(_("Conflicting Edits!")),
226 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, since doing so would overwrite the other author's changes.")),
227 HTML::p(_("In order to recover from this situation, follow these steps:")),
229 HTML::p(_("Sorry for the inconvenience.")));
233 function getTextArea () {
234 $request = &$this->request;
236 // wrap=virtual is not HTML4, but without it NS4 doesn't wrap long lines
237 $readonly = $this->canEdit() || $this->isConcurrentUpdate();
239 return HTML::textarea(array('class' => 'wikiedit',
240 'name' => 'edit[content]',
241 'rows' => $request->getPref('editHeight'),
242 'cols' => $request->getPref('editWidth'),
243 'readonly' => (bool) $readonly,
244 'wrap' => 'virtual'),
248 function getFormElements () {
249 $request = &$this->request;
250 $page = &$this->page;
253 $h = array('action' => 'edit',
254 'pagename' => $page->getName(),
255 'version' => $this->version,
256 'edit[current_version]' => $this->_currentVersion);
258 $el['HIDDEN_INPUTS'] = HiddenInputs($h);
261 $el['EDIT_TEXTAREA'] = $this->getTextArea();
264 = HTML::input(array('type' => 'text',
265 'class' => 'wikitext',
266 'name' => 'edit[summary]',
269 'value' => $this->meta['summary']));
271 = HTML::input(array('type' => 'checkbox',
272 'name' => 'edit[minor_edit]',
273 'checked' => (bool) $this->meta['is_minor_edit']));
275 = HTML::input(array('type' => 'checkbox',
276 'name' => 'edit[markup]',
278 'checked' => $this->meta['markup'] >= 2.0));
281 = HTML::input(array('type' => 'checkbox',
282 'name' => 'edit[locked]',
283 'disabled' => (bool) !$this->user->isadmin(),
284 'checked' => (bool) $this->meta['locked']));
286 $el['PREVIEW_B'] = Button('submit:edit[preview]', _("Preview"));
288 if (!$this->isConcurrentUpdate() && !$this->canEdit())
289 $el['SAVE_B'] = Button('submit:edit[save]', _("Save"));
291 $el['IS_CURRENT'] = $this->version == $this->current->getVersion();
297 function _restoreState () {
298 $request = &$this->request;
300 $posted = $request->getArg('edit');
301 $request->setArg('edit', false);
303 if (!$posted || !$request->isPost() || $request->getArg('action') != 'edit')
306 if (!isset($posted['content']) || !is_string($posted['content']))
308 $this->_content = preg_replace('/[ \t\r]+\n/', "\n",
309 rtrim($posted['content']));
311 $this->_currentVersion = (int) $posted['current_version'];
313 if ($this->_currentVersion < 0)
315 if ($this->_currentVersion > $this->current->getVersion())
316 return false; // FIXME: some kind of warning?
318 $is_new_markup = !empty($posted['markup']) && $posted['markup'] == 'new';
319 $meta['markup'] = $is_new_markup ? 2.0: false;
320 $meta['summary'] = trim(substr($posted['summary'], 0, 256));
321 $meta['locked'] = !empty($posted['locked']);
322 $meta['is_minor_edit'] = !empty($posted['minor_edit']);
324 $this->meta = array_merge($this->meta, $meta);
326 if (!empty($posted['preview']))
327 $this->editaction = 'preview';
328 elseif (!empty($posted['save']))
329 $this->editaction = 'save';
331 $this->editaction = 'edit';
336 function _initializeState () {
337 $request = &$this->request;
338 $current = &$this->current;
339 $selected = &$this->selected;
340 $user = &$this->user;
343 NoSuchRevision($request, $this->page, $this->version); // noreturn
345 $this->_currentVersion = $current->getVersion();
346 $this->_content = $selected->getPackedContent();
348 $this->meta['summary'] = '';
349 $this->meta['locked'] = $this->page->get('locked');
351 // If author same as previous author, default minor_edit to on.
352 $age = time() - $current->get('mtime');
353 $this->meta['is_minor_edit'] = ( $age < MINOR_EDIT_TIMEOUT
354 && $current->get('author') == $user->getId()
357 // Default for new pages is new-style markup.
358 if ($selected->hasDefaultContents())
359 $is_new_markup = true;
361 $is_new_markup = $selected->get('markup') >= 2.0;
363 $this->meta['markup'] = $is_new_markup ? 2.0: false;
364 $this->editaction = 'edit';
372 // c-hanging-comment-ender-p: nil
373 // indent-tabs-mode: nil