2 require_once 'lib/Template.php';
6 function PageEditor(&$request)
8 $this->request = &$request;
10 $this->user = $request->getUser();
11 $this->page = $request->getPage();
13 $this->current = $this->page->getCurrentRevision(false);
15 // HACKish short circuit to browse on action=create
16 if ($request->getArg('action') == 'create') {
17 if (!$this->current->hasDefaultContents())
18 $request->redirect(WikiURL($this->page->getName())); // noreturn
21 $this->meta = array('author' => $this->user->getId(),
22 'author_id' => $this->user->getAuthenticatedId(),
25 $this->tokens = array();
28 $backend = WYSIWYG_BACKEND;
29 // TODO: error message
30 require_once("lib/WysiwygEdit/$backend.php");
31 $class = "WysiwygEdit_$backend";
32 $this->WysiwygEdit = new $class();
35 require_once 'lib/Captcha.php';
36 $this->Captcha = new Captcha($this->meta);
39 $version = $request->getArg('version');
40 if ($version !== false) {
41 $this->selected = $this->page->getRevision($version);
42 $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;
51 $this->_initializeState();
52 $this->_initialEdit = true;
54 // The edit request has specified some initial content from a template
55 if (($template = $request->getArg('template'))
56 and $request->_dbi->isWikiPage($template)
58 $page = $request->_dbi->getPage($template);
59 $current = $page->getCurrentRevision();
60 $this->_content = $current->getPackedContent();
61 } elseif ($initial_content = $request->getArg('initial_content')) {
62 $this->_content = $initial_content;
63 $this->_redirect_to = $request->getArg('save_and_redirect_to');
67 header("Content-Type: text/html; charset=UTF-8");
73 $tokens = &$this->tokens;
74 $tokens['PAGE_LOCKED_MESSAGE'] = '';
75 $tokens['LOCK_CHANGED_MSG'] = '';
76 $tokens['CONCURRENT_UPDATE_MESSAGE'] = '';
79 if (isset($r->args['pref']['editWidth'])
80 and ($r->getPref('editWidth') != $r->args['pref']['editWidth'])
82 $r->_prefs->set('editWidth', $r->args['pref']['editWidth']);
84 if (isset($r->args['pref']['editHeight'])
85 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();
97 } elseif ($r->getArg('save_and_redirect_to') != "") {
98 if (ENABLE_CAPTCHA && $this->Captcha->Failed()) {
99 $this->tokens['PAGE_LOCKED_MESSAGE'] =
100 HTML::p(HTML::h1($this->Captcha->failed_msg));
101 } elseif ($this->savePage()) {
103 $request->setArg('action', false);
104 $r->redirect(WikiURL($r->getArg('save_and_redirect_to')));
105 return true; // Page saved.
108 } elseif ($this->editaction == 'save') {
109 if (ENABLE_CAPTCHA && $this->Captcha->Failed()) {
110 $this->tokens['PAGE_LOCKED_MESSAGE'] =
111 HTML::p(HTML::h1($this->Captcha->failed_msg));
112 } elseif ($this->savePage()) {
113 return true; // Page saved.
117 } // coming from loadfile conflicts
118 elseif ($this->editaction == 'keep_old') {
119 // keep old page and do nothing
120 $this->_redirectToBrowsePage();
121 //$r->redirect(WikiURL($r->getArg('save_and_redirect_to')));
123 } elseif ($this->editaction == 'overwrite') {
124 // take the new content without diff
125 $source = $this->request->getArg('loadfile');
126 require_once 'lib/loadsave.php';
127 $this->request->setArg('loadfile', 1);
128 $this->request->setArg('overwrite', 1);
129 $this->request->setArg('merge', 0);
130 LoadFileOrDir($this->request);
131 $this->_redirectToBrowsePage();
132 //$r->redirect(WikiURL($r->getArg('save_and_redirect_to')));
134 } elseif ($this->editaction == 'upload') {
136 $plugin = WikiPluginLoader("UpLoad");
138 // add link to content
142 if ($saveFailed and $this->isConcurrentUpdate()) {
143 // Get the text of the original page, and the two conflicting edits
144 // The diff3 class takes arrays as input. So retrieve content as
145 // an array, or convert it as necesary.
146 $orig = $this->page->getRevision($this->_currentVersion);
147 // FIXME: what if _currentVersion has be deleted?
148 $orig_content = $orig->getContent();
149 $this_content = explode("\n", $this->_content);
150 $other_content = $this->current->getContent();
151 require_once 'lib/diff3.php';
152 $diff = new diff3($orig_content, $this_content, $other_content);
153 $output = $diff->merged_output(_("Your version"), _("Other version"));
154 // Set the content of the textarea to the merged diff
155 // output, and update the version
156 $this->_content = implode("\n", $output);
157 $this->_currentVersion = $this->current->getVersion();
158 $this->version = $this->_currentVersion;
159 $unresolved = $diff->ConflictingBlocks;
160 $tokens['CONCURRENT_UPDATE_MESSAGE']
161 = $this->getConflictMessage($unresolved);
162 } elseif ($saveFailed && !$this->_isSpam) {
163 $tokens['CONCURRENT_UPDATE_MESSAGE'] =
164 HTML(HTML::h2(_("Some internal editing error")),
165 HTML::p(_("Your are probably trying to edit/create an invalid version of this page.")),
166 HTML::p(HTML::em(_("&version=-1 might help."))));
169 if ($this->editaction == 'edit_convert')
170 $tokens['PREVIEW_CONTENT'] = $this->getConvertedPreview();
171 if ($this->editaction == 'preview')
172 $tokens['PREVIEW_CONTENT'] = $this->getPreview(); // FIXME: convert to _MESSAGE?
173 if ($this->editaction == 'diff')
174 $tokens['PREVIEW_CONTENT'] = $this->getDiff();
176 // FIXME: NOT_CURRENT_MESSAGE?
177 $tokens = array_merge($tokens, $this->getFormElements());
179 if (ENABLE_EDIT_TOOLBAR and !ENABLE_WYSIWYG) {
180 require_once 'lib/EditToolbar.php';
181 $toolbar = new EditToolbar();
182 $tokens = array_merge($tokens, $toolbar->getTokens());
185 return $this->output('editpage', _("Edit: %s"));
188 function output($template, $title_fs)
191 $selected = &$this->selected;
192 $current = &$this->current;
194 if ($selected && $selected->getVersion() != $current->getVersion()) {
196 $pagelink = WikiLink($selected);
199 $pagelink = WikiLink($this->page);
202 $title = new FormattedText ($title_fs, $pagelink);
203 // not for dumphtml or viewsource
204 if (ENABLE_WYSIWYG and $template == 'editpage') {
205 $WikiTheme->addMoreHeaders($this->WysiwygEdit->Head());
206 //$tokens['PAGE_SOURCE'] = $this->WysiwygEdit->ConvertBefore($this->_content);
208 $template = Template($template, $this->tokens);
209 /* Tell google (and others) not to take notice of edit links */
210 if (GOOGLE_LINKS_NOFOLLOW)
211 $args = array('ROBOTS_META' => "noindex,nofollow");
212 GeneratePage($template, $title, $rev);
216 function viewSource()
218 assert($this->isInitialEdit());
219 assert($this->selected);
221 $this->tokens['PAGE_SOURCE'] = $this->_content;
222 $this->tokens['HIDDEN_INPUTS'] = HiddenInputs($this->request->getArgs());
223 return $this->output('viewsource', _("View Source: %s"));
226 function updateLock()
229 if (!ENABLE_PAGE_PUBLIC && !ENABLE_EXTERNAL_PAGES) {
230 if ((bool)$this->page->get('locked') == (bool)$this->locked)
231 return false; // Not changed.
234 if (!$this->user->isAdmin()) {
235 // FIXME: some sort of message
236 return false; // not allowed.
238 if ((bool)$this->page->get('locked') != (bool)$this->locked) {
239 $this->page->set('locked', (bool)$this->locked);
240 $this->tokens['LOCK_CHANGED_MSG']
242 ? _("Page now locked.")
243 : _("Page now unlocked.") . " ");
246 if (ENABLE_PAGE_PUBLIC and (bool)$this->page->get('public') != (bool)$this->public) {
247 $this->page->set('public', (bool)$this->public);
248 $this->tokens['LOCK_CHANGED_MSG']
250 ? _("Page now public.")
251 : _("Page now not-public."));
255 if (ENABLE_EXTERNAL_PAGES) {
256 if ((bool)$this->page->get('external') != (bool)$this->external) {
257 $this->page->set('external', (bool)$this->external);
258 $this->tokens['LOCK_CHANGED_MSG']
260 ? _("Page now external.")
261 : _("Page now not-external.")) . " ";
265 return $changed; // lock changed.
270 $request = &$this->request;
272 if ($this->isUnchanged()) {
273 // Allow admin lock/unlock even if
274 // no text changes were made.
275 if ($this->updateLock()) {
276 $dbi = $request->getDbh();
279 // Save failed. No changes made.
280 $this->_redirectToBrowsePage();
281 // user will probably not see the rest of this...
282 require_once 'lib/display.php';
283 // force browse of current version:
284 $request->setArg('action', false);
285 $request->setArg('version', false);
286 displayPage($request, 'nochanges');
290 if (!$this->user->isAdmin() and $this->isSpam()) {
291 $this->_isSpam = true;
294 // Save failed. No changes made.
295 $this->_redirectToBrowsePage();
296 // user will probably not see the rest of this...
297 require_once 'lib/display.php';
298 // force browse of current version:
299 $request->setArg('version', false);
300 displayPage($request, 'nochanges');
305 $page = &$this->page;
307 // Include any meta-data from original page version which
308 // has not been explicitly updated.
309 $meta = $this->selected->getMetaData();
310 $meta = array_merge($meta, $this->meta);
313 $this->_content = $this->getContent();
314 $newrevision = $page->save($this->_content,
317 : $this->_currentVersion + 1,
320 if (!isa($newrevision, 'WikiDB_PageRevision')) {
321 // Save failed. (Concurrent updates).
325 // New contents successfully saved...
328 // Clean out archived versions of this page.
329 require_once 'lib/ArchiveCleaner.php';
330 $cleaner = new ArchiveCleaner($GLOBALS['ExpireParams']);
331 $cleaner->cleanPageRevisions($page);
333 /* generate notification emails done in WikiDB::save to catch
334 all direct calls (admin plugins) */
336 // look at the errorstack
337 $errors = $GLOBALS['ErrorManager']->_postponed_errors;
338 $warnings = $GLOBALS['ErrorManager']->getPostponedErrorsAsHTML();
339 $GLOBALS['ErrorManager']->_postponed_errors = $errors;
341 $dbi = $request->getDbh();
345 if (empty($warnings->_content) && !$WikiTheme->getImageURL('signature')) {
346 // Do redirect to browse page if no signature has
347 // been defined. In this case, the user will most
348 // likely not see the rest of the HTML we generate
350 $request->setArg('action', false);
351 $this->_redirectToBrowsePage();
354 // Force browse of current page version.
355 $request->setArg('version', false);
356 // testme: does preview and more need action=edit?
357 $request->setArg('action', false);
359 $template = Template('savepage', $this->tokens);
360 $template->replace('CONTENT', $newrevision->getTransformedContent());
361 if (!empty($warnings->_content)) {
362 $template->replace('WARNINGS', $warnings);
363 unset($GLOBALS['ErrorManager']->_postponed_errors);
366 $pagelink = WikiLink($page);
368 GeneratePage($template, fmt("Saved: %s", $pagelink), $newrevision);
372 function isConcurrentUpdate()
374 assert($this->current->getVersion() >= $this->_currentVersion);
375 return $this->current->getVersion() != $this->_currentVersion;
380 return !$this->page->get('locked') || $this->user->isAdmin();
383 function isInitialEdit()
385 return $this->_initialEdit;
388 function isUnchanged()
390 $current = &$this->current;
392 if ($this->meta['markup'] != $current->get('markup'))
395 return $this->_content == $current->getPackedContent();
399 * Handle AntiSpam here. How? http://wikiblacklist.blogspot.com/
400 * Need to check dynamically some blacklist wikipage settings
401 * (plugin WikiAccessRestrictions) and some static blacklist.
403 * More than NUM_SPAM_LINKS (default: 20) new external links.
404 * Disabled if NUM_SPAM_LINKS is 0
405 * ENABLE_SPAMASSASSIN: content patterns by babycart (only php >= 4.3 for now)
406 * ENABLE_SPAMBLOCKLIST: content domain blacklist
410 $current = &$this->current;
411 $request = &$this->request;
413 $oldtext = $current->getPackedContent();
414 $newtext =& $this->_content;
415 $numlinks = $this->numLinks($newtext);
416 $newlinks = $numlinks - $this->numLinks($oldtext);
417 // FIXME: in longer texts the NUM_SPAM_LINKS number should be increased.
418 // better use a certain text : link ratio.
420 // 1. Not more than NUM_SPAM_LINKS (default: 20) new external links
421 if ((NUM_SPAM_LINKS > 0) and ($newlinks >= NUM_SPAM_LINKS)) {
422 // Allow strictly authenticated users?
423 // TODO: mail the admin?
424 $this->tokens['PAGE_LOCKED_MESSAGE'] =
425 HTML($this->getSpamMessage(),
426 HTML::p(HTML::strong(_("Too many external links."))));
429 // 2. external babycart (SpamAssassin) check
430 // This will probably prevent from discussing sex or viagra related topics. So beware.
431 if (ENABLE_SPAMASSASSIN) {
432 require_once 'lib/spam_babycart.php';
433 if ($babycart = check_babycart($newtext, $request->get("REMOTE_ADDR"),
434 $this->user->getId())
436 // TODO: mail the admin
437 if (is_array($babycart))
438 $this->tokens['PAGE_LOCKED_MESSAGE'] =
439 HTML($this->getSpamMessage(),
440 HTML::p(HTML::em(_("SpamAssassin reports: "),
441 join("\n", $babycart))));
445 // 3. extract (new) links and check surbl for blocked domains
446 if (ENABLE_SPAMBLOCKLIST and ($newlinks > 5)) {
447 require_once 'lib/SpamBlocklist.php';
448 require_once 'lib/InlineParser.php';
449 $parsed = TransformLinks($newtext);
450 $oldparsed = TransformLinks($oldtext);
452 foreach ($oldparsed->_content as $link) {
453 if (isa($link, 'Cached_ExternalLink') and !isa($link, 'Cached_InterwikiLink')) {
454 $uri = $link->_getURL($this->page->getName());
459 foreach ($parsed->_content as $link) {
460 if (isa($link, 'Cached_ExternalLink') and !isa($link, 'Cached_InterwikiLink')) {
461 $uri = $link->_getURL($this->page->getName());
462 // only check new links, so admins may add blocked links.
463 if (!array_key_exists($uri, $oldlinks) and ($res = IsBlackListed($uri))) {
464 // TODO: mail the admin
465 $this->tokens['PAGE_LOCKED_MESSAGE'] =
466 HTML($this->getSpamMessage(),
467 HTML::p(HTML::strong(_("External links contain blocked domains:")),
468 HTML::ul(HTML::li(sprintf(_("%s is listed at %s with %s"),
469 $uri . " [" . $res[2] . "]", $res[0], $res[1])))));
482 /** Number of external links in the wikitext
484 function numLinks(&$text)
486 return substr_count($text, "http://") + substr_count($text, "https://");
489 /** Header of the Anti Spam message
491 function getSpamMessage()
494 HTML(HTML::h2(_("Spam Prevention")),
495 HTML::p(_("This page edit seems to contain spam and was therefore not saved."),
497 _("Sorry for the inconvenience.")),
501 function getPreview()
503 require_once 'lib/PageType.php';
504 $this->_content = $this->getContent();
505 return new TransformedText($this->page, $this->_content, $this->meta);
508 function getConvertedPreview()
510 require_once 'lib/PageType.php';
511 $this->_content = $this->getContent();
512 $this->meta['markup'] = 2.0;
513 $this->_content = ConvertOldMarkup($this->_content);
514 return new TransformedText($this->page, $this->_content, $this->meta);
519 require_once 'lib/diff.php';
522 $diff = new Diff($this->current->getContent(), explode("\n", $this->getContent()));
523 if ($diff->isEmpty()) {
524 $html->pushContent(HTML::hr(),
525 HTML::p(array('class' => 'warning_msg'),
526 _("Versions are identical")));
528 // New CSS formatted unified diffs
529 $fmt = new HtmlUnifiedDiffFormatter;
530 $html->pushContent($fmt->format($diff));
535 // possibly convert HTMLAREA content back to Wiki markup
536 function getContent()
538 if (ENABLE_WYSIWYG) {
539 // don't store everything as html
540 if (!WYSIWYG_DEFAULT_PAGETYPE_HTML) {
541 // Wikiwyg shortcut to avoid the InlineTransformer:
542 if (WYSIWYG_BACKEND == "Wikiwyg") return $this->_content;
543 $xml_output = $this->WysiwygEdit->ConvertAfter($this->_content);
544 $this->_content = join("", $xml_output->_content);
546 $this->meta['pagetype'] = 'html';
548 return $this->_content;
550 return $this->_content;
554 function getLockedMessage()
557 HTML(HTML::h2(_("Page Locked")),
558 HTML::p(_("This page has been locked by the administrator so your changes can not be saved.")),
559 HTML::p(_("(Copy your changes to the clipboard. You can try editing a different page or save your text in a text editor.)")),
560 HTML::p(_("Sorry for the inconvenience.")));
563 function isModerated()
565 return $this->page->get('moderation');
568 function getModeratedMessage()
571 HTML(HTML::h2(WikiLink(_("ModeratedPage"))),
572 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")))),
573 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.",
574 WikiLink(_("UserPreferences")))));
577 function getConflictMessage($unresolved = false)
580 xgettext only knows about c/c++ line-continuation strings
581 it does not know about php's dot operator.
582 We want to translate this entire paragraph as one string, of course.
585 //$re_edit_link = Button('edit', _("Edit the new version"), $this->page);
588 $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.",
589 "<<<<<<< " . _("Your version"),
590 ">>>>>>> " . _("Other version")));
592 $message = HTML::p(_("Please check it through before saving."));
594 /*$steps = HTML::ol(HTML::li(_("Copy your changes to the clipboard or to another temporary place (e.g. text editor).")),
595 HTML::li(fmt("%s of the page. You should now see the most current version of the page. Your changes are no longer there.",
597 HTML::li(_("Make changes to the file again. Paste your additions from the clipboard (or text editor).")),
598 HTML::li(_("Save your updated changes.")));
601 HTML(HTML::h2(_("Conflicting Edits!")),
602 HTML::p(_("In the time since you started editing this page, another user has saved a new version of it.")),
603 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.")),
607 function getTextArea()
609 $request = &$this->request;
611 $readonly = !$this->canEdit(); // || $this->isConcurrentUpdate();
613 // WYSIWYG will need two pagetypes: raw wikitest and converted html
614 if (ENABLE_WYSIWYG) {
615 $this->_wikicontent = $this->_content;
616 $this->_content = $this->WysiwygEdit->ConvertBefore($this->_content);
617 // $this->getPreview();
618 //$this->_htmlcontent = $this->_content->asXML();
621 $textarea = HTML::textarea(array('class' => 'wikiedit',
622 'name' => 'edit[content]',
623 'id' => 'edit-content',
624 'rows' => $request->getPref('editHeight'),
625 'cols' => $request->getPref('editWidth'),
626 'readonly' => (bool)$readonly),
628 if (ENABLE_WYSIWYG) {
629 return $this->WysiwygEdit->Textarea($textarea, $this->_wikicontent,
630 $textarea->getAttr('name'));
635 function getFormElements()
638 $request = &$this->request;
639 $page = &$this->page;
641 $h = array('action' => 'edit',
642 'pagename' => $page->getName(),
643 'version' => $this->version,
644 'edit[pagetype]' => $this->meta['pagetype'],
645 'edit[current_version]' => $this->_currentVersion);
647 $el['HIDDEN_INPUTS'] = HiddenInputs($h);
648 $el['EDIT_TEXTAREA'] = $this->getTextArea();
649 if (ENABLE_CAPTCHA) {
650 $el = array_merge($el, $this->Captcha->getFormElements());
653 = HTML::input(array('type' => 'text',
654 'class' => 'wikitext',
655 'id' => 'edit-summary',
656 'name' => 'edit[summary]',
659 'value' => $this->meta['summary']));
661 = HTML::input(array('type' => 'checkbox',
662 'name' => 'edit[minor_edit]',
663 'id' => 'edit-minor_edit',
664 'checked' => (bool)$this->meta['is_minor_edit']));
666 = HTML::input(array('type' => 'checkbox',
667 'name' => 'edit[markup]',
669 'checked' => $this->meta['markup'] < 2.0,
670 'id' => 'useOldMarkup',
671 'onclick' => 'showOldMarkupRules(this.checked)'));
672 $el['OLD_MARKUP_CONVERT'] = ($this->meta['markup'] < 2.0)
673 ? Button('submit:edit[edit_convert]', _("Convert"), 'wikiaction') : '';
675 = HTML::input(array('type' => 'checkbox',
676 'name' => 'edit[locked]',
677 'id' => 'edit-locked',
678 'disabled' => (bool)!$this->user->isAdmin(),
679 'checked' => (bool)$this->locked));
680 if (ENABLE_PAGE_PUBLIC) {
682 = HTML::input(array('type' => 'checkbox',
683 'name' => 'edit[public]',
684 'id' => 'edit-public',
685 'disabled' => (bool)!$this->user->isAdmin(),
686 'checked' => (bool)$this->page->get('public')));
688 if (ENABLE_EXTERNAL_PAGES) {
690 = HTML::input(array('type' => 'checkbox',
691 'name' => 'edit[external]',
692 'id' => 'edit-external',
693 'disabled' => (bool)!$this->user->isAdmin(),
694 'checked' => (bool)$this->page->get('external')));
696 if (ENABLE_WYSIWYG) {
697 if (($this->version == 0) and ($request->getArg('mode') != 'wysiwyg')) {
698 $el['WYSIWYG_B'] = Button(array("action" => "edit", "mode" => "wysiwyg"), "Wysiwyg Editor");
702 $el['PREVIEW_B'] = Button('submit:edit[preview]', _("Preview"),
704 array('accesskey' => 'p',
705 'title' => 'Preview the current content [alt-p]'));
707 //if (!$this->isConcurrentUpdate() && $this->canEdit())
708 $el['SAVE_B'] = Button('submit:edit[save]',
709 _("Save"), 'wikiaction',
710 array('accesskey' => 's',
711 'title' => 'Save the current content as wikipage [alt-s]'));
712 $el['CHANGES_B'] = Button('submit:edit[diff]',
713 _("Changes"), 'wikiaction',
714 array('accesskey' => 'c',
715 'title' => 'Preview the current changes as diff [alt-c]'));
716 $el['UPLOAD_B'] = Button('submit:edit[upload]',
717 _("Upload"), 'wikiaction',
718 array('title' => 'Select a local file and press Upload to attach into this page'));
719 $el['SPELLCHECK_B'] = Button('submit:edit[SpellCheck]',
720 _("Spell Check"), 'wikiaction',
721 array('title' => 'Check the spelling'));
722 $el['IS_CURRENT'] = $this->version == $this->current->getVersion();
725 = HTML::input(array('type' => 'text',
728 'class' => "numeric",
729 'name' => 'pref[editWidth]',
730 'id' => 'pref-editWidth',
731 'value' => $request->getPref('editWidth'),
732 'onchange' => 'this.form.submit();'));
734 = HTML::input(array('type' => 'text',
737 'class' => "numeric",
738 'name' => 'pref[editHeight]',
739 'id' => 'pref-editHeight',
740 'value' => $request->getPref('editHeight'),
741 'onchange' => 'this.form.submit();'));
742 $el['SEP'] = $WikiTheme->getButtonSeparator();
743 $el['AUTHOR_MESSAGE'] = fmt("Author will be logged as %s.",
744 HTML::em($this->user->getId()));
749 function _redirectToBrowsePage()
751 $this->request->redirect(WikiURL($this->page, false, 'absolute_url'));
754 function _restoreState()
756 $request = &$this->request;
758 $posted = $request->getArg('edit');
759 $request->setArg('edit', false);
762 || !$request->isPost()
763 || !in_array($request->getArg('action'), array('edit', 'loadfile'))
767 if (!isset($posted['content']) || !is_string($posted['content']))
769 $this->_content = preg_replace('/[ \t\r]+\n/', "\n",
770 rtrim($posted['content']));
771 $this->_content = $this->getContent();
773 $this->_currentVersion = (int)$posted['current_version'];
775 if ($this->_currentVersion < 0)
777 if ($this->_currentVersion > $this->current->getVersion())
778 return false; // FIXME: some kind of warning?
780 $is_old_markup = !empty($posted['markup']) && $posted['markup'] == 'old';
781 $meta['markup'] = $is_old_markup ? false : 2.0;
782 $meta['summary'] = trim(substr($posted['summary'], 0, 256));
783 $meta['is_minor_edit'] = !empty($posted['minor_edit']);
784 $meta['pagetype'] = !empty($posted['pagetype']) ? $posted['pagetype'] : false;
786 $meta['captcha_input'] = !empty($posted['captcha_input']) ?
787 $posted['captcha_input'] : '';
789 $this->meta = array_merge($this->meta, $meta);
790 $this->locked = !empty($posted['locked']);
791 if (ENABLE_PAGE_PUBLIC)
792 $this->public = !empty($posted['public']);
793 if (ENABLE_EXTERNAL_PAGES)
794 $this->external = !empty($posted['external']);
796 foreach (array('preview', 'save', 'edit_convert',
797 'keep_old', 'overwrite', 'diff', 'upload') as $o) {
798 if (!empty($posted[$o]))
799 $this->editaction = $o;
801 if (empty($this->editaction))
802 $this->editaction = 'edit';
807 function _initializeState()
809 $request = &$this->request;
810 $current = &$this->current;
811 $selected = &$this->selected;
812 $user = &$this->user;
815 NoSuchRevision($request, $this->page, $this->version); // noreturn
817 $this->_currentVersion = $current->getVersion();
818 $this->_content = $selected->getPackedContent();
820 $this->locked = $this->page->get('locked');
822 // If author same as previous author, default minor_edit to on.
823 $age = $this->meta['mtime'] - $current->get('mtime');
824 $this->meta['is_minor_edit'] = ($age < MINOR_EDIT_TIMEOUT
825 && $current->get('author') == $user->getId()
828 // Default for new pages is new-style markup.
829 if ($selected->hasDefaultContents())
830 $is_new_markup = true;
832 $is_new_markup = $selected->get('markup') >= 2.0;
834 $this->meta['markup'] = $is_new_markup ? 2.0 : false;
835 $this->meta['pagetype'] = $selected->get('pagetype');
836 if ($this->meta['pagetype'] == 'wikiblog')
837 $this->meta['summary'] = $selected->get('summary'); // keep blog title
839 $this->meta['summary'] = '';
840 $this->editaction = 'edit';
844 class LoadFileConflictPageEditor
847 function editPage($saveFailed = true)
849 $tokens = &$this->tokens;
851 if (!$this->canEdit()) {
852 if ($this->isInitialEdit()) {
853 return $this->viewSource();
855 $tokens['PAGE_LOCKED_MESSAGE'] = $this->getLockedMessage();
856 } elseif ($this->editaction == 'save') {
857 if ($this->savePage()) {
858 return true; // Page saved.
863 if ($saveFailed || $this->isConcurrentUpdate()) {
864 // Get the text of the original page, and the two conflicting edits
865 // The diff class takes arrays as input. So retrieve content as
866 // an array, or convert it as necesary.
867 $orig = $this->page->getRevision($this->_currentVersion);
868 $this_content = explode("\n", $this->_content);
869 $other_content = $this->current->getContent();
870 require_once 'lib/diff.php';
871 $diff2 = new Diff($other_content, $this_content);
872 $context_lines = max(4, count($other_content) + 1,
873 count($this_content) + 1);
874 $fmt = new BlockDiffFormatter($context_lines);
876 $this->_content = $fmt->format($diff2);
877 // FIXME: integrate this into class BlockDiffFormatter
878 $this->_content = str_replace(">>>>>>>\n<<<<<<<\n", "=======\n",
880 $this->_content = str_replace("<<<<<<<\n>>>>>>>\n", "=======\n",
883 $this->_currentVersion = $this->current->getVersion();
884 $this->version = $this->_currentVersion;
885 $tokens['CONCURRENT_UPDATE_MESSAGE'] = $this->getConflictMessage();
888 if ($this->editaction == 'edit_convert')
889 $tokens['PREVIEW_CONTENT'] = $this->getConvertedPreview();
890 if ($this->editaction == 'preview')
891 $tokens['PREVIEW_CONTENT'] = $this->getPreview(); // FIXME: convert to _MESSAGE?
893 // FIXME: NOT_CURRENT_MESSAGE?
894 $tokens = array_merge($tokens, $this->getFormElements());
895 // we need all GET params for loadfile overwrite
896 if ($this->request->getArg('action') == 'loadfile') {
898 $this->tokens['HIDDEN_INPUTS'] =
900 (array('source' => $this->request->getArg('source'),
902 $this->tokens['HIDDEN_INPUTS']);
903 // add two conflict resolution buttons before preview and save.
904 $tokens['PREVIEW_B'] = HTML(
905 Button('submit:edit[keep_old]',
906 _("Keep old"), 'wikiaction'),
908 Button('submit:edit[overwrite]',
909 _("Overwrite with new"), 'wikiaction'),
911 $tokens['PREVIEW_B']);
913 if (ENABLE_EDIT_TOOLBAR and !ENABLE_WYSIWYG) {
914 include_once 'lib/EditToolbar.php';
915 $toolbar = new EditToolbar();
916 $tokens = array_merge($tokens, $toolbar->getTokens());
919 return $this->output('editpage', _("Merge and Edit: %s"));
922 function output($template, $title_fs)
924 $selected = &$this->selected;
925 $current = &$this->current;
927 if ($selected && $selected->getVersion() != $current->getVersion()) {
929 $pagelink = WikiLink($selected);
932 $pagelink = WikiLink($this->page);
935 $title = new FormattedText ($title_fs, $pagelink);
936 $this->tokens['HEADER'] = $title;
937 //hack! there's no TITLE in editpage, but in the previous top template
938 if (empty($this->tokens['PAGE_LOCKED_MESSAGE']))
939 $this->tokens['PAGE_LOCKED_MESSAGE'] = HTML::h3($title);
941 $this->tokens['PAGE_LOCKED_MESSAGE'] = HTML(HTML::h3($title),
942 $this->tokens['PAGE_LOCKED_MESSAGE']);
943 $template = Template($template, $this->tokens);
945 //GeneratePage($template, $title, $rev);
950 function getConflictMessage($unresolved = false)
952 $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.",
955 HTML::p(_("Please check it through before saving."))));
964 // c-hanging-comment-ender-p: nil
965 // indent-tabs-mode: nil