2 rcs_id('$Id: editpage.php,v 1.111 2007-06-03 17:12:00 rurban 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(false);
16 // HACKish short circuit to browse on action=create
17 if ($request->getArg('action') == 'create') {
18 if (! $this->current->hasDefaultContents())
19 $request->redirect(WikiURL($this->page->getName())); // noreturn
22 $this->meta = array('author' => $this->user->getId(),
23 'author_id' => $this->user->getAuthenticatedId(),
26 $this->tokens = array();
29 $backend = WYSIWYG_BACKEND;
30 // TODO: error message
31 require_once("lib/WysiwygEdit/$backend.php");
32 $class = "WysiwygEdit_$backend";
33 $this->WysiwygEdit = new $class();
36 require_once('lib/Captcha.php');
37 $this->Captcha = new Captcha($this->meta);
40 $version = $request->getArg('version');
41 if ($version !== false) {
42 $this->selected = $this->page->getRevision($version);
43 $this->version = $version;
46 $this->version = $this->current->getVersion();
47 $this->selected = $this->page->getRevision($this->version);
50 if ($this->_restoreState()) {
51 $this->_initialEdit = false;
54 $this->_initializeState();
55 $this->_initialEdit = true;
57 // The edit request has specified some initial content from a template
58 if ( ($template = $request->getArg('template'))
59 and $request->_dbi->isWikiPage($template))
61 $page = $request->_dbi->getPage($template);
62 $current = $page->getCurrentRevision();
63 $this->_content = $current->getPackedContent();
64 } elseif ($initial_content = $request->getArg('initial_content')) {
65 $this->_content = $initial_content;
66 $this->_redirect_to = $request->getArg('save_and_redirect_to');
70 header("Content-Type: text/html; charset=" . $GLOBALS['charset']);
73 function editPage () {
76 $tokens = &$this->tokens;
77 $tokens['PAGE_LOCKED_MESSAGE'] = '';
78 $tokens['CONCURRENT_UPDATE_MESSAGE'] = '';
81 if (isset($r->args['pref']['editWidth'])
82 and ($r->getPref('editWidth') != $r->args['pref']['editWidth'])) {
83 $r->_prefs->set('editWidth', $r->args['pref']['editWidth']);
85 if (isset($r->args['pref']['editHeight'])
86 and ($r->getPref('editHeight') != $r->args['pref']['editHeight'])) {
87 $r->_prefs->set('editHeight', $r->args['pref']['editHeight']);
90 if ($this->isModerated())
91 $tokens['PAGE_LOCKED_MESSAGE'] = $this->getModeratedMessage();
93 if (! $this->canEdit()) {
94 if ($this->isInitialEdit())
95 return $this->viewSource();
96 $tokens['PAGE_LOCKED_MESSAGE'] = $this->getLockedMessage();
98 elseif ($r->getArg('save_and_redirect_to') != "") {
99 if (ENABLE_CAPTCHA && $this->Captcha->Failed()) {
100 $this->tokens['PAGE_LOCKED_MESSAGE'] =
101 HTML::p(HTML::h1($this->Captcha->failed_msg));
103 elseif ( $this->savePage()) {
105 $r->redirect(WikiURL($r->getArg('save_and_redirect_to')));
106 return true; // Page saved.
110 elseif ($this->editaction == 'save') {
111 if (ENABLE_CAPTCHA && $this->Captcha->Failed()) {
112 $this->tokens['PAGE_LOCKED_MESSAGE'] =
113 HTML::p(HTML::h1($this->Captcha->failed_msg));
115 elseif ($this->savePage()) {
116 return true; // Page saved.
122 // coming from loadfile conflicts
123 elseif ($this->editaction == 'keep_old') {
124 // keep old page and do nothing
125 $this->_redirectToBrowsePage();
126 //$r->redirect(WikiURL($r->getArg('save_and_redirect_to')));
129 elseif ($this->editaction == 'overwrite') {
130 // take the new content without diff
131 $source = $this->request->getArg('loadfile');
132 require_once('lib/loadsave.php');
133 $this->request->setArg('loadfile', 1);
134 $this->request->setArg('overwrite', 1);
135 $this->request->setArg('merge', 0);
136 LoadFileOrDir($this->request);
137 $this->_redirectToBrowsePage();
138 //$r->redirect(WikiURL($r->getArg('save_and_redirect_to')));
142 if ($saveFailed and $this->isConcurrentUpdate())
144 // Get the text of the original page, and the two conflicting edits
145 // The diff3 class takes arrays as input. So retrieve content as
146 // an array, or convert it as necesary.
147 $orig = $this->page->getRevision($this->_currentVersion);
148 // FIXME: what if _currentVersion has be deleted?
149 $orig_content = $orig->getContent();
150 $this_content = explode("\n", $this->_content);
151 $other_content = $this->current->getContent();
152 require_once("lib/diff3.php");
153 $diff = new diff3($orig_content, $this_content, $other_content);
154 $output = $diff->merged_output(_("Your version"), _("Other version"));
155 // Set the content of the textarea to the merged diff
156 // output, and update the version
157 $this->_content = implode ("\n", $output);
158 $this->_currentVersion = $this->current->getVersion();
159 $this->version = $this->_currentVersion;
160 $unresolved = $diff->ConflictingBlocks;
161 $tokens['CONCURRENT_UPDATE_MESSAGE']
162 = $this->getConflictMessage($unresolved);
163 } elseif ($saveFailed && !$this->_isSpam) {
164 $tokens['CONCURRENT_UPDATE_MESSAGE'] =
165 HTML(HTML::h2(_("Some internal editing error")),
166 HTML::p(_("Your are probably trying to edit/create an invalid version of this page.")),
167 HTML::p(HTML::em(_("&version=-1 might help."))));
170 if ($this->editaction == 'edit_convert')
171 $tokens['PREVIEW_CONTENT'] = $this->getConvertedPreview();
172 if ($this->editaction == 'preview')
173 $tokens['PREVIEW_CONTENT'] = $this->getPreview(); // FIXME: convert to _MESSAGE?
175 // FIXME: NOT_CURRENT_MESSAGE?
176 $tokens = array_merge($tokens, $this->getFormElements());
178 if (ENABLE_EDIT_TOOLBAR and !ENABLE_WYSIWYG) {
179 require_once("lib/EditToolbar.php");
180 $toolbar = new EditToolbar();
181 $tokens = array_merge($tokens, $toolbar->getTokens());
184 return $this->output('editpage', _("Edit: %s"));
187 function output ($template, $title_fs) {
189 $selected = &$this->selected;
190 $current = &$this->current;
192 if ($selected && $selected->getVersion() != $current->getVersion()) {
194 $pagelink = WikiLink($selected);
198 $pagelink = WikiLink($this->page);
201 $title = new FormattedText ($title_fs, $pagelink);
202 // not for dumphtml or viewsource
203 if (ENABLE_WYSIWYG and $template == 'editpage') {
204 $WikiTheme->addMoreHeaders($this->WysiwygEdit->Head());
205 //$tokens['PAGE_SOURCE'] = $this->WysiwygEdit->ConvertBefore($this->_content);
207 $template = Template($template, $this->tokens);
208 /* Tell google (and others) not to take notice of edit links */
209 if (GOOGLE_LINKS_NOFOLLOW)
210 $args = array('ROBOTS_META' => "noindex,nofollow");
211 GeneratePage($template, $title, $rev);
216 function viewSource () {
217 assert($this->isInitialEdit());
218 assert($this->selected);
220 $this->tokens['PAGE_SOURCE'] = $this->_content;
221 $this->tokens['HIDDEN_INPUTS'] = HiddenInputs($this->request->getArgs());
222 return $this->output('viewsource', _("View Source: %s"));
225 function updateLock() {
226 if ((bool)$this->page->get('locked') == (bool)$this->locked)
227 return false; // Not changed.
229 if (!$this->user->isAdmin()) {
230 // FIXME: some sort of message
231 return false; // not allowed.
234 $this->page->set('locked', (bool)$this->locked);
235 $this->tokens['LOCK_CHANGED_MSG']
236 = $this->locked ? _("Page now locked.") : _("Page now unlocked.");
238 return true; // lock changed.
241 function savePage () {
242 $request = &$this->request;
244 if ($this->isUnchanged()) {
245 // Allow admin lock/unlock even if
246 // no text changes were made.
247 if ($this->updateLock()) {
248 $dbi = $request->getDbh();
251 // Save failed. No changes made.
252 $this->_redirectToBrowsePage();
253 // user will probably not see the rest of this...
254 require_once('lib/display.php');
255 // force browse of current version:
256 $request->setArg('version', false);
257 displayPage($request, 'nochanges');
261 if (!$this->user->isAdmin() and $this->isSpam()) {
262 $this->_isSpam = true;
265 // Save failed. No changes made.
266 $this->_redirectToBrowsePage();
267 // user will probably not see the rest of this...
268 require_once('lib/display.php');
269 // force browse of current version:
270 $request->setArg('version', false);
271 displayPage($request, 'nochanges');
276 $page = &$this->page;
278 // Include any meta-data from original page version which
279 // has not been explicitly updated.
280 // (Except don't propagate pgsrc_version --- moot for now,
281 // because at present it never gets into the db...)
282 $meta = $this->selected->getMetaData();
283 unset($meta['pgsrc_version']);
284 $meta = array_merge($meta, $this->meta);
287 $this->_content = $this->getContent();
288 $newrevision = $page->save($this->_content,
291 : $this->_currentVersion + 1,
294 if (!isa($newrevision, 'WikiDB_PageRevision')) {
295 // Save failed. (Concurrent updates).
299 // New contents successfully saved...
302 // Clean out archived versions of this page.
303 require_once('lib/ArchiveCleaner.php');
304 $cleaner = new ArchiveCleaner($GLOBALS['ExpireParams']);
305 $cleaner->cleanPageRevisions($page);
307 /* generate notification emails done in WikiDB::save to catch
308 all direct calls (admin plugins) */
310 // look at the errorstack
311 $errors = $GLOBALS['ErrorManager']->_postponed_errors;
312 $warnings = $GLOBALS['ErrorManager']->getPostponedErrorsAsHTML();
313 $GLOBALS['ErrorManager']->_postponed_errors = $errors;
315 $dbi = $request->getDbh();
319 if (empty($warnings->_content) && ! $WikiTheme->getImageURL('signature')) {
320 // Do redirect to browse page if no signature has
321 // been defined. In this case, the user will most
322 // likely not see the rest of the HTML we generate
324 $this->_redirectToBrowsePage();
327 // Force browse of current page version.
328 $request->setArg('version', false);
329 $request->setArg('action', "browse");
331 $template = Template('savepage', $this->tokens);
332 $template->replace('CONTENT', $newrevision->getTransformedContent());
333 if (!empty($warnings->_content)) {
334 $template->replace('WARNINGS', $warnings);
335 unset($GLOBALS['ErrorManager']->_postponed_errors);
338 $pagelink = WikiLink($page);
340 GeneratePage($template, fmt("Saved: %s", $pagelink), $newrevision);
344 function isConcurrentUpdate () {
345 assert($this->current->getVersion() >= $this->_currentVersion);
346 return $this->current->getVersion() != $this->_currentVersion;
349 function canEdit () {
350 return !$this->page->get('locked') || $this->user->isAdmin();
353 function isInitialEdit () {
354 return $this->_initialEdit;
357 function isUnchanged () {
358 $current = &$this->current;
360 if ($this->meta['markup'] != $current->get('markup'))
363 return $this->_content == $current->getPackedContent();
367 * Handle AntiSpam here. How? http://wikiblacklist.blogspot.com/
368 * Need to check dynamically some blacklist wikipage settings
369 * (plugin WikiAccessRestrictions) and some static blacklist.
371 * Always: More then 20 new external links
372 * ENABLE_SPAMASSASSIN: content patterns by babycart (only php >= 4.3 for now)
373 * ENABLE_SPAMBLOCKLIST: content domain blacklist
376 $current = &$this->current;
377 $request = &$this->request;
379 $oldtext = $current->getPackedContent();
380 $newtext =& $this->_content;
382 // FIXME: in longer texts the NUM_SPAM_LINKS number should be increased.
383 // better use a certain text : link ratio.
385 // 1. Not more then 20 new external links
386 if ($this->numLinks($newtext) - $this->numLinks($oldtext) >= NUM_SPAM_LINKS)
388 // Allow strictly authenticated users?
389 // TODO: mail the admin?
390 $this->tokens['PAGE_LOCKED_MESSAGE'] =
391 HTML($this->getSpamMessage(),
392 HTML::p(HTML::strong(_("Too many external links."))));
395 // 2. external babycart (SpamAssassin) check
396 // This will probably prevent from discussing sex or viagra related topics. So beware.
397 if (ENABLE_SPAMASSASSIN) {
398 require_once("lib/spam_babycart.php");
399 if ($babycart = check_babycart($newtext, $request->get("REMOTE_ADDR"),
400 $this->user->getId())) {
401 // TODO: mail the admin
402 if (is_array($babycart))
403 $this->tokens['PAGE_LOCKED_MESSAGE'] =
404 HTML($this->getSpamMessage(),
405 HTML::p(HTML::em(_("SpamAssassin reports: "),
406 join("\n", $babycart))));
410 // 3. extract (new) links and check surbl for blocked domains
411 if (ENABLE_SPAMBLOCKLIST and ($this->numLinks($newtext) > 5)) {
412 require_once("lib/SpamBlocklist.php");
413 require_once("lib/InlineParser.php");
414 $parsed = TransformLinks($newtext);
415 foreach ($parsed->_content as $link) {
416 if (isa($link, 'Cached_ExternalLink')) {
417 $uri = $link->_getURL($this->page->getName());
418 if ($res = IsBlackListed($uri)) {
419 // TODO: mail the admin
420 $this->tokens['PAGE_LOCKED_MESSAGE'] =
421 HTML($this->getSpamMessage(),
422 HTML::p(HTML::strong(_("External links contain blocked domains:")),
423 HTML::ul(HTML::li(sprintf(_("%s is listed at %s"),
424 $res[2], $res[0])))));
434 /** Number of external links in the wikitext
436 function numLinks(&$text) {
437 return substr_count($text, "http://") + substr_count($text, "https://");
440 /** Header of the Anti Spam message
442 function getSpamMessage () {
444 HTML(HTML::h2(_("Spam Prevention")),
445 HTML::p(_("This page edit seems to contain spam and was therefore not saved."),
447 _("Sorry for the inconvenience.")),
451 function getPreview () {
452 require_once('lib/PageType.php');
453 $this->_content = $this->getContent();
454 return new TransformedText($this->page, $this->_content, $this->meta);
457 function getConvertedPreview () {
458 require_once('lib/PageType.php');
459 $this->_content = $this->getContent();
460 $this->meta['markup'] = 2.0;
461 $this->_content = ConvertOldMarkup($this->_content);
462 return new TransformedText($this->page, $this->_content, $this->meta);
465 // possibly convert HTMLAREA content back to Wiki markup
466 function getContent () {
467 if (ENABLE_WYSIWYG) {
468 // don't store everything as html
469 if (!WYSIWYG_DEFAULT_PAGETYPE_HTML) {
470 // Wikiwyg shortcut to avoid the InlineTransformer:
471 if (WYSIWYG_BACKEND == "Wikiwyg") return $this->_content;
472 $xml_output = $this->WysiwygEdit->ConvertAfter($this->_content);
473 $this->_content = join("", $xml_output->_content);
475 $this->meta['pagetype'] = 'html';
477 return $this->_content;
479 return $this->_content;
483 function getLockedMessage () {
485 HTML(HTML::h2(_("Page Locked")),
486 HTML::p(_("This page has been locked by the administrator so your changes can not be saved.")),
487 HTML::p(_("(Copy your changes to the clipboard. You can try editing a different page or save your text in a text editor.)")),
488 HTML::p(_("Sorry for the inconvenience.")));
491 function isModerated() {
492 return $this->page->get('moderation');
494 function getModeratedMessage() {
496 HTML(HTML::h2(WikiLink(_("ModeratedPage"))),
497 HTML::p(fmt("You can edit away, but your changes will have to be approved by the defined moderators at the definition in %s", WikiLink(_("ModeratedPage")))),
498 HTML::p(fmt("The approval has a grace period of 5 days. If you have your E-Mail defined in your %s, you will get a notification of approval or rejection.",
499 WikiLink(_("UserPreferences")))));
501 function getConflictMessage ($unresolved = false) {
503 xgettext only knows about c/c++ line-continuation strings
504 it does not know about php's dot operator.
505 We want to translate this entire paragraph as one string, of course.
508 //$re_edit_link = Button('edit', _("Edit the new version"), $this->page);
511 $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.",
512 "<<<<<<< ". _("Your version"),
513 ">>>>>>> ". _("Other version")));
515 $message = HTML::p(_("Please check it through before saving."));
519 /*$steps = HTML::ol(HTML::li(_("Copy your changes to the clipboard or to another temporary place (e.g. text editor).")),
520 HTML::li(fmt("%s of the page. You should now see the most current version of the page. Your changes are no longer there.",
522 HTML::li(_("Make changes to the file again. Paste your additions from the clipboard (or text editor).")),
523 HTML::li(_("Save your updated changes.")));
526 HTML(HTML::h2(_("Conflicting Edits!")),
527 HTML::p(_("In the time since you started editing this page, another user has saved a new version of it.")),
528 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.")),
533 function getTextArea () {
534 $request = &$this->request;
536 $readonly = ! $this->canEdit(); // || $this->isConcurrentUpdate();
538 // WYSIWYG will need two pagetypes: raw wikitest and converted html
539 if (ENABLE_WYSIWYG) {
540 $this->_wikicontent = $this->_content;
541 $this->_content = $this->WysiwygEdit->ConvertBefore($this->_content);
542 // $this->getPreview();
543 //$this->_htmlcontent = $this->_content->asXML();
546 $textarea = HTML::textarea(array('class'=> 'wikiedit',
547 'name' => 'edit[content]',
548 'id' => 'edit-content',
549 'rows' => $request->getPref('editHeight'),
550 'cols' => $request->getPref('editWidth'),
551 'readonly' => (bool) $readonly),
553 /** <textarea wrap="virtual"> is not valid XHTML but Netscape 4 requires it
554 * to wrap long lines.
557 $textarea->setAttr('wrap', 'virtual');
558 if (ENABLE_WYSIWYG) {
559 return $this->WysiwygEdit->Textarea($textarea, $this->_wikicontent,
560 $textarea->getAttr('name'));
565 function getFormElements () {
567 $request = &$this->request;
568 $page = &$this->page;
570 $h = array('action' => 'edit',
571 'pagename' => $page->getName(),
572 'version' => $this->version,
573 'edit[pagetype]' => $this->meta['pagetype'],
574 'edit[current_version]' => $this->_currentVersion);
576 $el['HIDDEN_INPUTS'] = HiddenInputs($h);
577 $el['EDIT_TEXTAREA'] = $this->getTextArea();
578 if ( ENABLE_CAPTCHA ) {
579 $el = array_merge($el, $this->Captcha->getFormElements());
582 = HTML::input(array('type' => 'text',
583 'class' => 'wikitext',
584 'id' => 'edit-summary',
585 'name' => 'edit[summary]',
588 'value' => $this->meta['summary']));
590 = HTML::input(array('type' => 'checkbox',
591 'name' => 'edit[minor_edit]',
592 'id' => 'edit-minor_edit',
593 'checked' => (bool) $this->meta['is_minor_edit']));
595 = HTML::input(array('type' => 'checkbox',
596 'name' => 'edit[markup]',
598 'checked' => $this->meta['markup'] < 2.0,
599 'id' => 'useOldMarkup',
600 'onclick' => 'showOldMarkupRules(this.checked)'));
601 $el['OLD_MARKUP_CONVERT'] = ($this->meta['markup'] < 2.0)
602 ? Button('submit:edit[edit_convert]', _("Convert"), 'wikiaction') : '';
604 = HTML::input(array('type' => 'checkbox',
605 'name' => 'edit[locked]',
606 'id' => 'edit-locked',
607 'disabled' => (bool) !$this->user->isadmin(),
608 'checked' => (bool) $this->locked));
610 $el['PREVIEW_B'] = Button('submit:edit[preview]', _("Preview"),
612 array('accesskey'=> 'p'));
614 //if (!$this->isConcurrentUpdate() && $this->canEdit())
615 $el['SAVE_B'] = Button('submit:edit[save]',
616 _("Save"), 'wikiaction',
617 array('accesskey'=> 's'));
618 $el['IS_CURRENT'] = $this->version == $this->current->getVersion();
621 = HTML::input(array('type' => 'text',
624 'class' => "numeric",
625 'name' => 'pref[editWidth]',
626 'id' => 'pref-editWidth',
627 'value' => $request->getPref('editWidth'),
628 'onchange' => 'this.form.submit();'));
630 = HTML::input(array('type' => 'text',
633 'class' => "numeric",
634 'name' => 'pref[editHeight]',
635 'id' => 'pref-editHeight',
636 'value' => $request->getPref('editHeight'),
637 'onchange' => 'this.form.submit();'));
638 $el['SEP'] = $WikiTheme->getButtonSeparator();
639 $el['AUTHOR_MESSAGE'] = fmt("Author will be logged as %s.",
640 HTML::em($this->user->getId()));
645 function _redirectToBrowsePage() {
646 $this->request->redirect(WikiURL($this->page, false, 'absolute_url'));
649 function _restoreState () {
650 $request = &$this->request;
652 $posted = $request->getArg('edit');
653 $request->setArg('edit', false);
656 || !$request->isPost()
657 || !in_array($request->getArg('action'),array('edit','loadfile')))
660 if (!isset($posted['content']) || !is_string($posted['content']))
662 $this->_content = preg_replace('/[ \t\r]+\n/', "\n",
663 rtrim($posted['content']));
664 $this->_content = $this->getContent();
666 $this->_currentVersion = (int) $posted['current_version'];
668 if ($this->_currentVersion < 0)
670 if ($this->_currentVersion > $this->current->getVersion())
671 return false; // FIXME: some kind of warning?
673 $is_old_markup = !empty($posted['markup']) && $posted['markup'] == 'old';
674 $meta['markup'] = $is_old_markup ? false : 2.0;
675 $meta['summary'] = trim(substr($posted['summary'], 0, 256));
676 $meta['is_minor_edit'] = !empty($posted['minor_edit']);
677 $meta['pagetype'] = !empty($posted['pagetype']) ? $posted['pagetype'] : false;
678 if ( ENABLE_CAPTCHA )
679 $meta['captcha_input'] = !empty($posted['captcha_input']) ?
680 $posted['captcha_input'] : '';
682 $this->meta = array_merge($this->meta, $meta);
683 $this->locked = !empty($posted['locked']);
685 foreach (array('preview','save','edit_convert',
686 'keep_old','overwrite') as $o)
688 if (!empty($posted[$o]))
689 $this->editaction = $o;
691 if (empty($this->editaction))
692 $this->editaction = 'edit';
697 function _initializeState () {
698 $request = &$this->request;
699 $current = &$this->current;
700 $selected = &$this->selected;
701 $user = &$this->user;
704 NoSuchRevision($request, $this->page, $this->version); // noreturn
706 $this->_currentVersion = $current->getVersion();
707 $this->_content = $selected->getPackedContent();
709 $this->locked = $this->page->get('locked');
711 // If author same as previous author, default minor_edit to on.
712 $age = $this->meta['mtime'] - $current->get('mtime');
713 $this->meta['is_minor_edit'] = ( $age < MINOR_EDIT_TIMEOUT
714 && $current->get('author') == $user->getId()
717 // Default for new pages is new-style markup.
718 if ($selected->hasDefaultContents())
719 $is_new_markup = true;
721 $is_new_markup = $selected->get('markup') >= 2.0;
723 $this->meta['markup'] = $is_new_markup ? 2.0: false;
724 $this->meta['pagetype'] = $selected->get('pagetype');
725 if ($this->meta['pagetype'] == 'wikiblog')
726 $this->meta['summary'] = $selected->get('summary'); // keep blog title
728 $this->meta['summary'] = '';
729 $this->editaction = 'edit';
733 class LoadFileConflictPageEditor
736 function editPage ($saveFailed = true) {
737 $tokens = &$this->tokens;
739 if (!$this->canEdit()) {
740 if ($this->isInitialEdit()) {
741 return $this->viewSource();
743 $tokens['PAGE_LOCKED_MESSAGE'] = $this->getLockedMessage();
745 elseif ($this->editaction == 'save') {
746 if ($this->savePage()) {
747 return true; // Page saved.
752 if ($saveFailed || $this->isConcurrentUpdate())
754 // Get the text of the original page, and the two conflicting edits
755 // The diff class takes arrays as input. So retrieve content as
756 // an array, or convert it as necesary.
757 $orig = $this->page->getRevision($this->_currentVersion);
758 $this_content = explode("\n", $this->_content);
759 $other_content = $this->current->getContent();
760 require_once("lib/diff.php");
761 $diff2 = new Diff($other_content, $this_content);
762 $context_lines = max(4, count($other_content) + 1,
763 count($this_content) + 1);
764 $fmt = new BlockDiffFormatter($context_lines);
766 $this->_content = $fmt->format($diff2);
767 // FIXME: integrate this into class BlockDiffFormatter
768 $this->_content = str_replace(">>>>>>>\n<<<<<<<\n", "=======\n",
770 $this->_content = str_replace("<<<<<<<\n>>>>>>>\n", "=======\n",
773 $this->_currentVersion = $this->current->getVersion();
774 $this->version = $this->_currentVersion;
775 $tokens['CONCURRENT_UPDATE_MESSAGE'] = $this->getConflictMessage();
778 if ($this->editaction == 'edit_convert')
779 $tokens['PREVIEW_CONTENT'] = $this->getConvertedPreview();
780 if ($this->editaction == 'preview')
781 $tokens['PREVIEW_CONTENT'] = $this->getPreview(); // FIXME: convert to _MESSAGE?
783 // FIXME: NOT_CURRENT_MESSAGE?
784 $tokens = array_merge($tokens, $this->getFormElements());
785 // we need all GET params for loadfile overwrite
786 if ($this->request->getArg('action') == 'loadfile') {
788 $this->tokens['HIDDEN_INPUTS'] =
790 (array('source' => $this->request->getArg('source'),
792 $this->tokens['HIDDEN_INPUTS']);
793 // add two conflict resolution buttons before preview and save.
794 $tokens['PREVIEW_B'] = HTML(
795 Button('submit:edit[keep_old]',
796 _("Keep old"), 'wikiaction'),
798 Button('submit:edit[overwrite]',
799 _("Overwrite with new"), 'wikiaction'),
801 $tokens['PREVIEW_B']);
803 if (ENABLE_EDIT_TOOLBAR and !ENABLE_WYSIWYG) {
804 include_once("lib/EditToolbar.php");
805 $toolbar = new EditToolbar();
806 $tokens = array_merge($tokens, $toolbar->getTokens());
809 return $this->output('editpage', _("Merge and Edit: %s"));
812 function output ($template, $title_fs) {
813 $selected = &$this->selected;
814 $current = &$this->current;
816 if ($selected && $selected->getVersion() != $current->getVersion()) {
818 $pagelink = WikiLink($selected);
822 $pagelink = WikiLink($this->page);
825 $title = new FormattedText ($title_fs, $pagelink);
826 $this->tokens['HEADER'] = $title;
827 //hack! there's no TITLE in editpage, but in the previous top template
828 if (empty($this->tokens['PAGE_LOCKED_MESSAGE']))
829 $this->tokens['PAGE_LOCKED_MESSAGE'] = HTML::h3($title);
831 $this->tokens['PAGE_LOCKED_MESSAGE'] = HTML(HTML::h3($title),
832 $this->tokens['PAGE_LOCKED_MESSAGE']);
833 $template = Template($template, $this->tokens);
835 //GeneratePage($template, $title, $rev);
840 function getConflictMessage () {
841 $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.",
844 HTML::p(_("Please check it through before saving."))));
850 $Log: not supported by cvs2svn $
851 Revision 1.110 2007/01/07 18:42:00 rurban
852 Print ModeratedPage message on edit. Use GOOGLE_LINKS_NOFOLLOW. Improve id: edit: to edit-
854 Revision 1.109 2007/01/02 13:21:39 rurban
855 add two merge conflict buttons within loadfile: "Keep Old" and "Overwrite with new". enable edit toolbar there also. fix display of the Merge and Edit header.
857 Revision 1.108 2006/12/22 17:47:34 rurban
858 Display Warnings only once.
859 Add button accesskeys
861 Revision 1.107 2006/05/13 19:59:54 rurban
862 added wysiwyg_editor-1.3a feature by Jean-Nicolas GEREONE <jean-nicolas.gereone@st.com>
863 converted wysiwyg_editor-1.3a js to WysiwygEdit framework
864 changed default ENABLE_WYSIWYG = true and added WYSIWYG_BACKEND = Wikiwyg
866 Revision 1.106 2005/11/21 22:03:08 rurban
867 fix syntax error inside ENABLE_SPAMBLOCKLIST
869 Revision 1.105 2005/11/21 20:53:59 rurban
870 beautify request pref lines, no antispam if admin (netznetz request), user is a member anyway
872 Revision 1.104 2005/10/31 17:20:40 rurban
875 Revision 1.103 2005/10/31 17:09:13 rurban
876 use better constant WYSIWYG_DEFAULT_PAGETYPE_HTML
878 Revision 1.102 2005/10/31 16:47:14 rurban
879 enable wysiwyg html converters
881 Revision 1.101 2005/10/30 16:12:28 rurban
882 simplify viewsource tokens
884 Revision 1.100 2005/10/30 14:20:42 rurban
885 move Captcha specific vars and methods into a Captcha object
886 randomize Captcha chars positions and angles (smoothly)
888 Revision 1.99 2005/10/29 08:21:58 rurban
889 ENABLE_SPAMBLOCKLIST:
890 Check for links to blocked external tld domains in new edits, against
891 multi.surbl.org and bl.spamcop.net.
893 Revision 1.98 2005/10/10 19:37:04 rurban
894 change USE_HTMLAREA to ENABLE WYSIWYG, add NUM_SPAM_LINKS=20
896 Revision 1.97 2005/09/26 06:32:22 rurban
897 [] is forbidden in id tags. Renamed to use :
899 Revision 1.96 2005/05/06 17:54:22 rurban
900 silence Preview warnings for PAGE_LOCKED_MESSAGE, CONCURRENT_UPDATE_MESSAGE (thanks to schorni)
902 Revision 1.95 2005/04/25 20:17:14 rurban
903 captcha feature by Benjamin Drieu. Patch #1110699
905 Revision 1.94 2005/02/28 20:23:31 rurban
908 Revision 1.93 2005/02/27 19:31:52 rurban
909 hack: display errorstack without sideeffects (save and restore)
911 Revision 1.92 2005/01/29 20:37:21 rurban
912 no edit toolbar at all if ENABLE_EDITTOOLBAR = false
914 Revision 1.91 2005/01/25 07:05:49 rurban
915 extract toolbar code, support new tags to get rid of php inside templates
917 Revision 1.90 2005/01/22 12:46:15 rurban
918 fix oldmakrup button label
919 update pref[edit*] settings
921 Revision 1.89 2005/01/21 14:07:49 rurban
924 Revision 1.88 2004/12/17 16:39:03 rurban
927 Revision 1.87 2004/12/16 18:28:05 rurban
928 keep wikiblog summary = page title
930 Revision 1.86 2004/12/11 14:50:15 rurban
931 new edit_convert button, to get rid of old markup eventually
933 Revision 1.85 2004/12/06 19:49:56 rurban
934 enable action=remove which is undoable and seeable in RecentChanges: ADODB ony for now.
935 renamed delete_page to purge_page.
936 enable action=edit&version=-1 to force creation of a new version.
937 added BABYCART_PATH config
938 fixed magiqc in adodb.inc.php
941 Revision 1.84 2004/12/04 12:58:26 rurban
942 enable babycart Blog::SpamAssassin module on ENABLE_SPAMASSASSIN=true
943 (currently only for php >= 4.3.0)
945 Revision 1.83 2004/12/04 11:55:39 rurban
946 First simple AntiSpam prevention:
947 No more than 20 new http:// links allowed
949 Revision 1.82 2004/11/30 22:21:56 rurban
950 changed gif to optimized (pngout) png
952 Revision 1.81 2004/11/29 17:57:27 rurban
953 translated pulldown buttons
955 Revision 1.80 2004/11/25 17:20:51 rurban
956 and again a couple of more native db args: backlinks
958 Revision 1.79 2004/11/21 11:59:20 rurban
959 remove final \n to be ob_cache independent
961 Revision 1.78 2004/11/16 17:57:45 rurban
962 fix search&replace button
963 use new addTagButton machinery
964 new showPulldown for categories, TODO: in a seperate request
966 Revision 1.77 2004/11/15 15:52:35 rurban
969 Revision 1.76 2004/11/15 15:37:34 rurban
971 don't use document.write for replace, otherwise self.opener is not defined.
973 Revision 1.75 2004/09/16 08:00:52 rurban
976 Revision 1.74 2004/07/03 07:36:28 rurban
977 do not get unneccessary content
979 Revision 1.73 2004/06/16 21:23:44 rurban
980 fixed non-object fatal #215
982 Revision 1.72 2004/06/14 11:31:37 rurban
983 renamed global $Theme to $WikiTheme (gforge nameclash)
984 inherit PageList default options from PageList
985 default sortby=pagename
986 use options in PageList_Selectable (limit, sortby, ...)
987 added action revert, with button at action=diff
988 added option regex to WikiAdminSearchReplace
990 Revision 1.71 2004/06/03 18:06:29 rurban
991 fix file locking issues (only needed on write)
992 fixed immediate LANG and THEME in-session updates if not stored in prefs
993 advanced editpage toolbars (search & replace broken)
995 Revision 1.70 2004/06/02 20:47:47 rurban
996 dont use the wikiaction class
998 Revision 1.69 2004/06/02 10:17:56 rurban
999 integrated search/replace into toolbar
1000 added save+preview buttons
1002 Revision 1.68 2004/06/01 15:28:00 rurban
1003 AdminUser only ADMIN_USER not member of Administrators
1004 some RateIt improvements by dfrankow
1005 edit_toolbar buttons
1007 Revision _1.6 2004/05/26 15:48:00 syilek
1008 fixed problem with creating page with slashes from one true page
1010 Revision _1.5 2004/05/25 16:51:53 syilek
1011 added ability to create a page from the category page and not have to edit it
1013 Revision 1.67 2004/05/27 17:49:06 rurban
1014 renamed DB_Session to DbSession (in CVS also)
1015 added WikiDB->getParam and WikiDB->getAuthParam method to get rid of globals
1016 remove leading slash in error message
1017 added force_unlock parameter to File_Passwd (no return on stale locks)
1018 fixed adodb session AffectedRows
1019 added FileFinder helpers to unify local filenames and DATA_PATH names
1020 editpage.php: new edit toolbar javascript on ENABLE_EDIT_TOOLBAR
1022 Revision 1.66 2004/04/29 23:25:12 rurban
1023 re-ordered locale init (as in 1.3.9)
1024 fixed loadfile with subpages, and merge/restore anyway
1025 (sf.net bug #844188)
1027 Revision 1.65 2004/04/18 01:11:52 rurban
1028 more numeric pagename fixes.
1029 fixed action=upload with merge conflict warnings.
1030 charset changed from constant to global (dynamic utf-8 switching)
1032 Revision 1.64 2004/04/06 19:48:56 rurban
1033 temp workaround for action=edit AddComment form
1035 Revision 1.63 2004/03/24 19:39:02 rurban
1036 php5 workaround code (plus some interim debugging code in XmlElement)
1037 php5 doesn't work yet with the current XmlElement class constructors,
1038 WikiUserNew does work better than php4.
1039 rewrote WikiUserNew user upgrading to ease php5 update
1040 fixed pref handling in WikiUserNew
1041 added Email Notification
1042 added simple Email verification
1043 removed emailVerify userpref subclass: just a email property
1044 changed pref binary storage layout: numarray => hash of non default values
1045 print optimize message only if really done.
1046 forced new cookie policy: delete pref cookies, use only WIKI_ID as plain string.
1047 prefs should be stored in db or homepage, besides the current session.
1049 Revision 1.62 2004/03/17 18:41:05 rurban
1050 initial_content and template support for CreatePage
1052 Revision 1.61 2004/03/12 20:59:17 rurban
1053 important cookie fix by Konstantin Zadorozhny
1054 new editpage feature: JS_SEARCHREPLACE
1056 Revision 1.60 2004/02/15 21:34:37 rurban
1057 PageList enhanced and improved.
1058 fixed new WikiAdmin... plugins
1059 editpage, Theme with exp. htmlarea framework
1060 (htmlarea yet committed, this is really questionable)
1061 WikiUser... code with better session handling for prefs
1062 enhanced UserPreferences (again)
1063 RecentChanges for show_deleted: how should pages be deleted then?
1065 Revision 1.59 2003/12/07 20:35:26 carstenklapp
1066 Bugfix: Concurrent updates broken since after 1.3.4 release: Fatal
1067 error: Call to undefined function: gettransformedcontent() in
1068 /home/groups/p/ph/phpwiki/htdocs/phpwiki2/lib/editpage.php on line
1071 Revision 1.58 2003/03/10 18:25:22 dairiki
1072 Bug/typo fix. If you use the edit page to un/lock a page, it
1073 failed with: Fatal error: Call to a member function on a
1074 non-object in editpage.php on line 136
1076 Revision 1.57 2003/02/26 03:40:22 dairiki
1077 New action=create. Essentially the same as action=edit, except that if the
1078 page already exists, it falls back to action=browse.
1080 This is for use in the "question mark" links for unknown wiki words
1081 to avoid problems and confusion when following links from stale pages.
1082 (If the "unknown page" has been created in the interim, the user probably
1083 wants to view the page before editing it.)
1085 Revision 1.56 2003/02/21 18:07:14 dairiki
1086 Minor, nitpicky, currently inconsequential changes.
1088 Revision 1.55 2003/02/21 04:10:58 dairiki
1089 Fixes for new cached markup.
1090 Some minor code cleanups.
1092 Revision 1.54 2003/02/16 19:47:16 dairiki
1093 Update WikiDB timestamp when editing or deleting pages.
1095 Revision 1.53 2003/02/15 23:20:27 dairiki
1096 Redirect back to browse current version of page upon save,
1097 even when no changes were made.
1099 Revision 1.52 2003/01/03 22:22:00 carstenklapp
1100 Minor adjustments to diff block markers ("<<<<<<<"). Source reformatting.
1102 Revision 1.51 2003/01/03 02:43:26 carstenklapp
1103 New class LoadFileConflictPageEditor, for merging / comparing a loaded
1104 pgsrc file with an existing page.
1111 // c-basic-offset: 4
1112 // c-hanging-comment-ender-p: nil
1113 // indent-tabs-mode: nil