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 (ENABLE_WYSIWYG) {
658 if (($this->version == 0) and ($request->getArg('mode') != 'wysiwyg')) {
659 $el['WYSIWYG_B'] = Button(array("action" => "edit", "mode" => "wysiwyg"), "Wysiwyg Editor");
663 $el['PREVIEW_B'] = Button('submit:edit[preview]', _("Preview"),
665 array('accesskey'=> 'p',
666 'title' => 'Preview the current content [alt-p]'));
668 //if (!$this->isConcurrentUpdate() && $this->canEdit())
669 $el['SAVE_B'] = Button('submit:edit[save]',
670 _("Save"), 'wikiaction',
671 array('accesskey'=> 's',
672 'title' => 'Save the current content as wikipage [alt-s]'));
673 $el['CHANGES_B'] = Button('submit:edit[diff]',
674 _("Changes"), 'wikiaction',
675 array('accesskey'=> 'c',
676 'title' => 'Preview the current changes as diff [alt-c]'));
677 $el['UPLOAD_B'] = Button('submit:edit[upload]',
678 _("Upload"), 'wikiaction',
679 array('title' => 'Select a local file and press Upload to attach into this page'));
680 $el['SPELLCHECK_B'] = Button('submit:edit[SpellCheck]',
681 _("Spell Check"), 'wikiaction',
682 array('title' => 'Check the spelling'));
683 $el['IS_CURRENT'] = $this->version == $this->current->getVersion();
686 = HTML::input(array('type' => 'text',
689 'class' => "numeric",
690 'name' => 'pref[editWidth]',
691 'id' => 'pref-editWidth',
692 'value' => $request->getPref('editWidth'),
693 'onchange' => 'this.form.submit();'));
695 = HTML::input(array('type' => 'text',
698 'class' => "numeric",
699 'name' => 'pref[editHeight]',
700 'id' => 'pref-editHeight',
701 'value' => $request->getPref('editHeight'),
702 'onchange' => 'this.form.submit();'));
703 $el['SEP'] = $WikiTheme->getButtonSeparator();
704 $el['AUTHOR_MESSAGE'] = fmt("Author will be logged as %s.",
705 HTML::em($this->user->getId()));
710 function _redirectToBrowsePage() {
711 $this->request->redirect(WikiURL($this->page, false, 'absolute_url'));
714 function _restoreState () {
715 $request = &$this->request;
717 $posted = $request->getArg('edit');
718 $request->setArg('edit', false);
721 || !$request->isPost()
722 || !in_array($request->getArg('action'),array('edit','loadfile')))
725 if (!isset($posted['content']) || !is_string($posted['content']))
727 $this->_content = preg_replace('/[ \t\r]+\n/', "\n",
728 rtrim($posted['content']));
729 $this->_content = $this->getContent();
731 $this->_currentVersion = (int) $posted['current_version'];
733 if ($this->_currentVersion < 0)
735 if ($this->_currentVersion > $this->current->getVersion())
736 return false; // FIXME: some kind of warning?
738 $is_old_markup = !empty($posted['markup']) && $posted['markup'] == 'old';
739 $meta['markup'] = $is_old_markup ? false : 2.0;
740 $meta['summary'] = trim(substr($posted['summary'], 0, 256));
741 $meta['is_minor_edit'] = !empty($posted['minor_edit']);
742 $meta['pagetype'] = !empty($posted['pagetype']) ? $posted['pagetype'] : false;
743 if ( ENABLE_CAPTCHA )
744 $meta['captcha_input'] = !empty($posted['captcha_input']) ?
745 $posted['captcha_input'] : '';
747 $this->meta = array_merge($this->meta, $meta);
748 $this->locked = !empty($posted['locked']);
750 foreach (array('preview','save','edit_convert',
751 'keep_old','overwrite','diff','upload') as $o)
753 if (!empty($posted[$o]))
754 $this->editaction = $o;
756 if (empty($this->editaction))
757 $this->editaction = 'edit';
762 function _initializeState () {
763 $request = &$this->request;
764 $current = &$this->current;
765 $selected = &$this->selected;
766 $user = &$this->user;
769 NoSuchRevision($request, $this->page, $this->version); // noreturn
771 $this->_currentVersion = $current->getVersion();
772 $this->_content = $selected->getPackedContent();
774 $this->locked = $this->page->get('locked');
776 // If author same as previous author, default minor_edit to on.
777 $age = $this->meta['mtime'] - $current->get('mtime');
778 $this->meta['is_minor_edit'] = ( $age < MINOR_EDIT_TIMEOUT
779 && $current->get('author') == $user->getId()
782 // Default for new pages is new-style markup.
783 if ($selected->hasDefaultContents())
784 $is_new_markup = true;
786 $is_new_markup = $selected->get('markup') >= 2.0;
788 $this->meta['markup'] = $is_new_markup ? 2.0: false;
789 $this->meta['pagetype'] = $selected->get('pagetype');
790 if ($this->meta['pagetype'] == 'wikiblog')
791 $this->meta['summary'] = $selected->get('summary'); // keep blog title
793 $this->meta['summary'] = '';
794 $this->editaction = 'edit';
798 class LoadFileConflictPageEditor
801 function editPage ($saveFailed = true) {
802 $tokens = &$this->tokens;
804 if (!$this->canEdit()) {
805 if ($this->isInitialEdit()) {
806 return $this->viewSource();
808 $tokens['PAGE_LOCKED_MESSAGE'] = $this->getLockedMessage();
810 elseif ($this->editaction == 'save') {
811 if ($this->savePage()) {
812 return true; // Page saved.
817 if ($saveFailed || $this->isConcurrentUpdate())
819 // Get the text of the original page, and the two conflicting edits
820 // The diff class takes arrays as input. So retrieve content as
821 // an array, or convert it as necesary.
822 $orig = $this->page->getRevision($this->_currentVersion);
823 $this_content = explode("\n", $this->_content);
824 $other_content = $this->current->getContent();
825 require_once("lib/diff.php");
826 $diff2 = new Diff($other_content, $this_content);
827 $context_lines = max(4, count($other_content) + 1,
828 count($this_content) + 1);
829 $fmt = new BlockDiffFormatter($context_lines);
831 $this->_content = $fmt->format($diff2);
832 // FIXME: integrate this into class BlockDiffFormatter
833 $this->_content = str_replace(">>>>>>>\n<<<<<<<\n", "=======\n",
835 $this->_content = str_replace("<<<<<<<\n>>>>>>>\n", "=======\n",
838 $this->_currentVersion = $this->current->getVersion();
839 $this->version = $this->_currentVersion;
840 $tokens['CONCURRENT_UPDATE_MESSAGE'] = $this->getConflictMessage();
843 if ($this->editaction == 'edit_convert')
844 $tokens['PREVIEW_CONTENT'] = $this->getConvertedPreview();
845 if ($this->editaction == 'preview')
846 $tokens['PREVIEW_CONTENT'] = $this->getPreview(); // FIXME: convert to _MESSAGE?
848 // FIXME: NOT_CURRENT_MESSAGE?
849 $tokens = array_merge($tokens, $this->getFormElements());
850 // we need all GET params for loadfile overwrite
851 if ($this->request->getArg('action') == 'loadfile') {
853 $this->tokens['HIDDEN_INPUTS'] =
855 (array('source' => $this->request->getArg('source'),
857 $this->tokens['HIDDEN_INPUTS']);
858 // add two conflict resolution buttons before preview and save.
859 $tokens['PREVIEW_B'] = HTML(
860 Button('submit:edit[keep_old]',
861 _("Keep old"), 'wikiaction'),
863 Button('submit:edit[overwrite]',
864 _("Overwrite with new"), 'wikiaction'),
866 $tokens['PREVIEW_B']);
868 if (ENABLE_EDIT_TOOLBAR and !ENABLE_WYSIWYG) {
869 include_once("lib/EditToolbar.php");
870 $toolbar = new EditToolbar();
871 $tokens = array_merge($tokens, $toolbar->getTokens());
874 return $this->output('editpage', _("Merge and Edit: %s"));
877 function output ($template, $title_fs) {
878 $selected = &$this->selected;
879 $current = &$this->current;
881 if ($selected && $selected->getVersion() != $current->getVersion()) {
883 $pagelink = WikiLink($selected);
887 $pagelink = WikiLink($this->page);
890 $title = new FormattedText ($title_fs, $pagelink);
891 $this->tokens['HEADER'] = $title;
892 //hack! there's no TITLE in editpage, but in the previous top template
893 if (empty($this->tokens['PAGE_LOCKED_MESSAGE']))
894 $this->tokens['PAGE_LOCKED_MESSAGE'] = HTML::h3($title);
896 $this->tokens['PAGE_LOCKED_MESSAGE'] = HTML(HTML::h3($title),
897 $this->tokens['PAGE_LOCKED_MESSAGE']);
898 $template = Template($template, $this->tokens);
900 //GeneratePage($template, $title, $rev);
905 function getConflictMessage () {
906 $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.",
909 HTML::p(_("Please check it through before saving."))));
915 $Log: not supported by cvs2svn $
916 Revision 1.114 2007/07/18 09:49:31 labbenes
917 Add a wysiwyg button in page editor form for newly created pages (revision = 0). The switch to wysiwyg will not keep the entered contents.
919 Revision 1.113 2007/07/14 12:04:12 rurban
920 aesthetic request: remove ?action=edit after edit, add upload and diff
922 Revision 1.112 2007/06/09 20:05:35 rurban
923 fix and optimize ENABLE_SPAMBLOCKLIST and ($newlinks > 5))
925 Revision 1.111 2007/06/03 17:12:00 rurban
926 convenience: only check above 5 external links for blocked domains
928 Revision 1.110 2007/01/07 18:42:00 rurban
929 Print ModeratedPage message on edit. Use GOOGLE_LINKS_NOFOLLOW. Improve id: edit: to edit-
931 Revision 1.109 2007/01/02 13:21:39 rurban
932 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.
934 Revision 1.108 2006/12/22 17:47:34 rurban
935 Display Warnings only once.
936 Add button accesskeys
938 Revision 1.107 2006/05/13 19:59:54 rurban
939 added wysiwyg_editor-1.3a feature by Jean-Nicolas GEREONE <jean-nicolas.gereone@st.com>
940 converted wysiwyg_editor-1.3a js to WysiwygEdit framework
941 changed default ENABLE_WYSIWYG = true and added WYSIWYG_BACKEND = Wikiwyg
943 Revision 1.106 2005/11/21 22:03:08 rurban
944 fix syntax error inside ENABLE_SPAMBLOCKLIST
946 Revision 1.105 2005/11/21 20:53:59 rurban
947 beautify request pref lines, no antispam if admin (netznetz request), user is a member anyway
949 Revision 1.104 2005/10/31 17:20:40 rurban
952 Revision 1.103 2005/10/31 17:09:13 rurban
953 use better constant WYSIWYG_DEFAULT_PAGETYPE_HTML
955 Revision 1.102 2005/10/31 16:47:14 rurban
956 enable wysiwyg html converters
958 Revision 1.101 2005/10/30 16:12:28 rurban
959 simplify viewsource tokens
961 Revision 1.100 2005/10/30 14:20:42 rurban
962 move Captcha specific vars and methods into a Captcha object
963 randomize Captcha chars positions and angles (smoothly)
965 Revision 1.99 2005/10/29 08:21:58 rurban
966 ENABLE_SPAMBLOCKLIST:
967 Check for links to blocked external tld domains in new edits, against
968 multi.surbl.org and bl.spamcop.net.
970 Revision 1.98 2005/10/10 19:37:04 rurban
971 change USE_HTMLAREA to ENABLE WYSIWYG, add NUM_SPAM_LINKS=20
973 Revision 1.97 2005/09/26 06:32:22 rurban
974 [] is forbidden in id tags. Renamed to use :
976 Revision 1.96 2005/05/06 17:54:22 rurban
977 silence Preview warnings for PAGE_LOCKED_MESSAGE, CONCURRENT_UPDATE_MESSAGE (thanks to schorni)
979 Revision 1.95 2005/04/25 20:17:14 rurban
980 captcha feature by Benjamin Drieu. Patch #1110699
982 Revision 1.94 2005/02/28 20:23:31 rurban
985 Revision 1.93 2005/02/27 19:31:52 rurban
986 hack: display errorstack without sideeffects (save and restore)
988 Revision 1.92 2005/01/29 20:37:21 rurban
989 no edit toolbar at all if ENABLE_EDITTOOLBAR = false
991 Revision 1.91 2005/01/25 07:05:49 rurban
992 extract toolbar code, support new tags to get rid of php inside templates
994 Revision 1.90 2005/01/22 12:46:15 rurban
995 fix oldmakrup button label
996 update pref[edit*] settings
998 Revision 1.89 2005/01/21 14:07:49 rurban
1001 Revision 1.88 2004/12/17 16:39:03 rurban
1004 Revision 1.87 2004/12/16 18:28:05 rurban
1005 keep wikiblog summary = page title
1007 Revision 1.86 2004/12/11 14:50:15 rurban
1008 new edit_convert button, to get rid of old markup eventually
1010 Revision 1.85 2004/12/06 19:49:56 rurban
1011 enable action=remove which is undoable and seeable in RecentChanges: ADODB ony for now.
1012 renamed delete_page to purge_page.
1013 enable action=edit&version=-1 to force creation of a new version.
1014 added BABYCART_PATH config
1015 fixed magiqc in adodb.inc.php
1018 Revision 1.84 2004/12/04 12:58:26 rurban
1019 enable babycart Blog::SpamAssassin module on ENABLE_SPAMASSASSIN=true
1020 (currently only for php >= 4.3.0)
1022 Revision 1.83 2004/12/04 11:55:39 rurban
1023 First simple AntiSpam prevention:
1024 No more than 20 new http:// links allowed
1026 Revision 1.82 2004/11/30 22:21:56 rurban
1027 changed gif to optimized (pngout) png
1029 Revision 1.81 2004/11/29 17:57:27 rurban
1030 translated pulldown buttons
1032 Revision 1.80 2004/11/25 17:20:51 rurban
1033 and again a couple of more native db args: backlinks
1035 Revision 1.79 2004/11/21 11:59:20 rurban
1036 remove final \n to be ob_cache independent
1038 Revision 1.78 2004/11/16 17:57:45 rurban
1039 fix search&replace button
1040 use new addTagButton machinery
1041 new showPulldown for categories, TODO: in a seperate request
1043 Revision 1.77 2004/11/15 15:52:35 rurban
1044 improve js stability
1046 Revision 1.76 2004/11/15 15:37:34 rurban
1047 fix JS_SEARCHREPLACE
1048 don't use document.write for replace, otherwise self.opener is not defined.
1050 Revision 1.75 2004/09/16 08:00:52 rurban
1053 Revision 1.74 2004/07/03 07:36:28 rurban
1054 do not get unneccessary content
1056 Revision 1.73 2004/06/16 21:23:44 rurban
1057 fixed non-object fatal #215
1059 Revision 1.72 2004/06/14 11:31:37 rurban
1060 renamed global $Theme to $WikiTheme (gforge nameclash)
1061 inherit PageList default options from PageList
1062 default sortby=pagename
1063 use options in PageList_Selectable (limit, sortby, ...)
1064 added action revert, with button at action=diff
1065 added option regex to WikiAdminSearchReplace
1067 Revision 1.71 2004/06/03 18:06:29 rurban
1068 fix file locking issues (only needed on write)
1069 fixed immediate LANG and THEME in-session updates if not stored in prefs
1070 advanced editpage toolbars (search & replace broken)
1072 Revision 1.70 2004/06/02 20:47:47 rurban
1073 dont use the wikiaction class
1075 Revision 1.69 2004/06/02 10:17:56 rurban
1076 integrated search/replace into toolbar
1077 added save+preview buttons
1079 Revision 1.68 2004/06/01 15:28:00 rurban
1080 AdminUser only ADMIN_USER not member of Administrators
1081 some RateIt improvements by dfrankow
1082 edit_toolbar buttons
1084 Revision _1.6 2004/05/26 15:48:00 syilek
1085 fixed problem with creating page with slashes from one true page
1087 Revision _1.5 2004/05/25 16:51:53 syilek
1088 added ability to create a page from the category page and not have to edit it
1090 Revision 1.67 2004/05/27 17:49:06 rurban
1091 renamed DB_Session to DbSession (in CVS also)
1092 added WikiDB->getParam and WikiDB->getAuthParam method to get rid of globals
1093 remove leading slash in error message
1094 added force_unlock parameter to File_Passwd (no return on stale locks)
1095 fixed adodb session AffectedRows
1096 added FileFinder helpers to unify local filenames and DATA_PATH names
1097 editpage.php: new edit toolbar javascript on ENABLE_EDIT_TOOLBAR
1099 Revision 1.66 2004/04/29 23:25:12 rurban
1100 re-ordered locale init (as in 1.3.9)
1101 fixed loadfile with subpages, and merge/restore anyway
1102 (sf.net bug #844188)
1104 Revision 1.65 2004/04/18 01:11:52 rurban
1105 more numeric pagename fixes.
1106 fixed action=upload with merge conflict warnings.
1107 charset changed from constant to global (dynamic utf-8 switching)
1109 Revision 1.64 2004/04/06 19:48:56 rurban
1110 temp workaround for action=edit AddComment form
1112 Revision 1.63 2004/03/24 19:39:02 rurban
1113 php5 workaround code (plus some interim debugging code in XmlElement)
1114 php5 doesn't work yet with the current XmlElement class constructors,
1115 WikiUserNew does work better than php4.
1116 rewrote WikiUserNew user upgrading to ease php5 update
1117 fixed pref handling in WikiUserNew
1118 added Email Notification
1119 added simple Email verification
1120 removed emailVerify userpref subclass: just a email property
1121 changed pref binary storage layout: numarray => hash of non default values
1122 print optimize message only if really done.
1123 forced new cookie policy: delete pref cookies, use only WIKI_ID as plain string.
1124 prefs should be stored in db or homepage, besides the current session.
1126 Revision 1.62 2004/03/17 18:41:05 rurban
1127 initial_content and template support for CreatePage
1129 Revision 1.61 2004/03/12 20:59:17 rurban
1130 important cookie fix by Konstantin Zadorozhny
1131 new editpage feature: JS_SEARCHREPLACE
1133 Revision 1.60 2004/02/15 21:34:37 rurban
1134 PageList enhanced and improved.
1135 fixed new WikiAdmin... plugins
1136 editpage, Theme with exp. htmlarea framework
1137 (htmlarea yet committed, this is really questionable)
1138 WikiUser... code with better session handling for prefs
1139 enhanced UserPreferences (again)
1140 RecentChanges for show_deleted: how should pages be deleted then?
1142 Revision 1.59 2003/12/07 20:35:26 carstenklapp
1143 Bugfix: Concurrent updates broken since after 1.3.4 release: Fatal
1144 error: Call to undefined function: gettransformedcontent() in
1145 /home/groups/p/ph/phpwiki/htdocs/phpwiki2/lib/editpage.php on line
1148 Revision 1.58 2003/03/10 18:25:22 dairiki
1149 Bug/typo fix. If you use the edit page to un/lock a page, it
1150 failed with: Fatal error: Call to a member function on a
1151 non-object in editpage.php on line 136
1153 Revision 1.57 2003/02/26 03:40:22 dairiki
1154 New action=create. Essentially the same as action=edit, except that if the
1155 page already exists, it falls back to action=browse.
1157 This is for use in the "question mark" links for unknown wiki words
1158 to avoid problems and confusion when following links from stale pages.
1159 (If the "unknown page" has been created in the interim, the user probably
1160 wants to view the page before editing it.)
1162 Revision 1.56 2003/02/21 18:07:14 dairiki
1163 Minor, nitpicky, currently inconsequential changes.
1165 Revision 1.55 2003/02/21 04:10:58 dairiki
1166 Fixes for new cached markup.
1167 Some minor code cleanups.
1169 Revision 1.54 2003/02/16 19:47:16 dairiki
1170 Update WikiDB timestamp when editing or deleting pages.
1172 Revision 1.53 2003/02/15 23:20:27 dairiki
1173 Redirect back to browse current version of page upon save,
1174 even when no changes were made.
1176 Revision 1.52 2003/01/03 22:22:00 carstenklapp
1177 Minor adjustments to diff block markers ("<<<<<<<"). Source reformatting.
1179 Revision 1.51 2003/01/03 02:43:26 carstenklapp
1180 New class LoadFileConflictPageEditor, for merging / comparing a loaded
1181 pgsrc file with an existing page.
1188 // c-basic-offset: 4
1189 // c-hanging-comment-ender-p: nil
1190 // indent-tabs-mode: nil