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['LOCK_CHANGED_MSG'] = '';
79 $tokens['CONCURRENT_UPDATE_MESSAGE'] = '';
82 if (isset($r->args['pref']['editWidth'])
83 and ($r->getPref('editWidth') != $r->args['pref']['editWidth'])) {
84 $r->_prefs->set('editWidth', $r->args['pref']['editWidth']);
86 if (isset($r->args['pref']['editHeight'])
87 and ($r->getPref('editHeight') != $r->args['pref']['editHeight'])) {
88 $r->_prefs->set('editHeight', $r->args['pref']['editHeight']);
91 if ($this->isModerated())
92 $tokens['PAGE_LOCKED_MESSAGE'] = $this->getModeratedMessage();
94 if (! $this->canEdit()) {
95 if ($this->isInitialEdit())
96 return $this->viewSource();
97 $tokens['PAGE_LOCKED_MESSAGE'] = $this->getLockedMessage();
99 elseif ($r->getArg('save_and_redirect_to') != "") {
100 if (ENABLE_CAPTCHA && $this->Captcha->Failed()) {
101 $this->tokens['PAGE_LOCKED_MESSAGE'] =
102 HTML::p(HTML::h1($this->Captcha->failed_msg));
104 elseif ( $this->savePage()) {
106 $request->setArg('action', false);
107 $r->redirect(WikiURL($r->getArg('save_and_redirect_to')));
108 return true; // Page saved.
112 elseif ($this->editaction == 'save') {
113 if (ENABLE_CAPTCHA && $this->Captcha->Failed()) {
114 $this->tokens['PAGE_LOCKED_MESSAGE'] =
115 HTML::p(HTML::h1($this->Captcha->failed_msg));
117 elseif ($this->savePage()) {
118 return true; // Page saved.
124 // coming from loadfile conflicts
125 elseif ($this->editaction == 'keep_old') {
126 // keep old page and do nothing
127 $this->_redirectToBrowsePage();
128 //$r->redirect(WikiURL($r->getArg('save_and_redirect_to')));
131 elseif ($this->editaction == 'overwrite') {
132 // take the new content without diff
133 $source = $this->request->getArg('loadfile');
134 require_once 'lib/loadsave.php';
135 $this->request->setArg('loadfile', 1);
136 $this->request->setArg('overwrite', 1);
137 $this->request->setArg('merge', 0);
138 LoadFileOrDir($this->request);
139 $this->_redirectToBrowsePage();
140 //$r->redirect(WikiURL($r->getArg('save_and_redirect_to')));
143 elseif ($this->editaction == 'upload') {
145 $plugin = WikiPluginLoader("UpLoad");
147 // add link to content
151 if ($saveFailed and $this->isConcurrentUpdate())
153 // Get the text of the original page, and the two conflicting edits
154 // The diff3 class takes arrays as input. So retrieve content as
155 // an array, or convert it as necesary.
156 $orig = $this->page->getRevision($this->_currentVersion);
157 // FIXME: what if _currentVersion has be deleted?
158 $orig_content = $orig->getContent();
159 $this_content = explode("\n", $this->_content);
160 $other_content = $this->current->getContent();
161 require_once 'lib/diff3.php';
162 $diff = new diff3($orig_content, $this_content, $other_content);
163 $output = $diff->merged_output(_("Your version"), _("Other version"));
164 // Set the content of the textarea to the merged diff
165 // output, and update the version
166 $this->_content = implode ("\n", $output);
167 $this->_currentVersion = $this->current->getVersion();
168 $this->version = $this->_currentVersion;
169 $unresolved = $diff->ConflictingBlocks;
170 $tokens['CONCURRENT_UPDATE_MESSAGE']
171 = $this->getConflictMessage($unresolved);
172 } elseif ($saveFailed && !$this->_isSpam) {
173 $tokens['CONCURRENT_UPDATE_MESSAGE'] =
174 HTML(HTML::h2(_("Some internal editing error")),
175 HTML::p(_("Your are probably trying to edit/create an invalid version of this page.")),
176 HTML::p(HTML::em(_("&version=-1 might help."))));
179 if ($this->editaction == 'edit_convert')
180 $tokens['PREVIEW_CONTENT'] = $this->getConvertedPreview();
181 if ($this->editaction == 'preview')
182 $tokens['PREVIEW_CONTENT'] = $this->getPreview(); // FIXME: convert to _MESSAGE?
183 if ($this->editaction == 'diff')
184 $tokens['PREVIEW_CONTENT'] = $this->getDiff();
186 // FIXME: NOT_CURRENT_MESSAGE?
187 $tokens = array_merge($tokens, $this->getFormElements());
189 if (ENABLE_EDIT_TOOLBAR and !ENABLE_WYSIWYG) {
190 require_once 'lib/EditToolbar.php';
191 $toolbar = new EditToolbar();
192 $tokens = array_merge($tokens, $toolbar->getTokens());
195 return $this->output('editpage', _("Edit: %s"));
198 function output ($template, $title_fs) {
200 $selected = &$this->selected;
201 $current = &$this->current;
203 if ($selected && $selected->getVersion() != $current->getVersion()) {
205 $pagelink = WikiLink($selected);
209 $pagelink = WikiLink($this->page);
212 $title = new FormattedText ($title_fs, $pagelink);
213 // not for dumphtml or viewsource
214 if (ENABLE_WYSIWYG and $template == 'editpage') {
215 $WikiTheme->addMoreHeaders($this->WysiwygEdit->Head());
216 //$tokens['PAGE_SOURCE'] = $this->WysiwygEdit->ConvertBefore($this->_content);
218 $template = Template($template, $this->tokens);
219 /* Tell google (and others) not to take notice of edit links */
220 if (GOOGLE_LINKS_NOFOLLOW)
221 $args = array('ROBOTS_META' => "noindex,nofollow");
222 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() {
237 if (!ENABLE_PAGE_PUBLIC && !ENABLE_EXTERNAL_PAGES) {
238 if ((bool)$this->page->get('locked') == (bool)$this->locked)
239 return false; // Not changed.
242 if (!$this->user->isAdmin()) {
243 // FIXME: some sort of message
244 return false; // not allowed.
246 if ((bool)$this->page->get('locked') != (bool)$this->locked) {
247 $this->page->set('locked', (bool)$this->locked);
248 $this->tokens['LOCK_CHANGED_MSG']
250 ? _("Page now locked.")
251 : _("Page now unlocked.") . " ");
254 if (ENABLE_PAGE_PUBLIC and (bool)$this->page->get('public') != (bool)$this->public) {
255 $this->page->set('public', (bool)$this->public);
256 $this->tokens['LOCK_CHANGED_MSG']
258 ? _("Page now public.")
259 : _("Page now not-public."));
263 if (ENABLE_EXTERNAL_PAGES) {
264 if ((bool)$this->page->get('external') != (bool)$this->external) {
265 $this->page->set('external', (bool)$this->external);
266 $this->tokens['LOCK_CHANGED_MSG']
268 ? _("Page now external.")
269 : _("Page now not-external.")) . " ";
273 return $changed; // lock changed.
276 function savePage () {
277 $request = &$this->request;
279 if ($this->isUnchanged()) {
280 // Allow admin lock/unlock even if
281 // no text changes were made.
282 if ($this->updateLock()) {
283 $dbi = $request->getDbh();
286 // Save failed. No changes made.
287 $this->_redirectToBrowsePage();
288 // user will probably not see the rest of this...
289 require_once 'lib/display.php';
290 // force browse of current version:
291 $request->setArg('action', false);
292 $request->setArg('version', false);
293 displayPage($request, 'nochanges');
297 if (!$this->user->isAdmin() and $this->isSpam()) {
298 $this->_isSpam = true;
301 // Save failed. No changes made.
302 $this->_redirectToBrowsePage();
303 // user will probably not see the rest of this...
304 require_once 'lib/display.php';
305 // force browse of current version:
306 $request->setArg('version', false);
307 displayPage($request, 'nochanges');
312 $page = &$this->page;
314 // Include any meta-data from original page version which
315 // has not been explicitly updated.
316 // (Except don't propagate pgsrc_version --- moot for now,
317 // because at present it never gets into the db...)
318 $meta = $this->selected->getMetaData();
319 unset($meta['pgsrc_version']);
320 $meta = array_merge($meta, $this->meta);
323 $this->_content = $this->getContent();
324 $newrevision = $page->save($this->_content,
327 : $this->_currentVersion + 1,
330 if (!isa($newrevision, 'WikiDB_PageRevision')) {
331 // Save failed. (Concurrent updates).
335 // New contents successfully saved...
338 // Clean out archived versions of this page.
339 require_once 'lib/ArchiveCleaner.php';
340 $cleaner = new ArchiveCleaner($GLOBALS['ExpireParams']);
341 $cleaner->cleanPageRevisions($page);
343 /* generate notification emails done in WikiDB::save to catch
344 all direct calls (admin plugins) */
346 // look at the errorstack
347 $errors = $GLOBALS['ErrorManager']->_postponed_errors;
348 $warnings = $GLOBALS['ErrorManager']->getPostponedErrorsAsHTML();
349 $GLOBALS['ErrorManager']->_postponed_errors = $errors;
351 $dbi = $request->getDbh();
355 if (empty($warnings->_content) && ! $WikiTheme->getImageURL('signature')) {
356 // Do redirect to browse page if no signature has
357 // been defined. In this case, the user will most
358 // likely not see the rest of the HTML we generate
360 $request->setArg('action', false);
361 $this->_redirectToBrowsePage();
364 // Force browse of current page version.
365 $request->setArg('version', false);
366 // testme: does preview and more need action=edit?
367 $request->setArg('action', false);
369 $template = Template('savepage', $this->tokens);
370 $template->replace('CONTENT', $newrevision->getTransformedContent());
371 if (!empty($warnings->_content)) {
372 $template->replace('WARNINGS', $warnings);
373 unset($GLOBALS['ErrorManager']->_postponed_errors);
376 $pagelink = WikiLink($page);
378 GeneratePage($template, fmt("Saved: %s", $pagelink), $newrevision);
382 function isConcurrentUpdate () {
383 assert($this->current->getVersion() >= $this->_currentVersion);
384 return $this->current->getVersion() != $this->_currentVersion;
387 function canEdit () {
388 return !$this->page->get('locked') || $this->user->isAdmin();
391 function isInitialEdit () {
392 return $this->_initialEdit;
395 function isUnchanged () {
396 $current = &$this->current;
398 if ($this->meta['markup'] != $current->get('markup'))
401 return $this->_content == $current->getPackedContent();
405 * Handle AntiSpam here. How? http://wikiblacklist.blogspot.com/
406 * Need to check dynamically some blacklist wikipage settings
407 * (plugin WikiAccessRestrictions) and some static blacklist.
409 * More than NUM_SPAM_LINKS (default: 20) new external links.
410 * Disabled if NUM_SPAM_LINKS is 0
411 * ENABLE_SPAMASSASSIN: content patterns by babycart (only php >= 4.3 for now)
412 * ENABLE_SPAMBLOCKLIST: content domain blacklist
415 $current = &$this->current;
416 $request = &$this->request;
418 $oldtext = $current->getPackedContent();
419 $newtext =& $this->_content;
420 $numlinks = $this->numLinks($newtext);
421 $newlinks = $numlinks - $this->numLinks($oldtext);
422 // FIXME: in longer texts the NUM_SPAM_LINKS number should be increased.
423 // better use a certain text : link ratio.
425 // 1. Not more than NUM_SPAM_LINKS (default: 20) new external links
426 if ((NUM_SPAM_LINKS > 0) and ($newlinks >= NUM_SPAM_LINKS))
428 // Allow strictly authenticated users?
429 // TODO: mail the admin?
430 $this->tokens['PAGE_LOCKED_MESSAGE'] =
431 HTML($this->getSpamMessage(),
432 HTML::p(HTML::strong(_("Too many external links."))));
435 // 2. external babycart (SpamAssassin) check
436 // This will probably prevent from discussing sex or viagra related topics. So beware.
437 if (ENABLE_SPAMASSASSIN) {
438 require_once 'lib/spam_babycart.php';
439 if ($babycart = check_babycart($newtext, $request->get("REMOTE_ADDR"),
440 $this->user->getId())) {
441 // TODO: mail the admin
442 if (is_array($babycart))
443 $this->tokens['PAGE_LOCKED_MESSAGE'] =
444 HTML($this->getSpamMessage(),
445 HTML::p(HTML::em(_("SpamAssassin reports: "),
446 join("\n", $babycart))));
450 // 3. extract (new) links and check surbl for blocked domains
451 if (ENABLE_SPAMBLOCKLIST and ($newlinks > 5)) {
452 require_once 'lib/SpamBlocklist.php';
453 require_once 'lib/InlineParser.php';
454 $parsed = TransformLinks($newtext);
455 $oldparsed = TransformLinks($oldtext);
457 foreach ($oldparsed->_content as $link) {
458 if (isa($link, 'Cached_ExternalLink') and !isa($link, 'Cached_InterwikiLink')) {
459 $uri = $link->_getURL($this->page->getName());
464 foreach ($parsed->_content as $link) {
465 if (isa($link, 'Cached_ExternalLink') and !isa($link, 'Cached_InterwikiLink')) {
466 $uri = $link->_getURL($this->page->getName());
467 // only check new links, so admins may add blocked links.
468 if (!array_key_exists($uri, $oldlinks) and ($res = IsBlackListed($uri))) {
469 // TODO: mail the admin
470 $this->tokens['PAGE_LOCKED_MESSAGE'] =
471 HTML($this->getSpamMessage(),
472 HTML::p(HTML::strong(_("External links contain blocked domains:")),
473 HTML::ul(HTML::li(sprintf(_("%s is listed at %s with %s"),
474 $uri." [".$res[2]."]", $res[0], $res[1])))));
487 /** Number of external links in the wikitext
489 function numLinks(&$text) {
490 return substr_count($text, "http://") + substr_count($text, "https://");
493 /** Header of the Anti Spam message
495 function getSpamMessage () {
497 HTML(HTML::h2(_("Spam Prevention")),
498 HTML::p(_("This page edit seems to contain spam and was therefore not saved."),
500 _("Sorry for the inconvenience.")),
504 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 () {
511 require_once 'lib/PageType.php';
512 $this->_content = $this->getContent();
513 $this->meta['markup'] = 2.0;
514 $this->_content = ConvertOldMarkup($this->_content);
515 return new TransformedText($this->page, $this->_content, $this->meta);
518 function getDiff () {
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('[', _("Versions are identical"),
529 // New CSS formatted unified diffs
530 $fmt = new HtmlUnifiedDiffFormatter;
531 $html->pushContent($fmt->format($diff));
536 // possibly convert HTMLAREA content back to Wiki markup
537 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 () {
556 HTML(HTML::h2(_("Page Locked")),
557 HTML::p(_("This page has been locked by the administrator so your changes can not be saved.")),
558 HTML::p(_("(Copy your changes to the clipboard. You can try editing a different page or save your text in a text editor.)")),
559 HTML::p(_("Sorry for the inconvenience.")));
562 function isModerated() {
563 return $this->page->get('moderation');
565 function getModeratedMessage() {
567 HTML(HTML::h2(WikiLink(_("ModeratedPage"))),
568 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")))),
569 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.",
570 WikiLink(_("UserPreferences")))));
572 function getConflictMessage ($unresolved = false) {
574 xgettext only knows about c/c++ line-continuation strings
575 it does not know about php's dot operator.
576 We want to translate this entire paragraph as one string, of course.
579 //$re_edit_link = Button('edit', _("Edit the new version"), $this->page);
582 $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.",
583 "<<<<<<< ". _("Your version"),
584 ">>>>>>> ". _("Other version")));
586 $message = HTML::p(_("Please check it through before saving."));
590 /*$steps = HTML::ol(HTML::li(_("Copy your changes to the clipboard or to another temporary place (e.g. text editor).")),
591 HTML::li(fmt("%s of the page. You should now see the most current version of the page. Your changes are no longer there.",
593 HTML::li(_("Make changes to the file again. Paste your additions from the clipboard (or text editor).")),
594 HTML::li(_("Save your updated changes.")));
597 HTML(HTML::h2(_("Conflicting Edits!")),
598 HTML::p(_("In the time since you started editing this page, another user has saved a new version of it.")),
599 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.")),
604 function getTextArea () {
605 $request = &$this->request;
607 $readonly = ! $this->canEdit(); // || $this->isConcurrentUpdate();
609 // WYSIWYG will need two pagetypes: raw wikitest and converted html
610 if (ENABLE_WYSIWYG) {
611 $this->_wikicontent = $this->_content;
612 $this->_content = $this->WysiwygEdit->ConvertBefore($this->_content);
613 // $this->getPreview();
614 //$this->_htmlcontent = $this->_content->asXML();
617 $textarea = HTML::textarea(array('class'=> 'wikiedit',
618 'name' => 'edit[content]',
619 'id' => 'edit-content',
620 'rows' => $request->getPref('editHeight'),
621 'cols' => $request->getPref('editWidth'),
622 'readonly' => (bool) $readonly),
624 if (ENABLE_WYSIWYG) {
625 return $this->WysiwygEdit->Textarea($textarea, $this->_wikicontent,
626 $textarea->getAttr('name'));
631 function getFormElements () {
633 $request = &$this->request;
634 $page = &$this->page;
636 $h = array('action' => 'edit',
637 'pagename' => $page->getName(),
638 'version' => $this->version,
639 'edit[pagetype]' => $this->meta['pagetype'],
640 'edit[current_version]' => $this->_currentVersion);
642 $el['HIDDEN_INPUTS'] = HiddenInputs($h);
643 $el['EDIT_TEXTAREA'] = $this->getTextArea();
644 if ( ENABLE_CAPTCHA ) {
645 $el = array_merge($el, $this->Captcha->getFormElements());
648 = HTML::input(array('type' => 'text',
649 'class' => 'wikitext',
650 'id' => 'edit-summary',
651 'name' => 'edit[summary]',
654 'value' => $this->meta['summary']));
656 = HTML::input(array('type' => 'checkbox',
657 'name' => 'edit[minor_edit]',
658 'id' => 'edit-minor_edit',
659 'checked' => (bool) $this->meta['is_minor_edit']));
661 = HTML::input(array('type' => 'checkbox',
662 'name' => 'edit[markup]',
664 'checked' => $this->meta['markup'] < 2.0,
665 'id' => 'useOldMarkup',
666 'onclick' => 'showOldMarkupRules(this.checked)'));
667 $el['OLD_MARKUP_CONVERT'] = ($this->meta['markup'] < 2.0)
668 ? Button('submit:edit[edit_convert]', _("Convert"), 'wikiaction') : '';
670 = HTML::input(array('type' => 'checkbox',
671 'name' => 'edit[locked]',
672 'id' => 'edit-locked',
673 'disabled' => (bool) !$this->user->isAdmin(),
674 'checked' => (bool) $this->locked));
675 if (ENABLE_PAGE_PUBLIC) {
677 = HTML::input(array('type' => 'checkbox',
678 'name' => 'edit[public]',
679 'id' => 'edit-public',
680 'disabled' => (bool) !$this->user->isAdmin(),
681 'checked' => (bool) $this->page->get('public')));
683 if (ENABLE_EXTERNAL_PAGES) {
685 = HTML::input(array('type' => 'checkbox',
686 'name' => 'edit[external]',
687 'id' => 'edit-external',
688 'disabled' => (bool) !$this->user->isAdmin(),
689 'checked' => (bool) $this->page->get('external')));
691 if (ENABLE_WYSIWYG) {
692 if (($this->version == 0) and ($request->getArg('mode') != 'wysiwyg')) {
693 $el['WYSIWYG_B'] = Button(array("action" => "edit", "mode" => "wysiwyg"), "Wysiwyg Editor");
697 $el['PREVIEW_B'] = Button('submit:edit[preview]', _("Preview"),
699 array('accesskey'=> 'p',
700 'title' => 'Preview the current content [alt-p]'));
702 //if (!$this->isConcurrentUpdate() && $this->canEdit())
703 $el['SAVE_B'] = Button('submit:edit[save]',
704 _("Save"), 'wikiaction',
705 array('accesskey'=> 's',
706 'title' => 'Save the current content as wikipage [alt-s]'));
707 $el['CHANGES_B'] = Button('submit:edit[diff]',
708 _("Changes"), 'wikiaction',
709 array('accesskey'=> 'c',
710 'title' => 'Preview the current changes as diff [alt-c]'));
711 $el['UPLOAD_B'] = Button('submit:edit[upload]',
712 _("Upload"), 'wikiaction',
713 array('title' => 'Select a local file and press Upload to attach into this page'));
714 $el['SPELLCHECK_B'] = Button('submit:edit[SpellCheck]',
715 _("Spell Check"), 'wikiaction',
716 array('title' => 'Check the spelling'));
717 $el['IS_CURRENT'] = $this->version == $this->current->getVersion();
720 = HTML::input(array('type' => 'text',
723 'class' => "numeric",
724 'name' => 'pref[editWidth]',
725 'id' => 'pref-editWidth',
726 'value' => $request->getPref('editWidth'),
727 'onchange' => 'this.form.submit();'));
729 = HTML::input(array('type' => 'text',
732 'class' => "numeric",
733 'name' => 'pref[editHeight]',
734 'id' => 'pref-editHeight',
735 'value' => $request->getPref('editHeight'),
736 'onchange' => 'this.form.submit();'));
737 $el['SEP'] = $WikiTheme->getButtonSeparator();
738 $el['AUTHOR_MESSAGE'] = fmt("Author will be logged as %s.",
739 HTML::em($this->user->getId()));
744 function _redirectToBrowsePage() {
745 $this->request->redirect(WikiURL($this->page, false, 'absolute_url'));
748 function _restoreState () {
749 $request = &$this->request;
751 $posted = $request->getArg('edit');
752 $request->setArg('edit', false);
755 || !$request->isPost()
756 || !in_array($request->getArg('action'),array('edit','loadfile')))
759 if (!isset($posted['content']) || !is_string($posted['content']))
761 $this->_content = preg_replace('/[ \t\r]+\n/', "\n",
762 rtrim($posted['content']));
763 $this->_content = $this->getContent();
765 $this->_currentVersion = (int) $posted['current_version'];
767 if ($this->_currentVersion < 0)
769 if ($this->_currentVersion > $this->current->getVersion())
770 return false; // FIXME: some kind of warning?
772 $is_old_markup = !empty($posted['markup']) && $posted['markup'] == 'old';
773 $meta['markup'] = $is_old_markup ? false : 2.0;
774 $meta['summary'] = trim(substr($posted['summary'], 0, 256));
775 $meta['is_minor_edit'] = !empty($posted['minor_edit']);
776 $meta['pagetype'] = !empty($posted['pagetype']) ? $posted['pagetype'] : false;
777 if ( ENABLE_CAPTCHA )
778 $meta['captcha_input'] = !empty($posted['captcha_input']) ?
779 $posted['captcha_input'] : '';
781 $this->meta = array_merge($this->meta, $meta);
782 $this->locked = !empty($posted['locked']);
783 if (ENABLE_PAGE_PUBLIC)
784 $this->public = !empty($posted['public']);
785 if (ENABLE_EXTERNAL_PAGES)
786 $this->external = !empty($posted['external']);
788 foreach (array('preview','save','edit_convert',
789 'keep_old','overwrite','diff','upload') as $o)
791 if (!empty($posted[$o]))
792 $this->editaction = $o;
794 if (empty($this->editaction))
795 $this->editaction = 'edit';
800 function _initializeState () {
801 $request = &$this->request;
802 $current = &$this->current;
803 $selected = &$this->selected;
804 $user = &$this->user;
807 NoSuchRevision($request, $this->page, $this->version); // noreturn
809 $this->_currentVersion = $current->getVersion();
810 $this->_content = $selected->getPackedContent();
812 $this->locked = $this->page->get('locked');
814 // If author same as previous author, default minor_edit to on.
815 $age = $this->meta['mtime'] - $current->get('mtime');
816 $this->meta['is_minor_edit'] = ( $age < MINOR_EDIT_TIMEOUT
817 && $current->get('author') == $user->getId()
820 // Default for new pages is new-style markup.
821 if ($selected->hasDefaultContents())
822 $is_new_markup = true;
824 $is_new_markup = $selected->get('markup') >= 2.0;
826 $this->meta['markup'] = $is_new_markup ? 2.0: false;
827 $this->meta['pagetype'] = $selected->get('pagetype');
828 if ($this->meta['pagetype'] == 'wikiblog')
829 $this->meta['summary'] = $selected->get('summary'); // keep blog title
831 $this->meta['summary'] = '';
832 $this->editaction = 'edit';
836 class LoadFileConflictPageEditor
839 function editPage ($saveFailed = true) {
840 $tokens = &$this->tokens;
842 if (!$this->canEdit()) {
843 if ($this->isInitialEdit()) {
844 return $this->viewSource();
846 $tokens['PAGE_LOCKED_MESSAGE'] = $this->getLockedMessage();
848 elseif ($this->editaction == 'save') {
849 if ($this->savePage()) {
850 return true; // Page saved.
855 if ($saveFailed || $this->isConcurrentUpdate())
857 // Get the text of the original page, and the two conflicting edits
858 // The diff class takes arrays as input. So retrieve content as
859 // an array, or convert it as necesary.
860 $orig = $this->page->getRevision($this->_currentVersion);
861 $this_content = explode("\n", $this->_content);
862 $other_content = $this->current->getContent();
863 require_once 'lib/diff.php';
864 $diff2 = new Diff($other_content, $this_content);
865 $context_lines = max(4, count($other_content) + 1,
866 count($this_content) + 1);
867 $fmt = new BlockDiffFormatter($context_lines);
869 $this->_content = $fmt->format($diff2);
870 // FIXME: integrate this into class BlockDiffFormatter
871 $this->_content = str_replace(">>>>>>>\n<<<<<<<\n", "=======\n",
873 $this->_content = str_replace("<<<<<<<\n>>>>>>>\n", "=======\n",
876 $this->_currentVersion = $this->current->getVersion();
877 $this->version = $this->_currentVersion;
878 $tokens['CONCURRENT_UPDATE_MESSAGE'] = $this->getConflictMessage();
881 if ($this->editaction == 'edit_convert')
882 $tokens['PREVIEW_CONTENT'] = $this->getConvertedPreview();
883 if ($this->editaction == 'preview')
884 $tokens['PREVIEW_CONTENT'] = $this->getPreview(); // FIXME: convert to _MESSAGE?
886 // FIXME: NOT_CURRENT_MESSAGE?
887 $tokens = array_merge($tokens, $this->getFormElements());
888 // we need all GET params for loadfile overwrite
889 if ($this->request->getArg('action') == 'loadfile') {
891 $this->tokens['HIDDEN_INPUTS'] =
893 (array('source' => $this->request->getArg('source'),
895 $this->tokens['HIDDEN_INPUTS']);
896 // add two conflict resolution buttons before preview and save.
897 $tokens['PREVIEW_B'] = HTML(
898 Button('submit:edit[keep_old]',
899 _("Keep old"), 'wikiaction'),
901 Button('submit:edit[overwrite]',
902 _("Overwrite with new"), 'wikiaction'),
904 $tokens['PREVIEW_B']);
906 if (ENABLE_EDIT_TOOLBAR and !ENABLE_WYSIWYG) {
907 include_once 'lib/EditToolbar.php';
908 $toolbar = new EditToolbar();
909 $tokens = array_merge($tokens, $toolbar->getTokens());
912 return $this->output('editpage', _("Merge and Edit: %s"));
915 function output ($template, $title_fs) {
916 $selected = &$this->selected;
917 $current = &$this->current;
919 if ($selected && $selected->getVersion() != $current->getVersion()) {
921 $pagelink = WikiLink($selected);
925 $pagelink = WikiLink($this->page);
928 $title = new FormattedText ($title_fs, $pagelink);
929 $this->tokens['HEADER'] = $title;
930 //hack! there's no TITLE in editpage, but in the previous top template
931 if (empty($this->tokens['PAGE_LOCKED_MESSAGE']))
932 $this->tokens['PAGE_LOCKED_MESSAGE'] = HTML::h3($title);
934 $this->tokens['PAGE_LOCKED_MESSAGE'] = HTML(HTML::h3($title),
935 $this->tokens['PAGE_LOCKED_MESSAGE']);
936 $template = Template($template, $this->tokens);
938 //GeneratePage($template, $title, $rev);
943 function getConflictMessage ($unresolved = false) {
944 $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.",
947 HTML::p(_("Please check it through before saving."))));
956 // c-hanging-comment-ender-p: nil
957 // indent-tabs-mode: nil