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