2 rcs_id('$Id: editpage.php,v 1.112 2007-06-09 20:05:35 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;
381 $numlinks = $this->numLinks($newtext);
382 $newlinks = $numlinks - $this->numLinks($oldtext);
383 // FIXME: in longer texts the NUM_SPAM_LINKS number should be increased.
384 // better use a certain text : link ratio.
386 // 1. Not more then 20 new external links
387 if ($newlinks >= NUM_SPAM_LINKS)
389 // Allow strictly authenticated users?
390 // TODO: mail the admin?
391 $this->tokens['PAGE_LOCKED_MESSAGE'] =
392 HTML($this->getSpamMessage(),
393 HTML::p(HTML::strong(_("Too many external links."))));
396 // 2. external babycart (SpamAssassin) check
397 // This will probably prevent from discussing sex or viagra related topics. So beware.
398 if (ENABLE_SPAMASSASSIN) {
399 include_once("lib/spam_babycart.php");
400 if ($babycart = check_babycart($newtext, $request->get("REMOTE_ADDR"),
401 $this->user->getId())) {
402 // TODO: mail the admin
403 if (is_array($babycart))
404 $this->tokens['PAGE_LOCKED_MESSAGE'] =
405 HTML($this->getSpamMessage(),
406 HTML::p(HTML::em(_("SpamAssassin reports: "),
407 join("\n", $babycart))));
411 // 3. extract (new) links and check surbl for blocked domains
412 if (ENABLE_SPAMBLOCKLIST and ($newlinks > 5)) {
413 include_once("lib/SpamBlocklist.php");
414 include_once("lib/InlineParser.php");
415 $oldparsed = TransformLinks($oldtext);
417 foreach ($oldparsed->_content as $link) {
418 if (isa($link, 'Cached_ExternalLink') and !isa($link, 'Cached_InterwikiLink')) {
419 $uri = $link->_getURL($this->page->getName());
425 $parsed = TransformLinks($newtext);
426 foreach ($parsed->_content as $link) {
427 if (isa($link, 'Cached_ExternalLink') and !isa($link, 'Cached_InterwikiLink')) {
428 $uri = $link->_getURL($this->page->getName());
429 // only check new links, so admins may add blocked links.
430 if (!array_key_exists($uri, $oldlinks) and ($res = IsBlackListed($uri))) {
431 // TODO: mail the admin
432 $this->tokens['PAGE_LOCKED_MESSAGE'] =
433 HTML($this->getSpamMessage(),
434 HTML::p(HTML::strong(_("External links contain blocked domains:")),
435 HTML::ul(HTML::li(sprintf(_("%s is listed at %s with %s"),
436 $uri." [".$res[2]."]", $res[0], $res[1])))));
448 /** Number of external links in the wikitext
450 function numLinks(&$text) {
451 return substr_count($text, "http://") + substr_count($text, "https://");
454 /** Header of the Anti Spam message
456 function getSpamMessage () {
458 HTML(HTML::h2(_("Spam Prevention")),
459 HTML::p(_("This page edit seems to contain spam and was therefore not saved."),
461 _("Sorry for the inconvenience.")),
465 function getPreview () {
466 include_once('lib/PageType.php');
467 $this->_content = $this->getContent();
468 return new TransformedText($this->page, $this->_content, $this->meta);
471 function getConvertedPreview () {
472 include_once('lib/PageType.php');
473 $this->_content = $this->getContent();
474 $this->meta['markup'] = 2.0;
475 $this->_content = ConvertOldMarkup($this->_content);
476 return new TransformedText($this->page, $this->_content, $this->meta);
479 // possibly convert HTMLAREA content back to Wiki markup
480 function getContent () {
481 if (ENABLE_WYSIWYG) {
482 // don't store everything as html
483 if (!WYSIWYG_DEFAULT_PAGETYPE_HTML) {
484 // Wikiwyg shortcut to avoid the InlineTransformer:
485 if (WYSIWYG_BACKEND == "Wikiwyg") return $this->_content;
486 $xml_output = $this->WysiwygEdit->ConvertAfter($this->_content);
487 $this->_content = join("", $xml_output->_content);
489 $this->meta['pagetype'] = 'html';
491 return $this->_content;
493 return $this->_content;
497 function getLockedMessage () {
499 HTML(HTML::h2(_("Page Locked")),
500 HTML::p(_("This page has been locked by the administrator so your changes can not be saved.")),
501 HTML::p(_("(Copy your changes to the clipboard. You can try editing a different page or save your text in a text editor.)")),
502 HTML::p(_("Sorry for the inconvenience.")));
505 function isModerated() {
506 return $this->page->get('moderation');
508 function getModeratedMessage() {
510 HTML(HTML::h2(WikiLink(_("ModeratedPage"))),
511 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")))),
512 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.",
513 WikiLink(_("UserPreferences")))));
515 function getConflictMessage ($unresolved = false) {
517 xgettext only knows about c/c++ line-continuation strings
518 it does not know about php's dot operator.
519 We want to translate this entire paragraph as one string, of course.
522 //$re_edit_link = Button('edit', _("Edit the new version"), $this->page);
525 $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.",
526 "<<<<<<< ". _("Your version"),
527 ">>>>>>> ". _("Other version")));
529 $message = HTML::p(_("Please check it through before saving."));
533 /*$steps = HTML::ol(HTML::li(_("Copy your changes to the clipboard or to another temporary place (e.g. text editor).")),
534 HTML::li(fmt("%s of the page. You should now see the most current version of the page. Your changes are no longer there.",
536 HTML::li(_("Make changes to the file again. Paste your additions from the clipboard (or text editor).")),
537 HTML::li(_("Save your updated changes.")));
540 HTML(HTML::h2(_("Conflicting Edits!")),
541 HTML::p(_("In the time since you started editing this page, another user has saved a new version of it.")),
542 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.")),
547 function getTextArea () {
548 $request = &$this->request;
550 $readonly = ! $this->canEdit(); // || $this->isConcurrentUpdate();
552 // WYSIWYG will need two pagetypes: raw wikitest and converted html
553 if (ENABLE_WYSIWYG) {
554 $this->_wikicontent = $this->_content;
555 $this->_content = $this->WysiwygEdit->ConvertBefore($this->_content);
556 // $this->getPreview();
557 //$this->_htmlcontent = $this->_content->asXML();
560 $textarea = HTML::textarea(array('class'=> 'wikiedit',
561 'name' => 'edit[content]',
562 'id' => 'edit-content',
563 'rows' => $request->getPref('editHeight'),
564 'cols' => $request->getPref('editWidth'),
565 'readonly' => (bool) $readonly),
567 /** <textarea wrap="virtual"> is not valid XHTML but Netscape 4 requires it
568 * to wrap long lines.
571 $textarea->setAttr('wrap', 'virtual');
572 if (ENABLE_WYSIWYG) {
573 return $this->WysiwygEdit->Textarea($textarea, $this->_wikicontent,
574 $textarea->getAttr('name'));
579 function getFormElements () {
581 $request = &$this->request;
582 $page = &$this->page;
584 $h = array('action' => 'edit',
585 'pagename' => $page->getName(),
586 'version' => $this->version,
587 'edit[pagetype]' => $this->meta['pagetype'],
588 'edit[current_version]' => $this->_currentVersion);
590 $el['HIDDEN_INPUTS'] = HiddenInputs($h);
591 $el['EDIT_TEXTAREA'] = $this->getTextArea();
592 if ( ENABLE_CAPTCHA ) {
593 $el = array_merge($el, $this->Captcha->getFormElements());
596 = HTML::input(array('type' => 'text',
597 'class' => 'wikitext',
598 'id' => 'edit-summary',
599 'name' => 'edit[summary]',
602 'value' => $this->meta['summary']));
604 = HTML::input(array('type' => 'checkbox',
605 'name' => 'edit[minor_edit]',
606 'id' => 'edit-minor_edit',
607 'checked' => (bool) $this->meta['is_minor_edit']));
609 = HTML::input(array('type' => 'checkbox',
610 'name' => 'edit[markup]',
612 'checked' => $this->meta['markup'] < 2.0,
613 'id' => 'useOldMarkup',
614 'onclick' => 'showOldMarkupRules(this.checked)'));
615 $el['OLD_MARKUP_CONVERT'] = ($this->meta['markup'] < 2.0)
616 ? Button('submit:edit[edit_convert]', _("Convert"), 'wikiaction') : '';
618 = HTML::input(array('type' => 'checkbox',
619 'name' => 'edit[locked]',
620 'id' => 'edit-locked',
621 'disabled' => (bool) !$this->user->isadmin(),
622 'checked' => (bool) $this->locked));
624 $el['PREVIEW_B'] = Button('submit:edit[preview]', _("Preview"),
626 array('accesskey'=> 'p'));
628 //if (!$this->isConcurrentUpdate() && $this->canEdit())
629 $el['SAVE_B'] = Button('submit:edit[save]',
630 _("Save"), 'wikiaction',
631 array('accesskey'=> 's'));
632 $el['IS_CURRENT'] = $this->version == $this->current->getVersion();
635 = HTML::input(array('type' => 'text',
638 'class' => "numeric",
639 'name' => 'pref[editWidth]',
640 'id' => 'pref-editWidth',
641 'value' => $request->getPref('editWidth'),
642 'onchange' => 'this.form.submit();'));
644 = HTML::input(array('type' => 'text',
647 'class' => "numeric",
648 'name' => 'pref[editHeight]',
649 'id' => 'pref-editHeight',
650 'value' => $request->getPref('editHeight'),
651 'onchange' => 'this.form.submit();'));
652 $el['SEP'] = $WikiTheme->getButtonSeparator();
653 $el['AUTHOR_MESSAGE'] = fmt("Author will be logged as %s.",
654 HTML::em($this->user->getId()));
659 function _redirectToBrowsePage() {
660 $this->request->redirect(WikiURL($this->page, false, 'absolute_url'));
663 function _restoreState () {
664 $request = &$this->request;
666 $posted = $request->getArg('edit');
667 $request->setArg('edit', false);
670 || !$request->isPost()
671 || !in_array($request->getArg('action'),array('edit','loadfile')))
674 if (!isset($posted['content']) || !is_string($posted['content']))
676 $this->_content = preg_replace('/[ \t\r]+\n/', "\n",
677 rtrim($posted['content']));
678 $this->_content = $this->getContent();
680 $this->_currentVersion = (int) $posted['current_version'];
682 if ($this->_currentVersion < 0)
684 if ($this->_currentVersion > $this->current->getVersion())
685 return false; // FIXME: some kind of warning?
687 $is_old_markup = !empty($posted['markup']) && $posted['markup'] == 'old';
688 $meta['markup'] = $is_old_markup ? false : 2.0;
689 $meta['summary'] = trim(substr($posted['summary'], 0, 256));
690 $meta['is_minor_edit'] = !empty($posted['minor_edit']);
691 $meta['pagetype'] = !empty($posted['pagetype']) ? $posted['pagetype'] : false;
692 if ( ENABLE_CAPTCHA )
693 $meta['captcha_input'] = !empty($posted['captcha_input']) ?
694 $posted['captcha_input'] : '';
696 $this->meta = array_merge($this->meta, $meta);
697 $this->locked = !empty($posted['locked']);
699 foreach (array('preview','save','edit_convert',
700 'keep_old','overwrite') as $o)
702 if (!empty($posted[$o]))
703 $this->editaction = $o;
705 if (empty($this->editaction))
706 $this->editaction = 'edit';
711 function _initializeState () {
712 $request = &$this->request;
713 $current = &$this->current;
714 $selected = &$this->selected;
715 $user = &$this->user;
718 NoSuchRevision($request, $this->page, $this->version); // noreturn
720 $this->_currentVersion = $current->getVersion();
721 $this->_content = $selected->getPackedContent();
723 $this->locked = $this->page->get('locked');
725 // If author same as previous author, default minor_edit to on.
726 $age = $this->meta['mtime'] - $current->get('mtime');
727 $this->meta['is_minor_edit'] = ( $age < MINOR_EDIT_TIMEOUT
728 && $current->get('author') == $user->getId()
731 // Default for new pages is new-style markup.
732 if ($selected->hasDefaultContents())
733 $is_new_markup = true;
735 $is_new_markup = $selected->get('markup') >= 2.0;
737 $this->meta['markup'] = $is_new_markup ? 2.0: false;
738 $this->meta['pagetype'] = $selected->get('pagetype');
739 if ($this->meta['pagetype'] == 'wikiblog')
740 $this->meta['summary'] = $selected->get('summary'); // keep blog title
742 $this->meta['summary'] = '';
743 $this->editaction = 'edit';
747 class LoadFileConflictPageEditor
750 function editPage ($saveFailed = true) {
751 $tokens = &$this->tokens;
753 if (!$this->canEdit()) {
754 if ($this->isInitialEdit()) {
755 return $this->viewSource();
757 $tokens['PAGE_LOCKED_MESSAGE'] = $this->getLockedMessage();
759 elseif ($this->editaction == 'save') {
760 if ($this->savePage()) {
761 return true; // Page saved.
766 if ($saveFailed || $this->isConcurrentUpdate())
768 // Get the text of the original page, and the two conflicting edits
769 // The diff class takes arrays as input. So retrieve content as
770 // an array, or convert it as necesary.
771 $orig = $this->page->getRevision($this->_currentVersion);
772 $this_content = explode("\n", $this->_content);
773 $other_content = $this->current->getContent();
774 include_once("lib/diff.php");
775 $diff2 = new Diff($other_content, $this_content);
776 $context_lines = max(4, count($other_content) + 1,
777 count($this_content) + 1);
778 $fmt = new BlockDiffFormatter($context_lines);
780 $this->_content = $fmt->format($diff2);
781 // FIXME: integrate this into class BlockDiffFormatter
782 $this->_content = str_replace(">>>>>>>\n<<<<<<<\n", "=======\n",
784 $this->_content = str_replace("<<<<<<<\n>>>>>>>\n", "=======\n",
787 $this->_currentVersion = $this->current->getVersion();
788 $this->version = $this->_currentVersion;
789 $tokens['CONCURRENT_UPDATE_MESSAGE'] = $this->getConflictMessage();
792 if ($this->editaction == 'edit_convert')
793 $tokens['PREVIEW_CONTENT'] = $this->getConvertedPreview();
794 if ($this->editaction == 'preview')
795 $tokens['PREVIEW_CONTENT'] = $this->getPreview(); // FIXME: convert to _MESSAGE?
797 // FIXME: NOT_CURRENT_MESSAGE?
798 $tokens = array_merge($tokens, $this->getFormElements());
799 // we need all GET params for loadfile overwrite
800 if ($this->request->getArg('action') == 'loadfile') {
802 $this->tokens['HIDDEN_INPUTS'] =
804 (array('source' => $this->request->getArg('source'),
806 $this->tokens['HIDDEN_INPUTS']);
807 // add two conflict resolution buttons before preview and save.
808 $tokens['PREVIEW_B'] = HTML(
809 Button('submit:edit[keep_old]',
810 _("Keep old"), 'wikiaction'),
812 Button('submit:edit[overwrite]',
813 _("Overwrite with new"), 'wikiaction'),
815 $tokens['PREVIEW_B']);
817 if (ENABLE_EDIT_TOOLBAR and !ENABLE_WYSIWYG) {
818 include_once("lib/EditToolbar.php");
819 $toolbar = new EditToolbar();
820 $tokens = array_merge($tokens, $toolbar->getTokens());
823 return $this->output('editpage', _("Merge and Edit: %s"));
826 function output ($template, $title_fs) {
827 $selected = &$this->selected;
828 $current = &$this->current;
830 if ($selected && $selected->getVersion() != $current->getVersion()) {
832 $pagelink = WikiLink($selected);
836 $pagelink = WikiLink($this->page);
839 $title = new FormattedText ($title_fs, $pagelink);
840 $this->tokens['HEADER'] = $title;
841 //hack! there's no TITLE in editpage, but in the previous top template
842 if (empty($this->tokens['PAGE_LOCKED_MESSAGE']))
843 $this->tokens['PAGE_LOCKED_MESSAGE'] = HTML::h3($title);
845 $this->tokens['PAGE_LOCKED_MESSAGE'] = HTML(HTML::h3($title),
846 $this->tokens['PAGE_LOCKED_MESSAGE']);
847 $template = Template($template, $this->tokens);
849 //GeneratePage($template, $title, $rev);
854 function getConflictMessage () {
855 $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.",
858 HTML::p(_("Please check it through before saving."))));
864 $Log: not supported by cvs2svn $
865 Revision 1.111 2007/06/03 17:12:00 rurban
866 convenience: only check above 5 external links for blocked domains
868 Revision 1.110 2007/01/07 18:42:00 rurban
869 Print ModeratedPage message on edit. Use GOOGLE_LINKS_NOFOLLOW. Improve id: edit: to edit-
871 Revision 1.109 2007/01/02 13:21:39 rurban
872 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.
874 Revision 1.108 2006/12/22 17:47:34 rurban
875 Display Warnings only once.
876 Add button accesskeys
878 Revision 1.107 2006/05/13 19:59:54 rurban
879 added wysiwyg_editor-1.3a feature by Jean-Nicolas GEREONE <jean-nicolas.gereone@st.com>
880 converted wysiwyg_editor-1.3a js to WysiwygEdit framework
881 changed default ENABLE_WYSIWYG = true and added WYSIWYG_BACKEND = Wikiwyg
883 Revision 1.106 2005/11/21 22:03:08 rurban
884 fix syntax error inside ENABLE_SPAMBLOCKLIST
886 Revision 1.105 2005/11/21 20:53:59 rurban
887 beautify request pref lines, no antispam if admin (netznetz request), user is a member anyway
889 Revision 1.104 2005/10/31 17:20:40 rurban
892 Revision 1.103 2005/10/31 17:09:13 rurban
893 use better constant WYSIWYG_DEFAULT_PAGETYPE_HTML
895 Revision 1.102 2005/10/31 16:47:14 rurban
896 enable wysiwyg html converters
898 Revision 1.101 2005/10/30 16:12:28 rurban
899 simplify viewsource tokens
901 Revision 1.100 2005/10/30 14:20:42 rurban
902 move Captcha specific vars and methods into a Captcha object
903 randomize Captcha chars positions and angles (smoothly)
905 Revision 1.99 2005/10/29 08:21:58 rurban
906 ENABLE_SPAMBLOCKLIST:
907 Check for links to blocked external tld domains in new edits, against
908 multi.surbl.org and bl.spamcop.net.
910 Revision 1.98 2005/10/10 19:37:04 rurban
911 change USE_HTMLAREA to ENABLE WYSIWYG, add NUM_SPAM_LINKS=20
913 Revision 1.97 2005/09/26 06:32:22 rurban
914 [] is forbidden in id tags. Renamed to use :
916 Revision 1.96 2005/05/06 17:54:22 rurban
917 silence Preview warnings for PAGE_LOCKED_MESSAGE, CONCURRENT_UPDATE_MESSAGE (thanks to schorni)
919 Revision 1.95 2005/04/25 20:17:14 rurban
920 captcha feature by Benjamin Drieu. Patch #1110699
922 Revision 1.94 2005/02/28 20:23:31 rurban
925 Revision 1.93 2005/02/27 19:31:52 rurban
926 hack: display errorstack without sideeffects (save and restore)
928 Revision 1.92 2005/01/29 20:37:21 rurban
929 no edit toolbar at all if ENABLE_EDITTOOLBAR = false
931 Revision 1.91 2005/01/25 07:05:49 rurban
932 extract toolbar code, support new tags to get rid of php inside templates
934 Revision 1.90 2005/01/22 12:46:15 rurban
935 fix oldmakrup button label
936 update pref[edit*] settings
938 Revision 1.89 2005/01/21 14:07:49 rurban
941 Revision 1.88 2004/12/17 16:39:03 rurban
944 Revision 1.87 2004/12/16 18:28:05 rurban
945 keep wikiblog summary = page title
947 Revision 1.86 2004/12/11 14:50:15 rurban
948 new edit_convert button, to get rid of old markup eventually
950 Revision 1.85 2004/12/06 19:49:56 rurban
951 enable action=remove which is undoable and seeable in RecentChanges: ADODB ony for now.
952 renamed delete_page to purge_page.
953 enable action=edit&version=-1 to force creation of a new version.
954 added BABYCART_PATH config
955 fixed magiqc in adodb.inc.php
958 Revision 1.84 2004/12/04 12:58:26 rurban
959 enable babycart Blog::SpamAssassin module on ENABLE_SPAMASSASSIN=true
960 (currently only for php >= 4.3.0)
962 Revision 1.83 2004/12/04 11:55:39 rurban
963 First simple AntiSpam prevention:
964 No more than 20 new http:// links allowed
966 Revision 1.82 2004/11/30 22:21:56 rurban
967 changed gif to optimized (pngout) png
969 Revision 1.81 2004/11/29 17:57:27 rurban
970 translated pulldown buttons
972 Revision 1.80 2004/11/25 17:20:51 rurban
973 and again a couple of more native db args: backlinks
975 Revision 1.79 2004/11/21 11:59:20 rurban
976 remove final \n to be ob_cache independent
978 Revision 1.78 2004/11/16 17:57:45 rurban
979 fix search&replace button
980 use new addTagButton machinery
981 new showPulldown for categories, TODO: in a seperate request
983 Revision 1.77 2004/11/15 15:52:35 rurban
986 Revision 1.76 2004/11/15 15:37:34 rurban
988 don't use document.write for replace, otherwise self.opener is not defined.
990 Revision 1.75 2004/09/16 08:00:52 rurban
993 Revision 1.74 2004/07/03 07:36:28 rurban
994 do not get unneccessary content
996 Revision 1.73 2004/06/16 21:23:44 rurban
997 fixed non-object fatal #215
999 Revision 1.72 2004/06/14 11:31:37 rurban
1000 renamed global $Theme to $WikiTheme (gforge nameclash)
1001 inherit PageList default options from PageList
1002 default sortby=pagename
1003 use options in PageList_Selectable (limit, sortby, ...)
1004 added action revert, with button at action=diff
1005 added option regex to WikiAdminSearchReplace
1007 Revision 1.71 2004/06/03 18:06:29 rurban
1008 fix file locking issues (only needed on write)
1009 fixed immediate LANG and THEME in-session updates if not stored in prefs
1010 advanced editpage toolbars (search & replace broken)
1012 Revision 1.70 2004/06/02 20:47:47 rurban
1013 dont use the wikiaction class
1015 Revision 1.69 2004/06/02 10:17:56 rurban
1016 integrated search/replace into toolbar
1017 added save+preview buttons
1019 Revision 1.68 2004/06/01 15:28:00 rurban
1020 AdminUser only ADMIN_USER not member of Administrators
1021 some RateIt improvements by dfrankow
1022 edit_toolbar buttons
1024 Revision _1.6 2004/05/26 15:48:00 syilek
1025 fixed problem with creating page with slashes from one true page
1027 Revision _1.5 2004/05/25 16:51:53 syilek
1028 added ability to create a page from the category page and not have to edit it
1030 Revision 1.67 2004/05/27 17:49:06 rurban
1031 renamed DB_Session to DbSession (in CVS also)
1032 added WikiDB->getParam and WikiDB->getAuthParam method to get rid of globals
1033 remove leading slash in error message
1034 added force_unlock parameter to File_Passwd (no return on stale locks)
1035 fixed adodb session AffectedRows
1036 added FileFinder helpers to unify local filenames and DATA_PATH names
1037 editpage.php: new edit toolbar javascript on ENABLE_EDIT_TOOLBAR
1039 Revision 1.66 2004/04/29 23:25:12 rurban
1040 re-ordered locale init (as in 1.3.9)
1041 fixed loadfile with subpages, and merge/restore anyway
1042 (sf.net bug #844188)
1044 Revision 1.65 2004/04/18 01:11:52 rurban
1045 more numeric pagename fixes.
1046 fixed action=upload with merge conflict warnings.
1047 charset changed from constant to global (dynamic utf-8 switching)
1049 Revision 1.64 2004/04/06 19:48:56 rurban
1050 temp workaround for action=edit AddComment form
1052 Revision 1.63 2004/03/24 19:39:02 rurban
1053 php5 workaround code (plus some interim debugging code in XmlElement)
1054 php5 doesn't work yet with the current XmlElement class constructors,
1055 WikiUserNew does work better than php4.
1056 rewrote WikiUserNew user upgrading to ease php5 update
1057 fixed pref handling in WikiUserNew
1058 added Email Notification
1059 added simple Email verification
1060 removed emailVerify userpref subclass: just a email property
1061 changed pref binary storage layout: numarray => hash of non default values
1062 print optimize message only if really done.
1063 forced new cookie policy: delete pref cookies, use only WIKI_ID as plain string.
1064 prefs should be stored in db or homepage, besides the current session.
1066 Revision 1.62 2004/03/17 18:41:05 rurban
1067 initial_content and template support for CreatePage
1069 Revision 1.61 2004/03/12 20:59:17 rurban
1070 important cookie fix by Konstantin Zadorozhny
1071 new editpage feature: JS_SEARCHREPLACE
1073 Revision 1.60 2004/02/15 21:34:37 rurban
1074 PageList enhanced and improved.
1075 fixed new WikiAdmin... plugins
1076 editpage, Theme with exp. htmlarea framework
1077 (htmlarea yet committed, this is really questionable)
1078 WikiUser... code with better session handling for prefs
1079 enhanced UserPreferences (again)
1080 RecentChanges for show_deleted: how should pages be deleted then?
1082 Revision 1.59 2003/12/07 20:35:26 carstenklapp
1083 Bugfix: Concurrent updates broken since after 1.3.4 release: Fatal
1084 error: Call to undefined function: gettransformedcontent() in
1085 /home/groups/p/ph/phpwiki/htdocs/phpwiki2/lib/editpage.php on line
1088 Revision 1.58 2003/03/10 18:25:22 dairiki
1089 Bug/typo fix. If you use the edit page to un/lock a page, it
1090 failed with: Fatal error: Call to a member function on a
1091 non-object in editpage.php on line 136
1093 Revision 1.57 2003/02/26 03:40:22 dairiki
1094 New action=create. Essentially the same as action=edit, except that if the
1095 page already exists, it falls back to action=browse.
1097 This is for use in the "question mark" links for unknown wiki words
1098 to avoid problems and confusion when following links from stale pages.
1099 (If the "unknown page" has been created in the interim, the user probably
1100 wants to view the page before editing it.)
1102 Revision 1.56 2003/02/21 18:07:14 dairiki
1103 Minor, nitpicky, currently inconsequential changes.
1105 Revision 1.55 2003/02/21 04:10:58 dairiki
1106 Fixes for new cached markup.
1107 Some minor code cleanups.
1109 Revision 1.54 2003/02/16 19:47:16 dairiki
1110 Update WikiDB timestamp when editing or deleting pages.
1112 Revision 1.53 2003/02/15 23:20:27 dairiki
1113 Redirect back to browse current version of page upon save,
1114 even when no changes were made.
1116 Revision 1.52 2003/01/03 22:22:00 carstenklapp
1117 Minor adjustments to diff block markers ("<<<<<<<"). Source reformatting.
1119 Revision 1.51 2003/01/03 02:43:26 carstenklapp
1120 New class LoadFileConflictPageEditor, for merging / comparing a loaded
1121 pgsrc file with an existing page.
1128 // c-basic-offset: 4
1129 // c-hanging-comment-ender-p: nil
1130 // indent-tabs-mode: nil