2 rcs_id('$Id: editpage.php,v 1.78 2004-11-16 17:57:45 rurban Exp $');
4 require_once('lib/Template.php');
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');
17 function PageEditor (&$request) {
18 $this->request = &$request;
20 $this->user = $request->getUser();
21 $this->page = $request->getPage();
23 $this->current = $this->page->getCurrentRevision(false);
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
32 $this->meta = array('author' => $this->user->getId(),
33 'author_id' => $this->user->getAuthenticatedId(),
36 $this->tokens = array();
38 $version = $request->getArg('version');
39 if ($version !== false) {
40 $this->selected = $this->page->getRevision($version);
41 $this->version = $version;
44 $this->version = $this->current->getVersion();
45 $this->selected = $this->page->getRevision($this->version);
48 if ($this->_restoreState()) {
49 $this->_initialEdit = false;
52 $this->_initializeState();
53 $this->_initialEdit = true;
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');
67 header("Content-Type: text/html; charset=" . $GLOBALS['charset']);
70 function editPage () {
73 $tokens = &$this->tokens;
75 if (! $this->canEdit()) {
76 if ($this->isInitialEdit())
77 return $this->viewSource();
78 $tokens['PAGE_LOCKED_MESSAGE'] = $this->getLockedMessage();
80 elseif ($this->request->getArg('save_and_redirect_to') != "") {
81 if ($this->savePage()) {
83 $this->request->redirect(WikiURL($this->request->getArg('save_and_redirect_to')));
84 return true; // Page saved.
88 elseif ($this->editaction == 'save') {
89 if ($this->savePage()) {
90 return true; // Page saved.
95 if ($saveFailed || $this->isConcurrentUpdate())
97 // Get the text of the original page, and the two conflicting edits
98 // The diff3 class takes arrays as input. So retrieve content as
99 // an array, or convert it as necesary.
100 $orig = $this->page->getRevision($this->_currentVersion);
101 // FIXME: what if _currentVersion has be deleted?
102 $orig_content = $orig->getContent();
103 $this_content = explode("\n", $this->_content);
104 $other_content = $this->current->getContent();
105 include_once("lib/diff3.php");
106 $diff = new diff3($orig_content, $this_content, $other_content);
107 $output = $diff->merged_output(_("Your version"), _("Other version"));
108 // Set the content of the textarea to the merged diff
109 // output, and update the version
110 $this->_content = implode ("\n", $output);
111 $this->_currentVersion = $this->current->getVersion();
112 $this->version = $this->_currentVersion;
113 $unresolved = $diff->ConflictingBlocks;
114 $tokens['CONCURRENT_UPDATE_MESSAGE'] = $this->getConflictMessage($unresolved);
117 if ($this->editaction == 'preview')
118 $tokens['PREVIEW_CONTENT'] = $this->getPreview(); // FIXME: convert to _MESSAGE?
120 // FIXME: NOT_CURRENT_MESSAGE?
121 $tokens = array_merge($tokens, $this->getFormElements());
123 //FIXME: enable Undo button for all other buttons also, not only the search/replace button
124 if (defined('JS_SEARCHREPLACE') and JS_SEARCHREPLACE) {
125 $tokens['JS_SEARCHREPLACE'] = 1;
126 $undo_btn = $WikiTheme->getImageURL("ed_undo.gif");
127 $undo_d_btn = $WikiTheme->getImageURL("ed_undo_d.gif");
128 // JS_SEARCHREPLACE from walterzorn.de
129 $WikiTheme->addMoreHeaders(Javascript("
130 var f, sr_undo, replacewin, undo_buffer=new Array(), undo_buffer_index=0;
132 function define_f() {
133 f=document.getElementById('editpage');
134 f.editarea=document.getElementById('edit[content]');
135 sr_undo=document.getElementById('sr_undo');
139 function undo_enable(bool) {
141 sr_undo.src='".$undo_btn."';
145 sr_undo.disabled = false;
147 sr_undo.src='".$undo_d_btn."';
151 sr_undo.disabled = true;
152 if(sr_undo.blur) sr_undo.blur();
156 replacewin = window.open('','','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,height=90,width=450');
157 replacewin.window.document.write('<html><head><title>"
158 ._("Search & Replace")
159 ."</title><style type=\"text/css\"><'+'!'+'-- body, input {font-family:Tahoma,Arial,Helvetica,sans-serif;font-size:10pt;font-weight:bold;} td {font-size:9pt} --'+'></style></head><body bgcolor=\"#dddddd\" onload=\"if(document.forms[0].ein.focus) document.forms[0].ein.focus(); return false;\"><form><center><table><tr><td align=\"right\">'+'"
161 .":</td><td align=\"left\"><input type=\"text\" name=\"ein\" size=\"45\" maxlength=\"500\"></td></tr><tr><td align=\"right\">'+' "
163 .":</td><td align=\"left\"><input type=\"text\" name=\"aus\" size=\"45\" maxlength=\"500\"></td></tr><tr><td colspan=\"2\" align=\"center\"><input type=\"button\" value=\" "
165 ." \" onclick=\"if(self.opener)self.opener.do_replace(); return false;\"> <input type=\"button\" value=\""
167 ."\" onclick=\"self.close(); return false;\"></td></tr></table></center></form></body></html>');
168 replacewin.window.document.close();
171 function do_replace() {
172 var txt=undo_buffer[undo_buffer_index]=f.editarea.value, ein=new RegExp(replacewin.document.forms[0].ein.value,'g'), aus=replacewin.document.forms[0].aus.value;
173 if (ein==''||ein==null) {
174 if (replacewin) replacewin.window.document.forms[0].ein.focus();
177 var z_repl=txt.match(ein)? txt.match(ein).length : 0;
178 txt=txt.replace(ein,aus);
179 ein=ein.toString().substring(1,ein.toString().length-2);
180 result(z_repl, 'Substring \"'+ein+'\" found '+z_repl+' times. Replace with \"'+aus+'\"?', txt, 'String \"'+ein+'\" not found.');
181 replacewin.window.focus();
182 replacewin.window.document.forms[0].ein.focus();
185 function result(zahl,frage,txt,alert_txt) {
187 if(window.confirm(frage)==true) {
188 f.editarea.value=txt;
192 } else alert(alert_txt);
195 if(undo_buffer_index==0) return;
196 else if(undo_buffer_index>0) {
197 f.editarea.value=undo_buffer[undo_buffer_index-1];
198 undo_buffer[undo_buffer_index]=null;
200 if(undo_buffer_index==0) {
202 _("Operation undone")
208 //save a snapshot in the undo buffer (unused)
209 function undo_save() {
210 undo_buffer[undo_buffer_index]=f.editarea.value;
215 $WikiTheme->addMoreAttr('body'," onload='define_f()'");
217 $WikiTheme->addMoreAttr('body',"document.getElementById('edit[content]').editarea.focus()");
219 if (defined('ENABLE_EDIT_TOOLBAR') and ENABLE_EDIT_TOOLBAR) {
220 $WikiTheme->addMoreHeaders(JavaScript('',array('src' => $WikiTheme->_findData("toolbar.js"))));
221 $tokens['EDIT_TOOLBAR'] = $this->toolbar();
223 $tokens['EDIT_TOOLBAR'] = '';
226 return $this->output('editpage', _("Edit: %s"));
229 function toolbar () {
233 "image"=>"ed_format_bold.gif",
236 "sample"=>_("Bold text"),
237 "tip"=>_("Bold text")),
238 array("image"=>"ed_format_italic.gif",
241 "sample"=>_("Italic text"),
242 "tip"=>_("Italic text")),
243 array("image"=>"ed_pagelink.gif",
246 "sample"=>_("optional label | PageName"),
247 "tip"=>_("Link to page")),
248 array("image"=>"ed_link.gif",
251 "sample"=>_("optional label | http://www.example.com"),
252 "tip"=>_("External link (remember http:// prefix)")),
253 array("image"=>"ed_headline.gif",
256 "sample"=>_("Headline text"),
257 "tip"=>_("Level 1 headline")),
258 array("image"=>"ed_image.gif",
261 "sample"=>_("Example.jpg"),
262 "tip"=>_("Embedded image")),
263 array("image"=>"ed_nowiki.gif",
264 "open"=>"\\n\\<verbatim\\>\\n",
265 "close"=>"\\n\\</verbatim\\>\\n",
266 "sample"=>_("Insert non-formatted text here"),
267 "tip"=>_("Ignore wiki formatting")),
268 array("image"=>"ed_sig.gif",
269 "open" => " --" . $GLOBALS['request']->_user->UserName(),
272 "tip"=>_("Your signature")),
273 array("image"=>"ed_hr.gif",
274 "open"=>"\\n----\\n",
277 "tip"=>_("Horizontal line"))
279 $toolbar = "document.writeln(\"<div class=\\\"edit-toolbar\\\" id=\\\"toolbar\\\">\");\n";
281 $btn = new SubmitImageButton(_("Save"), "edit[save]", 'toolbar', $WikiTheme->getImageURL("ed_save.gif"));
282 $btn->addTooltip(_("Save"));
283 $toolbar.='document.writeln("'.addslashes($btn->asXml()).'");'."\n";
284 $btn = new SubmitImageButton(_("Preview"), "edit[preview]", 'toolbar', $WikiTheme->getImageURL("ed_preview.gif"));
285 $btn->addTooltip(_("Preview"));
286 $toolbar.='document.writeln("'.addslashes($btn->asXml()).'");'."\n";
288 foreach ($toolarray as $tool) {
289 $image = $WikiTheme->getImageURL($tool["image"]);
290 $open = $tool["open"];
291 $close = $tool["close"];
292 $sample = addslashes( $tool["sample"] );
293 // Note that we use the tip both for the ALT tag and the TITLE tag of the image.
294 // Older browsers show a "speedtip" type message only for ALT.
295 // Ideally these should be different, realistically they
296 // probably don't need to be.
297 $tip = addslashes( $tool["tip"] );
298 $toolbar.="addTagButton('$image','$tip','$open','$close','$sample');\n";
300 $toolbar.="addInfobox('" . addslashes( _("Click a button to get an example text") ) . "');\n";
302 if (JS_SEARCHREPLACE) {
303 $undo_d_btn = $WikiTheme->getImageURL("ed_undo_d.gif");
304 //$redo_btn = $WikiTheme->getImageURL("ed_redo.gif");
305 $sr_btn = $WikiTheme->getImageURL("ed_replace.gif");
306 $sr_html = HTML(HTML::img(array('class'=>"toolbar",
309 'title'=>_("Undo Search & Replace"),
310 'alt' =>_("Undo Search & Replace"),
311 'disabled'=>"disabled",
313 'onfocus' =>"if(this.blur && undo_buffer_index==0) this.blur()",
314 'onclick' =>"do_undo()")),
315 HTML::img(array('class'=>"toolbar",
317 'alt' =>_("Search & Replace"),
318 'title'=>_("Search & Replace"),
319 'onclick'=>"replace()")));
324 // Button to generate pagenames, display in extra window as pulldown and insert
325 // Button to generate plugins, display in extra window as pulldown and insert
326 // Button to generate categories, display in extra window as pulldown and insert
327 if (DEBUG and JS_SEARCHREPLACE) {
328 //TODO: delegate this calculation to a seperate pulldown action request
329 require_once('lib/TextSearchQuery.php');
330 $dbi =& $GLOBALS['request']->_dbi;
331 $pages = $dbi->titleSearch(new TextSearchQuery(''._("Category").' OR '._("Topic").''));
332 if ($pages->count()) {
333 $categories = array();
334 while ($p = $pages->next()){
335 $categories[] = $p->getName();
337 $more_buttons = HTML::img(array('class'=>"toolbar",
338 'src' => $WikiTheme->getImageURL("ed_category.gif"),
339 'title'=>_("Categories"),
340 'onclick'=>"showPulldown('".
342 ."',['".join("','",$categories)."'])"));
343 if ($sr_html) $sr_html = HTML($sr_html, $more_buttons);
344 else $sr_html = $more_buttons;
347 $toolbar_end = "document.writeln(\"</div>\");";
348 // don't use document.write for replace, otherwise self.opener is not defined.
350 return HTML(Javascript($toolbar),
352 Javascript($toolbar_end));
354 return HTML(Javascript($toolbar . $toolbar_end));
357 function output ($template, $title_fs) {
359 $selected = &$this->selected;
360 $current = &$this->current;
362 if ($selected && $selected->getVersion() != $current->getVersion()) {
364 $pagelink = WikiLink($selected);
368 $pagelink = WikiLink($this->page);
372 $title = new FormattedText ($title_fs, $pagelink);
373 if (USE_HTMLAREA and $template == 'editpage') {
374 $WikiTheme->addMoreHeaders(Edit_HtmlArea_Head());
375 //$tokens['PAGE_SOURCE'] = Edit_HtmlArea_ConvertBefore($this->_content);
377 $template = Template($template, $this->tokens);
378 GeneratePage($template, $title, $rev);
383 function viewSource () {
384 assert($this->isInitialEdit());
385 assert($this->selected);
387 $this->tokens['PAGE_SOURCE'] = $this->_content;
388 return $this->output('viewsource', _("View Source: %s"));
391 function updateLock() {
392 if ((bool)$this->page->get('locked') == (bool)$this->locked)
393 return false; // Not changed.
395 if (!$this->user->isAdmin()) {
396 // FIXME: some sort of message
397 return false; // not allowed.
400 $this->page->set('locked', (bool)$this->locked);
401 $this->tokens['LOCK_CHANGED_MSG']
402 = $this->locked ? _("Page now locked.") : _("Page now unlocked.");
404 return true; // lock changed.
407 function savePage () {
408 $request = &$this->request;
410 if ($this->isUnchanged()) {
411 // Allow admin lock/unlock even if
412 // no text changes were made.
413 if ($this->updateLock()) {
414 $dbi = $request->getDbh();
417 // Save failed. No changes made.
418 $this->_redirectToBrowsePage();
419 // user will probably not see the rest of this...
420 include_once('lib/display.php');
421 // force browse of current version:
422 $request->setArg('version', false);
423 displayPage($request, 'nochanges');
427 $page = &$this->page;
429 // Include any meta-data from original page version which
430 // has not been explicitly updated.
431 // (Except don't propagate pgsrc_version --- moot for now,
432 // because at present it never gets into the db...)
433 $meta = $this->selected->getMetaData();
434 unset($meta['pgsrc_version']);
435 $meta = array_merge($meta, $this->meta);
438 $this->_content = $this->getContent();
439 $newrevision = $page->save($this->_content, $this->_currentVersion + 1, $meta);
440 if (!isa($newrevision, 'wikidb_pagerevision')) {
441 // Save failed. (Concurrent updates).
445 // New contents successfully saved...
448 // Clean out archived versions of this page.
449 include_once('lib/ArchiveCleaner.php');
450 $cleaner = new ArchiveCleaner($GLOBALS['ExpireParams']);
451 $cleaner->cleanPageRevisions($page);
453 /* generate notification emails done in WikiDB::save to catch all direct calls
456 $dbi = $request->getDbh();
457 $warnings = $dbi->GenericWarnings();
461 if (empty($warnings) && ! $WikiTheme->getImageURL('signature')) {
462 // Do redirect to browse page if no signature has
463 // been defined. In this case, the user will most
464 // likely not see the rest of the HTML we generate
466 $this->_redirectToBrowsePage();
469 // Force browse of current page version.
470 $request->setArg('version', false);
471 //$request->setArg('action', false);
473 $template = Template('savepage', $this->tokens);
474 $template->replace('CONTENT', $newrevision->getTransformedContent());
475 if (!empty($warnings))
476 $template->replace('WARNINGS', $warnings);
478 $pagelink = WikiLink($page);
480 GeneratePage($template, fmt("Saved: %s", $pagelink), $newrevision);
484 function isConcurrentUpdate () {
485 assert($this->current->getVersion() >= $this->_currentVersion);
486 return $this->current->getVersion() != $this->_currentVersion;
489 function canEdit () {
490 return !$this->page->get('locked') || $this->user->isAdmin();
493 function isInitialEdit () {
494 return $this->_initialEdit;
497 function isUnchanged () {
498 $current = &$this->current;
500 if ($this->meta['markup'] != $current->get('markup'))
503 return $this->_content == $current->getPackedContent();
506 function getPreview () {
507 include_once('lib/PageType.php');
508 $this->_content = $this->getContent();
509 return new TransformedText($this->page, $this->_content, $this->meta);
512 // possibly convert HTMLAREA content back to Wiki markup
513 function getContent () {
515 $xml_output = Edit_HtmlArea_ConvertAfter($this->_content);
516 $this->_content = join("",$xml_output->_content);
517 return $this->_content;
519 return $this->_content;
523 function getLockedMessage () {
525 HTML(HTML::h2(_("Page Locked")),
526 HTML::p(_("This page has been locked by the administrator so your changes can not be saved.")),
527 HTML::p(_("(Copy your changes to the clipboard. You can try editing a different page or save your text in a text editor.)")),
528 HTML::p(_("Sorry for the inconvenience.")));
531 function getConflictMessage ($unresolved = false) {
533 xgettext only knows about c/c++ line-continuation strings
534 it does not know about php's dot operator.
535 We want to translate this entire paragraph as one string, of course.
538 //$re_edit_link = Button('edit', _("Edit the new version"), $this->page);
541 $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.",
542 "<<<<<<< ". _("Your version"),
543 ">>>>>>> ". _("Other version")));
545 $message = HTML::p(_("Please check it through before saving."));
549 /*$steps = HTML::ol(HTML::li(_("Copy your changes to the clipboard or to another temporary place (e.g. text editor).")),
550 HTML::li(fmt("%s of the page. You should now see the most current version of the page. Your changes are no longer there.",
552 HTML::li(_("Make changes to the file again. Paste your additions from the clipboard (or text editor).")),
553 HTML::li(_("Save your updated changes.")));
556 HTML(HTML::h2(_("Conflicting Edits!")),
557 HTML::p(_("In the time since you started editing this page, another user has saved a new version of it.")),
558 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.")),
563 function getTextArea () {
564 $request = &$this->request;
566 // wrap=virtual is not HTML4, but without it NS4 doesn't wrap
568 $readonly = ! $this->canEdit(); // || $this->isConcurrentUpdate();
570 $html = $this->getPreview();
571 $this->_wikicontent = $this->_content;
572 $this->_content = $html->asXML();
575 /** <textarea wrap="virtual"> is not valid xhtml but Netscape 4 requires it
576 * to wrap long lines.
578 $textarea = HTML::textarea(array('class' => 'wikiedit',
579 'name' => 'edit[content]',
580 'id' => 'edit[content]',
581 'rows' => $request->getPref('editHeight'),
582 'cols' => $request->getPref('editWidth'),
583 'readonly' => (bool) $readonly),
586 $textarea->setAttr('wrap','virtual');
588 return Edit_HtmlArea_Textarea($textarea,$this->_wikicontent,'edit[content]');
593 function getFormElements () {
594 $request = &$this->request;
595 $page = &$this->page;
598 $h = array('action' => 'edit',
599 'pagename' => $page->getName(),
600 'version' => $this->version,
601 'edit[pagetype]' => $this->meta['pagetype'],
602 'edit[current_version]' => $this->_currentVersion);
604 $el['HIDDEN_INPUTS'] = HiddenInputs($h);
605 $el['EDIT_TEXTAREA'] = $this->getTextArea();
607 = HTML::input(array('type' => 'text',
608 'class' => 'wikitext',
609 'name' => 'edit[summary]',
612 'value' => $this->meta['summary']));
614 = HTML::input(array('type' => 'checkbox',
615 'name' => 'edit[minor_edit]',
616 'checked' => (bool) $this->meta['is_minor_edit']));
618 = HTML::input(array('type' => 'checkbox',
619 'name' => 'edit[markup]',
621 'checked' => $this->meta['markup'] < 2.0,
622 'id' => 'useOldMarkup',
623 'onclick' => 'showOldMarkupRules(this.checked)'));
626 = HTML::input(array('type' => 'checkbox',
627 'name' => 'edit[locked]',
628 'disabled' => (bool) !$this->user->isadmin(),
629 'checked' => (bool) $this->locked));
631 $el['PREVIEW_B'] = Button('submit:edit[preview]', _("Preview"),
634 //if (!$this->isConcurrentUpdate() && $this->canEdit())
635 $el['SAVE_B'] = Button('submit:edit[save]', _("Save"), 'wikiaction');
637 $el['IS_CURRENT'] = $this->version == $this->current->getVersion();
642 function _redirectToBrowsePage() {
643 $this->request->redirect(WikiURL($this->page, false, 'absolute_url'));
647 function _restoreState () {
648 $request = &$this->request;
650 $posted = $request->getArg('edit');
651 $request->setArg('edit', false);
653 if (!$posted || !$request->isPost()
654 || $request->getArg('action') != 'edit')
657 if (!isset($posted['content']) || !is_string($posted['content']))
659 $this->_content = preg_replace('/[ \t\r]+\n/', "\n",
660 rtrim($posted['content']));
661 $this->_content = $this->getContent();
663 $this->_currentVersion = (int) $posted['current_version'];
665 if ($this->_currentVersion < 0)
667 if ($this->_currentVersion > $this->current->getVersion())
668 return false; // FIXME: some kind of warning?
670 $is_old_markup = !empty($posted['markup']) && $posted['markup'] == 'old';
671 $meta['markup'] = $is_old_markup ? false : 2.0;
672 $meta['summary'] = trim(substr($posted['summary'], 0, 256));
673 $meta['is_minor_edit'] = !empty($posted['minor_edit']);
674 $meta['pagetype'] = !empty($posted['pagetype']) ? $posted['pagetype'] : false;
675 $this->meta = array_merge($this->meta, $meta);
676 $this->locked = !empty($posted['locked']);
678 if (!empty($posted['preview']))
679 $this->editaction = 'preview';
680 elseif (!empty($posted['save']))
681 $this->editaction = 'save';
683 $this->editaction = 'edit';
688 function _initializeState () {
689 $request = &$this->request;
690 $current = &$this->current;
691 $selected = &$this->selected;
692 $user = &$this->user;
695 NoSuchRevision($request, $this->page, $this->version); // noreturn
697 $this->_currentVersion = $current->getVersion();
698 $this->_content = $selected->getPackedContent();
700 $this->meta['summary'] = '';
701 $this->locked = $this->page->get('locked');
703 // If author same as previous author, default minor_edit to on.
704 $age = $this->meta['mtime'] - $current->get('mtime');
705 $this->meta['is_minor_edit'] = ( $age < MINOR_EDIT_TIMEOUT
706 && $current->get('author') == $user->getId()
709 // Default for new pages is new-style markup.
710 if ($selected->hasDefaultContents())
711 $is_new_markup = true;
713 $is_new_markup = $selected->get('markup') >= 2.0;
715 $this->meta['markup'] = $is_new_markup ? 2.0: false;
716 $this->meta['pagetype'] = $selected->get('pagetype');
717 $this->editaction = 'edit';
721 class LoadFileConflictPageEditor
724 function editPage ($saveFailed = true) {
725 $tokens = &$this->tokens;
727 if (!$this->canEdit()) {
728 if ($this->isInitialEdit())
729 return $this->viewSource();
730 $tokens['PAGE_LOCKED_MESSAGE'] = $this->getLockedMessage();
732 elseif ($this->editaction == 'save') {
733 if ($this->savePage())
734 return true; // Page saved.
738 if ($saveFailed || $this->isConcurrentUpdate())
740 // Get the text of the original page, and the two conflicting edits
741 // The diff class takes arrays as input. So retrieve content as
742 // an array, or convert it as necesary.
743 $orig = $this->page->getRevision($this->_currentVersion);
744 $this_content = explode("\n", $this->_content);
745 $other_content = $this->current->getContent();
746 include_once("lib/diff.php");
747 $diff2 = new Diff($other_content, $this_content);
748 $context_lines = max(4, count($other_content) + 1,
749 count($this_content) + 1);
750 $fmt = new BlockDiffFormatter($context_lines);
752 $this->_content = $fmt->format($diff2);
753 // FIXME: integrate this into class BlockDiffFormatter
754 $this->_content = str_replace(">>>>>>>\n<<<<<<<\n", "=======\n",
756 $this->_content = str_replace("<<<<<<<\n>>>>>>>\n", "=======\n",
759 $this->_currentVersion = $this->current->getVersion();
760 $this->version = $this->_currentVersion;
761 $tokens['CONCURRENT_UPDATE_MESSAGE'] = $this->getConflictMessage();
764 if ($this->editaction == 'preview')
765 $tokens['PREVIEW_CONTENT'] = $this->getPreview(); // FIXME: convert to _MESSAGE?
767 // FIXME: NOT_CURRENT_MESSAGE?
769 $tokens = array_merge($tokens, $this->getFormElements());
771 return $this->output('editpage', _("Merge and Edit: %s"));
772 // FIXME: this doesn't display
775 function output ($template, $title_fs) {
776 $selected = &$this->selected;
777 $current = &$this->current;
779 if ($selected && $selected->getVersion() != $current->getVersion()) {
781 $pagelink = WikiLink($selected);
785 $pagelink = WikiLink($this->page);
788 $title = new FormattedText ($title_fs, $pagelink);
789 $template = Template($template, $this->tokens);
791 //GeneratePage($template, $title, $rev);
795 function getConflictMessage () {
796 $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.",
799 HTML::p(_("Please check it through before saving."))));
805 $Log: not supported by cvs2svn $
806 Revision 1.77 2004/11/15 15:52:35 rurban
809 Revision 1.76 2004/11/15 15:37:34 rurban
811 don't use document.write for replace, otherwise self.opener is not defined.
813 Revision 1.75 2004/09/16 08:00:52 rurban
816 Revision 1.74 2004/07/03 07:36:28 rurban
817 do not get unneccessary content
819 Revision 1.73 2004/06/16 21:23:44 rurban
820 fixed non-object fatal #215
822 Revision 1.72 2004/06/14 11:31:37 rurban
823 renamed global $Theme to $WikiTheme (gforge nameclash)
824 inherit PageList default options from PageList
825 default sortby=pagename
826 use options in PageList_Selectable (limit, sortby, ...)
827 added action revert, with button at action=diff
828 added option regex to WikiAdminSearchReplace
830 Revision 1.71 2004/06/03 18:06:29 rurban
831 fix file locking issues (only needed on write)
832 fixed immediate LANG and THEME in-session updates if not stored in prefs
833 advanced editpage toolbars (search & replace broken)
835 Revision 1.70 2004/06/02 20:47:47 rurban
836 dont use the wikiaction class
838 Revision 1.69 2004/06/02 10:17:56 rurban
839 integrated search/replace into toolbar
840 added save+preview buttons
842 Revision 1.68 2004/06/01 15:28:00 rurban
843 AdminUser only ADMIN_USER not member of Administrators
844 some RateIt improvements by dfrankow
847 Revision _1.6 2004/05/26 15:48:00 syilek
848 fixed problem with creating page with slashes from one true page
850 Revision _1.5 2004/05/25 16:51:53 syilek
851 added ability to create a page from the category page and not have to edit it
853 Revision 1.67 2004/05/27 17:49:06 rurban
854 renamed DB_Session to DbSession (in CVS also)
855 added WikiDB->getParam and WikiDB->getAuthParam method to get rid of globals
856 remove leading slash in error message
857 added force_unlock parameter to File_Passwd (no return on stale locks)
858 fixed adodb session AffectedRows
859 added FileFinder helpers to unify local filenames and DATA_PATH names
860 editpage.php: new edit toolbar javascript on ENABLE_EDIT_TOOLBAR
862 Revision 1.66 2004/04/29 23:25:12 rurban
863 re-ordered locale init (as in 1.3.9)
864 fixed loadfile with subpages, and merge/restore anyway
867 Revision 1.65 2004/04/18 01:11:52 rurban
868 more numeric pagename fixes.
869 fixed action=upload with merge conflict warnings.
870 charset changed from constant to global (dynamic utf-8 switching)
872 Revision 1.64 2004/04/06 19:48:56 rurban
873 temp workaround for action=edit AddComment form
875 Revision 1.63 2004/03/24 19:39:02 rurban
876 php5 workaround code (plus some interim debugging code in XmlElement)
877 php5 doesn't work yet with the current XmlElement class constructors,
878 WikiUserNew does work better than php4.
879 rewrote WikiUserNew user upgrading to ease php5 update
880 fixed pref handling in WikiUserNew
881 added Email Notification
882 added simple Email verification
883 removed emailVerify userpref subclass: just a email property
884 changed pref binary storage layout: numarray => hash of non default values
885 print optimize message only if really done.
886 forced new cookie policy: delete pref cookies, use only WIKI_ID as plain string.
887 prefs should be stored in db or homepage, besides the current session.
889 Revision 1.62 2004/03/17 18:41:05 rurban
890 initial_content and template support for CreatePage
892 Revision 1.61 2004/03/12 20:59:17 rurban
893 important cookie fix by Konstantin Zadorozhny
894 new editpage feature: JS_SEARCHREPLACE
896 Revision 1.60 2004/02/15 21:34:37 rurban
897 PageList enhanced and improved.
898 fixed new WikiAdmin... plugins
899 editpage, Theme with exp. htmlarea framework
900 (htmlarea yet committed, this is really questionable)
901 WikiUser... code with better session handling for prefs
902 enhanced UserPreferences (again)
903 RecentChanges for show_deleted: how should pages be deleted then?
905 Revision 1.59 2003/12/07 20:35:26 carstenklapp
906 Bugfix: Concurrent updates broken since after 1.3.4 release: Fatal
907 error: Call to undefined function: gettransformedcontent() in
908 /home/groups/p/ph/phpwiki/htdocs/phpwiki2/lib/editpage.php on line
911 Revision 1.58 2003/03/10 18:25:22 dairiki
912 Bug/typo fix. If you use the edit page to un/lock a page, it
913 failed with: Fatal error: Call to a member function on a
914 non-object in editpage.php on line 136
916 Revision 1.57 2003/02/26 03:40:22 dairiki
917 New action=create. Essentially the same as action=edit, except that if the
918 page already exists, it falls back to action=browse.
920 This is for use in the "question mark" links for unknown wiki words
921 to avoid problems and confusion when following links from stale pages.
922 (If the "unknown page" has been created in the interim, the user probably
923 wants to view the page before editing it.)
925 Revision 1.56 2003/02/21 18:07:14 dairiki
926 Minor, nitpicky, currently inconsequential changes.
928 Revision 1.55 2003/02/21 04:10:58 dairiki
929 Fixes for new cached markup.
930 Some minor code cleanups.
932 Revision 1.54 2003/02/16 19:47:16 dairiki
933 Update WikiDB timestamp when editing or deleting pages.
935 Revision 1.53 2003/02/15 23:20:27 dairiki
936 Redirect back to browse current version of page upon save,
937 even when no changes were made.
939 Revision 1.52 2003/01/03 22:22:00 carstenklapp
940 Minor adjustments to diff block markers ("<<<<<<<"). Source reformatting.
942 Revision 1.51 2003/01/03 02:43:26 carstenklapp
943 New class LoadFileConflictPageEditor, for merging / comparing a loaded
944 pgsrc file with an existing page.
952 // c-hanging-comment-ender-p: nil
953 // indent-tabs-mode: nil