2 rcs_id('$Id: editpage.php,v 1.114 2007-07-18 09:49:31 labbenes Exp $');
4 require_once('lib/Template.php');
8 function PageEditor (&$request) {
9 $this->request = &$request;
11 $this->user = $request->getUser();
12 $this->page = $request->getPage();
14 $this->current = $this->page->getCurrentRevision(false);
16 // HACKish short circuit to browse on action=create
17 if ($request->getArg('action') == 'create') {
18 if (! $this->current->hasDefaultContents())
19 $request->redirect(WikiURL($this->page->getName())); // noreturn
22 $this->meta = array('author' => $this->user->getId(),
23 'author_id' => $this->user->getAuthenticatedId(),
26 $this->tokens = array();
29 $backend = WYSIWYG_BACKEND;
30 // TODO: error message
31 require_once("lib/WysiwygEdit/$backend.php");
32 $class = "WysiwygEdit_$backend";
33 $this->WysiwygEdit = new $class();
36 require_once('lib/Captcha.php');
37 $this->Captcha = new Captcha($this->meta);
40 $version = $request->getArg('version');
41 if ($version !== false) {
42 $this->selected = $this->page->getRevision($version);
43 $this->version = $version;
46 $this->version = $this->current->getVersion();
47 $this->selected = $this->page->getRevision($this->version);
50 if ($this->_restoreState()) {
51 $this->_initialEdit = false;
54 $this->_initializeState();
55 $this->_initialEdit = true;
57 // The edit request has specified some initial content from a template
58 if ( ($template = $request->getArg('template'))
59 and $request->_dbi->isWikiPage($template))
61 $page = $request->_dbi->getPage($template);
62 $current = $page->getCurrentRevision();
63 $this->_content = $current->getPackedContent();
64 } elseif ($initial_content = $request->getArg('initial_content')) {
65 $this->_content = $initial_content;
66 $this->_redirect_to = $request->getArg('save_and_redirect_to');
70 header("Content-Type: text/html; charset=" . $GLOBALS['charset']);
73 function editPage () {
76 $tokens = &$this->tokens;
77 $tokens['PAGE_LOCKED_MESSAGE'] = '';
78 $tokens['CONCURRENT_UPDATE_MESSAGE'] = '';
81 if (isset($r->args['pref']['editWidth'])
82 and ($r->getPref('editWidth') != $r->args['pref']['editWidth'])) {
83 $r->_prefs->set('editWidth', $r->args['pref']['editWidth']);
85 if (isset($r->args['pref']['editHeight'])
86 and ($r->getPref('editHeight') != $r->args['pref']['editHeight'])) {
87 $r->_prefs->set('editHeight', $r->args['pref']['editHeight']);
90 if ($this->isModerated())
91 $tokens['PAGE_LOCKED_MESSAGE'] = $this->getModeratedMessage();
93 if (! $this->canEdit()) {
94 if ($this->isInitialEdit())
95 return $this->viewSource();
96 $tokens['PAGE_LOCKED_MESSAGE'] = $this->getLockedMessage();
98 elseif ($r->getArg('save_and_redirect_to') != "") {
99 if (ENABLE_CAPTCHA && $this->Captcha->Failed()) {
100 $this->tokens['PAGE_LOCKED_MESSAGE'] =
101 HTML::p(HTML::h1($this->Captcha->failed_msg));
103 elseif ( $this->savePage()) {
105 $request->setArg('action', false);
106 $r->redirect(WikiURL($r->getArg('save_and_redirect_to')));
107 return true; // Page saved.
111 elseif ($this->editaction == 'save') {
112 if (ENABLE_CAPTCHA && $this->Captcha->Failed()) {
113 $this->tokens['PAGE_LOCKED_MESSAGE'] =
114 HTML::p(HTML::h1($this->Captcha->failed_msg));
116 elseif ($this->savePage()) {
117 return true; // Page saved.
123 // coming from loadfile conflicts
124 elseif ($this->editaction == 'keep_old') {
125 // keep old page and do nothing
126 $this->_redirectToBrowsePage();
127 //$r->redirect(WikiURL($r->getArg('save_and_redirect_to')));
130 elseif ($this->editaction == 'overwrite') {
131 // take the new content without diff
132 $source = $this->request->getArg('loadfile');
133 require_once('lib/loadsave.php');
134 $this->request->setArg('loadfile', 1);
135 $this->request->setArg('overwrite', 1);
136 $this->request->setArg('merge', 0);
137 LoadFileOrDir($this->request);
138 $this->_redirectToBrowsePage();
139 //$r->redirect(WikiURL($r->getArg('save_and_redirect_to')));
142 elseif ($this->editaction == 'upload') {
144 $plugin = WikiPluginLoader("UpLoad");
146 // add link to content
150 if ($saveFailed and $this->isConcurrentUpdate())
152 // Get the text of the original page, and the two conflicting edits
153 // The diff3 class takes arrays as input. So retrieve content as
154 // an array, or convert it as necesary.
155 $orig = $this->page->getRevision($this->_currentVersion);
156 // FIXME: what if _currentVersion has be deleted?
157 $orig_content = $orig->getContent();
158 $this_content = explode("\n", $this->_content);
159 $other_content = $this->current->getContent();
160 require_once("lib/diff3.php");
161 $diff = new diff3($orig_content, $this_content, $other_content);
162 $output = $diff->merged_output(_("Your version"), _("Other version"));
163 // Set the content of the textarea to the merged diff
164 // output, and update the version
165 $this->_content = implode ("\n", $output);
166 $this->_currentVersion = $this->current->getVersion();
167 $this->version = $this->_currentVersion;
168 $unresolved = $diff->ConflictingBlocks;
169 $tokens['CONCURRENT_UPDATE_MESSAGE']
170 = $this->getConflictMessage($unresolved);
171 } elseif ($saveFailed && !$this->_isSpam) {
172 $tokens['CONCURRENT_UPDATE_MESSAGE'] =
173 HTML(HTML::h2(_("Some internal editing error")),
174 HTML::p(_("Your are probably trying to edit/create an invalid version of this page.")),
175 HTML::p(HTML::em(_("&version=-1 might help."))));
178 if ($this->editaction == 'edit_convert')
179 $tokens['PREVIEW_CONTENT'] = $this->getConvertedPreview();
180 if ($this->editaction == 'preview')
181 $tokens['PREVIEW_CONTENT'] = $this->getPreview(); // FIXME: convert to _MESSAGE?
182 if ($this->editaction == 'diff')
183 $tokens['PREVIEW_CONTENT'] = $this->getDiff();
185 // FIXME: NOT_CURRENT_MESSAGE?
186 $tokens = array_merge($tokens, $this->getFormElements());
188 if (ENABLE_EDIT_TOOLBAR and !ENABLE_WYSIWYG) {
189 require_once("lib/EditToolbar.php");
190 $toolbar = new EditToolbar();
191 $tokens = array_merge($tokens, $toolbar->getTokens());
194 return $this->output('editpage', _("Edit: %s"));
197 function output ($template, $title_fs) {
199 $selected = &$this->selected;
200 $current = &$this->current;
202 if ($selected && $selected->getVersion() != $current->getVersion()) {
204 $pagelink = WikiLink($selected);
208 $pagelink = WikiLink($this->page);
211 $title = new FormattedText ($title_fs, $pagelink);
212 // not for dumphtml or viewsource
213 if (ENABLE_WYSIWYG and $template == 'editpage') {
214 $WikiTheme->addMoreHeaders($this->WysiwygEdit->Head());
215 //$tokens['PAGE_SOURCE'] = $this->WysiwygEdit->ConvertBefore($this->_content);
217 $template = Template($template, $this->tokens);
218 /* Tell google (and others) not to take notice of edit links */
219 if (GOOGLE_LINKS_NOFOLLOW)
220 $args = array('ROBOTS_META' => "noindex,nofollow");
221 GeneratePage($template, $title, $rev);
226 function viewSource () {
227 assert($this->isInitialEdit());
228 assert($this->selected);
230 $this->tokens['PAGE_SOURCE'] = $this->_content;
231 $this->tokens['HIDDEN_INPUTS'] = HiddenInputs($this->request->getArgs());
232 return $this->output('viewsource', _("View Source: %s"));
235 function updateLock() {
236 if ((bool)$this->page->get('locked') == (bool)$this->locked)
237 return false; // Not changed.
239 if (!$this->user->isAdmin()) {
240 // FIXME: some sort of message
241 return false; // not allowed.
244 $this->page->set('locked', (bool)$this->locked);
245 $this->tokens['LOCK_CHANGED_MSG']
246 = $this->locked ? _("Page now locked.") : _("Page now unlocked.");
248 return true; // lock changed.
251 function savePage () {
252 $request = &$this->request;
254 if ($this->isUnchanged()) {
255 // Allow admin lock/unlock even if
256 // no text changes were made.
257 if ($this->updateLock()) {
258 $dbi = $request->getDbh();
261 // Save failed. No changes made.
262 $this->_redirectToBrowsePage();
263 // user will probably not see the rest of this...
264 require_once('lib/display.php');
265 // force browse of current version:
266 $request->setArg('action', false);
267 $request->setArg('version', false);
268 displayPage($request, 'nochanges');
272 if (!$this->user->isAdmin() and $this->isSpam()) {
273 $this->_isSpam = true;
276 // Save failed. No changes made.
277 $this->_redirectToBrowsePage();
278 // user will probably not see the rest of this...
279 require_once('lib/display.php');
280 // force browse of current version:
281 $request->setArg('version', false);
282 displayPage($request, 'nochanges');
287 $page = &$this->page;
289 // Include any meta-data from original page version which
290 // has not been explicitly updated.
291 // (Except don't propagate pgsrc_version --- moot for now,
292 // because at present it never gets into the db...)
293 $meta = $this->selected->getMetaData();
294 unset($meta['pgsrc_version']);
295 $meta = array_merge($meta, $this->meta);
298 $this->_content = $this->getContent();
299 $newrevision = $page->save($this->_content,
302 : $this->_currentVersion + 1,
305 if (!isa($newrevision, 'WikiDB_PageRevision')) {
306 // Save failed. (Concurrent updates).
310 // New contents successfully saved...
313 // Clean out archived versions of this page.
314 require_once('lib/ArchiveCleaner.php');
315 $cleaner = new ArchiveCleaner($GLOBALS['ExpireParams']);
316 $cleaner->cleanPageRevisions($page);
318 /* generate notification emails done in WikiDB::save to catch
319 all direct calls (admin plugins) */
321 // look at the errorstack
322 $errors = $GLOBALS['ErrorManager']->_postponed_errors;
323 $warnings = $GLOBALS['ErrorManager']->getPostponedErrorsAsHTML();
324 $GLOBALS['ErrorManager']->_postponed_errors = $errors;
326 $dbi = $request->getDbh();
330 if (empty($warnings->_content) && ! $WikiTheme->getImageURL('signature')) {
331 // Do redirect to browse page if no signature has
332 // been defined. In this case, the user will most
333 // likely not see the rest of the HTML we generate
335 $request->setArg('action', false);
336 $this->_redirectToBrowsePage();
339 // Force browse of current page version.
340 $request->setArg('version', false);
341 // testme: does preview and more need action=edit?
342 $request->setArg('action', false);
344 $template = Template('savepage', $this->tokens);
345 $template->replace('CONTENT', $newrevision->getTransformedContent());
346 if (!empty($warnings->_content)) {
347 $template->replace('WARNINGS', $warnings);
348 unset($GLOBALS['ErrorManager']->_postponed_errors);
351 $pagelink = WikiLink($page);
353 GeneratePage($template, fmt("Saved: %s", $pagelink), $newrevision);
357 function isConcurrentUpdate () {
358 assert($this->current->getVersion() >= $this->_currentVersion);
359 return $this->current->getVersion() != $this->_currentVersion;
362 function canEdit () {
363 return !$this->page->get('locked') || $this->user->isAdmin();
366 function isInitialEdit () {
367 return $this->_initialEdit;
370 function isUnchanged () {
371 $current = &$this->current;
373 if ($this->meta['markup'] != $current->get('markup'))
376 return $this->_content == $current->getPackedContent();
380 * Handle AntiSpam here. How? http://wikiblacklist.blogspot.com/
381 * Need to check dynamically some blacklist wikipage settings
382 * (plugin WikiAccessRestrictions) and some static blacklist.
384 * Always: More then 20 new external links
385 * ENABLE_SPAMASSASSIN: content patterns by babycart (only php >= 4.3 for now)
386 * ENABLE_SPAMBLOCKLIST: content domain blacklist
389 $current = &$this->current;
390 $request = &$this->request;
392 $oldtext = $current->getPackedContent();
393 $newtext =& $this->_content;
394 $numlinks = $this->numLinks($newtext);
395 $newlinks = $numlinks - $this->numLinks($oldtext);
396 // FIXME: in longer texts the NUM_SPAM_LINKS number should be increased.
397 // better use a certain text : link ratio.
399 // 1. Not more then 20 new external links
400 if ($newlinks >= NUM_SPAM_LINKS)
402 // Allow strictly authenticated users?
403 // TODO: mail the admin?
404 $this->tokens['PAGE_LOCKED_MESSAGE'] =
405 HTML($this->getSpamMessage(),
406 HTML::p(HTML::strong(_("Too many external links."))));
409 // 2. external babycart (SpamAssassin) check
410 // This will probably prevent from discussing sex or viagra related topics. So beware.
411 if (ENABLE_SPAMASSASSIN) {
412 require_once("lib/spam_babycart.php");
413 if ($babycart = check_babycart($newtext, $request->get("REMOTE_ADDR"),
414 $this->user->getId())) {
415 // TODO: mail the admin
416 if (is_array($babycart))
417 $this->tokens['PAGE_LOCKED_MESSAGE'] =
418 HTML($this->getSpamMessage(),
419 HTML::p(HTML::em(_("SpamAssassin reports: "),
420 join("\n", $babycart))));
424 // 3. extract (new) links and check surbl for blocked domains
425 if (ENABLE_SPAMBLOCKLIST and ($newlinks > 5)) {
426 require_once("lib/SpamBlocklist.php");
427 require_once("lib/InlineParser.php");
428 $parsed = TransformLinks($newtext);
429 $oldparsed = TransformLinks($oldtext);
431 foreach ($oldparsed->_content as $link) {
432 if (isa($link, 'Cached_ExternalLink') and !isa($link, 'Cached_InterwikiLink')) {
433 $uri = $link->_getURL($this->page->getName());
438 foreach ($parsed->_content as $link) {
439 if (isa($link, 'Cached_ExternalLink') and !isa($link, 'Cached_InterwikiLink')) {
440 $uri = $link->_getURL($this->page->getName());
441 // only check new links, so admins may add blocked links.
442 if (!array_key_exists($uri, $oldlinks) and ($res = IsBlackListed($uri))) {
443 // TODO: mail the admin
444 $this->tokens['PAGE_LOCKED_MESSAGE'] =
445 HTML($this->getSpamMessage(),
446 HTML::p(HTML::strong(_("External links contain blocked domains:")),
447 HTML::ul(HTML::li(sprintf(_("%s is listed at %s with %s"),
448 $uri." [".$res[2]."]", $res[0], $res[1])))));
461 /** Number of external links in the wikitext
463 function numLinks(&$text) {
464 return substr_count($text, "http://") + substr_count($text, "https://");
467 /** Header of the Anti Spam message
469 function getSpamMessage () {
471 HTML(HTML::h2(_("Spam Prevention")),
472 HTML::p(_("This page edit seems to contain spam and was therefore not saved."),
474 _("Sorry for the inconvenience.")),
478 function getPreview () {
479 require_once('lib/PageType.php');
480 $this->_content = $this->getContent();
481 return new TransformedText($this->page, $this->_content, $this->meta);
484 function getConvertedPreview () {
485 require_once('lib/PageType.php');
486 $this->_content = $this->getContent();
487 $this->meta['markup'] = 2.0;
488 $this->_content = ConvertOldMarkup($this->_content);
489 return new TransformedText($this->page, $this->_content, $this->meta);
492 function getDiff () {
493 require_once('lib/diff.php');
496 $diff = new Diff($this->current->getContent(), explode("\n", $this->getContent()));
497 if ($diff->isEmpty()) {
498 $html->pushContent(HTML::hr(),
499 HTML::p('[', _("Versions are identical"),
503 // New CSS formatted unified diffs (ugly in NS4).
504 $fmt = new HtmlUnifiedDiffFormatter;
505 // Use this for old table-formatted diffs.
506 //$fmt = new TableUnifiedDiffFormatter;
507 $html->pushContent($fmt->format($diff));
512 // possibly convert HTMLAREA content back to Wiki markup
513 function getContent () {
514 if (ENABLE_WYSIWYG) {
515 // don't store everything as html
516 if (!WYSIWYG_DEFAULT_PAGETYPE_HTML) {
517 // Wikiwyg shortcut to avoid the InlineTransformer:
518 if (WYSIWYG_BACKEND == "Wikiwyg") return $this->_content;
519 $xml_output = $this->WysiwygEdit->ConvertAfter($this->_content);
520 $this->_content = join("", $xml_output->_content);
522 $this->meta['pagetype'] = 'html';
524 return $this->_content;
526 return $this->_content;
530 function getLockedMessage () {
532 HTML(HTML::h2(_("Page Locked")),
533 HTML::p(_("This page has been locked by the administrator so your changes can not be saved.")),
534 HTML::p(_("(Copy your changes to the clipboard. You can try editing a different page or save your text in a text editor.)")),
535 HTML::p(_("Sorry for the inconvenience.")));
538 function isModerated() {
539 return $this->page->get('moderation');
541 function getModeratedMessage() {
543 HTML(HTML::h2(WikiLink(_("ModeratedPage"))),
544 HTML::p(fmt("You can edit away, but your changes will have to be approved by the defined moderators at the definition in %s", WikiLink(_("ModeratedPage")))),
545 HTML::p(fmt("The approval has a grace period of 5 days. If you have your E-Mail defined in your %s, you will get a notification of approval or rejection.",
546 WikiLink(_("UserPreferences")))));
548 function getConflictMessage ($unresolved = false) {
550 xgettext only knows about c/c++ line-continuation strings
551 it does not know about php's dot operator.
552 We want to translate this entire paragraph as one string, of course.
555 //$re_edit_link = Button('edit', _("Edit the new version"), $this->page);
558 $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.",
559 "<<<<<<< ". _("Your version"),
560 ">>>>>>> ". _("Other version")));
562 $message = HTML::p(_("Please check it through before saving."));
566 /*$steps = HTML::ol(HTML::li(_("Copy your changes to the clipboard or to another temporary place (e.g. text editor).")),
567 HTML::li(fmt("%s of the page. You should now see the most current version of the page. Your changes are no longer there.",
569 HTML::li(_("Make changes to the file again. Paste your additions from the clipboard (or text editor).")),
570 HTML::li(_("Save your updated changes.")));
573 HTML(HTML::h2(_("Conflicting Edits!")),
574 HTML::p(_("In the time since you started editing this page, another user has saved a new version of it.")),
575 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.")),
580 function getTextArea () {
581 $request = &$this->request;
583 $readonly = ! $this->canEdit(); // || $this->isConcurrentUpdate();
585 // WYSIWYG will need two pagetypes: raw wikitest and converted html
586 if (ENABLE_WYSIWYG) {
587 $this->_wikicontent = $this->_content;
588 $this->_content = $this->WysiwygEdit->ConvertBefore($this->_content);
589 // $this->getPreview();
590 //$this->_htmlcontent = $this->_content->asXML();
593 $textarea = HTML::textarea(array('class'=> 'wikiedit',
594 'name' => 'edit[content]',
595 'id' => 'edit-content',
596 'rows' => $request->getPref('editHeight'),
597 'cols' => $request->getPref('editWidth'),
598 'readonly' => (bool) $readonly),
600 /** <textarea wrap="virtual"> is not valid XHTML but Netscape 4 requires it
601 * to wrap long lines.
604 $textarea->setAttr('wrap', 'virtual');
605 if (ENABLE_WYSIWYG) {
606 return $this->WysiwygEdit->Textarea($textarea, $this->_wikicontent,
607 $textarea->getAttr('name'));
612 function getFormElements () {
614 $request = &$this->request;
615 $page = &$this->page;
617 $h = array('action' => 'edit',
618 'pagename' => $page->getName(),
619 'version' => $this->version,
620 'edit[pagetype]' => $this->meta['pagetype'],
621 'edit[current_version]' => $this->_currentVersion);
623 $el['HIDDEN_INPUTS'] = HiddenInputs($h);
624 $el['EDIT_TEXTAREA'] = $this->getTextArea();
625 if ( ENABLE_CAPTCHA ) {
626 $el = array_merge($el, $this->Captcha->getFormElements());
629 = HTML::input(array('type' => 'text',
630 'class' => 'wikitext',
631 'id' => 'edit-summary',
632 'name' => 'edit[summary]',
635 'value' => $this->meta['summary']));
637 = HTML::input(array('type' => 'checkbox',
638 'name' => 'edit[minor_edit]',
639 'id' => 'edit-minor_edit',
640 'checked' => (bool) $this->meta['is_minor_edit']));
642 = HTML::input(array('type' => 'checkbox',
643 'name' => 'edit[markup]',
645 'checked' => $this->meta['markup'] < 2.0,
646 'id' => 'useOldMarkup',
647 'onclick' => 'showOldMarkupRules(this.checked)'));
648 $el['OLD_MARKUP_CONVERT'] = ($this->meta['markup'] < 2.0)
649 ? Button('submit:edit[edit_convert]', _("Convert"), 'wikiaction') : '';
651 = HTML::input(array('type' => 'checkbox',
652 'name' => 'edit[locked]',
653 'id' => 'edit-locked',
654 'disabled' => (bool) !$this->user->isadmin(),
655 'checked' => (bool) $this->locked));
657 if (($this->version == 0) and ($request->getArg('mode') != 'wysiwyg')){
658 $el['WYSIWYG_B'] = Button(array("action" => "edit", "mode" => "wysiwyg"), "Wysiwyg Editor");
661 $el['PREVIEW_B'] = Button('submit:edit[preview]', _("Preview"),
663 array('accesskey'=> 'p',
664 'title' => 'Preview the current content [alt-p]'));
666 //if (!$this->isConcurrentUpdate() && $this->canEdit())
667 $el['SAVE_B'] = Button('submit:edit[save]',
668 _("Save"), 'wikiaction',
669 array('accesskey'=> 's',
670 'title' => 'Save the current content as wikipage [alt-s]'));
671 $el['CHANGES_B'] = Button('submit:edit[diff]',
672 _("Changes"), 'wikiaction',
673 array('accesskey'=> 'c',
674 'title' => 'Preview the current changes as diff [alt-c]'));
675 $el['UPLOAD_B'] = Button('submit:edit[upload]',
676 _("Upload"), 'wikiaction',
677 array('title' => 'Select a local file and press Upload to attach into this page'));
678 $el['SPELLCHECK_B'] = Button('submit:edit[SpellCheck]',
679 _("Spell Check"), 'wikiaction',
680 array('title' => 'Check the spelling'));
681 $el['IS_CURRENT'] = $this->version == $this->current->getVersion();
684 = HTML::input(array('type' => 'text',
687 'class' => "numeric",
688 'name' => 'pref[editWidth]',
689 'id' => 'pref-editWidth',
690 'value' => $request->getPref('editWidth'),
691 'onchange' => 'this.form.submit();'));
693 = HTML::input(array('type' => 'text',
696 'class' => "numeric",
697 'name' => 'pref[editHeight]',
698 'id' => 'pref-editHeight',
699 'value' => $request->getPref('editHeight'),
700 'onchange' => 'this.form.submit();'));
701 $el['SEP'] = $WikiTheme->getButtonSeparator();
702 $el['AUTHOR_MESSAGE'] = fmt("Author will be logged as %s.",
703 HTML::em($this->user->getId()));
708 function _redirectToBrowsePage() {
709 $this->request->redirect(WikiURL($this->page, false, 'absolute_url'));
712 function _restoreState () {
713 $request = &$this->request;
715 $posted = $request->getArg('edit');
716 $request->setArg('edit', false);
719 || !$request->isPost()
720 || !in_array($request->getArg('action'),array('edit','loadfile')))
723 if (!isset($posted['content']) || !is_string($posted['content']))
725 $this->_content = preg_replace('/[ \t\r]+\n/', "\n",
726 rtrim($posted['content']));
727 $this->_content = $this->getContent();
729 $this->_currentVersion = (int) $posted['current_version'];
731 if ($this->_currentVersion < 0)
733 if ($this->_currentVersion > $this->current->getVersion())
734 return false; // FIXME: some kind of warning?
736 $is_old_markup = !empty($posted['markup']) && $posted['markup'] == 'old';
737 $meta['markup'] = $is_old_markup ? false : 2.0;
738 $meta['summary'] = trim(substr($posted['summary'], 0, 256));
739 $meta['is_minor_edit'] = !empty($posted['minor_edit']);
740 $meta['pagetype'] = !empty($posted['pagetype']) ? $posted['pagetype'] : false;
741 if ( ENABLE_CAPTCHA )
742 $meta['captcha_input'] = !empty($posted['captcha_input']) ?
743 $posted['captcha_input'] : '';
745 $this->meta = array_merge($this->meta, $meta);
746 $this->locked = !empty($posted['locked']);
748 foreach (array('preview','save','edit_convert',
749 'keep_old','overwrite','diff','upload') as $o)
751 if (!empty($posted[$o]))
752 $this->editaction = $o;
754 if (empty($this->editaction))
755 $this->editaction = 'edit';
760 function _initializeState () {
761 $request = &$this->request;
762 $current = &$this->current;
763 $selected = &$this->selected;
764 $user = &$this->user;
767 NoSuchRevision($request, $this->page, $this->version); // noreturn
769 $this->_currentVersion = $current->getVersion();
770 $this->_content = $selected->getPackedContent();
772 $this->locked = $this->page->get('locked');
774 // If author same as previous author, default minor_edit to on.
775 $age = $this->meta['mtime'] - $current->get('mtime');
776 $this->meta['is_minor_edit'] = ( $age < MINOR_EDIT_TIMEOUT
777 && $current->get('author') == $user->getId()
780 // Default for new pages is new-style markup.
781 if ($selected->hasDefaultContents())
782 $is_new_markup = true;
784 $is_new_markup = $selected->get('markup') >= 2.0;
786 $this->meta['markup'] = $is_new_markup ? 2.0: false;
787 $this->meta['pagetype'] = $selected->get('pagetype');
788 if ($this->meta['pagetype'] == 'wikiblog')
789 $this->meta['summary'] = $selected->get('summary'); // keep blog title
791 $this->meta['summary'] = '';
792 $this->editaction = 'edit';
796 class LoadFileConflictPageEditor
799 function editPage ($saveFailed = true) {
800 $tokens = &$this->tokens;
802 if (!$this->canEdit()) {
803 if ($this->isInitialEdit()) {
804 return $this->viewSource();
806 $tokens['PAGE_LOCKED_MESSAGE'] = $this->getLockedMessage();
808 elseif ($this->editaction == 'save') {
809 if ($this->savePage()) {
810 return true; // Page saved.
815 if ($saveFailed || $this->isConcurrentUpdate())
817 // Get the text of the original page, and the two conflicting edits
818 // The diff class takes arrays as input. So retrieve content as
819 // an array, or convert it as necesary.
820 $orig = $this->page->getRevision($this->_currentVersion);
821 $this_content = explode("\n", $this->_content);
822 $other_content = $this->current->getContent();
823 require_once("lib/diff.php");
824 $diff2 = new Diff($other_content, $this_content);
825 $context_lines = max(4, count($other_content) + 1,
826 count($this_content) + 1);
827 $fmt = new BlockDiffFormatter($context_lines);
829 $this->_content = $fmt->format($diff2);
830 // FIXME: integrate this into class BlockDiffFormatter
831 $this->_content = str_replace(">>>>>>>\n<<<<<<<\n", "=======\n",
833 $this->_content = str_replace("<<<<<<<\n>>>>>>>\n", "=======\n",
836 $this->_currentVersion = $this->current->getVersion();
837 $this->version = $this->_currentVersion;
838 $tokens['CONCURRENT_UPDATE_MESSAGE'] = $this->getConflictMessage();
841 if ($this->editaction == 'edit_convert')
842 $tokens['PREVIEW_CONTENT'] = $this->getConvertedPreview();
843 if ($this->editaction == 'preview')
844 $tokens['PREVIEW_CONTENT'] = $this->getPreview(); // FIXME: convert to _MESSAGE?
846 // FIXME: NOT_CURRENT_MESSAGE?
847 $tokens = array_merge($tokens, $this->getFormElements());
848 // we need all GET params for loadfile overwrite
849 if ($this->request->getArg('action') == 'loadfile') {
851 $this->tokens['HIDDEN_INPUTS'] =
853 (array('source' => $this->request->getArg('source'),
855 $this->tokens['HIDDEN_INPUTS']);
856 // add two conflict resolution buttons before preview and save.
857 $tokens['PREVIEW_B'] = HTML(
858 Button('submit:edit[keep_old]',
859 _("Keep old"), 'wikiaction'),
861 Button('submit:edit[overwrite]',
862 _("Overwrite with new"), 'wikiaction'),
864 $tokens['PREVIEW_B']);
866 if (ENABLE_EDIT_TOOLBAR and !ENABLE_WYSIWYG) {
867 include_once("lib/EditToolbar.php");
868 $toolbar = new EditToolbar();
869 $tokens = array_merge($tokens, $toolbar->getTokens());
872 return $this->output('editpage', _("Merge and Edit: %s"));
875 function output ($template, $title_fs) {
876 $selected = &$this->selected;
877 $current = &$this->current;
879 if ($selected && $selected->getVersion() != $current->getVersion()) {
881 $pagelink = WikiLink($selected);
885 $pagelink = WikiLink($this->page);
888 $title = new FormattedText ($title_fs, $pagelink);
889 $this->tokens['HEADER'] = $title;
890 //hack! there's no TITLE in editpage, but in the previous top template
891 if (empty($this->tokens['PAGE_LOCKED_MESSAGE']))
892 $this->tokens['PAGE_LOCKED_MESSAGE'] = HTML::h3($title);
894 $this->tokens['PAGE_LOCKED_MESSAGE'] = HTML(HTML::h3($title),
895 $this->tokens['PAGE_LOCKED_MESSAGE']);
896 $template = Template($template, $this->tokens);
898 //GeneratePage($template, $title, $rev);
903 function getConflictMessage () {
904 $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.",
907 HTML::p(_("Please check it through before saving."))));
913 $Log: not supported by cvs2svn $
914 Revision 1.113 2007/07/14 12:04:12 rurban
915 aesthetic request: remove ?action=edit after edit, add upload and diff
917 Revision 1.112 2007/06/09 20:05:35 rurban
918 fix and optimize ENABLE_SPAMBLOCKLIST and ($newlinks > 5))
920 Revision 1.111 2007/06/03 17:12:00 rurban
921 convenience: only check above 5 external links for blocked domains
923 Revision 1.110 2007/01/07 18:42:00 rurban
924 Print ModeratedPage message on edit. Use GOOGLE_LINKS_NOFOLLOW. Improve id: edit: to edit-
926 Revision 1.109 2007/01/02 13:21:39 rurban
927 add two merge conflict buttons within loadfile: "Keep Old" and "Overwrite with new". enable edit toolbar there also. fix display of the Merge and Edit header.
929 Revision 1.108 2006/12/22 17:47:34 rurban
930 Display Warnings only once.
931 Add button accesskeys
933 Revision 1.107 2006/05/13 19:59:54 rurban
934 added wysiwyg_editor-1.3a feature by Jean-Nicolas GEREONE <jean-nicolas.gereone@st.com>
935 converted wysiwyg_editor-1.3a js to WysiwygEdit framework
936 changed default ENABLE_WYSIWYG = true and added WYSIWYG_BACKEND = Wikiwyg
938 Revision 1.106 2005/11/21 22:03:08 rurban
939 fix syntax error inside ENABLE_SPAMBLOCKLIST
941 Revision 1.105 2005/11/21 20:53:59 rurban
942 beautify request pref lines, no antispam if admin (netznetz request), user is a member anyway
944 Revision 1.104 2005/10/31 17:20:40 rurban
947 Revision 1.103 2005/10/31 17:09:13 rurban
948 use better constant WYSIWYG_DEFAULT_PAGETYPE_HTML
950 Revision 1.102 2005/10/31 16:47:14 rurban
951 enable wysiwyg html converters
953 Revision 1.101 2005/10/30 16:12:28 rurban
954 simplify viewsource tokens
956 Revision 1.100 2005/10/30 14:20:42 rurban
957 move Captcha specific vars and methods into a Captcha object
958 randomize Captcha chars positions and angles (smoothly)
960 Revision 1.99 2005/10/29 08:21:58 rurban
961 ENABLE_SPAMBLOCKLIST:
962 Check for links to blocked external tld domains in new edits, against
963 multi.surbl.org and bl.spamcop.net.
965 Revision 1.98 2005/10/10 19:37:04 rurban
966 change USE_HTMLAREA to ENABLE WYSIWYG, add NUM_SPAM_LINKS=20
968 Revision 1.97 2005/09/26 06:32:22 rurban
969 [] is forbidden in id tags. Renamed to use :
971 Revision 1.96 2005/05/06 17:54:22 rurban
972 silence Preview warnings for PAGE_LOCKED_MESSAGE, CONCURRENT_UPDATE_MESSAGE (thanks to schorni)
974 Revision 1.95 2005/04/25 20:17:14 rurban
975 captcha feature by Benjamin Drieu. Patch #1110699
977 Revision 1.94 2005/02/28 20:23:31 rurban
980 Revision 1.93 2005/02/27 19:31:52 rurban
981 hack: display errorstack without sideeffects (save and restore)
983 Revision 1.92 2005/01/29 20:37:21 rurban
984 no edit toolbar at all if ENABLE_EDITTOOLBAR = false
986 Revision 1.91 2005/01/25 07:05:49 rurban
987 extract toolbar code, support new tags to get rid of php inside templates
989 Revision 1.90 2005/01/22 12:46:15 rurban
990 fix oldmakrup button label
991 update pref[edit*] settings
993 Revision 1.89 2005/01/21 14:07:49 rurban
996 Revision 1.88 2004/12/17 16:39:03 rurban
999 Revision 1.87 2004/12/16 18:28:05 rurban
1000 keep wikiblog summary = page title
1002 Revision 1.86 2004/12/11 14:50:15 rurban
1003 new edit_convert button, to get rid of old markup eventually
1005 Revision 1.85 2004/12/06 19:49:56 rurban
1006 enable action=remove which is undoable and seeable in RecentChanges: ADODB ony for now.
1007 renamed delete_page to purge_page.
1008 enable action=edit&version=-1 to force creation of a new version.
1009 added BABYCART_PATH config
1010 fixed magiqc in adodb.inc.php
1013 Revision 1.84 2004/12/04 12:58:26 rurban
1014 enable babycart Blog::SpamAssassin module on ENABLE_SPAMASSASSIN=true
1015 (currently only for php >= 4.3.0)
1017 Revision 1.83 2004/12/04 11:55:39 rurban
1018 First simple AntiSpam prevention:
1019 No more than 20 new http:// links allowed
1021 Revision 1.82 2004/11/30 22:21:56 rurban
1022 changed gif to optimized (pngout) png
1024 Revision 1.81 2004/11/29 17:57:27 rurban
1025 translated pulldown buttons
1027 Revision 1.80 2004/11/25 17:20:51 rurban
1028 and again a couple of more native db args: backlinks
1030 Revision 1.79 2004/11/21 11:59:20 rurban
1031 remove final \n to be ob_cache independent
1033 Revision 1.78 2004/11/16 17:57:45 rurban
1034 fix search&replace button
1035 use new addTagButton machinery
1036 new showPulldown for categories, TODO: in a seperate request
1038 Revision 1.77 2004/11/15 15:52:35 rurban
1039 improve js stability
1041 Revision 1.76 2004/11/15 15:37:34 rurban
1042 fix JS_SEARCHREPLACE
1043 don't use document.write for replace, otherwise self.opener is not defined.
1045 Revision 1.75 2004/09/16 08:00:52 rurban
1048 Revision 1.74 2004/07/03 07:36:28 rurban
1049 do not get unneccessary content
1051 Revision 1.73 2004/06/16 21:23:44 rurban
1052 fixed non-object fatal #215
1054 Revision 1.72 2004/06/14 11:31:37 rurban
1055 renamed global $Theme to $WikiTheme (gforge nameclash)
1056 inherit PageList default options from PageList
1057 default sortby=pagename
1058 use options in PageList_Selectable (limit, sortby, ...)
1059 added action revert, with button at action=diff
1060 added option regex to WikiAdminSearchReplace
1062 Revision 1.71 2004/06/03 18:06:29 rurban
1063 fix file locking issues (only needed on write)
1064 fixed immediate LANG and THEME in-session updates if not stored in prefs
1065 advanced editpage toolbars (search & replace broken)
1067 Revision 1.70 2004/06/02 20:47:47 rurban
1068 dont use the wikiaction class
1070 Revision 1.69 2004/06/02 10:17:56 rurban
1071 integrated search/replace into toolbar
1072 added save+preview buttons
1074 Revision 1.68 2004/06/01 15:28:00 rurban
1075 AdminUser only ADMIN_USER not member of Administrators
1076 some RateIt improvements by dfrankow
1077 edit_toolbar buttons
1079 Revision _1.6 2004/05/26 15:48:00 syilek
1080 fixed problem with creating page with slashes from one true page
1082 Revision _1.5 2004/05/25 16:51:53 syilek
1083 added ability to create a page from the category page and not have to edit it
1085 Revision 1.67 2004/05/27 17:49:06 rurban
1086 renamed DB_Session to DbSession (in CVS also)
1087 added WikiDB->getParam and WikiDB->getAuthParam method to get rid of globals
1088 remove leading slash in error message
1089 added force_unlock parameter to File_Passwd (no return on stale locks)
1090 fixed adodb session AffectedRows
1091 added FileFinder helpers to unify local filenames and DATA_PATH names
1092 editpage.php: new edit toolbar javascript on ENABLE_EDIT_TOOLBAR
1094 Revision 1.66 2004/04/29 23:25:12 rurban
1095 re-ordered locale init (as in 1.3.9)
1096 fixed loadfile with subpages, and merge/restore anyway
1097 (sf.net bug #844188)
1099 Revision 1.65 2004/04/18 01:11:52 rurban
1100 more numeric pagename fixes.
1101 fixed action=upload with merge conflict warnings.
1102 charset changed from constant to global (dynamic utf-8 switching)
1104 Revision 1.64 2004/04/06 19:48:56 rurban
1105 temp workaround for action=edit AddComment form
1107 Revision 1.63 2004/03/24 19:39:02 rurban
1108 php5 workaround code (plus some interim debugging code in XmlElement)
1109 php5 doesn't work yet with the current XmlElement class constructors,
1110 WikiUserNew does work better than php4.
1111 rewrote WikiUserNew user upgrading to ease php5 update
1112 fixed pref handling in WikiUserNew
1113 added Email Notification
1114 added simple Email verification
1115 removed emailVerify userpref subclass: just a email property
1116 changed pref binary storage layout: numarray => hash of non default values
1117 print optimize message only if really done.
1118 forced new cookie policy: delete pref cookies, use only WIKI_ID as plain string.
1119 prefs should be stored in db or homepage, besides the current session.
1121 Revision 1.62 2004/03/17 18:41:05 rurban
1122 initial_content and template support for CreatePage
1124 Revision 1.61 2004/03/12 20:59:17 rurban
1125 important cookie fix by Konstantin Zadorozhny
1126 new editpage feature: JS_SEARCHREPLACE
1128 Revision 1.60 2004/02/15 21:34:37 rurban
1129 PageList enhanced and improved.
1130 fixed new WikiAdmin... plugins
1131 editpage, Theme with exp. htmlarea framework
1132 (htmlarea yet committed, this is really questionable)
1133 WikiUser... code with better session handling for prefs
1134 enhanced UserPreferences (again)
1135 RecentChanges for show_deleted: how should pages be deleted then?
1137 Revision 1.59 2003/12/07 20:35:26 carstenklapp
1138 Bugfix: Concurrent updates broken since after 1.3.4 release: Fatal
1139 error: Call to undefined function: gettransformedcontent() in
1140 /home/groups/p/ph/phpwiki/htdocs/phpwiki2/lib/editpage.php on line
1143 Revision 1.58 2003/03/10 18:25:22 dairiki
1144 Bug/typo fix. If you use the edit page to un/lock a page, it
1145 failed with: Fatal error: Call to a member function on a
1146 non-object in editpage.php on line 136
1148 Revision 1.57 2003/02/26 03:40:22 dairiki
1149 New action=create. Essentially the same as action=edit, except that if the
1150 page already exists, it falls back to action=browse.
1152 This is for use in the "question mark" links for unknown wiki words
1153 to avoid problems and confusion when following links from stale pages.
1154 (If the "unknown page" has been created in the interim, the user probably
1155 wants to view the page before editing it.)
1157 Revision 1.56 2003/02/21 18:07:14 dairiki
1158 Minor, nitpicky, currently inconsequential changes.
1160 Revision 1.55 2003/02/21 04:10:58 dairiki
1161 Fixes for new cached markup.
1162 Some minor code cleanups.
1164 Revision 1.54 2003/02/16 19:47:16 dairiki
1165 Update WikiDB timestamp when editing or deleting pages.
1167 Revision 1.53 2003/02/15 23:20:27 dairiki
1168 Redirect back to browse current version of page upon save,
1169 even when no changes were made.
1171 Revision 1.52 2003/01/03 22:22:00 carstenklapp
1172 Minor adjustments to diff block markers ("<<<<<<<"). Source reformatting.
1174 Revision 1.51 2003/01/03 02:43:26 carstenklapp
1175 New class LoadFileConflictPageEditor, for merging / comparing a loaded
1176 pgsrc file with an existing page.
1183 // c-basic-offset: 4
1184 // c-hanging-comment-ender-p: nil
1185 // indent-tabs-mode: nil