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());
184 $tokens['EDIT_TOOLBAR'] = '';
187 return $this->output('editpage', _("Edit: %s"));
190 function output($template, $title_fs)
193 $selected = &$this->selected;
194 $current = &$this->current;
196 if ($selected && $selected->getVersion() != $current->getVersion()) {
198 $pagelink = WikiLink($selected);
201 $pagelink = WikiLink($this->page);
204 $title = new FormattedText ($title_fs, $pagelink);
205 // not for dumphtml or viewsource
206 if (ENABLE_WYSIWYG and $template == 'editpage') {
207 $WikiTheme->addMoreHeaders($this->WysiwygEdit->Head());
208 //$tokens['PAGE_SOURCE'] = $this->WysiwygEdit->ConvertBefore($this->_content);
210 $template = Template($template, $this->tokens);
211 /* Tell google (and others) not to take notice of edit links */
212 if (GOOGLE_LINKS_NOFOLLOW)
213 $args = array('ROBOTS_META' => "noindex,nofollow");
214 GeneratePage($template, $title, $rev);
218 function viewSource()
220 assert($this->isInitialEdit());
221 assert($this->selected);
223 $this->tokens['PAGE_SOURCE'] = $this->_content;
224 $this->tokens['HIDDEN_INPUTS'] = HiddenInputs($this->request->getArgs());
225 return $this->output('viewsource', _("View Source: %s"));
228 function updateLock()
231 if (!ENABLE_PAGE_PUBLIC && !ENABLE_EXTERNAL_PAGES) {
232 if ((bool)$this->page->get('locked') == (bool)$this->locked)
233 return false; // Not changed.
236 if (!$this->user->isAdmin()) {
237 // FIXME: some sort of message
238 return false; // not allowed.
240 if ((bool)$this->page->get('locked') != (bool)$this->locked) {
241 $this->page->set('locked', (bool)$this->locked);
242 $this->tokens['LOCK_CHANGED_MSG']
244 ? _("Page now locked.")
245 : _("Page now unlocked.") . " ");
248 if (ENABLE_PAGE_PUBLIC and (bool)$this->page->get('public') != (bool)$this->public) {
249 $this->page->set('public', (bool)$this->public);
250 $this->tokens['LOCK_CHANGED_MSG']
252 ? _("Page now public.")
253 : _("Page now not-public."));
257 if (ENABLE_EXTERNAL_PAGES) {
258 if ((bool)$this->page->get('external') != (bool)$this->external) {
259 $this->page->set('external', (bool)$this->external);
260 $this->tokens['LOCK_CHANGED_MSG']
262 ? _("Page now external.")
263 : _("Page now not-external.")) . " ";
267 return $changed; // lock changed.
272 $request = &$this->request;
274 if ($this->isUnchanged()) {
275 // Allow admin lock/unlock even if
276 // no text changes were made.
277 if ($this->updateLock()) {
278 $dbi = $request->getDbh();
281 // Save failed. No changes made.
282 $this->_redirectToBrowsePage();
283 // user will probably not see the rest of this...
284 require_once 'lib/display.php';
285 // force browse of current version:
286 $request->setArg('action', false);
287 $request->setArg('version', false);
288 displayPage($request, 'nochanges');
292 if (!$this->user->isAdmin() and $this->isSpam()) {
293 $this->_isSpam = true;
296 // Save failed. No changes made.
297 $this->_redirectToBrowsePage();
298 // user will probably not see the rest of this...
299 require_once 'lib/display.php';
300 // force browse of current version:
301 $request->setArg('version', false);
302 displayPage($request, 'nochanges');
307 $page = &$this->page;
309 // Include any meta-data from original page version which
310 // has not been explicitly updated.
311 $meta = $this->selected->getMetaData();
312 $meta = array_merge($meta, $this->meta);
315 $this->_content = $this->getContent();
316 $newrevision = $page->save($this->_content,
319 : $this->_currentVersion + 1,
322 if (!isa($newrevision, 'WikiDB_PageRevision')) {
323 // Save failed. (Concurrent updates).
327 // New contents successfully saved...
330 // Clean out archived versions of this page.
331 require_once 'lib/ArchiveCleaner.php';
332 $cleaner = new ArchiveCleaner($GLOBALS['ExpireParams']);
333 $cleaner->cleanPageRevisions($page);
335 /* generate notification emails done in WikiDB::save to catch
336 all direct calls (admin plugins) */
338 // look at the errorstack
339 $errors = $GLOBALS['ErrorManager']->_postponed_errors;
340 $warnings = $GLOBALS['ErrorManager']->getPostponedErrorsAsHTML();
341 $GLOBALS['ErrorManager']->_postponed_errors = $errors;
343 $dbi = $request->getDbh();
347 if (empty($warnings->_content) && !$WikiTheme->getImageURL('signature')) {
348 // Do redirect to browse page if no signature has
349 // been defined. In this case, the user will most
350 // likely not see the rest of the HTML we generate
352 $request->setArg('action', false);
353 $this->_redirectToBrowsePage();
356 // Force browse of current page version.
357 $request->setArg('version', false);
358 // testme: does preview and more need action=edit?
359 $request->setArg('action', false);
361 $template = Template('savepage', $this->tokens);
362 $template->replace('CONTENT', $newrevision->getTransformedContent());
363 if (!empty($warnings->_content)) {
364 $template->replace('WARNINGS', $warnings);
365 unset($GLOBALS['ErrorManager']->_postponed_errors);
368 $pagelink = WikiLink($page);
370 GeneratePage($template, fmt("Saved: %s", $pagelink), $newrevision);
374 function isConcurrentUpdate()
376 assert($this->current->getVersion() >= $this->_currentVersion);
377 return $this->current->getVersion() != $this->_currentVersion;
382 return !$this->page->get('locked') || $this->user->isAdmin();
385 function isInitialEdit()
387 return $this->_initialEdit;
390 function isUnchanged()
392 $current = &$this->current;
394 if ($this->meta['markup'] != $current->get('markup'))
397 return $this->_content == $current->getPackedContent();
401 * Handle AntiSpam here. How? http://wikiblacklist.blogspot.com/
402 * Need to check dynamically some blacklist wikipage settings
403 * (plugin WikiAccessRestrictions) and some static blacklist.
405 * More than NUM_SPAM_LINKS (default: 20) new external links.
406 * Disabled if NUM_SPAM_LINKS is 0
407 * ENABLE_SPAMASSASSIN: content patterns by babycart (only php >= 4.3 for now)
408 * ENABLE_SPAMBLOCKLIST: content domain blacklist
412 $current = &$this->current;
413 $request = &$this->request;
415 $oldtext = $current->getPackedContent();
416 $newtext =& $this->_content;
417 $numlinks = $this->numLinks($newtext);
418 $newlinks = $numlinks - $this->numLinks($oldtext);
419 // FIXME: in longer texts the NUM_SPAM_LINKS number should be increased.
420 // better use a certain text : link ratio.
422 // 1. Not more than NUM_SPAM_LINKS (default: 20) new external links
423 if ((NUM_SPAM_LINKS > 0) and ($newlinks >= NUM_SPAM_LINKS)) {
424 // Allow strictly authenticated users?
425 // TODO: mail the admin?
426 $this->tokens['PAGE_LOCKED_MESSAGE'] =
427 HTML($this->getSpamMessage(),
428 HTML::p(HTML::strong(_("Too many external links."))));
431 // 2. external babycart (SpamAssassin) check
432 // This will probably prevent from discussing sex or viagra related topics. So beware.
433 if (ENABLE_SPAMASSASSIN) {
434 require_once 'lib/spam_babycart.php';
435 if ($babycart = check_babycart($newtext, $request->get("REMOTE_ADDR"),
436 $this->user->getId())
438 // TODO: mail the admin
439 if (is_array($babycart))
440 $this->tokens['PAGE_LOCKED_MESSAGE'] =
441 HTML($this->getSpamMessage(),
442 HTML::p(HTML::em(_("SpamAssassin reports: "),
443 join("\n", $babycart))));
447 // 3. extract (new) links and check surbl for blocked domains
448 if (ENABLE_SPAMBLOCKLIST and ($newlinks > 5)) {
449 require_once 'lib/SpamBlocklist.php';
450 require_once 'lib/InlineParser.php';
451 $parsed = TransformLinks($newtext);
452 $oldparsed = TransformLinks($oldtext);
454 foreach ($oldparsed->_content as $link) {
455 if (isa($link, 'Cached_ExternalLink') and !isa($link, 'Cached_InterwikiLink')) {
456 $uri = $link->_getURL($this->page->getName());
461 foreach ($parsed->_content as $link) {
462 if (isa($link, 'Cached_ExternalLink') and !isa($link, 'Cached_InterwikiLink')) {
463 $uri = $link->_getURL($this->page->getName());
464 // only check new links, so admins may add blocked links.
465 if (!array_key_exists($uri, $oldlinks) and ($res = IsBlackListed($uri))) {
466 // TODO: mail the admin
467 $this->tokens['PAGE_LOCKED_MESSAGE'] =
468 HTML($this->getSpamMessage(),
469 HTML::p(HTML::strong(_("External links contain blocked domains:")),
470 HTML::ul(HTML::li(sprintf(_("%s is listed at %s with %s"),
471 $uri . " [" . $res[2] . "]", $res[0], $res[1])))));
484 /** Number of external links in the wikitext
486 function numLinks(&$text)
488 return substr_count($text, "http://") + substr_count($text, "https://");
491 /** Header of the Anti Spam message
493 function getSpamMessage()
496 HTML(HTML::h2(_("Spam Prevention")),
497 HTML::p(_("This page edit seems to contain spam and was therefore not saved."),
499 _("Sorry for the inconvenience.")),
503 function getPreview()
505 require_once 'lib/PageType.php';
506 $this->_content = $this->getContent();
507 return new TransformedText($this->page, $this->_content, $this->meta);
510 function getConvertedPreview()
512 require_once 'lib/PageType.php';
513 $this->_content = $this->getContent();
514 $this->meta['markup'] = 2.0;
515 $this->_content = ConvertOldMarkup($this->_content);
516 return new TransformedText($this->page, $this->_content, $this->meta);
521 require_once 'lib/diff.php';
524 $diff = new Diff($this->current->getContent(), explode("\n", $this->getContent()));
525 if ($diff->isEmpty()) {
526 $html->pushContent(HTML::hr(),
527 HTML::p(array('class' => 'warning_msg'),
528 _("Versions are identical")));
530 // New CSS formatted unified diffs
531 $fmt = new HtmlUnifiedDiffFormatter;
532 $html->pushContent($fmt->format($diff));
537 // possibly convert HTMLAREA content back to Wiki markup
538 function getContent()
540 if (ENABLE_WYSIWYG) {
541 // don't store everything as html
542 if (!WYSIWYG_DEFAULT_PAGETYPE_HTML) {
543 // Wikiwyg shortcut to avoid the InlineTransformer:
544 if (WYSIWYG_BACKEND == "Wikiwyg") return $this->_content;
545 $xml_output = $this->WysiwygEdit->ConvertAfter($this->_content);
546 $this->_content = join("", $xml_output->_content);
548 $this->meta['pagetype'] = 'html';
550 return $this->_content;
552 return $this->_content;
556 function getLockedMessage()
559 HTML(HTML::h2(_("Page Locked")),
560 HTML::p(_("This page has been locked by the administrator so your changes can not be saved.")),
561 HTML::p(_("(Copy your changes to the clipboard. You can try editing a different page or save your text in a text editor.)")),
562 HTML::p(_("Sorry for the inconvenience.")));
565 function isModerated()
567 return $this->page->get('moderation');
570 function getModeratedMessage()
573 HTML(HTML::h2(WikiLink(_("ModeratedPage"))),
574 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")))),
575 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.",
576 WikiLink(_("UserPreferences")))));
579 function getConflictMessage($unresolved = false)
582 xgettext only knows about c/c++ line-continuation strings
583 it does not know about php's dot operator.
584 We want to translate this entire paragraph as one string, of course.
587 //$re_edit_link = Button('edit', _("Edit the new version"), $this->page);
590 $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.",
591 "<<<<<<< " . _("Your version"),
592 ">>>>>>> " . _("Other version")));
594 $message = HTML::p(_("Please check it through before saving."));
596 /*$steps = HTML::ol(HTML::li(_("Copy your changes to the clipboard or to another temporary place (e.g. text editor).")),
597 HTML::li(fmt("%s of the page. You should now see the most current version of the page. Your changes are no longer there.",
599 HTML::li(_("Make changes to the file again. Paste your additions from the clipboard (or text editor).")),
600 HTML::li(_("Save your updated changes.")));
603 HTML(HTML::h2(_("Conflicting Edits!")),
604 HTML::p(_("In the time since you started editing this page, another user has saved a new version of it.")),
605 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.")),
609 function getTextArea()
611 $request = &$this->request;
613 $readonly = !$this->canEdit(); // || $this->isConcurrentUpdate();
615 // WYSIWYG will need two pagetypes: raw wikitest and converted html
616 if (ENABLE_WYSIWYG) {
617 $this->_wikicontent = $this->_content;
618 $this->_content = $this->WysiwygEdit->ConvertBefore($this->_content);
619 // $this->getPreview();
620 //$this->_htmlcontent = $this->_content->asXML();
623 $textarea = HTML::textarea(array('class' => 'wikiedit',
624 'name' => 'edit[content]',
625 'id' => 'edit-content',
626 'rows' => $request->getPref('editHeight'),
627 'cols' => $request->getPref('editWidth'),
628 'readonly' => (bool)$readonly),
630 if (ENABLE_WYSIWYG) {
631 return $this->WysiwygEdit->Textarea($textarea, $this->_wikicontent,
632 $textarea->getAttr('name'));
637 function getFormElements()
640 $request = &$this->request;
641 $page = &$this->page;
643 $h = array('action' => 'edit',
644 'pagename' => $page->getName(),
645 'version' => $this->version,
646 'edit[pagetype]' => $this->meta['pagetype'],
647 'edit[current_version]' => $this->_currentVersion);
649 $el['HIDDEN_INPUTS'] = HiddenInputs($h);
650 $el['EDIT_TEXTAREA'] = $this->getTextArea();
651 if (ENABLE_CAPTCHA) {
652 $el = array_merge($el, $this->Captcha->getFormElements());
655 = HTML::input(array('type' => 'text',
656 'class' => 'wikitext',
657 'id' => 'edit-summary',
658 'name' => 'edit[summary]',
661 'value' => $this->meta['summary']));
663 = HTML::input(array('type' => 'checkbox',
664 'name' => 'edit[minor_edit]',
665 'id' => 'edit-minor_edit',
666 'checked' => (bool)$this->meta['is_minor_edit']));
668 = HTML::input(array('type' => 'checkbox',
669 'name' => 'edit[markup]',
671 'checked' => $this->meta['markup'] < 2.0,
672 'id' => 'useOldMarkup',
673 'onclick' => 'showOldMarkupRules(this.checked)'));
674 $el['OLD_MARKUP_CONVERT'] = ($this->meta['markup'] < 2.0)
675 ? Button('submit:edit[edit_convert]', _("Convert"), 'wikiaction') : '';
677 = HTML::input(array('type' => 'checkbox',
678 'name' => 'edit[locked]',
679 'id' => 'edit-locked',
680 'disabled' => (bool)!$this->user->isAdmin(),
681 'checked' => (bool)$this->locked));
682 if (ENABLE_PAGE_PUBLIC) {
684 = HTML::input(array('type' => 'checkbox',
685 'name' => 'edit[public]',
686 'id' => 'edit-public',
687 'disabled' => (bool)!$this->user->isAdmin(),
688 'checked' => (bool)$this->page->get('public')));
690 if (ENABLE_EXTERNAL_PAGES) {
692 = HTML::input(array('type' => 'checkbox',
693 'name' => 'edit[external]',
694 'id' => 'edit-external',
695 'disabled' => (bool)!$this->user->isAdmin(),
696 'checked' => (bool)$this->page->get('external')));
698 if (ENABLE_WYSIWYG) {
699 if (($this->version == 0) and ($request->getArg('mode') != 'wysiwyg')) {
700 $el['WYSIWYG_B'] = Button(array("action" => "edit", "mode" => "wysiwyg"), "Wysiwyg Editor");
704 $el['PREVIEW_B'] = Button('submit:edit[preview]', _("Preview"),
706 array('accesskey' => 'p',
707 'title' => 'Preview the current content [alt-p]'));
709 //if (!$this->isConcurrentUpdate() && $this->canEdit())
710 $el['SAVE_B'] = Button('submit:edit[save]',
711 _("Save"), 'wikiaction',
712 array('accesskey' => 's',
713 'title' => 'Save the current content as wikipage [alt-s]'));
714 $el['CHANGES_B'] = Button('submit:edit[diff]',
715 _("Changes"), 'wikiaction',
716 array('accesskey' => 'c',
717 'title' => 'Preview the current changes as diff [alt-c]'));
718 $el['UPLOAD_B'] = Button('submit:edit[upload]',
719 _("Upload"), 'wikiaction',
720 array('title' => 'Select a local file and press Upload to attach into this page'));
721 $el['SPELLCHECK_B'] = Button('submit:edit[SpellCheck]',
722 _("Spell Check"), 'wikiaction',
723 array('title' => 'Check the spelling'));
724 $el['IS_CURRENT'] = $this->version == $this->current->getVersion();
727 = HTML::input(array('type' => 'text',
730 'class' => "numeric",
731 'name' => 'pref[editWidth]',
732 'id' => 'pref-editWidth',
733 'value' => $request->getPref('editWidth'),
734 'onchange' => 'this.form.submit();'));
736 = HTML::input(array('type' => 'text',
739 'class' => "numeric",
740 'name' => 'pref[editHeight]',
741 'id' => 'pref-editHeight',
742 'value' => $request->getPref('editHeight'),
743 'onchange' => 'this.form.submit();'));
744 $el['SEP'] = $WikiTheme->getButtonSeparator();
745 $el['AUTHOR_MESSAGE'] = fmt("Author will be logged as %s.",
746 HTML::em($this->user->getId()));
751 function _redirectToBrowsePage()
753 $this->request->redirect(WikiURL($this->page, false, 'absolute_url'));
756 function _restoreState()
758 $request = &$this->request;
760 $posted = $request->getArg('edit');
761 $request->setArg('edit', false);
764 || !$request->isPost()
765 || !in_array($request->getArg('action'), array('edit', 'loadfile'))
769 if (!isset($posted['content']) || !is_string($posted['content']))
771 $this->_content = preg_replace('/[ \t\r]+\n/', "\n",
772 rtrim($posted['content']));
773 $this->_content = $this->getContent();
775 $this->_currentVersion = (int)$posted['current_version'];
777 if ($this->_currentVersion < 0)
779 if ($this->_currentVersion > $this->current->getVersion())
780 return false; // FIXME: some kind of warning?
782 $is_old_markup = !empty($posted['markup']) && $posted['markup'] == 'old';
783 $meta['markup'] = $is_old_markup ? false : 2.0;
784 $meta['summary'] = trim(substr($posted['summary'], 0, 256));
785 $meta['is_minor_edit'] = !empty($posted['minor_edit']);
786 $meta['pagetype'] = !empty($posted['pagetype']) ? $posted['pagetype'] : false;
788 $meta['captcha_input'] = !empty($posted['captcha_input']) ?
789 $posted['captcha_input'] : '';
791 $this->meta = array_merge($this->meta, $meta);
792 $this->locked = !empty($posted['locked']);
793 if (ENABLE_PAGE_PUBLIC)
794 $this->public = !empty($posted['public']);
795 if (ENABLE_EXTERNAL_PAGES)
796 $this->external = !empty($posted['external']);
798 foreach (array('preview', 'save', 'edit_convert',
799 'keep_old', 'overwrite', 'diff', 'upload') as $o) {
800 if (!empty($posted[$o]))
801 $this->editaction = $o;
803 if (empty($this->editaction))
804 $this->editaction = 'edit';
809 function _initializeState()
811 $request = &$this->request;
812 $current = &$this->current;
813 $selected = &$this->selected;
814 $user = &$this->user;
817 NoSuchRevision($request, $this->page, $this->version); // noreturn
819 $this->_currentVersion = $current->getVersion();
820 $this->_content = $selected->getPackedContent();
822 $this->locked = $this->page->get('locked');
824 // If author same as previous author, default minor_edit to on.
825 $age = $this->meta['mtime'] - $current->get('mtime');
826 $this->meta['is_minor_edit'] = ($age < MINOR_EDIT_TIMEOUT
827 && $current->get('author') == $user->getId()
830 // Default for new pages is new-style markup.
831 if ($selected->hasDefaultContents())
832 $is_new_markup = true;
834 $is_new_markup = $selected->get('markup') >= 2.0;
836 $this->meta['markup'] = $is_new_markup ? 2.0 : false;
837 $this->meta['pagetype'] = $selected->get('pagetype');
838 if ($this->meta['pagetype'] == 'wikiblog')
839 $this->meta['summary'] = $selected->get('summary'); // keep blog title
841 $this->meta['summary'] = '';
842 $this->editaction = 'edit';
846 class LoadFileConflictPageEditor
849 function editPage($saveFailed = true)
851 $tokens = &$this->tokens;
853 if (!$this->canEdit()) {
854 if ($this->isInitialEdit()) {
855 return $this->viewSource();
857 $tokens['PAGE_LOCKED_MESSAGE'] = $this->getLockedMessage();
858 } elseif ($this->editaction == 'save') {
859 if ($this->savePage()) {
860 return true; // Page saved.
865 if ($saveFailed || $this->isConcurrentUpdate()) {
866 // Get the text of the original page, and the two conflicting edits
867 // The diff class takes arrays as input. So retrieve content as
868 // an array, or convert it as necesary.
869 $orig = $this->page->getRevision($this->_currentVersion);
870 $this_content = explode("\n", $this->_content);
871 $other_content = $this->current->getContent();
872 require_once 'lib/diff.php';
873 $diff2 = new Diff($other_content, $this_content);
874 $context_lines = max(4, count($other_content) + 1,
875 count($this_content) + 1);
876 $fmt = new BlockDiffFormatter($context_lines);
878 $this->_content = $fmt->format($diff2);
879 // FIXME: integrate this into class BlockDiffFormatter
880 $this->_content = str_replace(">>>>>>>\n<<<<<<<\n", "=======\n",
882 $this->_content = str_replace("<<<<<<<\n>>>>>>>\n", "=======\n",
885 $this->_currentVersion = $this->current->getVersion();
886 $this->version = $this->_currentVersion;
887 $tokens['CONCURRENT_UPDATE_MESSAGE'] = $this->getConflictMessage();
890 if ($this->editaction == 'edit_convert')
891 $tokens['PREVIEW_CONTENT'] = $this->getConvertedPreview();
892 if ($this->editaction == 'preview')
893 $tokens['PREVIEW_CONTENT'] = $this->getPreview(); // FIXME: convert to _MESSAGE?
895 // FIXME: NOT_CURRENT_MESSAGE?
896 $tokens = array_merge($tokens, $this->getFormElements());
897 // we need all GET params for loadfile overwrite
898 if ($this->request->getArg('action') == 'loadfile') {
900 $this->tokens['HIDDEN_INPUTS'] =
902 (array('source' => $this->request->getArg('source'),
904 $this->tokens['HIDDEN_INPUTS']);
905 // add two conflict resolution buttons before preview and save.
906 $tokens['PREVIEW_B'] = HTML(
907 Button('submit:edit[keep_old]',
908 _("Keep old"), 'wikiaction'),
910 Button('submit:edit[overwrite]',
911 _("Overwrite with new"), 'wikiaction'),
913 $tokens['PREVIEW_B']);
915 if (ENABLE_EDIT_TOOLBAR and !ENABLE_WYSIWYG) {
916 include_once 'lib/EditToolbar.php';
917 $toolbar = new EditToolbar();
918 $tokens = array_merge($tokens, $toolbar->getTokens());
921 return $this->output('editpage', _("Merge and Edit: %s"));
924 function output($template, $title_fs)
926 $selected = &$this->selected;
927 $current = &$this->current;
929 if ($selected && $selected->getVersion() != $current->getVersion()) {
931 $pagelink = WikiLink($selected);
934 $pagelink = WikiLink($this->page);
937 $title = new FormattedText ($title_fs, $pagelink);
938 $this->tokens['HEADER'] = $title;
939 //hack! there's no TITLE in editpage, but in the previous top template
940 if (empty($this->tokens['PAGE_LOCKED_MESSAGE']))
941 $this->tokens['PAGE_LOCKED_MESSAGE'] = HTML::h3($title);
943 $this->tokens['PAGE_LOCKED_MESSAGE'] = HTML(HTML::h3($title),
944 $this->tokens['PAGE_LOCKED_MESSAGE']);
945 $template = Template($template, $this->tokens);
947 //GeneratePage($template, $title, $rev);
952 function getConflictMessage($unresolved = false)
954 $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.",
957 HTML::p(_("Please check it through before saving."))));
966 // c-hanging-comment-ender-p: nil
967 // indent-tabs-mode: nil