2 rcs_id('$Id: editpage.php,v 1.84 2004-12-04 12:58:26 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 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);
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.png");
127 $undo_d_btn = $WikiTheme->getImageURL("ed_undo_d.png");
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.png",
236 "sample"=>_("Bold text"),
237 "tip"=>_("Bold text")),
238 array("image"=>"ed_format_italic.png",
241 "sample"=>_("Italic text"),
242 "tip"=>_("Italic text")),
243 array("image"=>"ed_pagelink.png",
246 "sample"=>_("optional label | PageName"),
247 "tip"=>_("Link to page")),
248 array("image"=>"ed_link.png",
251 "sample"=>_("optional label | http://www.example.com"),
252 "tip"=>_("External link (remember http:// prefix)")),
253 array("image"=>"ed_headline.png",
256 "sample"=>_("Headline text"),
257 "tip"=>_("Level 1 headline")),
258 array("image"=>"ed_image.png",
261 "sample"=>_("Example.jpg"),
262 "tip"=>_("Embedded image")),
263 array("image"=>"ed_nowiki.png",
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.png",
269 "open" => " --" . $GLOBALS['request']->_user->UserName(),
272 "tip"=>_("Your signature")),
273 array("image"=>"ed_hr.png",
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.png"));
282 $btn->addTooltip(_("Save"));
283 $toolbar.='document.writeln("'.addslashes($btn->asXml()).'");'."\n";
284 $btn = new SubmitImageButton(_("Preview"), "edit[preview]", 'toolbar', $WikiTheme->getImageURL("ed_preview.png"));
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.png");
304 //$redo_btn = $WikiTheme->getImageURL("ed_redo.png");
305 $sr_btn = $WikiTheme->getImageURL("ed_replace.png");
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(''.
332 _("Category").' OR '.
334 if ($pages->count()) {
335 $categories = array();
336 while ($p = $pages->next()){
337 $categories[] = $p->getName();
339 $more_buttons = HTML::img(array('class'=>"toolbar",
340 'src' => $WikiTheme->getImageURL("ed_category.png"),
341 'title'=>_("AddCategory"),
342 'onclick'=>"showPulldown('".
343 _("Insert Categories (double-click)")
344 ."',['".join("','",$categories)."'],'"
348 if ($sr_html) $sr_html = HTML($sr_html, $more_buttons);
349 else $sr_html = $more_buttons;
352 $toolbar_end = "document.writeln(\"</div>\");";
353 // don't use document.write for replace, otherwise self.opener is not defined.
355 return HTML(Javascript($toolbar),
357 Javascript($toolbar_end));
359 return HTML(Javascript($toolbar . $toolbar_end));
362 function output ($template, $title_fs) {
364 $selected = &$this->selected;
365 $current = &$this->current;
367 if ($selected && $selected->getVersion() != $current->getVersion()) {
369 $pagelink = WikiLink($selected);
373 $pagelink = WikiLink($this->page);
377 $title = new FormattedText ($title_fs, $pagelink);
378 if (USE_HTMLAREA and $template == 'editpage') {
379 $WikiTheme->addMoreHeaders(Edit_HtmlArea_Head());
380 //$tokens['PAGE_SOURCE'] = Edit_HtmlArea_ConvertBefore($this->_content);
382 $template = Template($template, $this->tokens);
383 GeneratePage($template, $title, $rev);
388 function viewSource () {
389 assert($this->isInitialEdit());
390 assert($this->selected);
392 $this->tokens['PAGE_SOURCE'] = $this->_content;
393 return $this->output('viewsource', _("View Source: %s"));
396 function updateLock() {
397 if ((bool)$this->page->get('locked') == (bool)$this->locked)
398 return false; // Not changed.
400 if (!$this->user->isAdmin()) {
401 // FIXME: some sort of message
402 return false; // not allowed.
405 $this->page->set('locked', (bool)$this->locked);
406 $this->tokens['LOCK_CHANGED_MSG']
407 = $this->locked ? _("Page now locked.") : _("Page now unlocked.");
409 return true; // lock changed.
412 function savePage () {
413 $request = &$this->request;
415 if ($this->isUnchanged()) {
416 // Allow admin lock/unlock even if
417 // no text changes were made.
418 if ($this->updateLock()) {
419 $dbi = $request->getDbh();
422 // Save failed. No changes made.
423 $this->_redirectToBrowsePage();
424 // user will probably not see the rest of this...
425 include_once('lib/display.php');
426 // force browse of current version:
427 $request->setArg('version', false);
428 displayPage($request, 'nochanges');
432 if ($this->isSpam()) {
435 // Save failed. No changes made.
436 $this->_redirectToBrowsePage();
437 // user will probably not see the rest of this...
438 include_once('lib/display.php');
439 // force browse of current version:
440 $request->setArg('version', false);
441 displayPage($request, 'nochanges');
446 $page = &$this->page;
448 // Include any meta-data from original page version which
449 // has not been explicitly updated.
450 // (Except don't propagate pgsrc_version --- moot for now,
451 // because at present it never gets into the db...)
452 $meta = $this->selected->getMetaData();
453 unset($meta['pgsrc_version']);
454 $meta = array_merge($meta, $this->meta);
457 $this->_content = $this->getContent();
458 $newrevision = $page->save($this->_content, $this->_currentVersion + 1, $meta);
459 if (!isa($newrevision, 'wikidb_pagerevision')) {
460 // Save failed. (Concurrent updates).
464 // New contents successfully saved...
467 // Clean out archived versions of this page.
468 include_once('lib/ArchiveCleaner.php');
469 $cleaner = new ArchiveCleaner($GLOBALS['ExpireParams']);
470 $cleaner->cleanPageRevisions($page);
472 /* generate notification emails done in WikiDB::save to catch all direct calls
475 $dbi = $request->getDbh();
476 $warnings = $dbi->GenericWarnings();
480 if (empty($warnings) && ! $WikiTheme->getImageURL('signature')) {
481 // Do redirect to browse page if no signature has
482 // been defined. In this case, the user will most
483 // likely not see the rest of the HTML we generate
485 $this->_redirectToBrowsePage();
488 // Force browse of current page version.
489 $request->setArg('version', false);
490 //$request->setArg('action', false);
492 $template = Template('savepage', $this->tokens);
493 $template->replace('CONTENT', $newrevision->getTransformedContent());
494 if (!empty($warnings))
495 $template->replace('WARNINGS', $warnings);
497 $pagelink = WikiLink($page);
499 GeneratePage($template, fmt("Saved: %s", $pagelink), $newrevision);
503 function isConcurrentUpdate () {
504 assert($this->current->getVersion() >= $this->_currentVersion);
505 return $this->current->getVersion() != $this->_currentVersion;
508 function canEdit () {
509 return !$this->page->get('locked') || $this->user->isAdmin();
512 function isInitialEdit () {
513 return $this->_initialEdit;
516 function isUnchanged () {
517 $current = &$this->current;
519 if ($this->meta['markup'] != $current->get('markup'))
522 return $this->_content == $current->getPackedContent();
526 * Handle AntiSpam here. How? http://wikiblacklist.blogspot.com/
527 * Need to check dynamically some blacklist content (plugin WikiAccessRestrictions)
529 * More then 20 new external links
534 * content patterns by babycart
537 $current = &$this->current;
538 $request = &$this->request;
539 $oldtext = $current->getPackedContent();
540 $newtext =& $this->_content;
541 // 1. Not more then 20 new external links
542 if ($this->numLinks($newtext) - $this->numLinks($oldtext) >= 20) {
543 $this->tokens['PAGE_LOCKED_MESSAGE'] =
544 HTML($this->getSpamMessage(),
545 HTML::p(HTML::em(_("Too many external links."))));
548 // 2. external babycart (SpamAssassin) check
549 // This will probably prevent from discussing sex or viagra related topics. So beware.
550 if (ENABLE_SPAMASSASSIN) {
551 $user = $request->getUser();
552 include_once("lib/spam_babycart.php");
553 if ($babycart = check_babycart($newtext, $request->get("REMOTE_ADDR"), $user->getId())) {
554 if (is_array($babycart))
555 $this->tokens['PAGE_LOCKED_MESSAGE'] =
556 HTML($this->getSpamMessage(),
557 HTML::p(HTML::em(_("SpamAssassin reports: ", join("\n",$babycart)))));
564 /** Number of external links in the wikitext
566 function numLinks(&$text) {
567 return substr_count($text, "http://");
570 /** Header of the Anti Spam message
572 function getSpamMessage () {
574 HTML(HTML::h2(_("Spam Prevention")),
575 HTML::p(_("This page edit seems to contain spam and was therefore not saved."),
577 _("Sorry for the inconvenience.")),
581 function getPreview () {
582 include_once('lib/PageType.php');
583 $this->_content = $this->getContent();
584 return new TransformedText($this->page, $this->_content, $this->meta);
587 // possibly convert HTMLAREA content back to Wiki markup
588 function getContent () {
590 $xml_output = Edit_HtmlArea_ConvertAfter($this->_content);
591 $this->_content = join("",$xml_output->_content);
592 return $this->_content;
594 return $this->_content;
598 function getLockedMessage () {
600 HTML(HTML::h2(_("Page Locked")),
601 HTML::p(_("This page has been locked by the administrator so your changes can not be saved.")),
602 HTML::p(_("(Copy your changes to the clipboard. You can try editing a different page or save your text in a text editor.)")),
603 HTML::p(_("Sorry for the inconvenience.")));
606 function getConflictMessage ($unresolved = false) {
608 xgettext only knows about c/c++ line-continuation strings
609 it does not know about php's dot operator.
610 We want to translate this entire paragraph as one string, of course.
613 //$re_edit_link = Button('edit', _("Edit the new version"), $this->page);
616 $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.",
617 "<<<<<<< ". _("Your version"),
618 ">>>>>>> ". _("Other version")));
620 $message = HTML::p(_("Please check it through before saving."));
624 /*$steps = HTML::ol(HTML::li(_("Copy your changes to the clipboard or to another temporary place (e.g. text editor).")),
625 HTML::li(fmt("%s of the page. You should now see the most current version of the page. Your changes are no longer there.",
627 HTML::li(_("Make changes to the file again. Paste your additions from the clipboard (or text editor).")),
628 HTML::li(_("Save your updated changes.")));
631 HTML(HTML::h2(_("Conflicting Edits!")),
632 HTML::p(_("In the time since you started editing this page, another user has saved a new version of it.")),
633 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.")),
638 function getTextArea () {
639 $request = &$this->request;
641 // wrap=virtual is not HTML4, but without it NS4 doesn't wrap
643 $readonly = ! $this->canEdit(); // || $this->isConcurrentUpdate();
645 $html = $this->getPreview();
646 $this->_wikicontent = $this->_content;
647 $this->_content = $html->asXML();
650 /** <textarea wrap="virtual"> is not valid xhtml but Netscape 4 requires it
651 * to wrap long lines.
653 $textarea = HTML::textarea(array('class' => 'wikiedit',
654 'name' => 'edit[content]',
655 'id' => 'edit[content]',
656 'rows' => $request->getPref('editHeight'),
657 'cols' => $request->getPref('editWidth'),
658 'readonly' => (bool) $readonly),
661 $textarea->setAttr('wrap', 'virtual');
663 return Edit_HtmlArea_Textarea($textarea,$this->_wikicontent,'edit[content]');
669 * TODO: maybe support an uploadfile button.
671 function getFormElements () {
672 $request = &$this->request;
673 $page = &$this->page;
675 $h = array('action' => 'edit',
676 'pagename' => $page->getName(),
677 'version' => $this->version,
678 'edit[pagetype]' => $this->meta['pagetype'],
679 'edit[current_version]' => $this->_currentVersion);
681 $el['HIDDEN_INPUTS'] = HiddenInputs($h);
682 $el['EDIT_TEXTAREA'] = $this->getTextArea();
684 = HTML::input(array('type' => 'text',
685 'class' => 'wikitext',
686 'name' => 'edit[summary]',
689 'value' => $this->meta['summary']));
691 = HTML::input(array('type' => 'checkbox',
692 'name' => 'edit[minor_edit]',
693 'checked' => (bool) $this->meta['is_minor_edit']));
695 = HTML::input(array('type' => 'checkbox',
696 'name' => 'edit[markup]',
698 'checked' => $this->meta['markup'] < 2.0,
699 'id' => 'useOldMarkup',
700 'onclick' => 'showOldMarkupRules(this.checked)'));
703 = HTML::input(array('type' => 'checkbox',
704 'name' => 'edit[locked]',
705 'disabled' => (bool) !$this->user->isadmin(),
706 'checked' => (bool) $this->locked));
708 $el['PREVIEW_B'] = Button('submit:edit[preview]', _("Preview"),
711 //if (!$this->isConcurrentUpdate() && $this->canEdit())
712 $el['SAVE_B'] = Button('submit:edit[save]', _("Save"), 'wikiaction');
714 $el['IS_CURRENT'] = $this->version == $this->current->getVersion();
719 function _redirectToBrowsePage() {
720 $this->request->redirect(WikiURL($this->page, false, 'absolute_url'));
723 function _restoreState () {
724 $request = &$this->request;
726 $posted = $request->getArg('edit');
727 $request->setArg('edit', false);
729 if (!$posted || !$request->isPost()
730 || $request->getArg('action') != 'edit')
733 if (!isset($posted['content']) || !is_string($posted['content']))
735 $this->_content = preg_replace('/[ \t\r]+\n/', "\n",
736 rtrim($posted['content']));
737 $this->_content = $this->getContent();
739 $this->_currentVersion = (int) $posted['current_version'];
741 if ($this->_currentVersion < 0)
743 if ($this->_currentVersion > $this->current->getVersion())
744 return false; // FIXME: some kind of warning?
746 $is_old_markup = !empty($posted['markup']) && $posted['markup'] == 'old';
747 $meta['markup'] = $is_old_markup ? false : 2.0;
748 $meta['summary'] = trim(substr($posted['summary'], 0, 256));
749 $meta['is_minor_edit'] = !empty($posted['minor_edit']);
750 $meta['pagetype'] = !empty($posted['pagetype']) ? $posted['pagetype'] : false;
751 $this->meta = array_merge($this->meta, $meta);
752 $this->locked = !empty($posted['locked']);
754 if (!empty($posted['preview']))
755 $this->editaction = 'preview';
756 elseif (!empty($posted['save']))
757 $this->editaction = 'save';
759 $this->editaction = 'edit';
764 function _initializeState () {
765 $request = &$this->request;
766 $current = &$this->current;
767 $selected = &$this->selected;
768 $user = &$this->user;
771 NoSuchRevision($request, $this->page, $this->version); // noreturn
773 $this->_currentVersion = $current->getVersion();
774 $this->_content = $selected->getPackedContent();
776 $this->meta['summary'] = '';
777 $this->locked = $this->page->get('locked');
779 // If author same as previous author, default minor_edit to on.
780 $age = $this->meta['mtime'] - $current->get('mtime');
781 $this->meta['is_minor_edit'] = ( $age < MINOR_EDIT_TIMEOUT
782 && $current->get('author') == $user->getId()
785 // Default for new pages is new-style markup.
786 if ($selected->hasDefaultContents())
787 $is_new_markup = true;
789 $is_new_markup = $selected->get('markup') >= 2.0;
791 $this->meta['markup'] = $is_new_markup ? 2.0: false;
792 $this->meta['pagetype'] = $selected->get('pagetype');
793 $this->editaction = 'edit';
797 class LoadFileConflictPageEditor
800 function editPage ($saveFailed = true) {
801 $tokens = &$this->tokens;
803 if (!$this->canEdit()) {
804 if ($this->isInitialEdit())
805 return $this->viewSource();
806 $tokens['PAGE_LOCKED_MESSAGE'] = $this->getLockedMessage();
808 elseif ($this->editaction == 'save') {
809 if ($this->savePage())
810 return true; // Page saved.
814 if ($saveFailed || $this->isConcurrentUpdate())
816 // Get the text of the original page, and the two conflicting edits
817 // The diff class takes arrays as input. So retrieve content as
818 // an array, or convert it as necesary.
819 $orig = $this->page->getRevision($this->_currentVersion);
820 $this_content = explode("\n", $this->_content);
821 $other_content = $this->current->getContent();
822 include_once("lib/diff.php");
823 $diff2 = new Diff($other_content, $this_content);
824 $context_lines = max(4, count($other_content) + 1,
825 count($this_content) + 1);
826 $fmt = new BlockDiffFormatter($context_lines);
828 $this->_content = $fmt->format($diff2);
829 // FIXME: integrate this into class BlockDiffFormatter
830 $this->_content = str_replace(">>>>>>>\n<<<<<<<\n", "=======\n",
832 $this->_content = str_replace("<<<<<<<\n>>>>>>>\n", "=======\n",
835 $this->_currentVersion = $this->current->getVersion();
836 $this->version = $this->_currentVersion;
837 $tokens['CONCURRENT_UPDATE_MESSAGE'] = $this->getConflictMessage();
840 if ($this->editaction == 'preview')
841 $tokens['PREVIEW_CONTENT'] = $this->getPreview(); // FIXME: convert to _MESSAGE?
843 // FIXME: NOT_CURRENT_MESSAGE?
845 $tokens = array_merge($tokens, $this->getFormElements());
847 return $this->output('editpage', _("Merge and Edit: %s"));
848 // FIXME: this doesn't display
851 function output ($template, $title_fs) {
852 $selected = &$this->selected;
853 $current = &$this->current;
855 if ($selected && $selected->getVersion() != $current->getVersion()) {
857 $pagelink = WikiLink($selected);
861 $pagelink = WikiLink($this->page);
864 $title = new FormattedText ($title_fs, $pagelink);
865 $template = Template($template, $this->tokens);
867 //GeneratePage($template, $title, $rev);
871 function getConflictMessage () {
872 $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.",
875 HTML::p(_("Please check it through before saving."))));
881 $Log: not supported by cvs2svn $
882 Revision 1.83 2004/12/04 11:55:39 rurban
883 First simple AntiSpam prevention:
884 No more than 20 new http:// links allowed
886 Revision 1.82 2004/11/30 22:21:56 rurban
887 changed gif to optimized (pngout) png
889 Revision 1.81 2004/11/29 17:57:27 rurban
890 translated pulldown buttons
892 Revision 1.80 2004/11/25 17:20:51 rurban
893 and again a couple of more native db args: backlinks
895 Revision 1.79 2004/11/21 11:59:20 rurban
896 remove final \n to be ob_cache independent
898 Revision 1.78 2004/11/16 17:57:45 rurban
899 fix search&replace button
900 use new addTagButton machinery
901 new showPulldown for categories, TODO: in a seperate request
903 Revision 1.77 2004/11/15 15:52:35 rurban
906 Revision 1.76 2004/11/15 15:37:34 rurban
908 don't use document.write for replace, otherwise self.opener is not defined.
910 Revision 1.75 2004/09/16 08:00:52 rurban
913 Revision 1.74 2004/07/03 07:36:28 rurban
914 do not get unneccessary content
916 Revision 1.73 2004/06/16 21:23:44 rurban
917 fixed non-object fatal #215
919 Revision 1.72 2004/06/14 11:31:37 rurban
920 renamed global $Theme to $WikiTheme (gforge nameclash)
921 inherit PageList default options from PageList
922 default sortby=pagename
923 use options in PageList_Selectable (limit, sortby, ...)
924 added action revert, with button at action=diff
925 added option regex to WikiAdminSearchReplace
927 Revision 1.71 2004/06/03 18:06:29 rurban
928 fix file locking issues (only needed on write)
929 fixed immediate LANG and THEME in-session updates if not stored in prefs
930 advanced editpage toolbars (search & replace broken)
932 Revision 1.70 2004/06/02 20:47:47 rurban
933 dont use the wikiaction class
935 Revision 1.69 2004/06/02 10:17:56 rurban
936 integrated search/replace into toolbar
937 added save+preview buttons
939 Revision 1.68 2004/06/01 15:28:00 rurban
940 AdminUser only ADMIN_USER not member of Administrators
941 some RateIt improvements by dfrankow
944 Revision _1.6 2004/05/26 15:48:00 syilek
945 fixed problem with creating page with slashes from one true page
947 Revision _1.5 2004/05/25 16:51:53 syilek
948 added ability to create a page from the category page and not have to edit it
950 Revision 1.67 2004/05/27 17:49:06 rurban
951 renamed DB_Session to DbSession (in CVS also)
952 added WikiDB->getParam and WikiDB->getAuthParam method to get rid of globals
953 remove leading slash in error message
954 added force_unlock parameter to File_Passwd (no return on stale locks)
955 fixed adodb session AffectedRows
956 added FileFinder helpers to unify local filenames and DATA_PATH names
957 editpage.php: new edit toolbar javascript on ENABLE_EDIT_TOOLBAR
959 Revision 1.66 2004/04/29 23:25:12 rurban
960 re-ordered locale init (as in 1.3.9)
961 fixed loadfile with subpages, and merge/restore anyway
964 Revision 1.65 2004/04/18 01:11:52 rurban
965 more numeric pagename fixes.
966 fixed action=upload with merge conflict warnings.
967 charset changed from constant to global (dynamic utf-8 switching)
969 Revision 1.64 2004/04/06 19:48:56 rurban
970 temp workaround for action=edit AddComment form
972 Revision 1.63 2004/03/24 19:39:02 rurban
973 php5 workaround code (plus some interim debugging code in XmlElement)
974 php5 doesn't work yet with the current XmlElement class constructors,
975 WikiUserNew does work better than php4.
976 rewrote WikiUserNew user upgrading to ease php5 update
977 fixed pref handling in WikiUserNew
978 added Email Notification
979 added simple Email verification
980 removed emailVerify userpref subclass: just a email property
981 changed pref binary storage layout: numarray => hash of non default values
982 print optimize message only if really done.
983 forced new cookie policy: delete pref cookies, use only WIKI_ID as plain string.
984 prefs should be stored in db or homepage, besides the current session.
986 Revision 1.62 2004/03/17 18:41:05 rurban
987 initial_content and template support for CreatePage
989 Revision 1.61 2004/03/12 20:59:17 rurban
990 important cookie fix by Konstantin Zadorozhny
991 new editpage feature: JS_SEARCHREPLACE
993 Revision 1.60 2004/02/15 21:34:37 rurban
994 PageList enhanced and improved.
995 fixed new WikiAdmin... plugins
996 editpage, Theme with exp. htmlarea framework
997 (htmlarea yet committed, this is really questionable)
998 WikiUser... code with better session handling for prefs
999 enhanced UserPreferences (again)
1000 RecentChanges for show_deleted: how should pages be deleted then?
1002 Revision 1.59 2003/12/07 20:35:26 carstenklapp
1003 Bugfix: Concurrent updates broken since after 1.3.4 release: Fatal
1004 error: Call to undefined function: gettransformedcontent() in
1005 /home/groups/p/ph/phpwiki/htdocs/phpwiki2/lib/editpage.php on line
1008 Revision 1.58 2003/03/10 18:25:22 dairiki
1009 Bug/typo fix. If you use the edit page to un/lock a page, it
1010 failed with: Fatal error: Call to a member function on a
1011 non-object in editpage.php on line 136
1013 Revision 1.57 2003/02/26 03:40:22 dairiki
1014 New action=create. Essentially the same as action=edit, except that if the
1015 page already exists, it falls back to action=browse.
1017 This is for use in the "question mark" links for unknown wiki words
1018 to avoid problems and confusion when following links from stale pages.
1019 (If the "unknown page" has been created in the interim, the user probably
1020 wants to view the page before editing it.)
1022 Revision 1.56 2003/02/21 18:07:14 dairiki
1023 Minor, nitpicky, currently inconsequential changes.
1025 Revision 1.55 2003/02/21 04:10:58 dairiki
1026 Fixes for new cached markup.
1027 Some minor code cleanups.
1029 Revision 1.54 2003/02/16 19:47:16 dairiki
1030 Update WikiDB timestamp when editing or deleting pages.
1032 Revision 1.53 2003/02/15 23:20:27 dairiki
1033 Redirect back to browse current version of page upon save,
1034 even when no changes were made.
1036 Revision 1.52 2003/01/03 22:22:00 carstenklapp
1037 Minor adjustments to diff block markers ("<<<<<<<"). Source reformatting.
1039 Revision 1.51 2003/01/03 02:43:26 carstenklapp
1040 New class LoadFileConflictPageEditor, for merging / comparing a loaded
1041 pgsrc file with an existing page.
1048 // c-basic-offset: 4
1049 // c-hanging-comment-ender-p: nil
1050 // indent-tabs-mode: nil