2 rcs_id('$Id: editpage.php,v 1.89 2005-01-21 14:07:49 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'))
57 and $request->_dbi->isWikiPage($template)) {
58 $page = $request->_dbi->getPage($template);
59 $current = $page->getCurrentRevision();
60 $this->_content = $current->getPackedContent();
61 } elseif ($initial_content = $request->getArg('initial_content')) {
62 $this->_content = $initial_content;
63 $this->_redirect_to = $request->getArg('save_and_redirect_to');
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 and $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);
115 } elseif ($saveFailed) {
116 $tokens['CONCURRENT_UPDATE_MESSAGE'] =
117 HTML(HTML::h2(_("Some internal editing error")),
118 HTML::p(_("Your are probably trying to edit/create an invalid version of this page.")),
119 HTML::p(HTML::em(_("&version=-1 might help."))));
122 if ($this->editaction == 'edit_convert')
123 $tokens['PREVIEW_CONTENT'] = $this->getConvertedPreview();
124 if ($this->editaction == 'preview')
125 $tokens['PREVIEW_CONTENT'] = $this->getPreview(); // FIXME: convert to _MESSAGE?
127 // FIXME: NOT_CURRENT_MESSAGE?
128 $tokens = array_merge($tokens, $this->getFormElements());
130 //FIXME: enable Undo button for all other buttons also, not only the search/replace button
131 if (defined('JS_SEARCHREPLACE') and JS_SEARCHREPLACE) {
132 $tokens['JS_SEARCHREPLACE'] = 1;
133 $undo_btn = $WikiTheme->getImageURL("ed_undo.png");
134 $undo_d_btn = $WikiTheme->getImageURL("ed_undo_d.png");
135 // JS_SEARCHREPLACE from walterzorn.de
136 $WikiTheme->addMoreHeaders(Javascript("
137 var f, sr_undo, replacewin, undo_buffer=new Array(), undo_buffer_index=0;
139 function define_f() {
140 f=document.getElementById('editpage');
141 f.editarea=document.getElementById('edit[content]');
142 sr_undo=document.getElementById('sr_undo');
146 function undo_enable(bool) {
148 sr_undo.src='".$undo_btn."';
152 sr_undo.disabled = false;
154 sr_undo.src='".$undo_d_btn."';
158 sr_undo.disabled = true;
159 if(sr_undo.blur) sr_undo.blur();
163 replacewin = window.open('','','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,height=90,width=450');
164 replacewin.window.document.write('<html><head><title>"
165 ._("Search & Replace")
166 ."</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\">'+'"
168 .":</td><td align=\"left\"><input type=\"text\" name=\"ein\" size=\"45\" maxlength=\"500\"></td></tr><tr><td align=\"right\">'+' "
170 .":</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=\" "
172 ." \" onclick=\"if(self.opener)self.opener.do_replace(); return false;\"> <input type=\"button\" value=\""
174 ."\" onclick=\"self.close(); return false;\"></td></tr></table></center></form></body></html>');
175 replacewin.window.document.close();
178 function do_replace() {
179 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;
180 if (ein==''||ein==null) {
181 if (replacewin) replacewin.window.document.forms[0].ein.focus();
184 var z_repl=txt.match(ein)? txt.match(ein).length : 0;
185 txt=txt.replace(ein,aus);
186 ein=ein.toString().substring(1,ein.toString().length-2);
187 result(z_repl, 'Substring \"'+ein+'\" found '+z_repl+' times. Replace with \"'+aus+'\"?', txt, 'String \"'+ein+'\" not found.');
188 replacewin.window.focus();
189 replacewin.window.document.forms[0].ein.focus();
192 function result(zahl,frage,txt,alert_txt) {
194 if(window.confirm(frage)==true) {
195 f.editarea.value=txt;
199 } else alert(alert_txt);
202 if(undo_buffer_index==0) return;
203 else if(undo_buffer_index>0) {
204 f.editarea.value=undo_buffer[undo_buffer_index-1];
205 undo_buffer[undo_buffer_index]=null;
207 if(undo_buffer_index==0) {
209 _("Operation undone")
215 //save a snapshot in the undo buffer (unused)
216 function undo_save() {
217 undo_buffer[undo_buffer_index]=f.editarea.value;
222 $WikiTheme->addMoreAttr('body'," onload='define_f()'");
224 $WikiTheme->addMoreAttr('body',"document.getElementById('edit[content]').editarea.focus()");
226 if (defined('ENABLE_EDIT_TOOLBAR') and ENABLE_EDIT_TOOLBAR) {
227 $WikiTheme->addMoreHeaders(JavaScript('',array('src' => $WikiTheme->_findData("toolbar.js"))));
228 $tokens['EDIT_TOOLBAR'] = $this->toolbar();
230 $tokens['EDIT_TOOLBAR'] = '';
233 return $this->output('editpage', _("Edit: %s"));
236 function toolbar () {
240 "image"=>"ed_format_bold.png",
243 "sample"=>_("Bold text"),
244 "tip"=>_("Bold text")),
245 array("image"=>"ed_format_italic.png",
248 "sample"=>_("Italic text"),
249 "tip"=>_("Italic text")),
250 array("image"=>"ed_pagelink.png",
253 "sample"=>_("optional label | PageName"),
254 "tip"=>_("Link to page")),
255 array("image"=>"ed_link.png",
258 "sample"=>_("optional label | http://www.example.com"),
259 "tip"=>_("External link (remember http:// prefix)")),
260 array("image"=>"ed_headline.png",
263 "sample"=>_("Headline text"),
264 "tip"=>_("Level 1 headline")),
265 array("image"=>"ed_image.png",
268 "sample"=>_("Example.jpg"),
269 "tip"=>_("Embedded image")),
270 array("image"=>"ed_nowiki.png",
271 "open"=>"\\n\\<verbatim\\>\\n",
272 "close"=>"\\n\\</verbatim\\>\\n",
273 "sample"=>_("Insert non-formatted text here"),
274 "tip"=>_("Ignore wiki formatting")),
275 array("image"=>"ed_sig.png",
276 "open" => " --" . $GLOBALS['request']->_user->UserName(),
279 "tip"=>_("Your signature")),
280 array("image"=>"ed_hr.png",
281 "open"=>"\\n----\\n",
284 "tip"=>_("Horizontal line"))
286 $toolbar = "document.writeln(\"<div class=\\\"edit-toolbar\\\" id=\\\"toolbar\\\">\");\n";
288 $btn = new SubmitImageButton(_("Save"), "edit[save]", 'toolbar', $WikiTheme->getImageURL("ed_save.png"));
289 $btn->addTooltip(_("Save"));
290 $toolbar.='document.writeln("'.addslashes($btn->asXml()).'");'."\n";
291 $btn = new SubmitImageButton(_("Preview"), "edit[preview]", 'toolbar', $WikiTheme->getImageURL("ed_preview.png"));
292 $btn->addTooltip(_("Preview"));
293 $toolbar.='document.writeln("'.addslashes($btn->asXml()).'");'."\n";
295 foreach ($toolarray as $tool) {
296 $image = $WikiTheme->getImageURL($tool["image"]);
297 $open = $tool["open"];
298 $close = $tool["close"];
299 $sample = addslashes( $tool["sample"] );
300 // Note that we use the tip both for the ALT tag and the TITLE tag of the image.
301 // Older browsers show a "speedtip" type message only for ALT.
302 // Ideally these should be different, realistically they
303 // probably don't need to be.
304 $tip = addslashes( $tool["tip"] );
305 $toolbar.="addTagButton('$image','$tip','$open','$close','$sample');\n";
307 $toolbar.="addInfobox('" . addslashes( _("Click a button to get an example text") ) . "');\n";
309 if (JS_SEARCHREPLACE) {
310 $undo_d_btn = $WikiTheme->getImageURL("ed_undo_d.png");
311 //$redo_btn = $WikiTheme->getImageURL("ed_redo.png");
312 $sr_btn = $WikiTheme->getImageURL("ed_replace.png");
313 $sr_html = HTML(HTML::img(array('class'=>"toolbar",
316 'title'=>_("Undo Search & Replace"),
317 'alt' =>_("Undo Search & Replace"),
318 'disabled'=>"disabled",
320 'onfocus' =>"if(this.blur && undo_buffer_index==0) this.blur()",
321 'onclick' =>"do_undo()")),
322 HTML::img(array('class'=>"toolbar",
324 'alt' =>_("Search & Replace"),
325 'title'=>_("Search & Replace"),
326 'onclick'=>"replace()")));
331 // Button to generate pagenames, display in extra window as pulldown and insert
332 // Button to generate plugins, display in extra window as pulldown and insert
333 // Button to generate categories, display in extra window as pulldown and insert
334 if (DEBUG and JS_SEARCHREPLACE) {
335 //TODO: delegate this calculation to a seperate pulldown action request
336 require_once('lib/TextSearchQuery.php');
337 $dbi =& $GLOBALS['request']->_dbi;
338 $pages = $dbi->titleSearch(new TextSearchQuery(''.
339 _("Category").' OR '.
341 if ($pages->count()) {
342 $categories = array();
343 while ($p = $pages->next()){
344 $categories[] = $p->getName();
346 $more_buttons = HTML::img(array('class'=>"toolbar",
347 'src' => $WikiTheme->getImageURL("ed_category.png"),
348 'title'=>_("AddCategory"),
349 'onclick'=>"showPulldown('".
350 _("Insert Categories (double-click)")
351 ."',['".join("','",$categories)."'],'"
355 if ($sr_html) $sr_html = HTML($sr_html, $more_buttons);
356 else $sr_html = $more_buttons;
359 $toolbar_end = "document.writeln(\"</div>\");";
360 // don't use document.write for replace, otherwise self.opener is not defined.
362 return HTML(Javascript($toolbar),
364 Javascript($toolbar_end));
366 return HTML(Javascript($toolbar . $toolbar_end));
369 function output ($template, $title_fs) {
371 $selected = &$this->selected;
372 $current = &$this->current;
374 if ($selected && $selected->getVersion() != $current->getVersion()) {
376 $pagelink = WikiLink($selected);
380 $pagelink = WikiLink($this->page);
384 $title = new FormattedText ($title_fs, $pagelink);
385 if (USE_HTMLAREA and $template == 'editpage') {
386 $WikiTheme->addMoreHeaders(Edit_HtmlArea_Head());
387 //$tokens['PAGE_SOURCE'] = Edit_HtmlArea_ConvertBefore($this->_content);
389 $template = Template($template, $this->tokens);
390 GeneratePage($template, $title, $rev);
395 function viewSource () {
396 assert($this->isInitialEdit());
397 assert($this->selected);
399 $this->tokens['PAGE_SOURCE'] = $this->_content;
400 return $this->output('viewsource', _("View Source: %s"));
403 function updateLock() {
404 if ((bool)$this->page->get('locked') == (bool)$this->locked)
405 return false; // Not changed.
407 if (!$this->user->isAdmin()) {
408 // FIXME: some sort of message
409 return false; // not allowed.
412 $this->page->set('locked', (bool)$this->locked);
413 $this->tokens['LOCK_CHANGED_MSG']
414 = $this->locked ? _("Page now locked.") : _("Page now unlocked.");
416 return true; // lock changed.
419 function savePage () {
420 $request = &$this->request;
422 if ($this->isUnchanged()) {
423 // Allow admin lock/unlock even if
424 // no text changes were made.
425 if ($this->updateLock()) {
426 $dbi = $request->getDbh();
429 // Save failed. No changes made.
430 $this->_redirectToBrowsePage();
431 // user will probably not see the rest of this...
432 include_once('lib/display.php');
433 // force browse of current version:
434 $request->setArg('version', false);
435 displayPage($request, 'nochanges');
439 if ($this->isSpam()) {
442 // Save failed. No changes made.
443 $this->_redirectToBrowsePage();
444 // user will probably not see the rest of this...
445 include_once('lib/display.php');
446 // force browse of current version:
447 $request->setArg('version', false);
448 displayPage($request, 'nochanges');
453 $page = &$this->page;
455 // Include any meta-data from original page version which
456 // has not been explicitly updated.
457 // (Except don't propagate pgsrc_version --- moot for now,
458 // because at present it never gets into the db...)
459 $meta = $this->selected->getMetaData();
460 unset($meta['pgsrc_version']);
461 $meta = array_merge($meta, $this->meta);
464 $this->_content = $this->getContent();
465 $newrevision = $page->save($this->_content,
466 $this->version == -1 ? -1 : $this->_currentVersion + 1,
469 if (!isa($newrevision, 'WikiDB_PageRevision')) {
470 // Save failed. (Concurrent updates).
474 // New contents successfully saved...
477 // Clean out archived versions of this page.
478 include_once('lib/ArchiveCleaner.php');
479 $cleaner = new ArchiveCleaner($GLOBALS['ExpireParams']);
480 $cleaner->cleanPageRevisions($page);
482 /* generate notification emails done in WikiDB::save to catch all direct calls
485 $dbi = $request->getDbh();
486 $warnings = $dbi->GenericWarnings();
490 if (empty($warnings) && ! $WikiTheme->getImageURL('signature')) {
491 // Do redirect to browse page if no signature has
492 // been defined. In this case, the user will most
493 // likely not see the rest of the HTML we generate
495 $this->_redirectToBrowsePage();
498 // Force browse of current page version.
499 $request->setArg('version', false);
500 //$request->setArg('action', false);
502 $template = Template('savepage', $this->tokens);
503 $template->replace('CONTENT', $newrevision->getTransformedContent());
504 if (!empty($warnings))
505 $template->replace('WARNINGS', $warnings);
507 $pagelink = WikiLink($page);
509 GeneratePage($template, fmt("Saved: %s", $pagelink), $newrevision);
513 function isConcurrentUpdate () {
514 assert($this->current->getVersion() >= $this->_currentVersion);
515 return $this->current->getVersion() != $this->_currentVersion;
518 function canEdit () {
519 return !$this->page->get('locked') || $this->user->isAdmin();
522 function isInitialEdit () {
523 return $this->_initialEdit;
526 function isUnchanged () {
527 $current = &$this->current;
529 if ($this->meta['markup'] != $current->get('markup'))
532 return $this->_content == $current->getPackedContent();
536 * Handle AntiSpam here. How? http://wikiblacklist.blogspot.com/
537 * Need to check dynamically some blacklist wikipage settings (plugin WikiAccessRestrictions)
538 * and some static blacklist.
540 * More then 20 new external links
541 * content patterns by babycart (only php >= 4.3 for now)
548 $current = &$this->current;
549 $request = &$this->request;
551 $oldtext = $current->getPackedContent();
552 $newtext =& $this->_content;
553 // 1. Not more then 20 new external links
554 if ($this->numLinks($newtext) - $this->numLinks($oldtext) >= 20) {
556 $this->tokens['PAGE_LOCKED_MESSAGE'] =
557 HTML($this->getSpamMessage(),
558 HTML::p(HTML::em(_("Too many external links."))));
561 // 2. external babycart (SpamAssassin) check
562 // This will probably prevent from discussing sex or viagra related topics. So beware.
563 if (ENABLE_SPAMASSASSIN) {
564 $user = $request->getUser();
565 include_once("lib/spam_babycart.php");
566 if ($babycart = check_babycart($newtext, $request->get("REMOTE_ADDR"), $user->getId())) {
568 if (is_array($babycart))
569 $this->tokens['PAGE_LOCKED_MESSAGE'] =
570 HTML($this->getSpamMessage(),
571 HTML::p(HTML::em(_("SpamAssassin reports: ", join("\n", $babycart)))));
578 /** Number of external links in the wikitext
580 function numLinks(&$text) {
581 return substr_count($text, "http://");
584 /** Header of the Anti Spam message
586 function getSpamMessage () {
588 HTML(HTML::h2(_("Spam Prevention")),
589 HTML::p(_("This page edit seems to contain spam and was therefore not saved."),
591 _("Sorry for the inconvenience.")),
595 function getPreview () {
596 include_once('lib/PageType.php');
597 $this->_content = $this->getContent();
598 return new TransformedText($this->page, $this->_content, $this->meta);
601 function getConvertedPreview () {
602 include_once('lib/PageType.php');
603 $this->_content = $this->getContent();
604 $this->meta['markup'] = 2.0;
605 $this->_content = ConvertOldMarkup($this->_content);
606 return new TransformedText($this->page, $this->_content, $this->meta);
609 // possibly convert HTMLAREA content back to Wiki markup
610 function getContent () {
612 $xml_output = Edit_HtmlArea_ConvertAfter($this->_content);
613 $this->_content = join("", $xml_output->_content);
614 return $this->_content;
616 return $this->_content;
620 function getLockedMessage () {
622 HTML(HTML::h2(_("Page Locked")),
623 HTML::p(_("This page has been locked by the administrator so your changes can not be saved.")),
624 HTML::p(_("(Copy your changes to the clipboard. You can try editing a different page or save your text in a text editor.)")),
625 HTML::p(_("Sorry for the inconvenience.")));
628 function getConflictMessage ($unresolved = false) {
630 xgettext only knows about c/c++ line-continuation strings
631 it does not know about php's dot operator.
632 We want to translate this entire paragraph as one string, of course.
635 //$re_edit_link = Button('edit', _("Edit the new version"), $this->page);
638 $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.",
639 "<<<<<<< ". _("Your version"),
640 ">>>>>>> ". _("Other version")));
642 $message = HTML::p(_("Please check it through before saving."));
646 /*$steps = HTML::ol(HTML::li(_("Copy your changes to the clipboard or to another temporary place (e.g. text editor).")),
647 HTML::li(fmt("%s of the page. You should now see the most current version of the page. Your changes are no longer there.",
649 HTML::li(_("Make changes to the file again. Paste your additions from the clipboard (or text editor).")),
650 HTML::li(_("Save your updated changes.")));
653 HTML(HTML::h2(_("Conflicting Edits!")),
654 HTML::p(_("In the time since you started editing this page, another user has saved a new version of it.")),
655 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.")),
660 function getTextArea () {
661 $request = &$this->request;
663 // wrap=virtual is not HTML4, but without it NS4 doesn't wrap
665 $readonly = ! $this->canEdit(); // || $this->isConcurrentUpdate();
667 $html = $this->getPreview();
668 $this->_wikicontent = $this->_content;
669 $this->_content = $html->asXML();
672 /** <textarea wrap="virtual"> is not valid xhtml but Netscape 4 requires it
673 * to wrap long lines.
675 $textarea = HTML::textarea(array('class' => 'wikiedit',
676 'name' => 'edit[content]',
677 'id' => 'edit[content]',
678 'rows' => $request->getPref('editHeight'),
679 'cols' => $request->getPref('editWidth'),
680 'readonly' => (bool) $readonly),
683 $textarea->setAttr('wrap', 'virtual');
685 return Edit_HtmlArea_Textarea($textarea,$this->_wikicontent,'edit[content]');
691 * TODO: maybe support an uploadfile button.
693 function getFormElements () {
694 $request = &$this->request;
695 $page = &$this->page;
697 $h = array('action' => 'edit',
698 'pagename' => $page->getName(),
699 'version' => $this->version,
700 'edit[pagetype]' => $this->meta['pagetype'],
701 'edit[current_version]' => $this->_currentVersion);
703 $el['HIDDEN_INPUTS'] = HiddenInputs($h);
704 $el['EDIT_TEXTAREA'] = $this->getTextArea();
706 = HTML::input(array('type' => 'text',
707 'class' => 'wikitext',
708 'name' => 'edit[summary]',
711 'value' => $this->meta['summary']));
713 = HTML::input(array('type' => 'checkbox',
714 'name' => 'edit[minor_edit]',
715 'checked' => (bool) $this->meta['is_minor_edit']));
717 = HTML::input(array('type' => 'checkbox',
718 'name' => 'edit[markup]',
720 'checked' => $this->meta['markup'] < 2.0,
721 'id' => 'useOldMarkup',
722 'onclick' => 'showOldMarkupRules(this.checked)'));
723 $el['OLD_MARKUP_CONVERT'] = ($this->meta['markup'] < 2.0) ? Button('submit:edit[edit_convert]', _("Convert"), 'wikiaction') : '';
725 = HTML::input(array('type' => 'checkbox',
726 'name' => 'edit[locked]',
727 'disabled' => (bool) !$this->user->isadmin(),
728 'checked' => (bool) $this->locked));
730 $el['PREVIEW_B'] = Button('submit:edit[preview]', _("Preview"),
733 //if (!$this->isConcurrentUpdate() && $this->canEdit())
734 $el['SAVE_B'] = Button('submit:edit[save]', _("Save"), 'wikiaction');
736 $el['IS_CURRENT'] = $this->version == $this->current->getVersion();
741 function _redirectToBrowsePage() {
742 $this->request->redirect(WikiURL($this->page, false, 'absolute_url'));
745 function _restoreState () {
746 $request = &$this->request;
748 $posted = $request->getArg('edit');
749 $request->setArg('edit', false);
751 if (!$posted || !$request->isPost()
752 || $request->getArg('action') != 'edit')
755 if (!isset($posted['content']) || !is_string($posted['content']))
757 $this->_content = preg_replace('/[ \t\r]+\n/', "\n",
758 rtrim($posted['content']));
759 $this->_content = $this->getContent();
761 $this->_currentVersion = (int) $posted['current_version'];
763 if ($this->_currentVersion < 0)
765 if ($this->_currentVersion > $this->current->getVersion())
766 return false; // FIXME: some kind of warning?
768 $is_old_markup = !empty($posted['markup']) && $posted['markup'] == 'old';
769 $meta['markup'] = $is_old_markup ? false : 2.0;
770 $meta['summary'] = trim(substr($posted['summary'], 0, 256));
771 $meta['is_minor_edit'] = !empty($posted['minor_edit']);
772 $meta['pagetype'] = !empty($posted['pagetype']) ? $posted['pagetype'] : false;
773 $this->meta = array_merge($this->meta, $meta);
774 $this->locked = !empty($posted['locked']);
776 if (!empty($posted['preview']))
777 $this->editaction = 'preview';
778 elseif (!empty($posted['save']))
779 $this->editaction = 'save';
780 elseif (!empty($posted['edit_convert']))
781 $this->editaction = 'edit_convert';
783 $this->editaction = 'edit';
788 function _initializeState () {
789 $request = &$this->request;
790 $current = &$this->current;
791 $selected = &$this->selected;
792 $user = &$this->user;
795 NoSuchRevision($request, $this->page, $this->version); // noreturn
797 $this->_currentVersion = $current->getVersion();
798 $this->_content = $selected->getPackedContent();
800 $this->locked = $this->page->get('locked');
802 // If author same as previous author, default minor_edit to on.
803 $age = $this->meta['mtime'] - $current->get('mtime');
804 $this->meta['is_minor_edit'] = ( $age < MINOR_EDIT_TIMEOUT
805 && $current->get('author') == $user->getId()
808 // Default for new pages is new-style markup.
809 if ($selected->hasDefaultContents())
810 $is_new_markup = true;
812 $is_new_markup = $selected->get('markup') >= 2.0;
814 $this->meta['markup'] = $is_new_markup ? 2.0: false;
815 $this->meta['pagetype'] = $selected->get('pagetype');
816 if ($this->meta['pagetype'] == 'wikiblog')
817 $this->meta['summary'] = $selected->get('summary'); // keep blog title
819 $this->meta['summary'] = '';
820 $this->editaction = 'edit';
824 class LoadFileConflictPageEditor
827 function editPage ($saveFailed = true) {
828 $tokens = &$this->tokens;
830 if (!$this->canEdit()) {
831 if ($this->isInitialEdit())
832 return $this->viewSource();
833 $tokens['PAGE_LOCKED_MESSAGE'] = $this->getLockedMessage();
835 elseif ($this->editaction == 'save') {
836 if ($this->savePage())
837 return true; // Page saved.
841 if ($saveFailed || $this->isConcurrentUpdate())
843 // Get the text of the original page, and the two conflicting edits
844 // The diff class takes arrays as input. So retrieve content as
845 // an array, or convert it as necesary.
846 $orig = $this->page->getRevision($this->_currentVersion);
847 $this_content = explode("\n", $this->_content);
848 $other_content = $this->current->getContent();
849 include_once("lib/diff.php");
850 $diff2 = new Diff($other_content, $this_content);
851 $context_lines = max(4, count($other_content) + 1,
852 count($this_content) + 1);
853 $fmt = new BlockDiffFormatter($context_lines);
855 $this->_content = $fmt->format($diff2);
856 // FIXME: integrate this into class BlockDiffFormatter
857 $this->_content = str_replace(">>>>>>>\n<<<<<<<\n", "=======\n",
859 $this->_content = str_replace("<<<<<<<\n>>>>>>>\n", "=======\n",
862 $this->_currentVersion = $this->current->getVersion();
863 $this->version = $this->_currentVersion;
864 $tokens['CONCURRENT_UPDATE_MESSAGE'] = $this->getConflictMessage();
867 if ($this->editaction == 'edit_convert')
868 $tokens['PREVIEW_CONTENT'] = $this->getConvertedPreview();
869 if ($this->editaction == 'preview')
870 $tokens['PREVIEW_CONTENT'] = $this->getPreview(); // FIXME: convert to _MESSAGE?
872 // FIXME: NOT_CURRENT_MESSAGE?
874 $tokens = array_merge($tokens, $this->getFormElements());
876 return $this->output('editpage', _("Merge and Edit: %s"));
877 // FIXME: this doesn't display
880 function output ($template, $title_fs) {
881 $selected = &$this->selected;
882 $current = &$this->current;
884 if ($selected && $selected->getVersion() != $current->getVersion()) {
886 $pagelink = WikiLink($selected);
890 $pagelink = WikiLink($this->page);
893 $title = new FormattedText ($title_fs, $pagelink);
894 $template = Template($template, $this->tokens);
896 //GeneratePage($template, $title, $rev);
900 function getConflictMessage () {
901 $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.",
904 HTML::p(_("Please check it through before saving."))));
910 $Log: not supported by cvs2svn $
911 Revision 1.88 2004/12/17 16:39:03 rurban
914 Revision 1.87 2004/12/16 18:28:05 rurban
915 keep wikiblog summary = page title
917 Revision 1.86 2004/12/11 14:50:15 rurban
918 new edit_convert button, to get rid of old markup eventually
920 Revision 1.85 2004/12/06 19:49:56 rurban
921 enable action=remove which is undoable and seeable in RecentChanges: ADODB ony for now.
922 renamed delete_page to purge_page.
923 enable action=edit&version=-1 to force creation of a new version.
924 added BABYCART_PATH config
925 fixed magiqc in adodb.inc.php
928 Revision 1.84 2004/12/04 12:58:26 rurban
929 enable babycart Blog::SpamAssassin module on ENABLE_SPAMASSASSIN=true
930 (currently only for php >= 4.3.0)
932 Revision 1.83 2004/12/04 11:55:39 rurban
933 First simple AntiSpam prevention:
934 No more than 20 new http:// links allowed
936 Revision 1.82 2004/11/30 22:21:56 rurban
937 changed gif to optimized (pngout) png
939 Revision 1.81 2004/11/29 17:57:27 rurban
940 translated pulldown buttons
942 Revision 1.80 2004/11/25 17:20:51 rurban
943 and again a couple of more native db args: backlinks
945 Revision 1.79 2004/11/21 11:59:20 rurban
946 remove final \n to be ob_cache independent
948 Revision 1.78 2004/11/16 17:57:45 rurban
949 fix search&replace button
950 use new addTagButton machinery
951 new showPulldown for categories, TODO: in a seperate request
953 Revision 1.77 2004/11/15 15:52:35 rurban
956 Revision 1.76 2004/11/15 15:37:34 rurban
958 don't use document.write for replace, otherwise self.opener is not defined.
960 Revision 1.75 2004/09/16 08:00:52 rurban
963 Revision 1.74 2004/07/03 07:36:28 rurban
964 do not get unneccessary content
966 Revision 1.73 2004/06/16 21:23:44 rurban
967 fixed non-object fatal #215
969 Revision 1.72 2004/06/14 11:31:37 rurban
970 renamed global $Theme to $WikiTheme (gforge nameclash)
971 inherit PageList default options from PageList
972 default sortby=pagename
973 use options in PageList_Selectable (limit, sortby, ...)
974 added action revert, with button at action=diff
975 added option regex to WikiAdminSearchReplace
977 Revision 1.71 2004/06/03 18:06:29 rurban
978 fix file locking issues (only needed on write)
979 fixed immediate LANG and THEME in-session updates if not stored in prefs
980 advanced editpage toolbars (search & replace broken)
982 Revision 1.70 2004/06/02 20:47:47 rurban
983 dont use the wikiaction class
985 Revision 1.69 2004/06/02 10:17:56 rurban
986 integrated search/replace into toolbar
987 added save+preview buttons
989 Revision 1.68 2004/06/01 15:28:00 rurban
990 AdminUser only ADMIN_USER not member of Administrators
991 some RateIt improvements by dfrankow
994 Revision _1.6 2004/05/26 15:48:00 syilek
995 fixed problem with creating page with slashes from one true page
997 Revision _1.5 2004/05/25 16:51:53 syilek
998 added ability to create a page from the category page and not have to edit it
1000 Revision 1.67 2004/05/27 17:49:06 rurban
1001 renamed DB_Session to DbSession (in CVS also)
1002 added WikiDB->getParam and WikiDB->getAuthParam method to get rid of globals
1003 remove leading slash in error message
1004 added force_unlock parameter to File_Passwd (no return on stale locks)
1005 fixed adodb session AffectedRows
1006 added FileFinder helpers to unify local filenames and DATA_PATH names
1007 editpage.php: new edit toolbar javascript on ENABLE_EDIT_TOOLBAR
1009 Revision 1.66 2004/04/29 23:25:12 rurban
1010 re-ordered locale init (as in 1.3.9)
1011 fixed loadfile with subpages, and merge/restore anyway
1012 (sf.net bug #844188)
1014 Revision 1.65 2004/04/18 01:11:52 rurban
1015 more numeric pagename fixes.
1016 fixed action=upload with merge conflict warnings.
1017 charset changed from constant to global (dynamic utf-8 switching)
1019 Revision 1.64 2004/04/06 19:48:56 rurban
1020 temp workaround for action=edit AddComment form
1022 Revision 1.63 2004/03/24 19:39:02 rurban
1023 php5 workaround code (plus some interim debugging code in XmlElement)
1024 php5 doesn't work yet with the current XmlElement class constructors,
1025 WikiUserNew does work better than php4.
1026 rewrote WikiUserNew user upgrading to ease php5 update
1027 fixed pref handling in WikiUserNew
1028 added Email Notification
1029 added simple Email verification
1030 removed emailVerify userpref subclass: just a email property
1031 changed pref binary storage layout: numarray => hash of non default values
1032 print optimize message only if really done.
1033 forced new cookie policy: delete pref cookies, use only WIKI_ID as plain string.
1034 prefs should be stored in db or homepage, besides the current session.
1036 Revision 1.62 2004/03/17 18:41:05 rurban
1037 initial_content and template support for CreatePage
1039 Revision 1.61 2004/03/12 20:59:17 rurban
1040 important cookie fix by Konstantin Zadorozhny
1041 new editpage feature: JS_SEARCHREPLACE
1043 Revision 1.60 2004/02/15 21:34:37 rurban
1044 PageList enhanced and improved.
1045 fixed new WikiAdmin... plugins
1046 editpage, Theme with exp. htmlarea framework
1047 (htmlarea yet committed, this is really questionable)
1048 WikiUser... code with better session handling for prefs
1049 enhanced UserPreferences (again)
1050 RecentChanges for show_deleted: how should pages be deleted then?
1052 Revision 1.59 2003/12/07 20:35:26 carstenklapp
1053 Bugfix: Concurrent updates broken since after 1.3.4 release: Fatal
1054 error: Call to undefined function: gettransformedcontent() in
1055 /home/groups/p/ph/phpwiki/htdocs/phpwiki2/lib/editpage.php on line
1058 Revision 1.58 2003/03/10 18:25:22 dairiki
1059 Bug/typo fix. If you use the edit page to un/lock a page, it
1060 failed with: Fatal error: Call to a member function on a
1061 non-object in editpage.php on line 136
1063 Revision 1.57 2003/02/26 03:40:22 dairiki
1064 New action=create. Essentially the same as action=edit, except that if the
1065 page already exists, it falls back to action=browse.
1067 This is for use in the "question mark" links for unknown wiki words
1068 to avoid problems and confusion when following links from stale pages.
1069 (If the "unknown page" has been created in the interim, the user probably
1070 wants to view the page before editing it.)
1072 Revision 1.56 2003/02/21 18:07:14 dairiki
1073 Minor, nitpicky, currently inconsequential changes.
1075 Revision 1.55 2003/02/21 04:10:58 dairiki
1076 Fixes for new cached markup.
1077 Some minor code cleanups.
1079 Revision 1.54 2003/02/16 19:47:16 dairiki
1080 Update WikiDB timestamp when editing or deleting pages.
1082 Revision 1.53 2003/02/15 23:20:27 dairiki
1083 Redirect back to browse current version of page upon save,
1084 even when no changes were made.
1086 Revision 1.52 2003/01/03 22:22:00 carstenklapp
1087 Minor adjustments to diff block markers ("<<<<<<<"). Source reformatting.
1089 Revision 1.51 2003/01/03 02:43:26 carstenklapp
1090 New class LoadFileConflictPageEditor, for merging / comparing a loaded
1091 pgsrc file with an existing page.
1098 // c-basic-offset: 4
1099 // c-hanging-comment-ender-p: nil
1100 // indent-tabs-mode: nil