]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/editpage.php
no edit toolbar at all if ENABLE_EDITTOOLBAR = false
[SourceForge/phpwiki.git] / lib / editpage.php
1 <?php
2 rcs_id('$Id: editpage.php,v 1.92 2005-01-29 20:37:21 rurban Exp $');
3
4 require_once('lib/Template.php');
5
6 // USE_HTMLAREA - Support for some WYSIWYG HTML Editor
7 // Not yet enabled, since we cannot convert HTML to Wiki Markup yet.
8 // (See HtmlParser.php for the ongoing efforts)
9 // We might use a HTML PageType, which is contra wiki, but some people might prefer HTML markup.
10 // TODO: Change from constant to user preference variable (checkbox setting),
11 //       when HtmlParser is finished.
12 if (!defined('USE_HTMLAREA')) define('USE_HTMLAREA', false);
13 if (USE_HTMLAREA) require_once('lib/htmlarea.php');
14
15 class PageEditor
16 {
17     function PageEditor (&$request) {
18         $this->request = &$request;
19
20         $this->user = $request->getUser();
21         $this->page = $request->getPage();
22
23         $this->current = $this->page->getCurrentRevision(false);
24
25         // HACKish short circuit to browse on action=create
26         if ($request->getArg('action') == 'create') {
27             if (! $this->current->hasDefaultContents()) 
28                 $request->redirect(WikiURL($this->page->getName())); // noreturn
29         }
30         
31         
32         $this->meta = array('author' => $this->user->getId(),
33                             'author_id' => $this->user->getAuthenticatedId(),
34                             'mtime' => time());
35         
36         $this->tokens = array();
37         
38         $version = $request->getArg('version');
39         if ($version !== false) {
40             $this->selected = $this->page->getRevision($version);
41             $this->version = $version;
42         }
43         else {
44             $this->version = $this->current->getVersion();
45             $this->selected = $this->page->getRevision($this->version);
46         }
47
48         if ($this->_restoreState()) {
49             $this->_initialEdit = false;
50         }
51         else {
52             $this->_initializeState();
53             $this->_initialEdit = true;
54
55             // The edit request has specified some initial content from a template 
56             if (  ($template = $request->getArg('template'))
57                    and $request->_dbi->isWikiPage($template)) {
58                 $page = $request->_dbi->getPage($template);
59                 $current = $page->getCurrentRevision();
60                 $this->_content = $current->getPackedContent();
61             } elseif ($initial_content = $request->getArg('initial_content')) {
62                 $this->_content = $initial_content;
63                 $this->_redirect_to = $request->getArg('save_and_redirect_to');
64             }
65         }
66         if (!headers_sent())
67             header("Content-Type: text/html; charset=" . $GLOBALS['charset']);
68     }
69
70     function editPage () {
71         global $WikiTheme;
72         $saveFailed = false;
73         $tokens = &$this->tokens;
74         if (isset($this->request->args['pref']['editWidth'])
75             and ($this->request->getPref('editWidth') != $this->request->args['pref']['editWidth'])) {
76             $this->request->_prefs->set('editWidth', $this->request->args['pref']['editWidth']);
77         }
78         if (isset($this->request->args['pref']['editHeight'])
79             and ($this->request->getPref('editHeight') != $this->request->args['pref']['editHeight'])) {
80             $this->request->_prefs->set('editHeight', $this->request->args['pref']['editHeight']);
81         }
82
83         if (! $this->canEdit()) {
84             if ($this->isInitialEdit())
85                 return $this->viewSource();
86             $tokens['PAGE_LOCKED_MESSAGE'] = $this->getLockedMessage();
87         }
88         elseif ($this->request->getArg('save_and_redirect_to') != "") {
89             if ($this->savePage()) {
90                 // noreturn
91                 $this->request->redirect(WikiURL($this->request->getArg('save_and_redirect_to')));
92                 return true;    // Page saved.
93             }
94             $saveFailed = true;
95         }
96         elseif ($this->editaction == 'save') {
97             if ($this->savePage()) {
98                 return true;    // Page saved.
99             }
100             $saveFailed = true;
101         }
102
103         if ($saveFailed and $this->isConcurrentUpdate())
104         {
105             // Get the text of the original page, and the two conflicting edits
106             // The diff3 class takes arrays as input.  So retrieve content as
107             // an array, or convert it as necesary.
108             $orig = $this->page->getRevision($this->_currentVersion);
109             // FIXME: what if _currentVersion has be deleted?
110             $orig_content = $orig->getContent();
111             $this_content = explode("\n", $this->_content);
112             $other_content = $this->current->getContent();
113             include_once("lib/diff3.php");
114             $diff = new diff3($orig_content, $this_content, $other_content);
115             $output = $diff->merged_output(_("Your version"), _("Other version"));
116             // Set the content of the textarea to the merged diff
117             // output, and update the version
118             $this->_content = implode ("\n", $output);
119             $this->_currentVersion = $this->current->getVersion();
120             $this->version = $this->_currentVersion;
121             $unresolved = $diff->ConflictingBlocks;
122             $tokens['CONCURRENT_UPDATE_MESSAGE'] = $this->getConflictMessage($unresolved);
123         } elseif ($saveFailed) {
124             $tokens['CONCURRENT_UPDATE_MESSAGE'] = 
125                 HTML(HTML::h2(_("Some internal editing error")),
126                      HTML::p(_("Your are probably trying to edit/create an invalid version of this page.")),
127                      HTML::p(HTML::em(_("&version=-1 might help."))));
128         }
129
130         if ($this->editaction == 'edit_convert')
131             $tokens['PREVIEW_CONTENT'] = $this->getConvertedPreview();
132         if ($this->editaction == 'preview')
133             $tokens['PREVIEW_CONTENT'] = $this->getPreview(); // FIXME: convert to _MESSAGE?
134
135         // FIXME: NOT_CURRENT_MESSAGE?
136         $tokens = array_merge($tokens, $this->getFormElements());
137
138         if (ENABLE_EDIT_TOOLBAR) {
139             include_once("lib/EditToolbar.php");
140             $toolbar = new EditToolbar();
141             $tokens = array_merge($tokens, $toolbar->getTokens());
142         }
143
144         return $this->output('editpage', _("Edit: %s"));
145     }
146
147     function output ($template, $title_fs) {
148         global $WikiTheme;
149         $selected = &$this->selected;
150         $current = &$this->current;
151
152         if ($selected && $selected->getVersion() != $current->getVersion()) {
153             $rev = $selected;
154             $pagelink = WikiLink($selected);
155         }
156         else {
157             $rev = $current;
158             $pagelink = WikiLink($this->page);
159         }
160
161
162         $title = new FormattedText ($title_fs, $pagelink);
163         if (USE_HTMLAREA and $template == 'editpage') {
164             $WikiTheme->addMoreHeaders(Edit_HtmlArea_Head());
165             //$tokens['PAGE_SOURCE'] = Edit_HtmlArea_ConvertBefore($this->_content);
166         }
167         $template = Template($template, $this->tokens);
168         GeneratePage($template, $title, $rev);
169         return true;
170     }
171
172
173     function viewSource () {
174         assert($this->isInitialEdit());
175         assert($this->selected);
176
177         $this->tokens['PAGE_SOURCE'] = $this->_content;
178         return $this->output('viewsource', _("View Source: %s"));
179     }
180
181     function updateLock() {
182         if ((bool)$this->page->get('locked') == (bool)$this->locked)
183             return false;       // Not changed.
184
185         if (!$this->user->isAdmin()) {
186             // FIXME: some sort of message
187             return false;         // not allowed.
188         }
189
190         $this->page->set('locked', (bool)$this->locked);
191         $this->tokens['LOCK_CHANGED_MSG']
192             = $this->locked ? _("Page now locked.") : _("Page now unlocked.");
193
194         return true;            // lock changed.
195     }
196
197     function savePage () {
198         $request = &$this->request;
199
200         if ($this->isUnchanged()) {
201             // Allow admin lock/unlock even if
202             // no text changes were made.
203             if ($this->updateLock()) {
204                 $dbi = $request->getDbh();
205                 $dbi->touch();
206             }
207             // Save failed. No changes made.
208             $this->_redirectToBrowsePage();
209             // user will probably not see the rest of this...
210             include_once('lib/display.php');
211             // force browse of current version:
212             $request->setArg('version', false);
213             displayPage($request, 'nochanges');
214             return true;
215         }
216
217         if ($this->isSpam()) {
218             return false;
219             /*
220             // Save failed. No changes made.
221             $this->_redirectToBrowsePage();
222             // user will probably not see the rest of this...
223             include_once('lib/display.php');
224             // force browse of current version:
225             $request->setArg('version', false);
226             displayPage($request, 'nochanges');
227             return true;
228             */
229         }
230
231         $page = &$this->page;
232
233         // Include any meta-data from original page version which
234         // has not been explicitly updated.
235         // (Except don't propagate pgsrc_version --- moot for now,
236         //  because at present it never gets into the db...)
237         $meta = $this->selected->getMetaData();
238         unset($meta['pgsrc_version']);
239         $meta = array_merge($meta, $this->meta);
240         
241         // Save new revision
242         $this->_content = $this->getContent();
243         $newrevision = $page->save($this->_content, 
244                                    $this->version == -1 
245                                      ? -1 
246                                      : $this->_currentVersion + 1, 
247                                    // force new?
248                                    $meta);
249         if (!isa($newrevision, 'WikiDB_PageRevision')) {
250             // Save failed.  (Concurrent updates).
251             return false;
252         }
253         
254         // New contents successfully saved...
255         $this->updateLock();
256
257         // Clean out archived versions of this page.
258         include_once('lib/ArchiveCleaner.php');
259         $cleaner = new ArchiveCleaner($GLOBALS['ExpireParams']);
260         $cleaner->cleanPageRevisions($page);
261
262         /* generate notification emails done in WikiDB::save to catch all direct calls 
263           (admin plugins) */
264
265         $dbi = $request->getDbh();
266         $warnings = $dbi->GenericWarnings();
267         $dbi->touch();
268         
269         global $WikiTheme;
270         if (empty($warnings) && ! $WikiTheme->getImageURL('signature')) {
271             // Do redirect to browse page if no signature has
272             // been defined.  In this case, the user will most
273             // likely not see the rest of the HTML we generate
274             // (below).
275             $this->_redirectToBrowsePage();
276         }
277
278         // Force browse of current page version.
279         $request->setArg('version', false);
280         //$request->setArg('action', false);
281
282         $template = Template('savepage', $this->tokens);
283         $template->replace('CONTENT', $newrevision->getTransformedContent());
284         if (!empty($warnings))
285             $template->replace('WARNINGS', $warnings);
286
287         $pagelink = WikiLink($page);
288
289         GeneratePage($template, fmt("Saved: %s", $pagelink), $newrevision);
290         return true;
291     }
292
293     function isConcurrentUpdate () {
294         assert($this->current->getVersion() >= $this->_currentVersion);
295         return $this->current->getVersion() != $this->_currentVersion;
296     }
297
298     function canEdit () {
299         return !$this->page->get('locked') || $this->user->isAdmin();
300     }
301
302     function isInitialEdit () {
303         return $this->_initialEdit;
304     }
305
306     function isUnchanged () {
307         $current = &$this->current;
308
309         if ($this->meta['markup'] !=  $current->get('markup'))
310             return false;
311
312         return $this->_content == $current->getPackedContent();
313     }
314
315     /** 
316      * Handle AntiSpam here. How? http://wikiblacklist.blogspot.com/
317      * Need to check dynamically some blacklist wikipage settings 
318      * (plugin WikiAccessRestrictions) and some static blacklist.
319      * DONE: 
320      *   More then 20 new external links
321      *   content patterns by babycart (only php >= 4.3 for now)
322      * TODO:
323      *   IP blacklist 
324      *   domain blacklist
325      *   url patterns
326      */
327     function isSpam () {
328         $current = &$this->current;
329         $request = &$this->request;
330
331         $oldtext = $current->getPackedContent();
332         $newtext =& $this->_content;
333         // 1. Not more then 20 new external links
334         if ($this->numLinks($newtext) - $this->numLinks($oldtext) >= 20) {
335             // mail the admin?
336             $this->tokens['PAGE_LOCKED_MESSAGE'] = 
337                 HTML($this->getSpamMessage(),
338                      HTML::p(HTML::em(_("Too many external links."))));
339             return true;
340         }
341         // 2. external babycart (SpamAssassin) check
342         // This will probably prevent from discussing sex or viagra related topics. So beware.
343         if (ENABLE_SPAMASSASSIN) {
344             $user = $request->getUser();
345             include_once("lib/spam_babycart.php");
346             if ($babycart = check_babycart($newtext, $request->get("REMOTE_ADDR"), 
347                                            $user->getId())) {
348                 // mail the admin?
349                 if (is_array($babycart))
350                     $this->tokens['PAGE_LOCKED_MESSAGE'] = 
351                         HTML($this->getSpamMessage(),
352                              HTML::p(HTML::em(_("SpamAssassin reports: ", 
353                                                 join("\n", $babycart)))));
354                 return true;
355             }
356         }
357         return false;
358     }
359
360     /** Number of external links in the wikitext
361      */
362     function numLinks(&$text) {
363         return substr_count($text, "http://");
364     }
365
366     /** Header of the Anti Spam message 
367      */
368     function getSpamMessage () {
369         return
370             HTML(HTML::h2(_("Spam Prevention")),
371                  HTML::p(_("This page edit seems to contain spam and was therefore not saved."),
372                          HTML::br(),
373                          _("Sorry for the inconvenience.")),
374                  HTML::p(""));
375     }
376
377     function getPreview () {
378         include_once('lib/PageType.php');
379         $this->_content = $this->getContent();
380         return new TransformedText($this->page, $this->_content, $this->meta);
381     }
382
383     function getConvertedPreview () {
384         include_once('lib/PageType.php');
385         $this->_content = $this->getContent();
386         $this->meta['markup'] = 2.0;
387         $this->_content = ConvertOldMarkup($this->_content);
388         return new TransformedText($this->page, $this->_content, $this->meta);
389     }
390
391     // possibly convert HTMLAREA content back to Wiki markup
392     function getContent () {
393         if (USE_HTMLAREA) {
394             $xml_output = Edit_HtmlArea_ConvertAfter($this->_content);
395             $this->_content = join("", $xml_output->_content);
396             return $this->_content;
397         } else {
398             return $this->_content;
399         }
400     }
401
402     function getLockedMessage () {
403         return
404             HTML(HTML::h2(_("Page Locked")),
405                  HTML::p(_("This page has been locked by the administrator so your changes can not be saved.")),
406                  HTML::p(_("(Copy your changes to the clipboard. You can try editing a different page or save your text in a text editor.)")),
407                  HTML::p(_("Sorry for the inconvenience.")));
408     }
409
410     function getConflictMessage ($unresolved = false) {
411         /*
412          xgettext only knows about c/c++ line-continuation strings
413          it does not know about php's dot operator.
414          We want to translate this entire paragraph as one string, of course.
415          */
416
417         //$re_edit_link = Button('edit', _("Edit the new version"), $this->page);
418
419         if ($unresolved)
420             $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.",
421                                 "<<<<<<< ". _("Your version"),
422                                 ">>>>>>> ". _("Other version")));
423         else
424             $message = HTML::p(_("Please check it through before saving."));
425
426
427
428         /*$steps = HTML::ol(HTML::li(_("Copy your changes to the clipboard or to another temporary place (e.g. text editor).")),
429           HTML::li(fmt("%s of the page. You should now see the most current version of the page. Your changes are no longer there.",
430                        $re_edit_link)),
431           HTML::li(_("Make changes to the file again. Paste your additions from the clipboard (or text editor).")),
432           HTML::li(_("Save your updated changes.")));
433         */
434         return
435             HTML(HTML::h2(_("Conflicting Edits!")),
436                  HTML::p(_("In the time since you started editing this page, another user has saved a new version of it.")),
437                  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.")),
438                  $message);
439     }
440
441
442     function getTextArea () {
443         $request = &$this->request;
444
445         // wrap=virtual is not HTML4, but without it NS4 doesn't wrap
446         // long lines
447         $readonly = ! $this->canEdit(); // || $this->isConcurrentUpdate();
448         if (USE_HTMLAREA) {
449             $html = $this->getPreview();
450             $this->_wikicontent = $this->_content;
451             $this->_content = $html->asXML();
452         }
453
454         /** <textarea wrap="virtual"> is not valid xhtml but Netscape 4 requires it
455          * to wrap long lines.
456          */
457         $textarea = HTML::textarea(array('class' => 'wikiedit',
458                                          'name' => 'edit[content]',
459                                          'id'   => 'edit[content]',
460                                          'rows' => $request->getPref('editHeight'),
461                                          'cols' => $request->getPref('editWidth'),
462                                          'readonly' => (bool) $readonly),
463                                    $this->_content);
464         if (isBrowserNS4())
465             $textarea->setAttr('wrap', 'virtual');
466         if (USE_HTMLAREA)
467             return Edit_HtmlArea_Textarea($textarea,$this->_wikicontent,'edit[content]');
468         else
469             return $textarea;
470     }
471
472     function getFormElements () {
473         global $WikiTheme;
474         $request = &$this->request;
475         $page = &$this->page;
476
477         $h = array('action'   => 'edit',
478                    'pagename' => $page->getName(),
479                    'version'  => $this->version,
480                    'edit[pagetype]' => $this->meta['pagetype'],
481                    'edit[current_version]' => $this->_currentVersion);
482
483         $el['HIDDEN_INPUTS'] = HiddenInputs($h);
484         $el['EDIT_TEXTAREA'] = $this->getTextArea();
485         $el['SUMMARY_INPUT']
486             = HTML::input(array('type'  => 'text',
487                                 'class' => 'wikitext',
488                                 'id' => 'edit[summary]',
489                                 'name'  => 'edit[summary]',
490                                 'size'  => 50,
491                                 'maxlength' => 256,
492                                 'value' => $this->meta['summary']));
493         $el['MINOR_EDIT_CB']
494             = HTML::input(array('type' => 'checkbox',
495                                 'name'  => 'edit[minor_edit]',
496                                 'id' => 'edit[minor_edit]',
497                                 'checked' => (bool) $this->meta['is_minor_edit']));
498         $el['OLD_MARKUP_CB']
499             = HTML::input(array('type' => 'checkbox',
500                                 'name' => 'edit[markup]',
501                                 'value' => 'old',
502                                 'checked' => $this->meta['markup'] < 2.0,
503                                 'id' => 'useOldMarkup',
504                                 'onclick' => 'showOldMarkupRules(this.checked)'));
505         $el['OLD_MARKUP_CONVERT'] = ($this->meta['markup'] < 2.0) 
506             ? Button('submit:edit[edit_convert]', _("Convert"), 'wikiaction') : '';
507         $el['LOCKED_CB']
508             = HTML::input(array('type' => 'checkbox',
509                                 'name' => 'edit[locked]',
510                                 'id'   => 'edit[locked]',
511                                 'disabled' => (bool) !$this->user->isadmin(),
512                                 'checked'  => (bool) $this->locked));
513
514         $el['PREVIEW_B'] = Button('submit:edit[preview]', _("Preview"),
515                                   'wikiaction');
516
517         //if (!$this->isConcurrentUpdate() && $this->canEdit())
518         $el['SAVE_B'] = Button('submit:edit[save]', _("Save"), 'wikiaction');
519
520         $el['IS_CURRENT'] = $this->version == $this->current->getVersion();
521
522         $el['WIDTH_PREF'] = HTML::input(array('type' => 'text',
523                                     'size' => 3,
524                                     'maxlength' => 4,
525                                     'class' => "numeric",
526                                     'name' => 'pref[editWidth]',
527                                     'id'   => 'pref[editWidth]',
528                                     'value' => $request->getPref('editWidth'),
529                                     'onchange' => 'this.form.submit();'));
530         $el['HEIGHT_PREF'] = HTML::input(array('type' => 'text',
531                                      'size' => 3,
532                                      'maxlength' => 4,
533                                      'class' => "numeric",
534                                      'name' => 'pref[editHeight]',
535                                      'id'   => 'pref[editHeight]',
536                                      'value' => $request->getPref('editHeight'),
537                                      'onchange' => 'this.form.submit();'));
538         $el['SEP'] = $WikiTheme->getButtonSeparator();
539         $el['AUTHOR_MESSAGE'] = fmt("Author will be logged as %s.", HTML::em($this->user->getId()));
540         
541         return $el;
542     }
543
544     function _redirectToBrowsePage() {
545         $this->request->redirect(WikiURL($this->page, false, 'absolute_url'));
546     }
547
548     function _restoreState () {
549         $request = &$this->request;
550
551         $posted = $request->getArg('edit');
552         $request->setArg('edit', false);
553
554         if (!$posted || !$request->isPost()
555             || $request->getArg('action') != 'edit')
556             return false;
557
558         if (!isset($posted['content']) || !is_string($posted['content']))
559             return false;
560         $this->_content = preg_replace('/[ \t\r]+\n/', "\n",
561                                         rtrim($posted['content']));
562         $this->_content = $this->getContent();
563
564         $this->_currentVersion = (int) $posted['current_version'];
565
566         if ($this->_currentVersion < 0)
567             return false;
568         if ($this->_currentVersion > $this->current->getVersion())
569             return false;       // FIXME: some kind of warning?
570
571         $is_old_markup = !empty($posted['markup']) && $posted['markup'] == 'old';
572         $meta['markup'] = $is_old_markup ? false : 2.0;
573         $meta['summary'] = trim(substr($posted['summary'], 0, 256));
574         $meta['is_minor_edit'] = !empty($posted['minor_edit']);
575         $meta['pagetype'] = !empty($posted['pagetype']) ? $posted['pagetype'] : false;
576         $this->meta = array_merge($this->meta, $meta);
577         $this->locked = !empty($posted['locked']);
578
579         if (!empty($posted['preview']))
580             $this->editaction = 'preview';
581         elseif (!empty($posted['save']))
582             $this->editaction = 'save';
583         elseif (!empty($posted['edit_convert']))
584             $this->editaction = 'edit_convert';
585         else
586             $this->editaction = 'edit';
587
588         return true;
589     }
590
591     function _initializeState () {
592         $request = &$this->request;
593         $current = &$this->current;
594         $selected = &$this->selected;
595         $user = &$this->user;
596
597         if (!$selected)
598             NoSuchRevision($request, $this->page, $this->version); // noreturn
599
600         $this->_currentVersion = $current->getVersion();
601         $this->_content = $selected->getPackedContent();
602
603         $this->locked = $this->page->get('locked');
604
605         // If author same as previous author, default minor_edit to on.
606         $age = $this->meta['mtime'] - $current->get('mtime');
607         $this->meta['is_minor_edit'] = ( $age < MINOR_EDIT_TIMEOUT
608                                          && $current->get('author') == $user->getId()
609                                          );
610
611         // Default for new pages is new-style markup.
612         if ($selected->hasDefaultContents())
613             $is_new_markup = true;
614         else
615             $is_new_markup = $selected->get('markup') >= 2.0;
616
617         $this->meta['markup'] = $is_new_markup ? 2.0: false;
618         $this->meta['pagetype'] = $selected->get('pagetype');
619         if ($this->meta['pagetype'] == 'wikiblog')
620             $this->meta['summary'] = $selected->get('summary'); // keep blog title
621         else
622             $this->meta['summary'] = '';
623         $this->editaction = 'edit';
624     }
625 }
626
627 class LoadFileConflictPageEditor
628 extends PageEditor
629 {
630     function editPage ($saveFailed = true) {
631         $tokens = &$this->tokens;
632
633         if (!$this->canEdit()) {
634             if ($this->isInitialEdit())
635                 return $this->viewSource();
636             $tokens['PAGE_LOCKED_MESSAGE'] = $this->getLockedMessage();
637         }
638         elseif ($this->editaction == 'save') {
639             if ($this->savePage())
640                 return true;    // Page saved.
641             $saveFailed = true;
642         }
643
644         if ($saveFailed || $this->isConcurrentUpdate())
645         {
646             // Get the text of the original page, and the two conflicting edits
647             // The diff class takes arrays as input.  So retrieve content as
648             // an array, or convert it as necesary.
649             $orig = $this->page->getRevision($this->_currentVersion);
650             $this_content = explode("\n", $this->_content);
651             $other_content = $this->current->getContent();
652             include_once("lib/diff.php");
653             $diff2 = new Diff($other_content, $this_content);
654             $context_lines = max(4, count($other_content) + 1,
655                                  count($this_content) + 1);
656             $fmt = new BlockDiffFormatter($context_lines);
657
658             $this->_content = $fmt->format($diff2);
659             // FIXME: integrate this into class BlockDiffFormatter
660             $this->_content = str_replace(">>>>>>>\n<<<<<<<\n", "=======\n",
661                                           $this->_content);
662             $this->_content = str_replace("<<<<<<<\n>>>>>>>\n", "=======\n",
663                                           $this->_content);
664
665             $this->_currentVersion = $this->current->getVersion();
666             $this->version = $this->_currentVersion;
667             $tokens['CONCURRENT_UPDATE_MESSAGE'] = $this->getConflictMessage();
668         }
669
670         if ($this->editaction == 'edit_convert')
671             $tokens['PREVIEW_CONTENT'] = $this->getConvertedPreview();
672         if ($this->editaction == 'preview')
673             $tokens['PREVIEW_CONTENT'] = $this->getPreview(); // FIXME: convert to _MESSAGE?
674
675         // FIXME: NOT_CURRENT_MESSAGE?
676         $tokens = array_merge($tokens, $this->getFormElements());
677
678         return $this->output('editpage', _("Merge and Edit: %s"));
679         // FIXME: this doesn't display
680     }
681
682     function output ($template, $title_fs) {
683         $selected = &$this->selected;
684         $current = &$this->current;
685
686         if ($selected && $selected->getVersion() != $current->getVersion()) {
687             $rev = $selected;
688             $pagelink = WikiLink($selected);
689         }
690         else {
691             $rev = $current;
692             $pagelink = WikiLink($this->page);
693         }
694
695         $title = new FormattedText ($title_fs, $pagelink);
696         $template = Template($template, $this->tokens);
697
698         //GeneratePage($template, $title, $rev);
699         PrintXML($template);
700         return true;
701     }
702     function getConflictMessage () {
703         $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.",
704                                     "<<<<<<<",
705                                     "======="),
706                                 HTML::p(_("Please check it through before saving."))));
707         return $message;
708     }
709 }
710
711 /**
712  $Log: not supported by cvs2svn $
713  Revision 1.91  2005/01/25 07:05:49  rurban
714  extract toolbar code, support new tags to get rid of php inside templates
715
716  Revision 1.90  2005/01/22 12:46:15  rurban
717  fix oldmakrup button label
718  update pref[edit*] settings
719
720  Revision 1.89  2005/01/21 14:07:49  rurban
721  reformatting
722
723  Revision 1.88  2004/12/17 16:39:03  rurban
724  minor reformatting
725
726  Revision 1.87  2004/12/16 18:28:05  rurban
727  keep wikiblog summary = page title
728
729  Revision 1.86  2004/12/11 14:50:15  rurban
730  new edit_convert button, to get rid of old markup eventually
731
732  Revision 1.85  2004/12/06 19:49:56  rurban
733  enable action=remove which is undoable and seeable in RecentChanges: ADODB ony for now.
734  renamed delete_page to purge_page.
735  enable action=edit&version=-1 to force creation of a new version.
736  added BABYCART_PATH config
737  fixed magiqc in adodb.inc.php
738  and some more docs
739
740  Revision 1.84  2004/12/04 12:58:26  rurban
741  enable babycart Blog::SpamAssassin module on ENABLE_SPAMASSASSIN=true
742  (currently only for php >= 4.3.0)
743
744  Revision 1.83  2004/12/04 11:55:39  rurban
745  First simple AntiSpam prevention:
746    No more than 20 new http:// links allowed
747
748  Revision 1.82  2004/11/30 22:21:56  rurban
749  changed gif to optimized (pngout) png
750
751  Revision 1.81  2004/11/29 17:57:27  rurban
752  translated pulldown buttons
753
754  Revision 1.80  2004/11/25 17:20:51  rurban
755  and again a couple of more native db args: backlinks
756
757  Revision 1.79  2004/11/21 11:59:20  rurban
758  remove final \n to be ob_cache independent
759
760  Revision 1.78  2004/11/16 17:57:45  rurban
761  fix search&replace button
762  use new addTagButton machinery
763  new showPulldown for categories, TODO: in a seperate request
764
765  Revision 1.77  2004/11/15 15:52:35  rurban
766  improve js stability
767
768  Revision 1.76  2004/11/15 15:37:34  rurban
769  fix JS_SEARCHREPLACE
770    don't use document.write for replace, otherwise self.opener is not defined.
771
772  Revision 1.75  2004/09/16 08:00:52  rurban
773  just some comments
774
775  Revision 1.74  2004/07/03 07:36:28  rurban
776  do not get unneccessary content
777
778  Revision 1.73  2004/06/16 21:23:44  rurban
779  fixed non-object fatal #215
780
781  Revision 1.72  2004/06/14 11:31:37  rurban
782  renamed global $Theme to $WikiTheme (gforge nameclash)
783  inherit PageList default options from PageList
784    default sortby=pagename
785  use options in PageList_Selectable (limit, sortby, ...)
786  added action revert, with button at action=diff
787  added option regex to WikiAdminSearchReplace
788
789  Revision 1.71  2004/06/03 18:06:29  rurban
790  fix file locking issues (only needed on write)
791  fixed immediate LANG and THEME in-session updates if not stored in prefs
792  advanced editpage toolbars (search & replace broken)
793
794  Revision 1.70  2004/06/02 20:47:47  rurban
795  dont use the wikiaction class
796
797  Revision 1.69  2004/06/02 10:17:56  rurban
798  integrated search/replace into toolbar
799  added save+preview buttons
800
801  Revision 1.68  2004/06/01 15:28:00  rurban
802  AdminUser only ADMIN_USER not member of Administrators
803  some RateIt improvements by dfrankow
804  edit_toolbar buttons
805
806  Revision _1.6  2004/05/26 15:48:00  syilek
807  fixed problem with creating page with slashes from one true page
808
809  Revision _1.5  2004/05/25 16:51:53  syilek
810  added ability to create a page from the category page and not have to edit it
811
812  Revision 1.67  2004/05/27 17:49:06  rurban
813  renamed DB_Session to DbSession (in CVS also)
814  added WikiDB->getParam and WikiDB->getAuthParam method to get rid of globals
815  remove leading slash in error message
816  added force_unlock parameter to File_Passwd (no return on stale locks)
817  fixed adodb session AffectedRows
818  added FileFinder helpers to unify local filenames and DATA_PATH names
819  editpage.php: new edit toolbar javascript on ENABLE_EDIT_TOOLBAR
820
821  Revision 1.66  2004/04/29 23:25:12  rurban
822  re-ordered locale init (as in 1.3.9)
823  fixed loadfile with subpages, and merge/restore anyway
824    (sf.net bug #844188)
825
826  Revision 1.65  2004/04/18 01:11:52  rurban
827  more numeric pagename fixes.
828  fixed action=upload with merge conflict warnings.
829  charset changed from constant to global (dynamic utf-8 switching)
830
831  Revision 1.64  2004/04/06 19:48:56  rurban
832  temp workaround for action=edit AddComment form
833
834  Revision 1.63  2004/03/24 19:39:02  rurban
835  php5 workaround code (plus some interim debugging code in XmlElement)
836    php5 doesn't work yet with the current XmlElement class constructors,
837    WikiUserNew does work better than php4.
838  rewrote WikiUserNew user upgrading to ease php5 update
839  fixed pref handling in WikiUserNew
840  added Email Notification
841  added simple Email verification
842  removed emailVerify userpref subclass: just a email property
843  changed pref binary storage layout: numarray => hash of non default values
844  print optimize message only if really done.
845  forced new cookie policy: delete pref cookies, use only WIKI_ID as plain string.
846    prefs should be stored in db or homepage, besides the current session.
847
848  Revision 1.62  2004/03/17 18:41:05  rurban
849  initial_content and template support for CreatePage
850
851  Revision 1.61  2004/03/12 20:59:17  rurban
852  important cookie fix by Konstantin Zadorozhny
853  new editpage feature: JS_SEARCHREPLACE
854
855  Revision 1.60  2004/02/15 21:34:37  rurban
856  PageList enhanced and improved.
857  fixed new WikiAdmin... plugins
858  editpage, Theme with exp. htmlarea framework
859    (htmlarea yet committed, this is really questionable)
860  WikiUser... code with better session handling for prefs
861  enhanced UserPreferences (again)
862  RecentChanges for show_deleted: how should pages be deleted then?
863
864  Revision 1.59  2003/12/07 20:35:26  carstenklapp
865  Bugfix: Concurrent updates broken since after 1.3.4 release: Fatal
866  error: Call to undefined function: gettransformedcontent() in
867  /home/groups/p/ph/phpwiki/htdocs/phpwiki2/lib/editpage.php on line
868  205.
869
870  Revision 1.58  2003/03/10 18:25:22  dairiki
871  Bug/typo fix.  If you use the edit page to un/lock a page, it
872  failed with: Fatal error: Call to a member function on a
873  non-object in editpage.php on line 136
874
875  Revision 1.57  2003/02/26 03:40:22  dairiki
876  New action=create.  Essentially the same as action=edit, except that if the
877  page already exists, it falls back to action=browse.
878
879  This is for use in the "question mark" links for unknown wiki words
880  to avoid problems and confusion when following links from stale pages.
881  (If the "unknown page" has been created in the interim, the user probably
882  wants to view the page before editing it.)
883
884  Revision 1.56  2003/02/21 18:07:14  dairiki
885  Minor, nitpicky, currently inconsequential changes.
886
887  Revision 1.55  2003/02/21 04:10:58  dairiki
888  Fixes for new cached markup.
889  Some minor code cleanups.
890
891  Revision 1.54  2003/02/16 19:47:16  dairiki
892  Update WikiDB timestamp when editing or deleting pages.
893
894  Revision 1.53  2003/02/15 23:20:27  dairiki
895  Redirect back to browse current version of page upon save,
896  even when no changes were made.
897
898  Revision 1.52  2003/01/03 22:22:00  carstenklapp
899  Minor adjustments to diff block markers ("<<<<<<<"). Source reformatting.
900
901  Revision 1.51  2003/01/03 02:43:26  carstenklapp
902  New class LoadFileConflictPageEditor, for merging / comparing a loaded
903  pgsrc file with an existing page.
904
905  */
906
907 // Local Variables:
908 // mode: php
909 // tab-width: 8
910 // c-basic-offset: 4
911 // c-hanging-comment-ender-p: nil
912 // indent-tabs-mode: nil
913 // End:
914 ?>