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