2 rcs_id('$Id: editpage.php,v 1.110 2007-01-07 18:42: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 include_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 include_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 include_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 include_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 include_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 include_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 include_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)) {
412 include_once("lib/SpamBlocklist.php");
413 include_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 include_once('lib/PageType.php');
453 $this->_content = $this->getContent();
454 return new TransformedText($this->page, $this->_content, $this->meta);
457 function getConvertedPreview () {
458 include_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 include_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.109 2007/01/02 13:21:39 rurban
852 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.
854 Revision 1.108 2006/12/22 17:47:34 rurban
855 Display Warnings only once.
856 Add button accesskeys
858 Revision 1.107 2006/05/13 19:59:54 rurban
859 added wysiwyg_editor-1.3a feature by Jean-Nicolas GEREONE <jean-nicolas.gereone@st.com>
860 converted wysiwyg_editor-1.3a js to WysiwygEdit framework
861 changed default ENABLE_WYSIWYG = true and added WYSIWYG_BACKEND = Wikiwyg
863 Revision 1.106 2005/11/21 22:03:08 rurban
864 fix syntax error inside ENABLE_SPAMBLOCKLIST
866 Revision 1.105 2005/11/21 20:53:59 rurban
867 beautify request pref lines, no antispam if admin (netznetz request), user is a member anyway
869 Revision 1.104 2005/10/31 17:20:40 rurban
872 Revision 1.103 2005/10/31 17:09:13 rurban
873 use better constant WYSIWYG_DEFAULT_PAGETYPE_HTML
875 Revision 1.102 2005/10/31 16:47:14 rurban
876 enable wysiwyg html converters
878 Revision 1.101 2005/10/30 16:12:28 rurban
879 simplify viewsource tokens
881 Revision 1.100 2005/10/30 14:20:42 rurban
882 move Captcha specific vars and methods into a Captcha object
883 randomize Captcha chars positions and angles (smoothly)
885 Revision 1.99 2005/10/29 08:21:58 rurban
886 ENABLE_SPAMBLOCKLIST:
887 Check for links to blocked external tld domains in new edits, against
888 multi.surbl.org and bl.spamcop.net.
890 Revision 1.98 2005/10/10 19:37:04 rurban
891 change USE_HTMLAREA to ENABLE WYSIWYG, add NUM_SPAM_LINKS=20
893 Revision 1.97 2005/09/26 06:32:22 rurban
894 [] is forbidden in id tags. Renamed to use :
896 Revision 1.96 2005/05/06 17:54:22 rurban
897 silence Preview warnings for PAGE_LOCKED_MESSAGE, CONCURRENT_UPDATE_MESSAGE (thanks to schorni)
899 Revision 1.95 2005/04/25 20:17:14 rurban
900 captcha feature by Benjamin Drieu. Patch #1110699
902 Revision 1.94 2005/02/28 20:23:31 rurban
905 Revision 1.93 2005/02/27 19:31:52 rurban
906 hack: display errorstack without sideeffects (save and restore)
908 Revision 1.92 2005/01/29 20:37:21 rurban
909 no edit toolbar at all if ENABLE_EDITTOOLBAR = false
911 Revision 1.91 2005/01/25 07:05:49 rurban
912 extract toolbar code, support new tags to get rid of php inside templates
914 Revision 1.90 2005/01/22 12:46:15 rurban
915 fix oldmakrup button label
916 update pref[edit*] settings
918 Revision 1.89 2005/01/21 14:07:49 rurban
921 Revision 1.88 2004/12/17 16:39:03 rurban
924 Revision 1.87 2004/12/16 18:28:05 rurban
925 keep wikiblog summary = page title
927 Revision 1.86 2004/12/11 14:50:15 rurban
928 new edit_convert button, to get rid of old markup eventually
930 Revision 1.85 2004/12/06 19:49:56 rurban
931 enable action=remove which is undoable and seeable in RecentChanges: ADODB ony for now.
932 renamed delete_page to purge_page.
933 enable action=edit&version=-1 to force creation of a new version.
934 added BABYCART_PATH config
935 fixed magiqc in adodb.inc.php
938 Revision 1.84 2004/12/04 12:58:26 rurban
939 enable babycart Blog::SpamAssassin module on ENABLE_SPAMASSASSIN=true
940 (currently only for php >= 4.3.0)
942 Revision 1.83 2004/12/04 11:55:39 rurban
943 First simple AntiSpam prevention:
944 No more than 20 new http:// links allowed
946 Revision 1.82 2004/11/30 22:21:56 rurban
947 changed gif to optimized (pngout) png
949 Revision 1.81 2004/11/29 17:57:27 rurban
950 translated pulldown buttons
952 Revision 1.80 2004/11/25 17:20:51 rurban
953 and again a couple of more native db args: backlinks
955 Revision 1.79 2004/11/21 11:59:20 rurban
956 remove final \n to be ob_cache independent
958 Revision 1.78 2004/11/16 17:57:45 rurban
959 fix search&replace button
960 use new addTagButton machinery
961 new showPulldown for categories, TODO: in a seperate request
963 Revision 1.77 2004/11/15 15:52:35 rurban
966 Revision 1.76 2004/11/15 15:37:34 rurban
968 don't use document.write for replace, otherwise self.opener is not defined.
970 Revision 1.75 2004/09/16 08:00:52 rurban
973 Revision 1.74 2004/07/03 07:36:28 rurban
974 do not get unneccessary content
976 Revision 1.73 2004/06/16 21:23:44 rurban
977 fixed non-object fatal #215
979 Revision 1.72 2004/06/14 11:31:37 rurban
980 renamed global $Theme to $WikiTheme (gforge nameclash)
981 inherit PageList default options from PageList
982 default sortby=pagename
983 use options in PageList_Selectable (limit, sortby, ...)
984 added action revert, with button at action=diff
985 added option regex to WikiAdminSearchReplace
987 Revision 1.71 2004/06/03 18:06:29 rurban
988 fix file locking issues (only needed on write)
989 fixed immediate LANG and THEME in-session updates if not stored in prefs
990 advanced editpage toolbars (search & replace broken)
992 Revision 1.70 2004/06/02 20:47:47 rurban
993 dont use the wikiaction class
995 Revision 1.69 2004/06/02 10:17:56 rurban
996 integrated search/replace into toolbar
997 added save+preview buttons
999 Revision 1.68 2004/06/01 15:28:00 rurban
1000 AdminUser only ADMIN_USER not member of Administrators
1001 some RateIt improvements by dfrankow
1002 edit_toolbar buttons
1004 Revision _1.6 2004/05/26 15:48:00 syilek
1005 fixed problem with creating page with slashes from one true page
1007 Revision _1.5 2004/05/25 16:51:53 syilek
1008 added ability to create a page from the category page and not have to edit it
1010 Revision 1.67 2004/05/27 17:49:06 rurban
1011 renamed DB_Session to DbSession (in CVS also)
1012 added WikiDB->getParam and WikiDB->getAuthParam method to get rid of globals
1013 remove leading slash in error message
1014 added force_unlock parameter to File_Passwd (no return on stale locks)
1015 fixed adodb session AffectedRows
1016 added FileFinder helpers to unify local filenames and DATA_PATH names
1017 editpage.php: new edit toolbar javascript on ENABLE_EDIT_TOOLBAR
1019 Revision 1.66 2004/04/29 23:25:12 rurban
1020 re-ordered locale init (as in 1.3.9)
1021 fixed loadfile with subpages, and merge/restore anyway
1022 (sf.net bug #844188)
1024 Revision 1.65 2004/04/18 01:11:52 rurban
1025 more numeric pagename fixes.
1026 fixed action=upload with merge conflict warnings.
1027 charset changed from constant to global (dynamic utf-8 switching)
1029 Revision 1.64 2004/04/06 19:48:56 rurban
1030 temp workaround for action=edit AddComment form
1032 Revision 1.63 2004/03/24 19:39:02 rurban
1033 php5 workaround code (plus some interim debugging code in XmlElement)
1034 php5 doesn't work yet with the current XmlElement class constructors,
1035 WikiUserNew does work better than php4.
1036 rewrote WikiUserNew user upgrading to ease php5 update
1037 fixed pref handling in WikiUserNew
1038 added Email Notification
1039 added simple Email verification
1040 removed emailVerify userpref subclass: just a email property
1041 changed pref binary storage layout: numarray => hash of non default values
1042 print optimize message only if really done.
1043 forced new cookie policy: delete pref cookies, use only WIKI_ID as plain string.
1044 prefs should be stored in db or homepage, besides the current session.
1046 Revision 1.62 2004/03/17 18:41:05 rurban
1047 initial_content and template support for CreatePage
1049 Revision 1.61 2004/03/12 20:59:17 rurban
1050 important cookie fix by Konstantin Zadorozhny
1051 new editpage feature: JS_SEARCHREPLACE
1053 Revision 1.60 2004/02/15 21:34:37 rurban
1054 PageList enhanced and improved.
1055 fixed new WikiAdmin... plugins
1056 editpage, Theme with exp. htmlarea framework
1057 (htmlarea yet committed, this is really questionable)
1058 WikiUser... code with better session handling for prefs
1059 enhanced UserPreferences (again)
1060 RecentChanges for show_deleted: how should pages be deleted then?
1062 Revision 1.59 2003/12/07 20:35:26 carstenklapp
1063 Bugfix: Concurrent updates broken since after 1.3.4 release: Fatal
1064 error: Call to undefined function: gettransformedcontent() in
1065 /home/groups/p/ph/phpwiki/htdocs/phpwiki2/lib/editpage.php on line
1068 Revision 1.58 2003/03/10 18:25:22 dairiki
1069 Bug/typo fix. If you use the edit page to un/lock a page, it
1070 failed with: Fatal error: Call to a member function on a
1071 non-object in editpage.php on line 136
1073 Revision 1.57 2003/02/26 03:40:22 dairiki
1074 New action=create. Essentially the same as action=edit, except that if the
1075 page already exists, it falls back to action=browse.
1077 This is for use in the "question mark" links for unknown wiki words
1078 to avoid problems and confusion when following links from stale pages.
1079 (If the "unknown page" has been created in the interim, the user probably
1080 wants to view the page before editing it.)
1082 Revision 1.56 2003/02/21 18:07:14 dairiki
1083 Minor, nitpicky, currently inconsequential changes.
1085 Revision 1.55 2003/02/21 04:10:58 dairiki
1086 Fixes for new cached markup.
1087 Some minor code cleanups.
1089 Revision 1.54 2003/02/16 19:47:16 dairiki
1090 Update WikiDB timestamp when editing or deleting pages.
1092 Revision 1.53 2003/02/15 23:20:27 dairiki
1093 Redirect back to browse current version of page upon save,
1094 even when no changes were made.
1096 Revision 1.52 2003/01/03 22:22:00 carstenklapp
1097 Minor adjustments to diff block markers ("<<<<<<<"). Source reformatting.
1099 Revision 1.51 2003/01/03 02:43:26 carstenklapp
1100 New class LoadFileConflictPageEditor, for merging / comparing a loaded
1101 pgsrc file with an existing page.
1108 // c-basic-offset: 4
1109 // c-hanging-comment-ender-p: nil
1110 // indent-tabs-mode: nil