]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/editpage.php
important cookie fix by Konstantin Zadorozhny
[SourceForge/phpwiki.git] / lib / editpage.php
1 <?php
2 rcs_id('$Id: editpage.php,v 1.61 2004-03-12 20:59:17 rurban Exp $');
3
4 require_once('lib/Template.php');
5
6 // Not yet enabled, since we cannot convert HTML to Wiki Markup yet.
7 // We might use a HTML PageType, which is contra wiki, but some people might prefer HTML markup.
8 // Todo: change from constant to user preference variable. (or checkbox setting)
9 if (!defined('USE_HTMLAREA')) define('USE_HTMLAREA',false);
10 if (USE_HTMLAREA) require_once('lib/htmlarea.php');
11
12 class PageEditor
13 {
14     function PageEditor (&$request) {
15         $this->request = &$request;
16
17         $this->user = $request->getUser();
18         $this->page = $request->getPage();
19
20         $this->current = $this->page->getCurrentRevision();
21
22         // HACKish short circuit to browse on action=create
23         if ($request->getArg('action') == 'create') {
24             if (! $this->current->hasDefaultContents()) 
25                 $request->redirect(WikiURL($this->page->getName())); // noreturn
26         }
27         
28         
29         $this->meta = array('author' => $this->user->getId(),
30                             'author_id' => $this->user->getAuthenticatedId(),
31                             'mtime' => time());
32         
33         $this->tokens = array();
34         
35         $version = $request->getArg('version');
36         if ($version !== false) {
37             $this->selected = $this->page->getRevision($version);
38             $this->version = $version;
39         }
40         else {
41             $this->selected = $this->current;
42             $this->version = $this->current->getVersion();
43         }
44
45         if ($this->_restoreState()) {
46             $this->_initialEdit = false;
47         }
48         else {
49             $this->_initializeState();
50             $this->_initialEdit = true;
51         }
52
53         header("Content-Type: text/html; charset=" . CHARSET);
54     }
55
56     function editPage () {
57         $saveFailed = false;
58         $tokens = &$this->tokens;
59
60         if (! $this->canEdit()) {
61             if ($this->isInitialEdit())
62                 return $this->viewSource();
63             $tokens['PAGE_LOCKED_MESSAGE'] = $this->getLockedMessage();
64         }
65         elseif ($this->editaction == 'save') {
66             if ($this->savePage())
67                 return true;    // Page saved.
68             $saveFailed = true;
69         }
70
71         if ($saveFailed || $this->isConcurrentUpdate())
72         {
73             // Get the text of the original page, and the two conflicting edits
74             // The diff3 class takes arrays as input.  So retrieve content as
75             // an array, or convert it as necesary.
76             $orig = $this->page->getRevision($this->_currentVersion);
77             // FIXME: what if _currentVersion has be deleted?
78             $orig_content = $orig->getContent();
79             $this_content = explode("\n", $this->_content);
80             $other_content = $this->current->getContent();
81             include_once("lib/diff3.php");
82             $diff = new diff3($orig_content, $this_content, $other_content);
83             $output = $diff->merged_output(_("Your version"), _("Other version"));
84             // Set the content of the textarea to the merged diff
85             // output, and update the version
86             $this->_content = implode ("\n", $output);
87             $this->_currentVersion = $this->current->getVersion();
88             $this->version = $this->_currentVersion;
89             $unresolved = $diff->ConflictingBlocks;
90             $tokens['CONCURRENT_UPDATE_MESSAGE'] = $this->getConflictMessage($unresolved);
91         }
92
93         if ($this->editaction == 'preview')
94             $tokens['PREVIEW_CONTENT'] = $this->getPreview(); // FIXME: convert to _MESSAGE?
95
96         // FIXME: NOT_CURRENT_MESSAGE?
97
98         $tokens = array_merge($tokens, $this->getFormElements());
99
100         if (defined('JS_SEARCHREPLACE') and JS_SEARCHREPLACE) {
101             $tokens['JS_SEARCHREPLACE'] = 1;
102             $GLOBALS['Theme']->addMoreHeaders(Javascript("
103 var wart=0, d, f, x='', replacewin, pretxt=new Array(), pretxt_anzahl=0;
104 var fag='<font face=\"arial,helvetica,sans-serif\" size=\"-1\">', fr='<font color=\"#cc0000\">', spn='<span class=\"grey\">';
105
106 function define_f() {
107    f=document.getElementById('editpage');
108    f.editarea=document.getElementById('edit[content]');
109    if(f.rck.style) f.rck.style.color='#ececec';
110 }
111
112 function replace() {
113    replacewin=window.open('','','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,height=90,width=450');
114    replacewin.window.document.write('<html><head><title>"._("Search & Replace")."</title><style type=\"text/css\"><'+'!'+'-- input.btt {font-family:Tahoma,Verdana,Geneva,sans-serif;font-size:10pt} --'+'></style></head><body bgcolor=\"#dddddd\" onload=\"if(document.forms[0].ein.focus) document.forms[0].ein.focus()\"><form><center><table><tr><td align=\"right\">'+fag+'"._("Search").":</font></td><td align=\"left\"><input type=\"text\" name=\"ein\" size=\"50\" maxlength=\"500\"></td></tr><tr><td align=\"right\">'+fag+' "._("Replace with").":</font></td><td align=\"left\"><input type=\"text\" name=\"aus\" size=\"50\" maxlength=\"500\"></td></tr><tr><td colspan=\"2\" align=\"center\"><input class=\"btt\" type=\"button\" value=\" "._("OK")." \" onclick=\"self.opener.do_replace()\">&nbsp;&nbsp;&nbsp;<input class=\"btt\" type=\"button\" value=\""._("Close")."\" onclick=\"self.close()\"></td></tr></table></center></form></body></html>');
115    replacewin.window.document.close();
116 }
117
118 function do_replace() {
119    var txt=pretxt[pretxt_anzahl]=f.editarea.value, ein=new RegExp(replacewin.document.forms[0].ein.value,'g'), aus=replacewin.document.forms[0].aus.value;
120    if(ein==''||ein==null) {
121       replacewin.window.document.forms[0].ein.focus();
122       return;
123    }
124    var z_repl=txt.match(ein)? txt.match(ein).length : 0;
125    txt=txt.replace(ein,aus);
126    ein=ein.toString().substring(1,ein.toString().length-2);
127    result(z_repl, 'Substring \"'+ein+'\" found '+z_repl+' times. Replace with \"'+aus+'\"?', txt, 'String \"'+ein+'\" not found.');
128    replacewin.window.focus();
129    replacewin.window.document.forms[0].ein.focus();
130 }
131 function result(zahl,frage,txt,alert_txt) {
132    if(wart!=0&&wart.window) {
133       wart.window.close();
134       wart=0;
135    }
136    if(zahl>0) {
137       if(window.confirm(frage)==true) {
138          f.editarea.value=txt;
139          pretxt_anzahl++;
140          if(f.rck.style) f.rck.style.color='#000000';
141          f.rck.value='"._("Undo")."';
142       }
143    } else alert(alert_txt);
144 }
145 function rueck() {
146    if(pretxt_anzahl==0) return;
147    else if(pretxt_anzahl>0) {
148       f.editarea.value=pretxt[pretxt_anzahl-1];
149       pretxt[pretxt_anzahl]=null;
150       pretxt_anzahl--;
151       if(pretxt_anzahl==0) {
152          alert('Operation undone.');
153          if(f.rck.style) f.rck.style.color='#ececec';
154          f.rck.value='("._("Undo").")';
155          if(f.rck.blur) f.rck.blur();
156       }
157    }
158 }
159 function speich() {
160    pretxt[pretxt_anzahl]=f.editarea.value;
161    pretxt_anzahl++;
162    if(f.rck.style) f.rck.style.color='#000000';
163    f.rck.value='"._("Undo")."';
164 }
165 "));
166             $GLOBALS['Theme']->addMoreAttr('body'," onload='define_f()'");
167         }
168
169         return $this->output('editpage', _("Edit: %s"));
170     }
171
172     function output ($template, $title_fs) {
173         global $Theme;
174         $selected = &$this->selected;
175         $current = &$this->current;
176
177         if ($selected && $selected->getVersion() != $current->getVersion()) {
178             $rev = $selected;
179             $pagelink = WikiLink($selected);
180         }
181         else {
182             $rev = $current;
183             $pagelink = WikiLink($this->page);
184         }
185
186
187         $title = new FormattedText ($title_fs, $pagelink);
188         if ($template == 'editpage' and USE_HTMLAREA) {
189             $Theme->addMoreHeaders(Edit_HtmlArea_Head());
190             //$tokens['PAGE_SOURCE'] = Edit_HtmlArea_ConvertBefore($this->_content);
191         }
192         $template = Template($template, $this->tokens);
193         GeneratePage($template, $title, $rev);
194         return true;
195     }
196
197
198     function viewSource () {
199         assert($this->isInitialEdit());
200         assert($this->selected);
201
202         $this->tokens['PAGE_SOURCE'] = $this->_content;
203         return $this->output('viewsource', _("View Source: %s"));
204     }
205
206     function updateLock() {
207         if ((bool)$this->page->get('locked') == (bool)$this->locked)
208             return false;       // Not changed.
209
210         if (!$this->user->isAdmin()) {
211             // FIXME: some sort of message
212             return false;         // not allowed.
213         }
214
215         $this->page->set('locked', (bool)$this->locked);
216         $this->tokens['LOCK_CHANGED_MSG']
217             = $this->locked ? _("Page now locked.") : _("Page now unlocked.");
218
219         return true;            // lock changed.
220     }
221
222     function savePage () {
223         $request = &$this->request;
224
225         if ($this->isUnchanged()) {
226             // Allow admin lock/unlock even if
227             // no text changes were made.
228             if ($this->updateLock()) {
229                 $dbi = $request->getDbh();
230                 $dbi->touch();
231             }
232             // Save failed. No changes made.
233             $this->_redirectToBrowsePage();
234             // user will probably not see the rest of this...
235             include_once('lib/display.php');
236             // force browse of current version:
237             $request->setArg('version', false);
238             displayPage($request, 'nochanges');
239             return true;
240         }
241
242         $page = &$this->page;
243
244         // Include any meta-data from original page version which
245         // has not been explicitly updated.
246         // (Except don't propagate pgsrc_version --- moot for now,
247         //  because at present it never gets into the db...)
248         $meta = $this->selected->getMetaData();
249         unset($meta['pgsrc_version']);
250         $meta = array_merge($meta, $this->meta);
251         
252         // Save new revision
253         $this->_content = $this->getContent();
254         $newrevision = $page->save($this->_content, $this->_currentVersion + 1, $meta);
255         if (!isa($newrevision, 'wikidb_pagerevision')) {
256             // Save failed.  (Concurrent updates).
257             return false;
258         }
259         
260         // New contents successfully saved...
261         $this->updateLock();
262
263         // Clean out archived versions of this page.
264         include_once('lib/ArchiveCleaner.php');
265         $cleaner = new ArchiveCleaner($GLOBALS['ExpireParams']);
266         $cleaner->cleanPageRevisions($page);
267
268         $dbi = $request->getDbh();
269         $warnings = $dbi->GenericWarnings();
270         $dbi->touch();
271         
272         global $Theme;
273         if (empty($warnings) && ! $Theme->getImageURL('signature')) {
274             // Do redirect to browse page if no signature has
275             // been defined.  In this case, the user will most
276             // likely not see the rest of the HTML we generate
277             // (below).
278             $this->_redirectToBrowsePage();
279         }
280
281         // Force browse of current page version.
282         $request->setArg('version', false);
283
284         $template = Template('savepage', $this->tokens);
285         $template->replace('CONTENT', $newrevision->getTransformedContent());
286         if (!empty($warnings))
287             $template->replace('WARNINGS', $warnings);
288
289         $pagelink = WikiLink($page);
290
291         GeneratePage($template, fmt("Saved: %s", $pagelink), $newrevision);
292         return true;
293     }
294
295     function isConcurrentUpdate () {
296         assert($this->current->getVersion() >= $this->_currentVersion);
297         return $this->current->getVersion() != $this->_currentVersion;
298     }
299
300     function canEdit () {
301         return !$this->page->get('locked') || $this->user->isAdmin();
302     }
303
304     function isInitialEdit () {
305         return $this->_initialEdit;
306     }
307
308     function isUnchanged () {
309         $current = &$this->current;
310
311         if ($this->meta['markup'] !=  $current->get('markup'))
312             return false;
313
314         return $this->_content == $current->getPackedContent();
315     }
316
317     function getPreview () {
318         include_once('lib/PageType.php');
319         $this->_content = $this->getContent();
320         return new TransformedText($this->page, $this->_content, $this->meta);
321     }
322
323     // possibly convert HTMLAREA content back to Wiki markup
324     function getContent () {
325         if (USE_HTMLAREA) {
326             $xml_output = Edit_HtmlArea_ConvertAfter($this->_content);
327             $this->_content = join("",$xml_output->_content);
328             return $this->_content;
329         } else {
330             return $this->_content;
331         }
332     }
333
334     function getLockedMessage () {
335         return
336             HTML(HTML::h2(_("Page Locked")),
337                  HTML::p(_("This page has been locked by the administrator so your changes can not be saved.")),
338                  HTML::p(_("(Copy your changes to the clipboard. You can try editing a different page or save your text in a text editor.)")),
339                  HTML::p(_("Sorry for the inconvenience.")));
340     }
341
342     function getConflictMessage ($unresolved = false) {
343         /*
344          xgettext only knows about c/c++ line-continuation strings
345          it does not know about php's dot operator.
346          We want to translate this entire paragraph as one string, of course.
347          */
348
349         //$re_edit_link = Button('edit', _("Edit the new version"), $this->page);
350
351         if ($unresolved)
352             $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.",
353                                 "<<<<<<< ". _("Your version"),
354                                 ">>>>>>> ". _("Other version")));
355         else
356             $message = HTML::p(_("Please check it through before saving."));
357
358
359
360         /*$steps = HTML::ol(HTML::li(_("Copy your changes to the clipboard or to another temporary place (e.g. text editor).")),
361           HTML::li(fmt("%s of the page. You should now see the most current version of the page. Your changes are no longer there.",
362                        $re_edit_link)),
363           HTML::li(_("Make changes to the file again. Paste your additions from the clipboard (or text editor).")),
364           HTML::li(_("Save your updated changes.")));
365         */
366         return
367             HTML(HTML::h2(_("Conflicting Edits!")),
368                  HTML::p(_("In the time since you started editing this page, another user has saved a new version of it.")),
369                  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.")),
370                  $message);
371     }
372
373
374     function getTextArea () {
375         $request = &$this->request;
376
377         // wrap=virtual is not HTML4, but without it NS4 doesn't wrap
378         // long lines
379         $readonly = ! $this->canEdit(); // || $this->isConcurrentUpdate();
380         if (USE_HTMLAREA) {
381             $html = $this->getPreview();
382             $this->_wikicontent = $this->_content;
383             $this->_content = $html->asXML();
384         }
385         $textarea = HTML::textarea(array('class' => 'wikiedit',
386                                          'name' => 'edit[content]',
387                                          'id'   => 'edit[content]',
388                                          'rows' => $request->getPref('editHeight'),
389                                          'cols' => $request->getPref('editWidth'),
390                                          'readonly' => (bool) $readonly,
391                                          'wrap' => 'virtual'),
392                                    $this->_content);
393         if (USE_HTMLAREA)
394             return Edit_HtmlArea_Textarea($textarea,$this->_wikicontent,'edit[content]');
395         else
396             return $textarea;
397     }
398
399     function getFormElements () {
400         $request = &$this->request;
401         $page = &$this->page;
402
403
404         $h = array('action'   => 'edit',
405                    'pagename' => $page->getName(),
406                    'version'  => $this->version,
407                    'edit[pagetype]' => $this->meta['pagetype'],
408                    'edit[current_version]' => $this->_currentVersion);
409
410         $el['HIDDEN_INPUTS'] = HiddenInputs($h);
411
412
413         $el['EDIT_TEXTAREA'] = $this->getTextArea();
414
415         $el['SUMMARY_INPUT']
416             = HTML::input(array('type'  => 'text',
417                                 'class' => 'wikitext',
418                                 'name'  => 'edit[summary]',
419                                 'size'  => 50,
420                                 'maxlength' => 256,
421                                 'value' => $this->meta['summary']));
422         $el['MINOR_EDIT_CB']
423             = HTML::input(array('type' => 'checkbox',
424                                 'name'  => 'edit[minor_edit]',
425                                 'checked' => (bool) $this->meta['is_minor_edit']));
426         $el['OLD_MARKUP_CB']
427             = HTML::input(array('type' => 'checkbox',
428                                 'name' => 'edit[markup]',
429                                 'value' => 'old',
430                                 'checked' => $this->meta['markup'] < 2.0,
431                                 'id' => 'useOldMarkup',
432                                 'onclick' => 'showOldMarkupRules(this.checked)'));
433
434         $el['LOCKED_CB']
435             = HTML::input(array('type' => 'checkbox',
436                                 'name' => 'edit[locked]',
437                                 'disabled' => (bool) !$this->user->isadmin(),
438                                 'checked'  => (bool) $this->locked));
439
440         $el['PREVIEW_B'] = Button('submit:edit[preview]', _("Preview"),
441                                   'wikiaction');
442
443         //if (!$this->isConcurrentUpdate() && $this->canEdit())
444         $el['SAVE_B'] = Button('submit:edit[save]', _("Save"), 'wikiaction');
445
446         $el['IS_CURRENT'] = $this->version == $this->current->getVersion();
447
448         return $el;
449     }
450
451     function _redirectToBrowsePage() {
452         $this->request->redirect(WikiURL($this->page, false, 'absolute_url'));
453     }
454     
455
456     function _restoreState () {
457         $request = &$this->request;
458
459         $posted = $request->getArg('edit');
460         $request->setArg('edit', false);
461
462         if (!$posted || !$request->isPost()
463             || $request->getArg('action') != 'edit')
464             return false;
465
466         if (!isset($posted['content']) || !is_string($posted['content']))
467             return false;
468         $this->_content = preg_replace('/[ \t\r]+\n/', "\n",
469                                         rtrim($posted['content']));
470         $this->_content = $this->getContent();
471
472         $this->_currentVersion = (int) $posted['current_version'];
473
474         if ($this->_currentVersion < 0)
475             return false;
476         if ($this->_currentVersion > $this->current->getVersion())
477             return false;       // FIXME: some kind of warning?
478
479         $is_old_markup = !empty($posted['markup']) && $posted['markup'] == 'old';
480         $meta['markup'] = $is_old_markup ? false : 2.0;
481         $meta['summary'] = trim(substr($posted['summary'], 0, 256));
482         $meta['is_minor_edit'] = !empty($posted['minor_edit']);
483         $meta['pagetype'] = !empty($posted['pagetype']) ? $posted['pagetype'] : false;
484         $this->meta = array_merge($this->meta, $meta);
485         $this->locked = !empty($posted['locked']);
486
487         if (!empty($posted['preview']))
488             $this->editaction = 'preview';
489         elseif (!empty($posted['save']))
490             $this->editaction = 'save';
491         else
492             $this->editaction = 'edit';
493
494         return true;
495     }
496
497     function _initializeState () {
498         $request = &$this->request;
499         $current = &$this->current;
500         $selected = &$this->selected;
501         $user = &$this->user;
502
503         if (!$selected)
504             NoSuchRevision($request, $this->page, $this->version); // noreturn
505
506         $this->_currentVersion = $current->getVersion();
507         $this->_content = $selected->getPackedContent();
508
509         $this->meta['summary'] = '';
510         $this->locked = $this->page->get('locked');
511
512         // If author same as previous author, default minor_edit to on.
513         $age = $this->meta['mtime'] - $current->get('mtime');
514         $this->meta['is_minor_edit'] = ( $age < MINOR_EDIT_TIMEOUT
515                                          && $current->get('author') == $user->getId()
516                                          );
517
518         // Default for new pages is new-style markup.
519         if ($selected->hasDefaultContents())
520             $is_new_markup = true;
521         else
522             $is_new_markup = $selected->get('markup') >= 2.0;
523
524         $this->meta['markup'] = $is_new_markup ? 2.0: false;
525         $this->meta['pagetype'] = $selected->get('pagetype');
526         $this->editaction = 'edit';
527     }
528 }
529
530 class LoadFileConflictPageEditor
531 extends PageEditor
532 {
533     function editPage ($saveFailed = true) {
534         $tokens = &$this->tokens;
535
536         if (!$this->canEdit()) {
537             if ($this->isInitialEdit())
538                 return $this->viewSource();
539             $tokens['PAGE_LOCKED_MESSAGE'] = $this->getLockedMessage();
540         }
541         elseif ($this->editaction == 'save') {
542             if ($this->savePage())
543                 return true;    // Page saved.
544             $saveFailed = true;
545         }
546
547         if ($saveFailed || $this->isConcurrentUpdate())
548         {
549             // Get the text of the original page, and the two conflicting edits
550             // The diff class takes arrays as input.  So retrieve content as
551             // an array, or convert it as necesary.
552             $orig = $this->page->getRevision($this->_currentVersion);
553             $this_content = explode("\n", $this->_content);
554             $other_content = $this->current->getContent();
555             include_once("lib/diff.php");
556             $diff2 = new Diff($other_content, $this_content);
557             $context_lines = max(4, count($other_content) + 1,
558                                  count($this_content) + 1);
559             $fmt = new BlockDiffFormatter($context_lines);
560
561             $this->_content = $fmt->format($diff2);
562             // FIXME: integrate this into class BlockDiffFormatter
563             $this->_content = str_replace(">>>>>>>\n<<<<<<<\n", "=======\n",
564                                           $this->_content);
565             $this->_content = str_replace("<<<<<<<\n>>>>>>>\n", "=======\n",
566                                           $this->_content);
567
568             $this->_currentVersion = $this->current->getVersion();
569             $this->version = $this->_currentVersion;
570             $tokens['CONCURRENT_UPDATE_MESSAGE'] = $this->getConflictMessage();
571         }
572
573         if ($this->editaction == 'preview')
574             $tokens['PREVIEW_CONTENT'] = $this->getPreview(); // FIXME: convert to _MESSAGE?
575
576         // FIXME: NOT_CURRENT_MESSAGE?
577
578         $tokens = array_merge($tokens, $this->getFormElements());
579
580         return $this->output('editpage', _("Merge and Edit: %s"));
581         // FIXME: this doesn't display
582     }
583
584     function output ($template, $title_fs) {
585         $selected = &$this->selected;
586         $current = &$this->current;
587
588         if ($selected && $selected->getVersion() != $current->getVersion()) {
589             $rev = $selected;
590             $pagelink = WikiLink($selected);
591         }
592         else {
593             $rev = $current;
594             $pagelink = WikiLink($this->page);
595         }
596
597         $title = new FormattedText ($title_fs, $pagelink);
598         $template = Template($template, $this->tokens);
599
600         //GeneratePage($template, $title, $rev);
601         PrintXML($template);
602         return true;
603     }
604     function getConflictMessage () {
605         $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.",
606                                     "<<<<<<<",
607                                     "======="),
608                                 HTML::p(_("Please check it through before saving."))));
609         return $message;
610     }
611 }
612
613 /**
614  $Log: not supported by cvs2svn $
615  Revision 1.60  2004/02/15 21:34:37  rurban
616  PageList enhanced and improved.
617  fixed new WikiAdmin... plugins
618  editpage, Theme with exp. htmlarea framework
619    (htmlarea yet committed, this is really questionable)
620  WikiUser... code with better session handling for prefs
621  enhanced UserPreferences (again)
622  RecentChanges for show_deleted: how should pages be deleted then?
623
624  Revision 1.59  2003/12/07 20:35:26  carstenklapp
625  Bugfix: Concurrent updates broken since after 1.3.4 release: Fatal
626  error: Call to undefined function: gettransformedcontent() in
627  /home/groups/p/ph/phpwiki/htdocs/phpwiki2/lib/editpage.php on line
628  205.
629
630  Revision 1.58  2003/03/10 18:25:22  dairiki
631  Bug/typo fix.  If you use the edit page to un/lock a page, it
632  failed with: Fatal error: Call to a member function on a
633  non-object in editpage.php on line 136
634
635  Revision 1.57  2003/02/26 03:40:22  dairiki
636  New action=create.  Essentially the same as action=edit, except that if the
637  page already exists, it falls back to action=browse.
638
639  This is for use in the "question mark" links for unknown wiki words
640  to avoid problems and confusion when following links from stale pages.
641  (If the "unknown page" has been created in the interim, the user probably
642  wants to view the page before editing it.)
643
644  Revision 1.56  2003/02/21 18:07:14  dairiki
645  Minor, nitpicky, currently inconsequential changes.
646
647  Revision 1.55  2003/02/21 04:10:58  dairiki
648  Fixes for new cached markup.
649  Some minor code cleanups.
650
651  Revision 1.54  2003/02/16 19:47:16  dairiki
652  Update WikiDB timestamp when editing or deleting pages.
653
654  Revision 1.53  2003/02/15 23:20:27  dairiki
655  Redirect back to browse current version of page upon save,
656  even when no changes were made.
657
658  Revision 1.52  2003/01/03 22:22:00  carstenklapp
659  Minor adjustments to diff block markers ("<<<<<<<"). Source reformatting.
660
661  Revision 1.51  2003/01/03 02:43:26  carstenklapp
662  New class LoadFileConflictPageEditor, for merging / comparing a loaded
663  pgsrc file with an existing page.
664
665  */
666
667 // Local Variables:
668 // mode: php
669 // tab-width: 8
670 // c-basic-offset: 4
671 // c-hanging-comment-ender-p: nil
672 // indent-tabs-mode: nil
673 // End:
674 ?>