]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/editpage.php
renamed DB_Session to DbSession (in CVS also)
[SourceForge/phpwiki.git] / lib / editpage.php
1 <?php
2 rcs_id('$Id: editpage.php,v 1.67 2004-05-27 17:49:06 rurban Exp $');
3
4 require_once('lib/Template.php');
5
6 // Not yet enabled, since we cannot convert HTML to Wiki Markup yet.
7 // We might use a HTML PageType, which is contra wiki, but some people might prefer HTML markup.
8 // Todo: change from constant to user preference variable. (or checkbox setting)
9 if (!defined('USE_HTMLAREA')) define('USE_HTMLAREA',false);
10 if (USE_HTMLAREA) require_once('lib/htmlarea.php');
11
12 class PageEditor
13 {
14     function PageEditor (&$request) {
15         $this->request = &$request;
16
17         $this->user = $request->getUser();
18         $this->page = $request->getPage();
19
20         $this->current = $this->page->getCurrentRevision();
21
22         // HACKish short circuit to browse on action=create
23         if ($request->getArg('action') == 'create') {
24             if (! $this->current->hasDefaultContents()) 
25                 $request->redirect(WikiURL($this->page->getName())); // noreturn
26         }
27         
28         
29         $this->meta = array('author' => $this->user->getId(),
30                             'author_id' => $this->user->getAuthenticatedId(),
31                             'mtime' => time());
32         
33         $this->tokens = array();
34         
35         $version = $request->getArg('version');
36         if ($version !== false) {
37             $this->selected = $this->page->getRevision($version);
38             $this->version = $version;
39         }
40         else {
41             $this->selected = $this->current;
42             $this->version = $this->current->getVersion();
43         }
44
45         if ($this->_restoreState()) {
46             $this->_initialEdit = false;
47         }
48         else {
49             $this->_initializeState();
50             $this->_initialEdit = true;
51
52             // The edit request has specified some initial content from a template 
53             if (  ($template = $request->getArg('template')) and 
54                   $request->_dbi->isWikiPage($template)) {
55                 $page = $request->_dbi->getPage($template);
56                 $current = $page->getCurrentRevision();
57                 $this->_content = $current->getPackedContent();
58             } elseif ($initial_content = $request->getArg('initial_content')) {
59                 $this->_content = $initial_content;
60             }
61         }
62         if (!headers_sent())
63             header("Content-Type: text/html; charset=" . $GLOBALS['charset']);
64     }
65
66     function editPage () {
67         $saveFailed = false;
68         $tokens = &$this->tokens;
69
70         if (! $this->canEdit()) {
71             if ($this->isInitialEdit())
72                 return $this->viewSource();
73             $tokens['PAGE_LOCKED_MESSAGE'] = $this->getLockedMessage();
74         }
75         elseif ($this->editaction == 'save') {
76             if ($this->savePage())
77                 return true;    // Page saved.
78             $saveFailed = true;
79         }
80
81         if ($saveFailed || $this->isConcurrentUpdate())
82         {
83             // Get the text of the original page, and the two conflicting edits
84             // The diff3 class takes arrays as input.  So retrieve content as
85             // an array, or convert it as necesary.
86             $orig = $this->page->getRevision($this->_currentVersion);
87             // FIXME: what if _currentVersion has be deleted?
88             $orig_content = $orig->getContent();
89             $this_content = explode("\n", $this->_content);
90             $other_content = $this->current->getContent();
91             include_once("lib/diff3.php");
92             $diff = new diff3($orig_content, $this_content, $other_content);
93             $output = $diff->merged_output(_("Your version"), _("Other version"));
94             // Set the content of the textarea to the merged diff
95             // output, and update the version
96             $this->_content = implode ("\n", $output);
97             $this->_currentVersion = $this->current->getVersion();
98             $this->version = $this->_currentVersion;
99             $unresolved = $diff->ConflictingBlocks;
100             $tokens['CONCURRENT_UPDATE_MESSAGE'] = $this->getConflictMessage($unresolved);
101         }
102
103         if ($this->editaction == 'preview')
104             $tokens['PREVIEW_CONTENT'] = $this->getPreview(); // FIXME: convert to _MESSAGE?
105
106         // FIXME: NOT_CURRENT_MESSAGE?
107
108         $tokens = array_merge($tokens, $this->getFormElements());
109
110         if (defined('JS_SEARCHREPLACE') and JS_SEARCHREPLACE) {
111             $tokens['JS_SEARCHREPLACE'] = 1;
112             $GLOBALS['Theme']->addMoreHeaders(Javascript("
113 var wart=0, d, f, x='', replacewin, pretxt=new Array(), pretxt_anzahl=0;
114 var fag='<font face=\"arial,helvetica,sans-serif\" size=\"-1\">', fr='<font color=\"#cc0000\">', spn='<span class=\"grey\">';
115
116 function define_f() {
117    f=document.getElementById('editpage');
118    f.editarea=document.getElementById('edit[content]');
119    if(f.rck.style) f.rck.style.color='#ececec';
120    f.editarea.focus();
121 }
122
123 function replace() {
124    replacewin=window.open('','','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,height=90,width=450');
125    replacewin.window.document.write('<html><head><title>"._("Search & Replace")."</title><style type=\"text/css\"><'+'!'+'-- input.btt {font-family:Tahoma,Verdana,Geneva,sans-serif;font-size:10pt} --'+'></style></head><body bgcolor=\"#dddddd\" onload=\"if(document.forms[0].ein.focus) document.forms[0].ein.focus()\"><form><center><table><tr><td align=\"right\">'+fag+'"._("Search").":</font></td><td align=\"left\"><input type=\"text\" name=\"ein\" size=\"50\" maxlength=\"500\"></td></tr><tr><td align=\"right\">'+fag+' "._("Replace with").":</font></td><td align=\"left\"><input type=\"text\" name=\"aus\" size=\"50\" maxlength=\"500\"></td></tr><tr><td colspan=\"2\" align=\"center\"><input class=\"btt\" type=\"button\" value=\" "._("OK")." \" onclick=\"self.opener.do_replace()\">&nbsp;&nbsp;&nbsp;<input class=\"btt\" type=\"button\" value=\""._("Close")."\" onclick=\"self.close()\"></td></tr></table></center></form></body></html>');
126    replacewin.window.document.close();
127 }
128
129 function do_replace() {
130    var txt=pretxt[pretxt_anzahl]=f.editarea.value, ein=new RegExp(replacewin.document.forms[0].ein.value,'g'), aus=replacewin.document.forms[0].aus.value;
131    if(ein==''||ein==null) {
132       replacewin.window.document.forms[0].ein.focus();
133       return;
134    }
135    var z_repl=txt.match(ein)? txt.match(ein).length : 0;
136    txt=txt.replace(ein,aus);
137    ein=ein.toString().substring(1,ein.toString().length-2);
138    result(z_repl, 'Substring \"'+ein+'\" found '+z_repl+' times. Replace with \"'+aus+'\"?', txt, 'String \"'+ein+'\" not found.');
139    replacewin.window.focus();
140    replacewin.window.document.forms[0].ein.focus();
141 }
142 function result(zahl,frage,txt,alert_txt) {
143    if(wart!=0&&wart.window) {
144       wart.window.close();
145       wart=0;
146    }
147    if(zahl>0) {
148       if(window.confirm(frage)==true) {
149          f.editarea.value=txt;
150          pretxt_anzahl++;
151          if(f.rck.style) f.rck.style.color='#000000';
152          f.rck.value='"._("Undo")."';
153       }
154    } else alert(alert_txt);
155 }
156 function rueck() {
157    if(pretxt_anzahl==0) return;
158    else if(pretxt_anzahl>0) {
159       f.editarea.value=pretxt[pretxt_anzahl-1];
160       pretxt[pretxt_anzahl]=null;
161       pretxt_anzahl--;
162       if(pretxt_anzahl==0) {
163          alert('Operation undone.');
164          if(f.rck.style) f.rck.style.color='#ececec';
165          f.rck.value='("._("Undo").")';
166          if(f.rck.blur) f.rck.blur();
167       }
168    }
169 }
170 function speich() {
171    pretxt[pretxt_anzahl]=f.editarea.value;
172    pretxt_anzahl++;
173    if(f.rck.style) f.rck.style.color='#000000';
174    f.rck.value='"._("Undo")."';
175 }
176 "));
177             $GLOBALS['Theme']->addMoreAttr('body'," onload='define_f()'");
178         } else {
179             $GLOBALS['Theme']->addMoreAttr('body',"document.getElementById('edit[content]').editarea.focus()");
180         }
181         if (defined('ENABLE_EDIT_TOOLBAR') and ENABLE_EDIT_TOOLBAR) {
182             $GLOBALS['Theme']->addMoreHeaders(JavaScript('',array('src'=>$GLOBALS['Theme']->_findData("toolbar.js"))));
183             $tokens['EDIT_TOOLBAR'] = $this->toolbar();
184         } else {
185             $tokens['EDIT_TOOLBAR'] = '';
186         }
187
188         return $this->output('editpage', _("Edit: %s"));
189     }
190
191     function toolbar () {
192         global $Theme;
193         $toolarray = array(
194                            array(
195                                  "image"=>"button_bold.png",
196                                  "open"=>"*",
197                                  "close"=>"*",
198                                  "sample"=>_("bold_sample"),
199                                  "tip"=>_("bold_tip")),
200                            array("image"=>"button_italic.png",
201                                  "open"=>"_",
202                                  "close"=>"_",
203                                  "sample"=>_("italic_sample"),
204                                  "tip"=>_("italic_tip")),
205                            array("image"=>"button_link.png",
206                                  "open"=>"[",
207                                  "close"=>"]",
208                                  "sample"=>_("link_sample"),
209                                  "tip"=>_("link_tip")),
210                            array("image"=>"button_extlink.png",
211                                  "open"=>"[",
212                                  "close"=>"]",
213                                  "sample"=>_("extlink_sample"),
214                                  "tip"=>_("extlink_tip")),
215                            array("image"=>"button_headline.png",
216                                  "open"=>"\\n!!! ",
217                                  "close"=>"\\n",
218                                  "sample"=>_("headline_sample"),
219                                  "tip"=>_("headline_tip")),
220                            array("image"=>"button_image.png",
221                                  "open"=>"[ ",
222                                  "close"=>" ]",
223                                  "sample"=>_("image_sample"),
224                                  "tip"=>_("image_tip")),
225                            array("image"=>"button_nowiki.png",
226                                  "open"=>"\\n\\<verbatim\\>\\n",
227                                  "close"=>"\\n\\</verbatim\\>\\n",
228                                  "sample"=>_("nowiki_sample"),
229                                  "tip"=>_("nowiki_tip")),
230                            array("image"=>"button_sig.png",
231                                  "open" => "--" . $GLOBALS['request']->_user->UserName(),
232                                  "close" => "",
233                                  "sample"=>"",
234                                  "tip"=>_("sig_tip")),
235                            array("image"=>"button_hr.png",
236                                  "open"=>"\\n----\\n",
237                                  "close"=>"",
238                                  "sample"=>"",
239                                  "tip"=>_("hr_tip"))
240                            );
241         $toolbar = "document.writeln(\"<div id=\\\"toolbar\\\">\");\n";
242         foreach ($toolarray as $tool) {
243             $image = $Theme->getImageURL($tool["image"]);
244             $open  = $tool["open"];
245             $close = $tool["close"];
246             $sample = addslashes( $tool["sample"] );
247             // Note that we use the tip both for the ALT tag and the TITLE tag of the image.
248             // Older browsers show a "speedtip" type message only for ALT.
249             // Ideally these should be different, realistically they
250             // probably don't need to be.
251             $tip = addslashes( $tool["tip"] );
252             $toolbar.="addButton('$image','$tip','$open','$close','$sample');\n";
253         }
254         $toolbar.="addInfobox('" . addslashes( _( "infobox" ) ) . "');\n";
255         $toolbar.="document.writeln(\"</div>\");";
256         return Javascript($toolbar);
257     }
258
259     function output ($template, $title_fs) {
260         global $Theme;
261         $selected = &$this->selected;
262         $current = &$this->current;
263
264         if ($selected && $selected->getVersion() != $current->getVersion()) {
265             $rev = $selected;
266             $pagelink = WikiLink($selected);
267         }
268         else {
269             $rev = $current;
270             $pagelink = WikiLink($this->page);
271         }
272
273
274         $title = new FormattedText ($title_fs, $pagelink);
275         if ($template == 'editpage' and USE_HTMLAREA) {
276             $Theme->addMoreHeaders(Edit_HtmlArea_Head());
277             //$tokens['PAGE_SOURCE'] = Edit_HtmlArea_ConvertBefore($this->_content);
278         }
279         $template = Template($template, $this->tokens);
280         GeneratePage($template, $title, $rev);
281         return true;
282     }
283
284
285     function viewSource () {
286         assert($this->isInitialEdit());
287         assert($this->selected);
288
289         $this->tokens['PAGE_SOURCE'] = $this->_content;
290         return $this->output('viewsource', _("View Source: %s"));
291     }
292
293     function updateLock() {
294         if ((bool)$this->page->get('locked') == (bool)$this->locked)
295             return false;       // Not changed.
296
297         if (!$this->user->isAdmin()) {
298             // FIXME: some sort of message
299             return false;         // not allowed.
300         }
301
302         $this->page->set('locked', (bool)$this->locked);
303         $this->tokens['LOCK_CHANGED_MSG']
304             = $this->locked ? _("Page now locked.") : _("Page now unlocked.");
305
306         return true;            // lock changed.
307     }
308
309     function savePage () {
310         $request = &$this->request;
311
312         if ($this->isUnchanged()) {
313             // Allow admin lock/unlock even if
314             // no text changes were made.
315             if ($this->updateLock()) {
316                 $dbi = $request->getDbh();
317                 $dbi->touch();
318             }
319             // Save failed. No changes made.
320             $this->_redirectToBrowsePage();
321             // user will probably not see the rest of this...
322             include_once('lib/display.php');
323             // force browse of current version:
324             $request->setArg('version', false);
325             displayPage($request, 'nochanges');
326             return true;
327         }
328
329         $page = &$this->page;
330
331         // Include any meta-data from original page version which
332         // has not been explicitly updated.
333         // (Except don't propagate pgsrc_version --- moot for now,
334         //  because at present it never gets into the db...)
335         $meta = $this->selected->getMetaData();
336         unset($meta['pgsrc_version']);
337         $meta = array_merge($meta, $this->meta);
338         
339         // Save new revision
340         $this->_content = $this->getContent();
341         $newrevision = $page->save($this->_content, $this->_currentVersion + 1, $meta);
342         if (!isa($newrevision, 'wikidb_pagerevision')) {
343             // Save failed.  (Concurrent updates).
344             return false;
345         }
346         
347         // New contents successfully saved...
348         $this->updateLock();
349
350         // Clean out archived versions of this page.
351         include_once('lib/ArchiveCleaner.php');
352         $cleaner = new ArchiveCleaner($GLOBALS['ExpireParams']);
353         $cleaner->cleanPageRevisions($page);
354
355         /* generate notification emails done in WikiDB::save to catch all direct calls 
356           (admin plugins) */
357
358         $dbi = $request->getDbh();
359         $warnings = $dbi->GenericWarnings();
360         $dbi->touch();
361         
362         global $Theme;
363         if (empty($warnings) && ! $Theme->getImageURL('signature')) {
364             // Do redirect to browse page if no signature has
365             // been defined.  In this case, the user will most
366             // likely not see the rest of the HTML we generate
367             // (below).
368             $this->_redirectToBrowsePage();
369         }
370
371         // Force browse of current page version.
372         $request->setArg('version', false);
373         //$request->setArg('action', false);
374
375         $template = Template('savepage', $this->tokens);
376         $template->replace('CONTENT', $newrevision->getTransformedContent());
377         if (!empty($warnings))
378             $template->replace('WARNINGS', $warnings);
379
380         $pagelink = WikiLink($page);
381
382         GeneratePage($template, fmt("Saved: %s", $pagelink), $newrevision);
383         return true;
384     }
385
386     function isConcurrentUpdate () {
387         assert($this->current->getVersion() >= $this->_currentVersion);
388         return $this->current->getVersion() != $this->_currentVersion;
389     }
390
391     function canEdit () {
392         return !$this->page->get('locked') || $this->user->isAdmin();
393     }
394
395     function isInitialEdit () {
396         return $this->_initialEdit;
397     }
398
399     function isUnchanged () {
400         $current = &$this->current;
401
402         if ($this->meta['markup'] !=  $current->get('markup'))
403             return false;
404
405         return $this->_content == $current->getPackedContent();
406     }
407
408     function getPreview () {
409         include_once('lib/PageType.php');
410         $this->_content = $this->getContent();
411         return new TransformedText($this->page, $this->_content, $this->meta);
412     }
413
414     // possibly convert HTMLAREA content back to Wiki markup
415     function getContent () {
416         if (USE_HTMLAREA) {
417             $xml_output = Edit_HtmlArea_ConvertAfter($this->_content);
418             $this->_content = join("",$xml_output->_content);
419             return $this->_content;
420         } else {
421             return $this->_content;
422         }
423     }
424
425     function getLockedMessage () {
426         return
427             HTML(HTML::h2(_("Page Locked")),
428                  HTML::p(_("This page has been locked by the administrator so your changes can not be saved.")),
429                  HTML::p(_("(Copy your changes to the clipboard. You can try editing a different page or save your text in a text editor.)")),
430                  HTML::p(_("Sorry for the inconvenience.")));
431     }
432
433     function getConflictMessage ($unresolved = false) {
434         /*
435          xgettext only knows about c/c++ line-continuation strings
436          it does not know about php's dot operator.
437          We want to translate this entire paragraph as one string, of course.
438          */
439
440         //$re_edit_link = Button('edit', _("Edit the new version"), $this->page);
441
442         if ($unresolved)
443             $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.",
444                                 "<<<<<<< ". _("Your version"),
445                                 ">>>>>>> ". _("Other version")));
446         else
447             $message = HTML::p(_("Please check it through before saving."));
448
449
450
451         /*$steps = HTML::ol(HTML::li(_("Copy your changes to the clipboard or to another temporary place (e.g. text editor).")),
452           HTML::li(fmt("%s of the page. You should now see the most current version of the page. Your changes are no longer there.",
453                        $re_edit_link)),
454           HTML::li(_("Make changes to the file again. Paste your additions from the clipboard (or text editor).")),
455           HTML::li(_("Save your updated changes.")));
456         */
457         return
458             HTML(HTML::h2(_("Conflicting Edits!")),
459                  HTML::p(_("In the time since you started editing this page, another user has saved a new version of it.")),
460                  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.")),
461                  $message);
462     }
463
464
465     function getTextArea () {
466         $request = &$this->request;
467
468         // wrap=virtual is not HTML4, but without it NS4 doesn't wrap
469         // long lines
470         $readonly = ! $this->canEdit(); // || $this->isConcurrentUpdate();
471         if (USE_HTMLAREA) {
472             $html = $this->getPreview();
473             $this->_wikicontent = $this->_content;
474             $this->_content = $html->asXML();
475         }
476         $textarea = HTML::textarea(array('class' => 'wikiedit',
477                                          'name' => 'edit[content]',
478                                          'id'   => 'edit[content]',
479                                          'rows' => $request->getPref('editHeight'),
480                                          'cols' => $request->getPref('editWidth'),
481                                          'readonly' => (bool) $readonly,
482                                          'wrap' => 'virtual'),
483                                    $this->_content);
484         if (USE_HTMLAREA)
485             return Edit_HtmlArea_Textarea($textarea,$this->_wikicontent,'edit[content]');
486         else
487             return $textarea;
488     }
489
490     function getFormElements () {
491         $request = &$this->request;
492         $page = &$this->page;
493
494
495         $h = array('action'   => 'edit',
496                    'pagename' => $page->getName(),
497                    'version'  => $this->version,
498                    'edit[pagetype]' => $this->meta['pagetype'],
499                    'edit[current_version]' => $this->_currentVersion);
500
501         $el['HIDDEN_INPUTS'] = HiddenInputs($h);
502
503
504         $el['EDIT_TEXTAREA'] = $this->getTextArea();
505
506         $el['SUMMARY_INPUT']
507             = HTML::input(array('type'  => 'text',
508                                 'class' => 'wikitext',
509                                 'name'  => 'edit[summary]',
510                                 'size'  => 50,
511                                 'maxlength' => 256,
512                                 'value' => $this->meta['summary']));
513         $el['MINOR_EDIT_CB']
514             = HTML::input(array('type' => 'checkbox',
515                                 'name'  => 'edit[minor_edit]',
516                                 'checked' => (bool) $this->meta['is_minor_edit']));
517         $el['OLD_MARKUP_CB']
518             = HTML::input(array('type' => 'checkbox',
519                                 'name' => 'edit[markup]',
520                                 'value' => 'old',
521                                 'checked' => $this->meta['markup'] < 2.0,
522                                 'id' => 'useOldMarkup',
523                                 'onclick' => 'showOldMarkupRules(this.checked)'));
524
525         $el['LOCKED_CB']
526             = HTML::input(array('type' => 'checkbox',
527                                 'name' => 'edit[locked]',
528                                 'disabled' => (bool) !$this->user->isadmin(),
529                                 'checked'  => (bool) $this->locked));
530
531         $el['PREVIEW_B'] = Button('submit:edit[preview]', _("Preview"),
532                                   'wikiaction');
533
534         //if (!$this->isConcurrentUpdate() && $this->canEdit())
535         $el['SAVE_B'] = Button('submit:edit[save]', _("Save"), 'wikiaction');
536
537         $el['IS_CURRENT'] = $this->version == $this->current->getVersion();
538
539         return $el;
540     }
541
542     function _redirectToBrowsePage() {
543         $this->request->redirect(WikiURL($this->page, false, 'absolute_url'));
544     }
545     
546
547     function _restoreState () {
548         $request = &$this->request;
549
550         $posted = $request->getArg('edit');
551         $request->setArg('edit', false);
552
553         if (!$posted || !$request->isPost()
554             || $request->getArg('action') != 'edit')
555             return false;
556
557         if (!isset($posted['content']) || !is_string($posted['content']))
558             return false;
559         $this->_content = preg_replace('/[ \t\r]+\n/', "\n",
560                                         rtrim($posted['content']));
561         $this->_content = $this->getContent();
562
563         $this->_currentVersion = (int) $posted['current_version'];
564
565         if ($this->_currentVersion < 0)
566             return false;
567         if ($this->_currentVersion > $this->current->getVersion())
568             return false;       // FIXME: some kind of warning?
569
570         $is_old_markup = !empty($posted['markup']) && $posted['markup'] == 'old';
571         $meta['markup'] = $is_old_markup ? false : 2.0;
572         $meta['summary'] = trim(substr($posted['summary'], 0, 256));
573         $meta['is_minor_edit'] = !empty($posted['minor_edit']);
574         $meta['pagetype'] = !empty($posted['pagetype']) ? $posted['pagetype'] : false;
575         $this->meta = array_merge($this->meta, $meta);
576         $this->locked = !empty($posted['locked']);
577
578         if (!empty($posted['preview']))
579             $this->editaction = 'preview';
580         elseif (!empty($posted['save']))
581             $this->editaction = 'save';
582         else
583             $this->editaction = 'edit';
584
585         return true;
586     }
587
588     function _initializeState () {
589         $request = &$this->request;
590         $current = &$this->current;
591         $selected = &$this->selected;
592         $user = &$this->user;
593
594         if (!$selected)
595             NoSuchRevision($request, $this->page, $this->version); // noreturn
596
597         $this->_currentVersion = $current->getVersion();
598         $this->_content = $selected->getPackedContent();
599
600         $this->meta['summary'] = '';
601         $this->locked = $this->page->get('locked');
602
603         // If author same as previous author, default minor_edit to on.
604         $age = $this->meta['mtime'] - $current->get('mtime');
605         $this->meta['is_minor_edit'] = ( $age < MINOR_EDIT_TIMEOUT
606                                          && $current->get('author') == $user->getId()
607                                          );
608
609         // Default for new pages is new-style markup.
610         if ($selected->hasDefaultContents())
611             $is_new_markup = true;
612         else
613             $is_new_markup = $selected->get('markup') >= 2.0;
614
615         $this->meta['markup'] = $is_new_markup ? 2.0: false;
616         $this->meta['pagetype'] = $selected->get('pagetype');
617         $this->editaction = 'edit';
618     }
619 }
620
621 class LoadFileConflictPageEditor
622 extends PageEditor
623 {
624     function editPage ($saveFailed = true) {
625         $tokens = &$this->tokens;
626
627         if (!$this->canEdit()) {
628             if ($this->isInitialEdit())
629                 return $this->viewSource();
630             $tokens['PAGE_LOCKED_MESSAGE'] = $this->getLockedMessage();
631         }
632         elseif ($this->editaction == 'save') {
633             if ($this->savePage())
634                 return true;    // Page saved.
635             $saveFailed = true;
636         }
637
638         if ($saveFailed || $this->isConcurrentUpdate())
639         {
640             // Get the text of the original page, and the two conflicting edits
641             // The diff class takes arrays as input.  So retrieve content as
642             // an array, or convert it as necesary.
643             $orig = $this->page->getRevision($this->_currentVersion);
644             $this_content = explode("\n", $this->_content);
645             $other_content = $this->current->getContent();
646             include_once("lib/diff.php");
647             $diff2 = new Diff($other_content, $this_content);
648             $context_lines = max(4, count($other_content) + 1,
649                                  count($this_content) + 1);
650             $fmt = new BlockDiffFormatter($context_lines);
651
652             $this->_content = $fmt->format($diff2);
653             // FIXME: integrate this into class BlockDiffFormatter
654             $this->_content = str_replace(">>>>>>>\n<<<<<<<\n", "=======\n",
655                                           $this->_content);
656             $this->_content = str_replace("<<<<<<<\n>>>>>>>\n", "=======\n",
657                                           $this->_content);
658
659             $this->_currentVersion = $this->current->getVersion();
660             $this->version = $this->_currentVersion;
661             $tokens['CONCURRENT_UPDATE_MESSAGE'] = $this->getConflictMessage();
662         }
663
664         if ($this->editaction == 'preview')
665             $tokens['PREVIEW_CONTENT'] = $this->getPreview(); // FIXME: convert to _MESSAGE?
666
667         // FIXME: NOT_CURRENT_MESSAGE?
668
669         $tokens = array_merge($tokens, $this->getFormElements());
670
671         return $this->output('editpage', _("Merge and Edit: %s"));
672         // FIXME: this doesn't display
673     }
674
675     function output ($template, $title_fs) {
676         $selected = &$this->selected;
677         $current = &$this->current;
678
679         if ($selected && $selected->getVersion() != $current->getVersion()) {
680             $rev = $selected;
681             $pagelink = WikiLink($selected);
682         }
683         else {
684             $rev = $current;
685             $pagelink = WikiLink($this->page);
686         }
687
688         $title = new FormattedText ($title_fs, $pagelink);
689         $template = Template($template, $this->tokens);
690
691         //GeneratePage($template, $title, $rev);
692         PrintXML($template);
693         return true;
694     }
695     function getConflictMessage () {
696         $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.",
697                                     "<<<<<<<",
698                                     "======="),
699                                 HTML::p(_("Please check it through before saving."))));
700         return $message;
701     }
702 }
703
704 /**
705  $Log: not supported by cvs2svn $
706  Revision 1.66  2004/04/29 23:25:12  rurban
707  re-ordered locale init (as in 1.3.9)
708  fixed loadfile with subpages, and merge/restore anyway
709    (sf.net bug #844188)
710
711  Revision 1.65  2004/04/18 01:11:52  rurban
712  more numeric pagename fixes.
713  fixed action=upload with merge conflict warnings.
714  charset changed from constant to global (dynamic utf-8 switching)
715
716  Revision 1.64  2004/04/06 19:48:56  rurban
717  temp workaround for action=edit AddComment form
718
719  Revision 1.63  2004/03/24 19:39:02  rurban
720  php5 workaround code (plus some interim debugging code in XmlElement)
721    php5 doesn't work yet with the current XmlElement class constructors,
722    WikiUserNew does work better than php4.
723  rewrote WikiUserNew user upgrading to ease php5 update
724  fixed pref handling in WikiUserNew
725  added Email Notification
726  added simple Email verification
727  removed emailVerify userpref subclass: just a email property
728  changed pref binary storage layout: numarray => hash of non default values
729  print optimize message only if really done.
730  forced new cookie policy: delete pref cookies, use only WIKI_ID as plain string.
731    prefs should be stored in db or homepage, besides the current session.
732
733  Revision 1.62  2004/03/17 18:41:05  rurban
734  initial_content and template support for CreatePage
735
736  Revision 1.61  2004/03/12 20:59:17  rurban
737  important cookie fix by Konstantin Zadorozhny
738  new editpage feature: JS_SEARCHREPLACE
739
740  Revision 1.60  2004/02/15 21:34:37  rurban
741  PageList enhanced and improved.
742  fixed new WikiAdmin... plugins
743  editpage, Theme with exp. htmlarea framework
744    (htmlarea yet committed, this is really questionable)
745  WikiUser... code with better session handling for prefs
746  enhanced UserPreferences (again)
747  RecentChanges for show_deleted: how should pages be deleted then?
748
749  Revision 1.59  2003/12/07 20:35:26  carstenklapp
750  Bugfix: Concurrent updates broken since after 1.3.4 release: Fatal
751  error: Call to undefined function: gettransformedcontent() in
752  /home/groups/p/ph/phpwiki/htdocs/phpwiki2/lib/editpage.php on line
753  205.
754
755  Revision 1.58  2003/03/10 18:25:22  dairiki
756  Bug/typo fix.  If you use the edit page to un/lock a page, it
757  failed with: Fatal error: Call to a member function on a
758  non-object in editpage.php on line 136
759
760  Revision 1.57  2003/02/26 03:40:22  dairiki
761  New action=create.  Essentially the same as action=edit, except that if the
762  page already exists, it falls back to action=browse.
763
764  This is for use in the "question mark" links for unknown wiki words
765  to avoid problems and confusion when following links from stale pages.
766  (If the "unknown page" has been created in the interim, the user probably
767  wants to view the page before editing it.)
768
769  Revision 1.56  2003/02/21 18:07:14  dairiki
770  Minor, nitpicky, currently inconsequential changes.
771
772  Revision 1.55  2003/02/21 04:10:58  dairiki
773  Fixes for new cached markup.
774  Some minor code cleanups.
775
776  Revision 1.54  2003/02/16 19:47:16  dairiki
777  Update WikiDB timestamp when editing or deleting pages.
778
779  Revision 1.53  2003/02/15 23:20:27  dairiki
780  Redirect back to browse current version of page upon save,
781  even when no changes were made.
782
783  Revision 1.52  2003/01/03 22:22:00  carstenklapp
784  Minor adjustments to diff block markers ("<<<<<<<"). Source reformatting.
785
786  Revision 1.51  2003/01/03 02:43:26  carstenklapp
787  New class LoadFileConflictPageEditor, for merging / comparing a loaded
788  pgsrc file with an existing page.
789
790  */
791
792 // Local Variables:
793 // mode: php
794 // tab-width: 8
795 // c-basic-offset: 4
796 // c-hanging-comment-ender-p: nil
797 // indent-tabs-mode: nil
798 // End:
799 ?>