2 require_once 'lib/Template.php';
6 function PageEditor (&$request) {
7 $this->request = &$request;
9 $this->user = $request->getUser();
10 $this->page = $request->getPage();
12 $this->current = $this->page->getCurrentRevision(false);
14 // HACKish short circuit to browse on action=create
15 if ($request->getArg('action') == 'create') {
16 if (! $this->current->hasDefaultContents())
17 $request->redirect(WikiURL($this->page->getName())); // noreturn
20 $this->meta = array('author' => $this->user->getId(),
21 'author_id' => $this->user->getAuthenticatedId(),
24 $this->tokens = array();
27 $backend = WYSIWYG_BACKEND;
28 // TODO: error message
29 require_once("lib/WysiwygEdit/$backend.php");
30 $class = "WysiwygEdit_$backend";
31 $this->WysiwygEdit = new $class();
34 require_once 'lib/Captcha.php';
35 $this->Captcha = new Captcha($this->meta);
38 $version = $request->getArg('version');
39 if ($version !== false) {
40 $this->selected = $this->page->getRevision($version);
41 $this->version = $version;
44 $this->version = $this->current->getVersion();
45 $this->selected = $this->page->getRevision($this->version);
48 if ($this->_restoreState()) {
49 $this->_initialEdit = false;
52 $this->_initializeState();
53 $this->_initialEdit = true;
55 // The edit request has specified some initial content from a template
56 if ( ($template = $request->getArg('template'))
57 and $request->_dbi->isWikiPage($template))
59 $page = $request->_dbi->getPage($template);
60 $current = $page->getCurrentRevision();
61 $this->_content = $current->getPackedContent();
62 } elseif ($initial_content = $request->getArg('initial_content')) {
63 $this->_content = $initial_content;
64 $this->_redirect_to = $request->getArg('save_and_redirect_to');
68 header("Content-Type: text/html; charset=" . $GLOBALS['charset']);
71 function editPage () {
74 $tokens = &$this->tokens;
75 $tokens['PAGE_LOCKED_MESSAGE'] = '';
76 $tokens['LOCK_CHANGED_MSG'] = '';
77 $tokens['CONCURRENT_UPDATE_MESSAGE'] = '';
80 if (isset($r->args['pref']['editWidth'])
81 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'])) {
86 $r->_prefs->set('editHeight', $r->args['pref']['editHeight']);
89 if ($this->isModerated())
90 $tokens['PAGE_LOCKED_MESSAGE'] = $this->getModeratedMessage();
92 if (! $this->canEdit()) {
93 if ($this->isInitialEdit())
94 return $this->viewSource();
95 $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));
102 elseif ( $this->savePage()) {
104 $request->setArg('action', false);
105 $r->redirect(WikiURL($r->getArg('save_and_redirect_to')));
106 return true; // Page saved.
110 elseif ($this->editaction == 'save') {
111 if (ENABLE_CAPTCHA && $this->Captcha->Failed()) {
112 $this->tokens['PAGE_LOCKED_MESSAGE'] =
113 HTML::p(HTML::h1($this->Captcha->failed_msg));
115 elseif ($this->savePage()) {
116 return true; // Page saved.
122 // coming from loadfile conflicts
123 elseif ($this->editaction == 'keep_old') {
124 // keep old page and do nothing
125 $this->_redirectToBrowsePage();
126 //$r->redirect(WikiURL($r->getArg('save_and_redirect_to')));
129 elseif ($this->editaction == 'overwrite') {
130 // take the new content without diff
131 $source = $this->request->getArg('loadfile');
132 require_once 'lib/loadsave.php';
133 $this->request->setArg('loadfile', 1);
134 $this->request->setArg('overwrite', 1);
135 $this->request->setArg('merge', 0);
136 LoadFileOrDir($this->request);
137 $this->_redirectToBrowsePage();
138 //$r->redirect(WikiURL($r->getArg('save_and_redirect_to')));
141 elseif ($this->editaction == 'upload') {
143 $plugin = WikiPluginLoader("UpLoad");
145 // add link to content
149 if ($saveFailed and $this->isConcurrentUpdate())
151 // Get the text of the original page, and the two conflicting edits
152 // The diff3 class takes arrays as input. So retrieve content as
153 // an array, or convert it as necesary.
154 $orig = $this->page->getRevision($this->_currentVersion);
155 // FIXME: what if _currentVersion has be deleted?
156 $orig_content = $orig->getContent();
157 $this_content = explode("\n", $this->_content);
158 $other_content = $this->current->getContent();
159 require_once 'lib/diff3.php';
160 $diff = new diff3($orig_content, $this_content, $other_content);
161 $output = $diff->merged_output(_("Your version"), _("Other version"));
162 // Set the content of the textarea to the merged diff
163 // output, and update the version
164 $this->_content = implode ("\n", $output);
165 $this->_currentVersion = $this->current->getVersion();
166 $this->version = $this->_currentVersion;
167 $unresolved = $diff->ConflictingBlocks;
168 $tokens['CONCURRENT_UPDATE_MESSAGE']
169 = $this->getConflictMessage($unresolved);
170 } elseif ($saveFailed && !$this->_isSpam) {
171 $tokens['CONCURRENT_UPDATE_MESSAGE'] =
172 HTML(HTML::h2(_("Some internal editing error")),
173 HTML::p(_("Your are probably trying to edit/create an invalid version of this page.")),
174 HTML::p(HTML::em(_("&version=-1 might help."))));
177 if ($this->editaction == 'edit_convert')
178 $tokens['PREVIEW_CONTENT'] = $this->getConvertedPreview();
179 if ($this->editaction == 'preview')
180 $tokens['PREVIEW_CONTENT'] = $this->getPreview(); // FIXME: convert to _MESSAGE?
181 if ($this->editaction == 'diff')
182 $tokens['PREVIEW_CONTENT'] = $this->getDiff();
184 // FIXME: NOT_CURRENT_MESSAGE?
185 $tokens = array_merge($tokens, $this->getFormElements());
187 if (ENABLE_EDIT_TOOLBAR and !ENABLE_WYSIWYG) {
188 require_once 'lib/EditToolbar.php';
189 $toolbar = new EditToolbar();
190 $tokens = array_merge($tokens, $toolbar->getTokens());
193 return $this->output('editpage', _("Edit: %s"));
196 function output ($template, $title_fs) {
198 $selected = &$this->selected;
199 $current = &$this->current;
201 if ($selected && $selected->getVersion() != $current->getVersion()) {
203 $pagelink = WikiLink($selected);
207 $pagelink = WikiLink($this->page);
210 $title = new FormattedText ($title_fs, $pagelink);
211 // not for dumphtml or viewsource
212 if (ENABLE_WYSIWYG and $template == 'editpage') {
213 $WikiTheme->addMoreHeaders($this->WysiwygEdit->Head());
214 //$tokens['PAGE_SOURCE'] = $this->WysiwygEdit->ConvertBefore($this->_content);
216 $template = Template($template, $this->tokens);
217 /* Tell google (and others) not to take notice of edit links */
218 if (GOOGLE_LINKS_NOFOLLOW)
219 $args = array('ROBOTS_META' => "noindex,nofollow");
220 GeneratePage($template, $title, $rev);
224 function viewSource () {
225 assert($this->isInitialEdit());
226 assert($this->selected);
228 $this->tokens['PAGE_SOURCE'] = $this->_content;
229 $this->tokens['HIDDEN_INPUTS'] = HiddenInputs($this->request->getArgs());
230 return $this->output('viewsource', _("View Source: %s"));
233 function updateLock() {
235 if (!ENABLE_PAGE_PUBLIC && !ENABLE_EXTERNAL_PAGES) {
236 if ((bool)$this->page->get('locked') == (bool)$this->locked)
237 return false; // Not changed.
240 if (!$this->user->isAdmin()) {
241 // FIXME: some sort of message
242 return false; // not allowed.
244 if ((bool)$this->page->get('locked') != (bool)$this->locked) {
245 $this->page->set('locked', (bool)$this->locked);
246 $this->tokens['LOCK_CHANGED_MSG']
248 ? _("Page now locked.")
249 : _("Page now unlocked.") . " ");
252 if (ENABLE_PAGE_PUBLIC and (bool)$this->page->get('public') != (bool)$this->public) {
253 $this->page->set('public', (bool)$this->public);
254 $this->tokens['LOCK_CHANGED_MSG']
256 ? _("Page now public.")
257 : _("Page now not-public."));
261 if (ENABLE_EXTERNAL_PAGES) {
262 if ((bool)$this->page->get('external') != (bool)$this->external) {
263 $this->page->set('external', (bool)$this->external);
264 $this->tokens['LOCK_CHANGED_MSG']
266 ? _("Page now external.")
267 : _("Page now not-external.")) . " ";
271 return $changed; // lock changed.
274 function savePage () {
275 $request = &$this->request;
277 if ($this->isUnchanged()) {
278 // Allow admin lock/unlock even if
279 // no text changes were made.
280 if ($this->updateLock()) {
281 $dbi = $request->getDbh();
284 // Save failed. No changes made.
285 $this->_redirectToBrowsePage();
286 // user will probably not see the rest of this...
287 require_once 'lib/display.php';
288 // force browse of current version:
289 $request->setArg('action', false);
290 $request->setArg('version', false);
291 displayPage($request, 'nochanges');
295 if (!$this->user->isAdmin() and $this->isSpam()) {
296 $this->_isSpam = true;
299 // Save failed. No changes made.
300 $this->_redirectToBrowsePage();
301 // user will probably not see the rest of this...
302 require_once 'lib/display.php';
303 // force browse of current version:
304 $request->setArg('version', false);
305 displayPage($request, 'nochanges');
310 $page = &$this->page;
312 // Include any meta-data from original page version which
313 // has not been explicitly updated.
314 // (Except don't propagate pgsrc_version --- moot for now,
315 // because at present it never gets into the db...)
316 $meta = $this->selected->getMetaData();
317 unset($meta['pgsrc_version']);
318 $meta = array_merge($meta, $this->meta);
321 $this->_content = $this->getContent();
322 $newrevision = $page->save($this->_content,
325 : $this->_currentVersion + 1,
328 if (!isa($newrevision, 'WikiDB_PageRevision')) {
329 // Save failed. (Concurrent updates).
333 // New contents successfully saved...
336 // Clean out archived versions of this page.
337 require_once 'lib/ArchiveCleaner.php';
338 $cleaner = new ArchiveCleaner($GLOBALS['ExpireParams']);
339 $cleaner->cleanPageRevisions($page);
341 /* generate notification emails done in WikiDB::save to catch
342 all direct calls (admin plugins) */
344 // look at the errorstack
345 $errors = $GLOBALS['ErrorManager']->_postponed_errors;
346 $warnings = $GLOBALS['ErrorManager']->getPostponedErrorsAsHTML();
347 $GLOBALS['ErrorManager']->_postponed_errors = $errors;
349 $dbi = $request->getDbh();
353 if (empty($warnings->_content) && ! $WikiTheme->getImageURL('signature')) {
354 // Do redirect to browse page if no signature has
355 // been defined. In this case, the user will most
356 // likely not see the rest of the HTML we generate
358 $request->setArg('action', false);
359 $this->_redirectToBrowsePage();
362 // Force browse of current page version.
363 $request->setArg('version', false);
364 // testme: does preview and more need action=edit?
365 $request->setArg('action', false);
367 $template = Template('savepage', $this->tokens);
368 $template->replace('CONTENT', $newrevision->getTransformedContent());
369 if (!empty($warnings->_content)) {
370 $template->replace('WARNINGS', $warnings);
371 unset($GLOBALS['ErrorManager']->_postponed_errors);
374 $pagelink = WikiLink($page);
376 GeneratePage($template, fmt("Saved: %s", $pagelink), $newrevision);
380 function isConcurrentUpdate () {
381 assert($this->current->getVersion() >= $this->_currentVersion);
382 return $this->current->getVersion() != $this->_currentVersion;
385 function canEdit () {
386 return !$this->page->get('locked') || $this->user->isAdmin();
389 function isInitialEdit () {
390 return $this->_initialEdit;
393 function isUnchanged () {
394 $current = &$this->current;
396 if ($this->meta['markup'] != $current->get('markup'))
399 return $this->_content == $current->getPackedContent();
403 * Handle AntiSpam here. How? http://wikiblacklist.blogspot.com/
404 * Need to check dynamically some blacklist wikipage settings
405 * (plugin WikiAccessRestrictions) and some static blacklist.
407 * More than NUM_SPAM_LINKS (default: 20) new external links.
408 * Disabled if NUM_SPAM_LINKS is 0
409 * ENABLE_SPAMASSASSIN: content patterns by babycart (only php >= 4.3 for now)
410 * ENABLE_SPAMBLOCKLIST: content domain blacklist
413 $current = &$this->current;
414 $request = &$this->request;
416 $oldtext = $current->getPackedContent();
417 $newtext =& $this->_content;
418 $numlinks = $this->numLinks($newtext);
419 $newlinks = $numlinks - $this->numLinks($oldtext);
420 // FIXME: in longer texts the NUM_SPAM_LINKS number should be increased.
421 // better use a certain text : link ratio.
423 // 1. Not more than NUM_SPAM_LINKS (default: 20) new external links
424 if ((NUM_SPAM_LINKS > 0) and ($newlinks >= NUM_SPAM_LINKS))
426 // Allow strictly authenticated users?
427 // TODO: mail the admin?
428 $this->tokens['PAGE_LOCKED_MESSAGE'] =
429 HTML($this->getSpamMessage(),
430 HTML::p(HTML::strong(_("Too many external links."))));
433 // 2. external babycart (SpamAssassin) check
434 // This will probably prevent from discussing sex or viagra related topics. So beware.
435 if (ENABLE_SPAMASSASSIN) {
436 require_once 'lib/spam_babycart.php';
437 if ($babycart = check_babycart($newtext, $request->get("REMOTE_ADDR"),
438 $this->user->getId())) {
439 // TODO: mail the admin
440 if (is_array($babycart))
441 $this->tokens['PAGE_LOCKED_MESSAGE'] =
442 HTML($this->getSpamMessage(),
443 HTML::p(HTML::em(_("SpamAssassin reports: "),
444 join("\n", $babycart))));
448 // 3. extract (new) links and check surbl for blocked domains
449 if (ENABLE_SPAMBLOCKLIST and ($newlinks > 5)) {
450 require_once 'lib/SpamBlocklist.php';
451 require_once 'lib/InlineParser.php';
452 $parsed = TransformLinks($newtext);
453 $oldparsed = TransformLinks($oldtext);
455 foreach ($oldparsed->_content as $link) {
456 if (isa($link, 'Cached_ExternalLink') and !isa($link, 'Cached_InterwikiLink')) {
457 $uri = $link->_getURL($this->page->getName());
462 foreach ($parsed->_content as $link) {
463 if (isa($link, 'Cached_ExternalLink') and !isa($link, 'Cached_InterwikiLink')) {
464 $uri = $link->_getURL($this->page->getName());
465 // only check new links, so admins may add blocked links.
466 if (!array_key_exists($uri, $oldlinks) and ($res = IsBlackListed($uri))) {
467 // TODO: mail the admin
468 $this->tokens['PAGE_LOCKED_MESSAGE'] =
469 HTML($this->getSpamMessage(),
470 HTML::p(HTML::strong(_("External links contain blocked domains:")),
471 HTML::ul(HTML::li(sprintf(_("%s is listed at %s with %s"),
472 $uri." [".$res[2]."]", $res[0], $res[1])))));
485 /** Number of external links in the wikitext
487 function numLinks(&$text) {
488 return substr_count($text, "http://") + substr_count($text, "https://");
491 /** Header of the Anti Spam message
493 function getSpamMessage () {
495 HTML(HTML::h2(_("Spam Prevention")),
496 HTML::p(_("This page edit seems to contain spam and was therefore not saved."),
498 _("Sorry for the inconvenience.")),
502 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 () {
509 require_once 'lib/PageType.php';
510 $this->_content = $this->getContent();
511 $this->meta['markup'] = 2.0;
512 $this->_content = ConvertOldMarkup($this->_content);
513 return new TransformedText($this->page, $this->_content, $this->meta);
516 function getDiff () {
517 require_once 'lib/diff.php';
520 $diff = new Diff($this->current->getContent(), explode("\n", $this->getContent()));
521 if ($diff->isEmpty()) {
522 $html->pushContent(HTML::hr(),
523 HTML::p('[', _("Versions are identical"),
527 // New CSS formatted unified diffs
528 $fmt = new HtmlUnifiedDiffFormatter;
529 $html->pushContent($fmt->format($diff));
534 // possibly convert HTMLAREA content back to Wiki markup
535 function getContent () {
536 if (ENABLE_WYSIWYG) {
537 // don't store everything as html
538 if (!WYSIWYG_DEFAULT_PAGETYPE_HTML) {
539 // Wikiwyg shortcut to avoid the InlineTransformer:
540 if (WYSIWYG_BACKEND == "Wikiwyg") return $this->_content;
541 $xml_output = $this->WysiwygEdit->ConvertAfter($this->_content);
542 $this->_content = join("", $xml_output->_content);
544 $this->meta['pagetype'] = 'html';
546 return $this->_content;
548 return $this->_content;
552 function getLockedMessage () {
554 HTML(HTML::h2(_("Page Locked")),
555 HTML::p(_("This page has been locked by the administrator so your changes can not be saved.")),
556 HTML::p(_("(Copy your changes to the clipboard. You can try editing a different page or save your text in a text editor.)")),
557 HTML::p(_("Sorry for the inconvenience.")));
560 function isModerated() {
561 return $this->page->get('moderation');
563 function getModeratedMessage() {
565 HTML(HTML::h2(WikiLink(_("ModeratedPage"))),
566 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")))),
567 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.",
568 WikiLink(_("UserPreferences")))));
570 function getConflictMessage ($unresolved = false) {
572 xgettext only knows about c/c++ line-continuation strings
573 it does not know about php's dot operator.
574 We want to translate this entire paragraph as one string, of course.
577 //$re_edit_link = Button('edit', _("Edit the new version"), $this->page);
580 $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.",
581 "<<<<<<< ". _("Your version"),
582 ">>>>>>> ". _("Other version")));
584 $message = HTML::p(_("Please check it through before saving."));
588 /*$steps = HTML::ol(HTML::li(_("Copy your changes to the clipboard or to another temporary place (e.g. text editor).")),
589 HTML::li(fmt("%s of the page. You should now see the most current version of the page. Your changes are no longer there.",
591 HTML::li(_("Make changes to the file again. Paste your additions from the clipboard (or text editor).")),
592 HTML::li(_("Save your updated changes.")));
595 HTML(HTML::h2(_("Conflicting Edits!")),
596 HTML::p(_("In the time since you started editing this page, another user has saved a new version of it.")),
597 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.")),
602 function getTextArea () {
603 $request = &$this->request;
605 $readonly = ! $this->canEdit(); // || $this->isConcurrentUpdate();
607 // WYSIWYG will need two pagetypes: raw wikitest and converted html
608 if (ENABLE_WYSIWYG) {
609 $this->_wikicontent = $this->_content;
610 $this->_content = $this->WysiwygEdit->ConvertBefore($this->_content);
611 // $this->getPreview();
612 //$this->_htmlcontent = $this->_content->asXML();
615 $textarea = HTML::textarea(array('class'=> 'wikiedit',
616 'name' => 'edit[content]',
617 'id' => 'edit-content',
618 'rows' => $request->getPref('editHeight'),
619 'cols' => $request->getPref('editWidth'),
620 'readonly' => (bool) $readonly),
622 if (ENABLE_WYSIWYG) {
623 return $this->WysiwygEdit->Textarea($textarea, $this->_wikicontent,
624 $textarea->getAttr('name'));
629 function getFormElements () {
631 $request = &$this->request;
632 $page = &$this->page;
634 $h = array('action' => 'edit',
635 'pagename' => $page->getName(),
636 'version' => $this->version,
637 'edit[pagetype]' => $this->meta['pagetype'],
638 'edit[current_version]' => $this->_currentVersion);
640 $el['HIDDEN_INPUTS'] = HiddenInputs($h);
641 $el['EDIT_TEXTAREA'] = $this->getTextArea();
642 if ( ENABLE_CAPTCHA ) {
643 $el = array_merge($el, $this->Captcha->getFormElements());
646 = HTML::input(array('type' => 'text',
647 'class' => 'wikitext',
648 'id' => 'edit-summary',
649 'name' => 'edit[summary]',
652 'value' => $this->meta['summary']));
654 = HTML::input(array('type' => 'checkbox',
655 'name' => 'edit[minor_edit]',
656 'id' => 'edit-minor_edit',
657 'checked' => (bool) $this->meta['is_minor_edit']));
659 = HTML::input(array('type' => 'checkbox',
660 'name' => 'edit[markup]',
662 'checked' => $this->meta['markup'] < 2.0,
663 'id' => 'useOldMarkup',
664 'onclick' => 'showOldMarkupRules(this.checked)'));
665 $el['OLD_MARKUP_CONVERT'] = ($this->meta['markup'] < 2.0)
666 ? Button('submit:edit[edit_convert]', _("Convert"), 'wikiaction') : '';
668 = HTML::input(array('type' => 'checkbox',
669 'name' => 'edit[locked]',
670 'id' => 'edit-locked',
671 'disabled' => (bool) !$this->user->isAdmin(),
672 'checked' => (bool) $this->locked));
673 if (ENABLE_PAGE_PUBLIC) {
675 = HTML::input(array('type' => 'checkbox',
676 'name' => 'edit[public]',
677 'id' => 'edit-public',
678 'disabled' => (bool) !$this->user->isAdmin(),
679 'checked' => (bool) $this->page->get('public')));
681 if (ENABLE_EXTERNAL_PAGES) {
683 = HTML::input(array('type' => 'checkbox',
684 'name' => 'edit[external]',
685 'id' => 'edit-external',
686 'disabled' => (bool) !$this->user->isAdmin(),
687 'checked' => (bool) $this->page->get('external')));
689 if (ENABLE_WYSIWYG) {
690 if (($this->version == 0) and ($request->getArg('mode') != 'wysiwyg')) {
691 $el['WYSIWYG_B'] = Button(array("action" => "edit", "mode" => "wysiwyg"), "Wysiwyg Editor");
695 $el['PREVIEW_B'] = Button('submit:edit[preview]', _("Preview"),
697 array('accesskey'=> 'p',
698 'title' => 'Preview the current content [alt-p]'));
700 //if (!$this->isConcurrentUpdate() && $this->canEdit())
701 $el['SAVE_B'] = Button('submit:edit[save]',
702 _("Save"), 'wikiaction',
703 array('accesskey'=> 's',
704 'title' => 'Save the current content as wikipage [alt-s]'));
705 $el['CHANGES_B'] = Button('submit:edit[diff]',
706 _("Changes"), 'wikiaction',
707 array('accesskey'=> 'c',
708 'title' => 'Preview the current changes as diff [alt-c]'));
709 $el['UPLOAD_B'] = Button('submit:edit[upload]',
710 _("Upload"), 'wikiaction',
711 array('title' => 'Select a local file and press Upload to attach into this page'));
712 $el['SPELLCHECK_B'] = Button('submit:edit[SpellCheck]',
713 _("Spell Check"), 'wikiaction',
714 array('title' => 'Check the spelling'));
715 $el['IS_CURRENT'] = $this->version == $this->current->getVersion();
718 = HTML::input(array('type' => 'text',
721 'class' => "numeric",
722 'name' => 'pref[editWidth]',
723 'id' => 'pref-editWidth',
724 'value' => $request->getPref('editWidth'),
725 'onchange' => 'this.form.submit();'));
727 = HTML::input(array('type' => 'text',
730 'class' => "numeric",
731 'name' => 'pref[editHeight]',
732 'id' => 'pref-editHeight',
733 'value' => $request->getPref('editHeight'),
734 'onchange' => 'this.form.submit();'));
735 $el['SEP'] = $WikiTheme->getButtonSeparator();
736 $el['AUTHOR_MESSAGE'] = fmt("Author will be logged as %s.",
737 HTML::em($this->user->getId()));
742 function _redirectToBrowsePage() {
743 $this->request->redirect(WikiURL($this->page, false, 'absolute_url'));
746 function _restoreState () {
747 $request = &$this->request;
749 $posted = $request->getArg('edit');
750 $request->setArg('edit', false);
753 || !$request->isPost()
754 || !in_array($request->getArg('action'),array('edit','loadfile')))
757 if (!isset($posted['content']) || !is_string($posted['content']))
759 $this->_content = preg_replace('/[ \t\r]+\n/', "\n",
760 rtrim($posted['content']));
761 $this->_content = $this->getContent();
763 $this->_currentVersion = (int) $posted['current_version'];
765 if ($this->_currentVersion < 0)
767 if ($this->_currentVersion > $this->current->getVersion())
768 return false; // FIXME: some kind of warning?
770 $is_old_markup = !empty($posted['markup']) && $posted['markup'] == 'old';
771 $meta['markup'] = $is_old_markup ? false : 2.0;
772 $meta['summary'] = trim(substr($posted['summary'], 0, 256));
773 $meta['is_minor_edit'] = !empty($posted['minor_edit']);
774 $meta['pagetype'] = !empty($posted['pagetype']) ? $posted['pagetype'] : false;
775 if ( ENABLE_CAPTCHA )
776 $meta['captcha_input'] = !empty($posted['captcha_input']) ?
777 $posted['captcha_input'] : '';
779 $this->meta = array_merge($this->meta, $meta);
780 $this->locked = !empty($posted['locked']);
781 if (ENABLE_PAGE_PUBLIC)
782 $this->public = !empty($posted['public']);
783 if (ENABLE_EXTERNAL_PAGES)
784 $this->external = !empty($posted['external']);
786 foreach (array('preview','save','edit_convert',
787 'keep_old','overwrite','diff','upload') as $o)
789 if (!empty($posted[$o]))
790 $this->editaction = $o;
792 if (empty($this->editaction))
793 $this->editaction = 'edit';
798 function _initializeState () {
799 $request = &$this->request;
800 $current = &$this->current;
801 $selected = &$this->selected;
802 $user = &$this->user;
805 NoSuchRevision($request, $this->page, $this->version); // noreturn
807 $this->_currentVersion = $current->getVersion();
808 $this->_content = $selected->getPackedContent();
810 $this->locked = $this->page->get('locked');
812 // If author same as previous author, default minor_edit to on.
813 $age = $this->meta['mtime'] - $current->get('mtime');
814 $this->meta['is_minor_edit'] = ( $age < MINOR_EDIT_TIMEOUT
815 && $current->get('author') == $user->getId()
818 // Default for new pages is new-style markup.
819 if ($selected->hasDefaultContents())
820 $is_new_markup = true;
822 $is_new_markup = $selected->get('markup') >= 2.0;
824 $this->meta['markup'] = $is_new_markup ? 2.0: false;
825 $this->meta['pagetype'] = $selected->get('pagetype');
826 if ($this->meta['pagetype'] == 'wikiblog')
827 $this->meta['summary'] = $selected->get('summary'); // keep blog title
829 $this->meta['summary'] = '';
830 $this->editaction = 'edit';
834 class LoadFileConflictPageEditor
837 function editPage ($saveFailed = true) {
838 $tokens = &$this->tokens;
840 if (!$this->canEdit()) {
841 if ($this->isInitialEdit()) {
842 return $this->viewSource();
844 $tokens['PAGE_LOCKED_MESSAGE'] = $this->getLockedMessage();
846 elseif ($this->editaction == 'save') {
847 if ($this->savePage()) {
848 return true; // Page saved.
853 if ($saveFailed || $this->isConcurrentUpdate())
855 // Get the text of the original page, and the two conflicting edits
856 // The diff class takes arrays as input. So retrieve content as
857 // an array, or convert it as necesary.
858 $orig = $this->page->getRevision($this->_currentVersion);
859 $this_content = explode("\n", $this->_content);
860 $other_content = $this->current->getContent();
861 require_once 'lib/diff.php';
862 $diff2 = new Diff($other_content, $this_content);
863 $context_lines = max(4, count($other_content) + 1,
864 count($this_content) + 1);
865 $fmt = new BlockDiffFormatter($context_lines);
867 $this->_content = $fmt->format($diff2);
868 // FIXME: integrate this into class BlockDiffFormatter
869 $this->_content = str_replace(">>>>>>>\n<<<<<<<\n", "=======\n",
871 $this->_content = str_replace("<<<<<<<\n>>>>>>>\n", "=======\n",
874 $this->_currentVersion = $this->current->getVersion();
875 $this->version = $this->_currentVersion;
876 $tokens['CONCURRENT_UPDATE_MESSAGE'] = $this->getConflictMessage();
879 if ($this->editaction == 'edit_convert')
880 $tokens['PREVIEW_CONTENT'] = $this->getConvertedPreview();
881 if ($this->editaction == 'preview')
882 $tokens['PREVIEW_CONTENT'] = $this->getPreview(); // FIXME: convert to _MESSAGE?
884 // FIXME: NOT_CURRENT_MESSAGE?
885 $tokens = array_merge($tokens, $this->getFormElements());
886 // we need all GET params for loadfile overwrite
887 if ($this->request->getArg('action') == 'loadfile') {
889 $this->tokens['HIDDEN_INPUTS'] =
891 (array('source' => $this->request->getArg('source'),
893 $this->tokens['HIDDEN_INPUTS']);
894 // add two conflict resolution buttons before preview and save.
895 $tokens['PREVIEW_B'] = HTML(
896 Button('submit:edit[keep_old]',
897 _("Keep old"), 'wikiaction'),
899 Button('submit:edit[overwrite]',
900 _("Overwrite with new"), 'wikiaction'),
902 $tokens['PREVIEW_B']);
904 if (ENABLE_EDIT_TOOLBAR and !ENABLE_WYSIWYG) {
905 include_once 'lib/EditToolbar.php';
906 $toolbar = new EditToolbar();
907 $tokens = array_merge($tokens, $toolbar->getTokens());
910 return $this->output('editpage', _("Merge and Edit: %s"));
913 function output ($template, $title_fs) {
914 $selected = &$this->selected;
915 $current = &$this->current;
917 if ($selected && $selected->getVersion() != $current->getVersion()) {
919 $pagelink = WikiLink($selected);
923 $pagelink = WikiLink($this->page);
926 $title = new FormattedText ($title_fs, $pagelink);
927 $this->tokens['HEADER'] = $title;
928 //hack! there's no TITLE in editpage, but in the previous top template
929 if (empty($this->tokens['PAGE_LOCKED_MESSAGE']))
930 $this->tokens['PAGE_LOCKED_MESSAGE'] = HTML::h3($title);
932 $this->tokens['PAGE_LOCKED_MESSAGE'] = HTML(HTML::h3($title),
933 $this->tokens['PAGE_LOCKED_MESSAGE']);
934 $template = Template($template, $this->tokens);
936 //GeneratePage($template, $title, $rev);
941 function getConflictMessage ($unresolved = false) {
942 $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.",
945 HTML::p(_("Please check it through before saving."))));
954 // c-hanging-comment-ender-p: nil
955 // indent-tabs-mode: nil