Revision history for MinorEditHack


Revision [18730]

Last edited on 2008-01-28 00:12:34 by FishPete [Modified links pointing to docs server]

No Differences

Revision [14767]

Edited on 2006-07-04 04:55:23 by FishPete [small change in recentmajorchanges.php source code, layout of page]
Additions:
@@======Minor Edit Hack======@@
First a warning, I am new to php and mysql, what I did was mostly trial and trial and trial and lots of errors - so if you find redudant code or you have suggestions for improvements , please tell me!
====What does it do?====
This hack of mine gives the users the possibility to mark pageupdates as minor changes (typos etc.). I also wrote an action called "recentmajorchanges" which allows the user to see only major, only minor or all changes during a number of days.
====What has to be changed?====
====Known Issues====
the handler "clone" throws a warning. Just add a ",0" to the ""SavePage(...)"" function call, i.e. %%(php) $this->SavePage($to, $pagecontent, $note,0); #create target page. %%
I don't know if there are calls to ""SavePage"" anywhere else. If so, these actions etc. will also throw a warning, but they should work despite the warning.
====to do====
-mark minor changes when 'all' changes are beeing displayed
-userspecific default number of days to display?
if (!isset($minorchange)) $minorchange='0';// inserted by FishPete; if SavePage is called without the $minorchange parameter, assume no minorchange and continue
-4.7.2006: minor change, I just altered RECENT_MAJOR_CHANGES_HEADER etc. to get rid of WORD_FOR_DAY and altered the echo statement which uses these definitions. The lines are marked with //edited 4.7.2006 --FishPete
if (!defined('RECENT_MAJOR_CHANGES_HEADING')) define('RECENT_MAJOR_CHANGES_HEADING', '=====Major Changes During the Last %s Day(s)====='); //edited 4.7.2006
if (!defined('RECENT_MINOR_CHANGES_HEADING')) define('RECENT_MINOR_CHANGES_HEADING', '=====Minor Changes During the Last %s Day(s)====='); //edited 4.7.2006
if (!defined('All_RECENT_CHANGES_HEADING')) define('ALL_RECENT_CHANGES_HEADING', '=====Changes During the Last %s Day(s)====='); //edited 4.7.2006
// if (!defined('WORD_FOR_DAY')) define ('WORD_FOR_DAY', ' Day(s)'); //edited 4.7.2006
echo $this->Format(sprintf($heading, $days_to_show).' --- '); //edited 4.7.2006
%%
Deletions:
======Minor Edit Hack======
<<I successfully patched my wiki tonight. Have a look at http://www.kindred.de/SchreckNet/wikka.php?wakka=SandBox You won't see much, because its a private wiki but one minor and one major change is visible to unregistered users. I will delete this link in a few days<<>>**@@Please Backup your data, I don't see where my code could be harmful, but better be safe than sorry!@@**>>
::c::First a warning, I am new to php and mysql, what I did was mostly trial and trial and trial and lots of errors - so if you find redudant code or you have suggestions for improvements , please tell me!
======What does it do?======
This hack of mine gives the users the possibility to mark pageupdates as minor changes (typos etc.).
I wrote an action called "recentmajorchanges" which allows the user to see only major, only minor or all changes during a number of days.
=====What has to be changed?=====
=====Known Bugs=====
the handler "clone" throws a warning. Should be no problem, just add a ",0" to the ""SavePage(...)"" function call. Didn't have to time to check yet. It works despite of the warning
=====to do=====
-maybe mark minor changes when 'all' changes are beeing displayed
-maybe userspecific default number of days to display
if (!isset($minorchange)) $minorchange='0';// inserted by FishPete
if (!defined('RECENT_MAJOR_CHANGES_HEADING')) define('RECENT_MAJOR_CHANGES_HEADING', 'Major Changes During the Last '); //edited
if (!defined('RECENT_MINOR_CHANGES_HEADING')) define('RECENT_MINOR_CHANGES_HEADING', 'Minor Changes During the Last '); //edited
if (!defined('All_RECENT_CHANGES_HEADING')) define('ALL_RECENT_CHANGES_HEADING', 'Changes During the Last '); //edited
if (!defined('WORD_FOR_DAY')) define ('WORD_FOR_DAY', ' Day(s)'); //edited
echo $this->Format('====='.$heading.$days_to_show.WORD_FOR_DAY.'===== --- ');


Revision [14766]

Edited on 2006-07-03 06:41:36 by FishPete [added sorting of results to "to do"]
Additions:
-maybe sort all edits of one particular Page together, show only edit notes, date and history link if Page is not latest


Revision [14736]

Edited on 2006-06-29 08:19:40 by FishPete ["bug" fix in edit.php]
Additions:
29.6.06: I just added a line to edit.php to show the checkbox during "preview mode". -FishPete


Revision [14729]

Edited on 2006-06-28 19:34:17 by FishPete [minor changes ;-)]
Additions:
======What does it do?======
This hack of mine gives the users the possibility to mark pageupdates as minor changes (typos etc.).
I wrote an action called "recentmajorchanges" which allows the user to see only major, only minor or all changes during a number of days.
=====Known Bugs=====
=====to do=====
-Layout of this page
Pages which were edited twice appear twice in the list. That's a feature, not a bug ;-)
Deletions:
=====What does it do?=====
This hack of mine gives the users the possibility to mark pageupdates as minor ones (typos etc.).
I wrote an action called "recentmajorchanges" which allows the user to see only major, only minor or all changes during the last number of days.
====Known Bugs====
====to do====


Revision [14728]

Edited on 2006-06-28 19:24:42 by FishPete [its working]
Additions:
<<I successfully patched my wiki tonight. Have a look at http://www.kindred.de/SchreckNet/wikka.php?wakka=SandBox You won't see much, because its a private wiki but one minor and one major change is visible to unregistered users. I will delete this link in a few days<<>>**@@Please Backup your data, I don't see where my code could be harmful, but better be safe than sorry!@@**>>
::c::First a warning, I am new to php and mysql, what I did was mostly trial and trial and trial and lots of errors - so if you find redudant code or you have suggestions for improvements , please tell me!
====Known Bugs====
the handler "clone" throws a warning. Should be no problem, just add a ",0" to the ""SavePage(...)"" function call. Didn't have to time to check yet. It works despite of the warning
====to do====
-better layout of recentmajorchanges
-maybe mark minor changes when 'all' changes are beeing displayed
-maybe userspecific default number of days to display
-...
I wrote a function to display changes during the last days to be used instead of ""LoadRecentlyChanged()"" Just insert it right after the function ""LoadRecentlyChanged()""
CategoryUserContributions
Deletions:
>>**@@Please Backup your data, I don't see where my code could be harmful, but better be safe than sorry!@@**>>
''PLEASE NOTE: ''
I have only tested this modification on my local system, I will apply it to my acutal server tonight (following the instruction I give here. Lets see *g*) and post a link as soon as its done!
::c::
First a warning, I am new to php and mysql, what I did was mostly trial and trial and trial and lots of errors - so if you find redudant code or you have suggestions for improvements , please tell me!
I wrote a function to display changes during the last days to be used instead of ""LoadRecentlyChanged()""
/<?php


Revision [14726]

Edited on 2006-06-28 18:54:01 by FishPete [still untested]
Additions:
The next thing to do is add a checkbox to /handlers/pages/edit.php which allows the user to mark a change as a minor one. Since the little code changes are all over the place in this file I'll post the whole file on MinorEditHackEditPHP. The lines I changed are commented with " ""<i>edited by FishPete</i>"". Just search for ""FishPete"" in the file and it should take you to the new lines.
====The action ""RecentMajorChanges""====
I took out the user specific maximum of changes to show, but its easy to take it back in. just un-comment the lines .
/<?php
* Display a list of recently changed pages, distinguishes between major and minor changes
* @param: $days_to_show: how many days of changes should be displayed.
* @param: $what_to_show: eather 'minor', 'major' or 'all' changes should be displayed
foreach ($vars as $param => $value)
switch ($param)
{
case 'days':
case 'show':
case ('all'):
$what_to_show='all';
$heading = ALL_RECENT_CHANGES_HEADING;
break;
case ('minor'):
$what_to_show='minor';
$heading = RECENT_MINOR_CHANGES_HEADING;
break;
case ('major'):
$what_to_show='major';
$heading=RECENT_MAJOR_CHANGES_HEADING;
break;
}
if (isset($_REQUEST['days']) && ($_REQUEST['days']>0)) $days_to_show=$_REQUEST['days'];
if (isset($_REQUEST['days'])&& ($_REQUEST['days']>0)) $days_to_show=$_REQUEST['days'];
if (isset($_REQUEST['days'])&& ($_REQUEST['days']>0)) $days_to_show=$_REQUEST['days'];
<input name="days" type="text", size="1" maxlenght="2" value="'.$days_to_show.'"> days ago<br>
<input name="show_major" type="submit" value="'.SHOW_MAJOR_BUTTON_TEXT.'">
<input name="show_minor" type="submit" value="'.SHOW_MINOR_BUTTON_TEXT.'">
<input name="show_all" type="submit" value="'.SHOW_ALL_BUTTON_TEXT.'"></p>
/*if ($user = $this->GetUser())
Deletions:
The next thing to do is add a checkbox to /handlers/pages/edit.php which allows the user to mark a change as a minor one. Since the little code changes are all over the place in this file I'll post the whole file. The lines I changed are commented with " ""<i>edited by FishPete</i>"". Just search for ""FishPete"" in the file and it should take you to the new lines.
* Display a form to edit the current page.
* @package Handlers
* @name Edit
* @author {@link http://wikkawiki.org/JsnX Jason Tourtelotte} (original code)
* @author {@link http://wikkawiki.org/Dartar Dario Taraborelli} (preliminary code cleanup, i18n)
* @author {@link http://wikkawiki.org/DotMG Mahefa Randimbisoa} (bugfixes)
* @author {@link http://wikkawiki.org/FishPete Peter Fischaleck} (Minor Edit Hack)
* @since Wikka 1.1.6.2
* @todo - move main <div> to templating class;
* - optimization using history.back();
* - use central regex library for validation;
// defaults
if(!defined('VALID_PAGENAME_PATTERN')) define ('VALID_PAGENAME_PATTERN', '/^[A-Za-zÄÖÜßäöü]+[A-Za-z0-9ÄÖÜßäöü]*$/s');
if(!defined('MAX_TAG_LENGTH')) define ('MAX_TAG_LENGTH', 75);
if(!defined('MAX_EDIT_NOTE_LENGTH')) define ('MAX_EDIT_NOTE_LENGTH', 50);
if(!defined('PREVIEW_HEADER')) define('PREVIEW_HEADER', 'Preview');
if(!defined('LABEL_EDIT_NOTE')) define('LABEL_EDIT_NOTE', 'Please add a note on your edit');
if (!defined('INPUT_ERROR_STYLE')) define('INPUT_ERROR_STYLE', 'class="highlight"');
if(!defined('ERROR_INVALID_PAGENAME')) define('ERROR_INVALID_PAGENAME', 'This page name is invalid. Valid page names must start with a letter and contain only letters and numbers.');
if(!defined('ERROR_OVERWRITE_ALERT')) define('ERROR_OVERWRITE_ALERT', 'OVERWRITE ALERT: This page was modified by someone else while you were editing it.<br /> Please copy your changes and re-edit this page.');
if(!defined('ERROR_MISSING_EDIT_NOTE')) define('ERROR_MISSING_EDIT_NOTE', 'MISSING EDIT NOTE: Please fill in an edit note!');
if(!defined('ERROR_TAG_TOO_LONG')) define('ERROR_TAG_TOO_LONG', 'Tag too long! %d characters max.');
if(!defined('ERROR_NO_WRITE_ACCESS')) define('ERROR_NO_WRITE_ACCESS', 'You don\'t have write access to this page. You might need to register an account to be able to edit this page.');
if(!defined('MESSAGE_AUTO_RESIZE')) define('MESSAGE_AUTO_RESIZE', 'Clicking on %s will automatically truncate the tag to the correct size');
if(!defined('INPUT_SUBMIT_PREVIEW')) define('INPUT_SUBMIT_PREVIEW', 'Preview');
if(!defined('INPUT_SUBMIT_STORE')) define('INPUT_SUBMIT_STORE', 'Store');
if(!defined('INPUT_SUBMIT_REEDIT')) define('INPUT_SUBMIT_REEDIT', 'Re-edit');
if(!defined('INPUT_BUTTON_CANCEL')) define('INPUT_BUTTON_CANCEL', 'Cancel');
if(!defined('INPUT_SUBMIT_RENAME')) define('INPUT_SUBMIT_RENAME', 'Rename');
if(!defined('ACCESSKEY_STORE')) define('ACCESSKEY_STORE', 's');
if(!defined('ACCESSKEY_REEDIT')) define('ACCESSKEY_REEDIT', 'r');
if(!defined('ACCESSKEY_PREVIEW')) define('ACCESSKEY_PREVIEW', 'p');
if(!defined('SHOWCODE_LINK')) define('SHOWCODE_LINK', 'View formatting code for this page');
if(!defined('SHOWCODE_LINK_TITLE')) define('SHOWCODE_LINK_TITLE', 'Click to view page formatting code');
if(!defined('MINOR_CHANGE_FLAG_TEXT')) define('MINOR_CHANGE_FLAG_TEXT', 'Please check if your change is a minor one');//edit by FishPete
$error = '';
$highlight_note = '';
$ondblclick = ''; //#123
if (isset($_POST['submit']) && ($_POST['submit'] == 'Preview') && ($user = $this->GetUser()) && ($user['doubleclickedit'] != 'N'))
$ondblclick = ' ondblclick=\'document.getElementById("reedit_id").click();\'';
//history.back() not working on IE. (changes are lost)
//however, history.back() works fine in FF, and this is the optimized choice
//TODO Optimization: Look $_SERVER['HTTP_USER_AGENT'] and use history.back() for good browsers like FF.
<div class="page"<?php echo $ondblclick;?>>
if (!(preg_match(VALID_PAGENAME_PATTERN, $this->tag))) { //TODO use central regex library
echo '<em>'.ERROR_INVALID_PAGENAME.'</em>';
elseif ($this->HasAccess("write") && $this->HasAccess("read"))
$newtag = $output = '';
if (isset($_POST['newtag'])) $newtag = $_POST['newtag'];
if ($newtag !== '') $this->Redirect($this->Href('edit', $newtag));
if ($_POST)
// strip CRLF line endings down to LF to achieve consistency ... plus it saves database space.
// Note: these codes must remain enclosed in double-quotes to work!
$body = str_replace("\r\n", "\n", $_POST['body']);
$body = preg_replace("/\n[ ]{4}/", "\n\t", $body); // @@@ FIXME: misses first line and multiple sets of four spaces
// we don't need to escape here, we do that just before display (i.e., treat note just like body!)
$note = trim($_POST['note']);
// only if saving:
if ($_POST['submit'] == 'Store')
// check for overwriting
if ($this->page)
if ($this->page['id'] != $_POST['previous'])
$error = ERROR_OVERWRITE_ALERT;
// check for edit note
if (($this->config['require_edit_note'] == 1) && $_POST['note'] == '')
$error .= ERROR_MISSING_EDIT_NOTE;
$highlight_note= INPUT_ERROR_STYLE;
// store
if (!$error)
// only save if new body differs from old body
if ($body != $this->page['body']) {
// add page (revisions)

//begin edit by FishPete
//$this->SavePage($this->tag, $body, $note);
if ($_POST['minor_change_flag']=='minor_change') //checkbox 'minor_change_flag' was cklicked by User
{
$this->SavePage($this->tag, $body, $note, '1');// save page as a minor change
}
else //checkbox was not clicked
{
$this->SavePage($this->tag, $body, $note, '0');// save page as major change
}
// end edit by FishPete

// now we render it internally so we can write the updated link table.
$this->ClearLinkTable();
$this->StartLinkTracking();
$dummy = $this->Header();
$dummy .= $this->Format($body);
$dummy .= $this->Footer();
$this->StopLinkTracking();
$this->WriteLinkTable();
$this->ClearLinkTable();
// forward
$this->Redirect($this->Href());
// fetch fields
$previous = $this->page['id'];
if (isset($_POST['previous'])) $previous = $_POST['previous'];
if (!isset($body)) $body = $this->page['body'];
$body = preg_replace("/\n[ ]{4}/", "\n\t", $body); // @@@ FIXME: misses first line and multiple sets of four spaces - JW 2005-01-16
if ($result = mysql_query("describe ".$this->config['table_prefix']."pages tag")) {
$field = mysql_fetch_assoc($result);
if (preg_match("/varchar\((\d+)\)/", $field['Type'], $matches)) $maxtaglen = $matches[1];
else
$maxtaglen = MAX_TAG_LENGTH;
if (isset($_POST['submit']) && $_POST['submit'] == INPUT_SUBMIT_PREVIEW) # preview output
$preview_buttons = '<hr />'."\n";
// We need to escape ALL entity refs before display so we display them _as_ entities instead of interpreting them
// so we use htmlspecialchars on the edit note (as on the body)
if ($this->config['require_edit_note'] != 2) //check if edit_notes are enabled
$preview_buttons .= '<input size="'.MAX_EDIT_NOTE_LENGTH.'" type="text" name="note" value="'.htmlspecialchars($note).'" '.$highlight_note.'/>'.LABEL_EDIT_NOTE.'<br />'."\n";
$preview_buttons .= '<input name="submit" type="submit" value="'.INPUT_SUBMIT_STORE.'" accesskey="'.ACCESSKEY_STORE.'" />'."\n".
'<input name="submit" type="submit" value="'.INPUT_SUBMIT_REEDIT.'" accesskey="'.ACCESSKEY_REEDIT.'" id="reedit_id" />'."\n".
'<input type="button" value="'.INPUT_BUTTON_CANCEL.'" onclick="document.location=\''.$this->href('').'\';" />'."\n";
$output .= '<div class="previewhead">'.PREVIEW_HEADER.'</div>'."\n";
$output .= $this->Format($body);
$output .=
$this->FormOpen('edit')."\n".
'<input type="hidden" name="previous" value="'.$previous.'" />'."\n".
// We need to escape ALL entity refs before display so we display them _as_ entities instead of interpreting them
// hence htmlspecialchars() instead of htmlspecialchars_ent() which UNescapes entities!
'<input type="hidden" name="body" value="'.htmlspecialchars($body).'" />'."\n";
$output .= "<br />\n".$preview_buttons.$this->FormClose()."\n";
elseif (!$this->page && strlen($this->tag) > $maxtaglen) # rename page
$this->tag = substr($this->tag, 0, $maxtaglen); // truncate tag to feed a backlinks-handler with the correct value. may be omited. it only works if the link to a backlinks-handler is built in the footer.
$output = '<em class="error">'.sprintf(ERROR_TAG_TOO_LONG, $maxtaglen).'</em><br />'."\n";
$output .= sprintf(MESSAGE_AUTO_RESIZE, INPUT_SUBMIT_RENAME).'<br /><br />'."\n";
$output .= $this->FormOpen('edit');
$output .= '<input name="newtag" size="'.MAX_TAG_LENGTH.'" value="'.$this->htmlspecialchars_ent($this->tag).'" />';
$output .= '<input name="submit" type="submit" value="'.INPUT_SUBMIT_RENAME.'" />'."\n";
$output .= $this->FormClose();
else # edit page
// display form
if ($error)
$output .= '<em class="error">'.$error.'</em>'."\n";
// append a comment?
if (isset($_REQUEST['appendcomment']))
$body = trim($body)."\n\n----\n\n--".$this->GetUserName().' ('.strftime("%c").')';
$output .=
$this->FormOpen('edit').
'<input type="hidden" name="previous" value="'.$previous.'" />'."\n".
// We need to escape ALL entity refs before display so we display them _as_ entities instead of interpreting them
// hence htmlspecialchars() instead of htmlspecialchars_ent() which UNescapes entities!
'<textarea id="body" name="body">'.htmlspecialchars($body).'</textarea><br />'."\n";
//note add Edit
// We need to escape ALL entity refs before display so we display them _as_ entities instead of interpreting them
// so we use htmlspecialchars on the edit note (as on the body)
if ($this->config['require_edit_note'] != 2) //check if edit_notes are enabled
$output .= '<input size="'.MAX_EDIT_NOTE_LENGTH.'" type="text" name="note" value="'.htmlspecialchars($note).'" '.$highlight_note.'/> '.LABEL_EDIT_NOTE.'<br />'."\n";

$output .= '<input type="checkbox" name="minor_change_flag" value="minor_change"> '.MINOR_CHANGE_FLAG_TEXT.'<br>'."\n";// Edit by FishPete


//finish
$output .= '<input name="submit" type="submit" value="'.INPUT_SUBMIT_STORE.'" accesskey="'.ACCESSKEY_STORE.'" /> <input name="submit" type="submit" value="'.INPUT_SUBMIT_PREVIEW.'" accesskey="'.ACCESSKEY_PREVIEW.'" /> <input type="button" value="'.INPUT_BUTTON_CANCEL.'" onclick="document.location=\''.$this->Href('').'\';" />'."\n".
$this->FormClose();
if ($this->config['gui_editor'] == 1)
$output .= '<script type="text/javascript" src="3rdparty/plugins/wikiedit/protoedit.js"></script>'."\n".
'<script type="text/javascript" src="3rdparty/plugins/wikiedit/wikiedit2.js"></script>'."\n";
$output .= '<script type="text/javascript">'." wE = new WikiEdit(); wE.init('body','WikiEdit','editornamecss');".'</script>'."\n";
echo $output;
$message = '<em>'.ERROR_NO_WRITE_ACCESS.'</em><br />'."\n".
"<br />\n".
'<a href="'.$this->Href('showcode').'" title="'.SHOWCODE_LINK_TITLE.'">'.SHOWCODE_LINK.'</a>'.
"<br />\n";
echo $message;
</div>
the
installableactiontemplate_version => '1.0'
random_setting => 'this will be added to the main config array'
echo $this->config['random_setting'];
echo '<p class="easier">Other typical wiki stuff goes here...</p>';
===The action ""RecentMajorChanges""====
* Display a list of recently changed pages, which are major changes .
foreach ($vars as $param => $value)
switch ($param)
case 'days':
case 'show':
case ('all'):
$what_to_show='all';
$heading = ALL_RECENT_CHANGES_HEADING;
break;
case ('minor'):
$what_to_show='minor';
$heading = RECENT_MINOR_CHANGES_HEADING;
break;
case ('major'):
$what_to_show='major';
$heading=RECENT_MAJOR_CHANGES_HEADING;
break;
}
if (isset($_REQUEST['test']) && ($_REQUEST['test']>0)) $days_to_show=$_REQUEST['test'];
if (isset($_REQUEST['test'])&& ($_REQUEST['test']>0)) $days_to_show=$_REQUEST['test'];
if (isset($_REQUEST['test'])&& ($_REQUEST['test']>0)) $days_to_show=$_REQUEST['test'];
<input name="test" type="text", size="1" maxlenght="2" value="'.$days_to_show.'"> days ago<br>
<input name="show_all" type="submit" value="show all">
<input name="show_major" type="submit" value="show only major changes">
<input name="show_minor" type="submit" value="show only minor changes"></p>
/*if ($user = $this->GetUser())


Revision [14725]

Edited on 2006-06-28 18:25:12 by FishPete [first version. not tested yet!]
Additions:
======Minor Edit Hack======
>>**@@Please Backup your data, I don't see where my code could be harmful, but better be safe than sorry!@@**>>
''PLEASE NOTE: ''
I have only tested this modification on my local system, I will apply it to my acutal server tonight (following the instruction I give here. Lets see *g*) and post a link as soon as its done!
::c::
First a warning, I am new to php and mysql, what I did was mostly trial and trial and trial and lots of errors - so if you find redudant code or you have suggestions for improvements , please tell me!
=====What does it do?=====
This hack of mine gives the users the possibility to mark pageupdates as minor ones (typos etc.).
I wrote an action called "recentmajorchanges" which allows the user to see only major, only minor or all changes during the last number of days.
=====What has to be changed?=====
-a new field calles "minorchanges" has to be added to the table "wikka_pages" in the MYSQL database
-the function ""SavePage"" in wakka.class.php has to be changed
-the function ""ChangedDuringLastDays"" is "new"
-the edit handler has to be updated
-the action recentmajorchanges is "new"
====Change to the MYSQL Database====
As a fist step you have to add a cell to the table "pages" in the MYSQL Database called "minorchange", which consists of a boolean value. FALSE or 0 meaning "no minor change", TRUE or !=0 means "minorchange"
the MYSQL Query is:
ALTER TABLE `wikka_pages` ADD `minorchange` BOOL NOT NULL DEFAULT '0';
''NOTE'': I'm assuming you use the standart table prefix ''wikka_'' here!
====The PHP Code====
===Changes in /libs/wakka.class.php===
==""SavePage""==
The function ""SavePage"" in /libs/wakka.class.php has to be altered to be able to save the minorchange flag. inserted lines are commented
function SavePage($tag, $body, $note, $minorchange) //editet by FishPete
{
if (!isset($minorchange)) $minorchange='0';// inserted by FishPete
// get current user
$user = $this->GetUserName();
// TODO: check write privilege
if ($this->HasAccess("write", $tag))
{
// is page new?
if (!$oldPage = $this->LoadPage($tag))
{
// current user is owner if user is logged in, otherwise, no owner.
if ($this->GetUser()) $owner = $user;
}
else
{
// aha! page isn't new. keep owner!
$owner = $oldPage["owner"];
}
// set all other revisions to old
$this->Query("update ".$this->config["table_prefix"]."pages set latest = 'N' where tag = '".mysql_real_escape_string($tag)."'");
// add new revision
$this->Query("insert into ".$this->config["table_prefix"]."pages set ".
"tag = '".mysql_real_escape_string($tag)."', ".
"time = now(), ".
"owner = '".mysql_real_escape_string($owner)."', ".
"user = '".mysql_real_escape_string($user)."', ".
"note = '".mysql_real_escape_string($note)."', ".
"latest = 'Y', ".
"minorchange = ".$minorchange.", ". // inserted by FishPete
"body = '".mysql_real_escape_string($body)."'");
if ($pingdata = $this->GetPingParams($this->config["wikiping_server"], $tag, $user, $note))
$this->WikiPing($pingdata);
}
}
==""ChangedDuringLastDays""==
I wrote a function to display changes during the last days to be used instead of ""LoadRecentlyChanged()""
/*$interval: number of days which should be displayed
* $show: whether to show all, only major or only minor changes
* returns array of pages which were changed during the last ($interval) days and are according to $show criteria
*/

function LoadChangedDuringLastDays($interval, $show)
{
switch ($show)
{
case 'all':
$param=''; //no additional parameter in the MYSQL Query
break;
case 'major':
$param='AND minorchange = 0'; //to be used in the MYSQL Query
break;
case 'minor':
$param='AND minorchange !=0'; //to be used in the MYSQL Query
break;
}
if ($pages = $this->LoadAll("select * from ".$this->config["table_prefix"]."pages where time> DATE_SUB(now(),INTERVAL ".$interval." DAY) ".$param." order by time desc"))
{
foreach ($pages as $page)
{
$this->CachePage($page);
}
return $pages;
}
}
===Changes in /handlers/page/edit.php===
The next thing to do is add a checkbox to /handlers/pages/edit.php which allows the user to mark a change as a minor one. Since the little code changes are all over the place in this file I'll post the whole file. The lines I changed are commented with " ""<i>edited by FishPete</i>"". Just search for ""FishPete"" in the file and it should take you to the new lines.
/**
* Display a form to edit the current page.
*
* @package Handlers
* @name Edit
*
* @author {@link http://wikkawiki.org/JsnX Jason Tourtelotte} (original code)
* @author {@link http://wikkawiki.org/Dartar Dario Taraborelli} (preliminary code cleanup, i18n)
* @author {@link http://wikkawiki.org/DotMG Mahefa Randimbisoa} (bugfixes)
* @author {@link http://wikkawiki.org/FishPete Peter Fischaleck} (Minor Edit Hack)
* @since Wikka 1.1.6.2
*
* @todo - move main <div> to templating class;
* - optimization using history.back();
* - use central regex library for validation;
*/
// defaults
if(!defined('VALID_PAGENAME_PATTERN')) define ('VALID_PAGENAME_PATTERN', '/^[A-Za-zÄÖÜßäöü]+[A-Za-z0-9ÄÖÜßäöü]*$/s');
if(!defined('MAX_TAG_LENGTH')) define ('MAX_TAG_LENGTH', 75);
if(!defined('MAX_EDIT_NOTE_LENGTH')) define ('MAX_EDIT_NOTE_LENGTH', 50);
//i18n
if(!defined('PREVIEW_HEADER')) define('PREVIEW_HEADER', 'Preview');
if(!defined('LABEL_EDIT_NOTE')) define('LABEL_EDIT_NOTE', 'Please add a note on your edit');
if (!defined('INPUT_ERROR_STYLE')) define('INPUT_ERROR_STYLE', 'class="highlight"');
if(!defined('ERROR_INVALID_PAGENAME')) define('ERROR_INVALID_PAGENAME', 'This page name is invalid. Valid page names must start with a letter and contain only letters and numbers.');
if(!defined('ERROR_OVERWRITE_ALERT')) define('ERROR_OVERWRITE_ALERT', 'OVERWRITE ALERT: This page was modified by someone else while you were editing it.<br /> Please copy your changes and re-edit this page.');
if(!defined('ERROR_MISSING_EDIT_NOTE')) define('ERROR_MISSING_EDIT_NOTE', 'MISSING EDIT NOTE: Please fill in an edit note!');
if(!defined('ERROR_TAG_TOO_LONG')) define('ERROR_TAG_TOO_LONG', 'Tag too long! %d characters max.');
if(!defined('ERROR_NO_WRITE_ACCESS')) define('ERROR_NO_WRITE_ACCESS', 'You don\'t have write access to this page. You might need to register an account to be able to edit this page.');
if(!defined('MESSAGE_AUTO_RESIZE')) define('MESSAGE_AUTO_RESIZE', 'Clicking on %s will automatically truncate the tag to the correct size');
if(!defined('INPUT_SUBMIT_PREVIEW')) define('INPUT_SUBMIT_PREVIEW', 'Preview');
if(!defined('INPUT_SUBMIT_STORE')) define('INPUT_SUBMIT_STORE', 'Store');
if(!defined('INPUT_SUBMIT_REEDIT')) define('INPUT_SUBMIT_REEDIT', 'Re-edit');
if(!defined('INPUT_BUTTON_CANCEL')) define('INPUT_BUTTON_CANCEL', 'Cancel');
if(!defined('INPUT_SUBMIT_RENAME')) define('INPUT_SUBMIT_RENAME', 'Rename');
if(!defined('ACCESSKEY_STORE')) define('ACCESSKEY_STORE', 's');
if(!defined('ACCESSKEY_REEDIT')) define('ACCESSKEY_REEDIT', 'r');
if(!defined('ACCESSKEY_PREVIEW')) define('ACCESSKEY_PREVIEW', 'p');
if(!defined('SHOWCODE_LINK')) define('SHOWCODE_LINK', 'View formatting code for this page');
if(!defined('SHOWCODE_LINK_TITLE')) define('SHOWCODE_LINK_TITLE', 'Click to view page formatting code');
if(!defined('MINOR_CHANGE_FLAG_TEXT')) define('MINOR_CHANGE_FLAG_TEXT', 'Please check if your change is a minor one');//edit by FishPete
//initialization
$error = '';
$highlight_note = '';
$ondblclick = ''; //#123
if (isset($_POST['submit']) && ($_POST['submit'] == 'Preview') && ($user = $this->GetUser()) && ($user['doubleclickedit'] != 'N'))
{
$ondblclick = ' ondblclick=\'document.getElementById("reedit_id").click();\'';
//history.back() not working on IE. (changes are lost)
//however, history.back() works fine in FF, and this is the optimized choice
//TODO Optimization: Look $_SERVER['HTTP_USER_AGENT'] and use history.back() for good browsers like FF.
}
<div class="page"<?php echo $ondblclick;?>>
if (!(preg_match(VALID_PAGENAME_PATTERN, $this->tag))) { //TODO use central regex library
echo '<em>'.ERROR_INVALID_PAGENAME.'</em>';
}
elseif ($this->HasAccess("write") && $this->HasAccess("read"))
{
$newtag = $output = '';
if (isset($_POST['newtag'])) $newtag = $_POST['newtag'];
if ($newtag !== '') $this->Redirect($this->Href('edit', $newtag));
if ($_POST)
{
// strip CRLF line endings down to LF to achieve consistency ... plus it saves database space.
// Note: these codes must remain enclosed in double-quotes to work!
$body = str_replace("\r\n", "\n", $_POST['body']);
$body = preg_replace("/\n[ ]{4}/", "\n\t", $body); // @@@ FIXME: misses first line and multiple sets of four spaces
// we don't need to escape here, we do that just before display (i.e., treat note just like body!)
$note = trim($_POST['note']);
// only if saving:
if ($_POST['submit'] == 'Store')
{
// check for overwriting
if ($this->page)
{
if ($this->page['id'] != $_POST['previous'])
{
$error = ERROR_OVERWRITE_ALERT;
}
}
// check for edit note
if (($this->config['require_edit_note'] == 1) && $_POST['note'] == '')
{
$error .= ERROR_MISSING_EDIT_NOTE;
$highlight_note= INPUT_ERROR_STYLE;
}
// store
if (!$error)
{
// only save if new body differs from old body
if ($body != $this->page['body']) {
// add page (revisions)

//begin edit by FishPete
//$this->SavePage($this->tag, $body, $note);
if ($_POST['minor_change_flag']=='minor_change') //checkbox 'minor_change_flag' was cklicked by User
{
$this->SavePage($this->tag, $body, $note, '1');// save page as a minor change
}
else //checkbox was not clicked
{
$this->SavePage($this->tag, $body, $note, '0');// save page as major change
}
// end edit by FishPete

// now we render it internally so we can write the updated link table.
$this->ClearLinkTable();
$this->StartLinkTracking();
$dummy = $this->Header();
$dummy .= $this->Format($body);
$dummy .= $this->Footer();
$this->StopLinkTracking();
$this->WriteLinkTable();
$this->ClearLinkTable();
}
// forward
$this->Redirect($this->Href());
}
}
}
// fetch fields
$previous = $this->page['id'];
if (isset($_POST['previous'])) $previous = $_POST['previous'];
if (!isset($body)) $body = $this->page['body'];
$body = preg_replace("/\n[ ]{4}/", "\n\t", $body); // @@@ FIXME: misses first line and multiple sets of four spaces - JW 2005-01-16
if ($result = mysql_query("describe ".$this->config['table_prefix']."pages tag")) {
$field = mysql_fetch_assoc($result);
if (preg_match("/varchar\((\d+)\)/", $field['Type'], $matches)) $maxtaglen = $matches[1];
}
else
{
$maxtaglen = MAX_TAG_LENGTH;
}
if (isset($_POST['submit']) && $_POST['submit'] == INPUT_SUBMIT_PREVIEW) # preview output
{
$preview_buttons = '<hr />'."\n";
// We need to escape ALL entity refs before display so we display them _as_ entities instead of interpreting them
// so we use htmlspecialchars on the edit note (as on the body)
if ($this->config['require_edit_note'] != 2) //check if edit_notes are enabled
{
$preview_buttons .= '<input size="'.MAX_EDIT_NOTE_LENGTH.'" type="text" name="note" value="'.htmlspecialchars($note).'" '.$highlight_note.'/>'.LABEL_EDIT_NOTE.'<br />'."\n";
}
$preview_buttons .= '<input name="submit" type="submit" value="'.INPUT_SUBMIT_STORE.'" accesskey="'.ACCESSKEY_STORE.'" />'."\n".
'<input name="submit" type="submit" value="'.INPUT_SUBMIT_REEDIT.'" accesskey="'.ACCESSKEY_REEDIT.'" id="reedit_id" />'."\n".
'<input type="button" value="'.INPUT_BUTTON_CANCEL.'" onclick="document.location=\''.$this->href('').'\';" />'."\n";
$output .= '<div class="previewhead">'.PREVIEW_HEADER.'</div>'."\n";
$output .= $this->Format($body);
$output .=
$this->FormOpen('edit')."\n".
'<input type="hidden" name="previous" value="'.$previous.'" />'."\n".
// We need to escape ALL entity refs before display so we display them _as_ entities instead of interpreting them
// hence htmlspecialchars() instead of htmlspecialchars_ent() which UNescapes entities!
'<input type="hidden" name="body" value="'.htmlspecialchars($body).'" />'."\n";
$output .= "<br />\n".$preview_buttons.$this->FormClose()."\n";
}
elseif (!$this->page && strlen($this->tag) > $maxtaglen) # rename page
{
$this->tag = substr($this->tag, 0, $maxtaglen); // truncate tag to feed a backlinks-handler with the correct value. may be omited. it only works if the link to a backlinks-handler is built in the footer.
$output = '<em class="error">'.sprintf(ERROR_TAG_TOO_LONG, $maxtaglen).'</em><br />'."\n";
$output .= sprintf(MESSAGE_AUTO_RESIZE, INPUT_SUBMIT_RENAME).'<br /><br />'."\n";
$output .= $this->FormOpen('edit');
$output .= '<input name="newtag" size="'.MAX_TAG_LENGTH.'" value="'.$this->htmlspecialchars_ent($this->tag).'" />';
$output .= '<input name="submit" type="submit" value="'.INPUT_SUBMIT_RENAME.'" />'."\n";
$output .= $this->FormClose();
}
else # edit page
{
// display form
if ($error)
{
$output .= '<em class="error">'.$error.'</em>'."\n";
}
// append a comment?
if (isset($_REQUEST['appendcomment']))
{
$body = trim($body)."\n\n----\n\n--".$this->GetUserName().' ('.strftime("%c").')';
}
$output .=
$this->FormOpen('edit').
'<input type="hidden" name="previous" value="'.$previous.'" />'."\n".
// We need to escape ALL entity refs before display so we display them _as_ entities instead of interpreting them
// hence htmlspecialchars() instead of htmlspecialchars_ent() which UNescapes entities!
'<textarea id="body" name="body">'.htmlspecialchars($body).'</textarea><br />'."\n";
//note add Edit
// We need to escape ALL entity refs before display so we display them _as_ entities instead of interpreting them
// so we use htmlspecialchars on the edit note (as on the body)
if ($this->config['require_edit_note'] != 2) //check if edit_notes are enabled
{
$output .= '<input size="'.MAX_EDIT_NOTE_LENGTH.'" type="text" name="note" value="'.htmlspecialchars($note).'" '.$highlight_note.'/> '.LABEL_EDIT_NOTE.'<br />'."\n";
}


$output .= '<input type="checkbox" name="minor_change_flag" value="minor_change"> '.MINOR_CHANGE_FLAG_TEXT.'<br>'."\n";// Edit by FishPete


//finish
$output .= '<input name="submit" type="submit" value="'.INPUT_SUBMIT_STORE.'" accesskey="'.ACCESSKEY_STORE.'" /> <input name="submit" type="submit" value="'.INPUT_SUBMIT_PREVIEW.'" accesskey="'.ACCESSKEY_PREVIEW.'" /> <input type="button" value="'.INPUT_BUTTON_CANCEL.'" onclick="document.location=\''.$this->Href('').'\';" />'."\n".
$this->FormClose();
if ($this->config['gui_editor'] == 1)
{
$output .= '<script type="text/javascript" src="3rdparty/plugins/wikiedit/protoedit.js"></script>'."\n".
'<script type="text/javascript" src="3rdparty/plugins/wikiedit/wikiedit2.js"></script>'."\n";
$output .= '<script type="text/javascript">'." wE = new WikiEdit(); wE.init('body','WikiEdit','editornamecss');".'</script>'."\n";
}
}
echo $output;
}
else
{
$message = '<em>'.ERROR_NO_WRITE_ACCESS.'</em><br />'."\n".
"<br />\n".
'<a href="'.$this->Href('showcode').'" title="'.SHOWCODE_LINK_TITLE.'">'.SHOWCODE_LINK.'</a>'.
"<br />\n";
echo $message;
}
</div>
the
===The action ""RecentMajorChanges""====
This file is mainly the action recentchanges which I altered a bit. Save this code as /actions/recentmajorchanges.php
/**
* Display a list of recently changed pages, which are major changes .
*
* @package Actions
* @name RecentChanges
*
* @author {@link http://www.mornography.de/ Hendrik Mans} (wakka code)
* @author {@link http://wikkawiki.org/DarTar Dario Taraborelli} (preliminary code cleanup)
* @author {@link http://wikkawiki.org/FishPete Peter Fischaleck} (minor changes hack)
*
*/
//defaults
if(!defined('REVISION_DATE_FORMAT')) define('REVISION_DATE_FORMAT', 'D, d M Y');
if(!defined('REVISION_TIME_FORMAT')) define('REVISION_TIME_FORMAT', 'H:i T');
if (!defined('PAGE_EDITOR_DIVIDER')) define ('PAGE_EDITOR_DIVIDER', '→');
if (!defined('MAX_REVISION_NUMBER')) define ('MAX_REVISION_NUMBER', '50');
//i18n
if (!defined('RECENT_MAJOR_CHANGES_HEADING')) define('RECENT_MAJOR_CHANGES_HEADING', 'Major Changes During the Last '); //edited
if (!defined('RECENT_MINOR_CHANGES_HEADING')) define('RECENT_MINOR_CHANGES_HEADING', 'Minor Changes During the Last '); //edited
if (!defined('All_RECENT_CHANGES_HEADING')) define('ALL_RECENT_CHANGES_HEADING', 'Changes During the Last '); //edited
if (!defined('WORD_FOR_DAY')) define ('WORD_FOR_DAY', ' Day(s)'); //edited
if (!defined('SHOW_ALL_BUTTON_TEXT')) define ('SHOW_ALL_BUTTON_TEXT', 'show all changes');
if (!defined('SHOW_MINOR_BUTTON_TEXT')) define ('SHOW_MINOR_BUTTON_TEXT', 'show only minor changes');
if (!defined('SHOW_MAJOR_BUTTON_TEXT')) define ('SHOW_MAJOR_BUTTON_TEXT', 'show only major changes');
if (!defined('UNREGISTERED_USER')) define('UNREGISTERED_USER', 'unregistered user ');
if (!defined('LABEL_HISTORY')) define('LABEL_HISTORY', 'history');
if (!defined('TITLE_REVISION_LINK')) define('TITLE_REVISION_LINK', 'View recent revisions list for %s');
if (!defined('TITLE_HISTORY_LINK')) define('TITLE_HISTORY_LINK', 'View edit history of %s');
if (!defined('WIKIPING_ENABLED')) define('WIKIPING_ENABLED', 'WikiPing enabled: Changes on this wiki are broadcast to <a href="http://%1$s">http://%1$s</a>');
if (!defined('NO_RECENTLY_CHANGED_PAGES')) define ('NO_RECENTLY_CHANGED_PAGES', 'There are no recently changed pages.');
if (!defined('NO_READABLE_RECENTLY_CHANGED_PAGES')) define ('NO_READABLE_RECENTLY_CHANGED_PAGES', 'There are no recently changed pages you have access to.');
//initialization
//$max = 0;
$readable = 0;
//defaults
if ( !isset($days_to_show)) $days_to_show = 7;
$what_to_show = 'major';
$heading=RECENT_MAJOR_CHANGES_HEADING;
// get the parameters
if (is_array($vars))
{
foreach ($vars as $param => $value)
{
switch ($param)
{
case 'days':
$days_to_show = $value;
break;
case 'show':
switch ($value)
{
case ('all'):
$what_to_show='all';
$heading = ALL_RECENT_CHANGES_HEADING;
break;
case ('minor'):
$what_to_show='minor';
$heading = RECENT_MINOR_CHANGES_HEADING;
break;
case ('major'):
$what_to_show='major';
$heading=RECENT_MAJOR_CHANGES_HEADING;
break;
}
}
}
}
if (isset($_REQUEST['show_minor']))
{
if (isset($_REQUEST['test']) && ($_REQUEST['test']>0)) $days_to_show=$_REQUEST['test'];
$what_to_show='minor';
$heading = RECENT_MINOR_CHANGES_HEADING;
}
if (isset($_REQUEST['show_major']))
{
if (isset($_REQUEST['test'])&& ($_REQUEST['test']>0)) $days_to_show=$_REQUEST['test'];
$what_to_show='major';
$heading = RECENT_MAJOR_CHANGES_HEADING;
}
if (isset($_REQUEST['show_all']))
{
if (isset($_REQUEST['test'])&& ($_REQUEST['test']>0)) $days_to_show=$_REQUEST['test'];
$what_to_show='all';
$heading = ALL_RECENT_CHANGES_HEADING;
}
echo $this->FormOpen("", "", "get");
echo('
<p>
Show pages changed up unto
<input name="test" type="text", size="1" maxlenght="2" value="'.$days_to_show.'"> days ago<br>
<input name="show_all" type="submit" value="show all">
<input name="show_major" type="submit" value="show only major changes">
<input name="show_minor" type="submit" value="show only minor changes"></p>
');

echo $this->FormClose();
echo $this->Format('====='.$heading.$days_to_show.WORD_FOR_DAY.'===== --- ');
if ($pages = $this->LoadChangedDuringLastDays($days_to_show, $what_to_show)) //edited by FishPete
{
$curday = '';
//print feed link icon
//echo '<p><a href="'.$this->href('recentchanges.xml', $this->page['tag']).'"><img src="images/xml.png" width="36" height="14" alt="XML" /></a></p>'."\n";
/*if ($user = $this->GetUser())
{
$max = $user['changescount'];
} else
{
$max = MAX_REVISION_NUMBER;
}*/
//foreach ($pages as $i => $page)
foreach ($pages as $page)
{
//if (($i < $max) && $this->HasAccess('read', $page['tag']))
if ($this->HasAccess('read', $page['tag'])) //edited by FishPete
{
$readable++;
// day header
list($day, $time) = explode(' ', $page['time']);
if ($day != $curday)
{
$dateformatted = date(REVISION_DATE_FORMAT, strtotime($day));
if ($curday)
{
echo '</span><br />'."\n";
}
echo '<strong>'.$dateformatted.':</strong><br />'."\n".'<span class="recentchanges">'."\n";
$curday = $day;
}
$timeformatted = date(REVISION_TIME_FORMAT, strtotime($page["time"]));
$page_edited_by = $page['user'];
if (!$this->LoadUser($page_edited_by)) $page_edited_by .= ' ('.UNREGISTERED_USER.')';
// print entry
if ($page['note'])
{
$note = ' <span class="pagenote">['.$this->htmlspecialchars_ent($page['note']).']</span>';
}
else
{
$note = '';
}
echo '    ('.$this->Link($page['tag'], 'revisions', $timeformatted, 0, 1, sprintf(TITLE_REVISION_LINK, $page['tag'])).') ['.$this->Link($page['tag'], 'history', LABEL_HISTORY, 0, 1, sprintf(TITLE_HISTORY_LINK, $page['tag'])).'] -  '.$this->Link($page['tag'], '', '', 0).' '.PAGE_EDITOR_DIVIDER.' '.$page_edited_by.' '.$note.'<br />'."\n";
}
}

if ($readable == 0)
{
echo '<em>'.NO_READABLE_RECENTLY_CHANGED_PAGES.'</em>';
}
echo '</span>'."\n";
//wikiping instructions
$wikipingserver = $this->config['wikiping_server'];
if (!$wikipingserver == '')
{
$wikipingserver_url_parsed = parse_url($wikipingserver);
$wikipingserver_host = $wikipingserver_url_parsed['host'];
printf('<br /><br />['.WIKIPING_ENABLED.']', $wikipingserver_host);
}
}
else
{
echo '<em>'.NO_RECENTLY_CHANGED_PAGES.'</em>';
}
echo $this->Format(' ::c:: ');
Deletions:
=====InstallableActions Template=====
>>**See also:**
~-PluginDirectory - A home for your installable actions/plugins
>>::c::
The main title will be used in the summary column of the ""InstallableActions"" list, so make sure it's descriptive.
====The Read Me (Optional)====
You should put any important notes here. The user will see them before anything has happened to their system.
%%(readme)
This code may BlowYourHouseUp. SoBeCareful.
The license is GNU.
====The Data Model (Optional)====
If your action requires some MySQL modifications, put them here.
# INSTALL STEP
CREATE TABLE prefix_testing123 (
page_tag varchar(75) NOT NULL default '',
PRIMARY KEY (page_tag)
) TYPE=MyISAM;
# INSTALL STEP
CREATE TABLE prefix_testingtesting123 (
page_tag varchar(75) NOT NULL default '',
PRIMARY KEY (page_tag)
) TYPE=MyISAM;
# INSTALL STEP
# REMOVAL STEP
DROP TABLE IF EXISTS prefix_testing123;
# REMOVAL STEP
DROP TABLE IF EXISTS prefix_testingtesting123;
# REMOVAL STEP
====The CSS Definitions (Optional)====
If your action requires CSS styles, put them here. They will automatically be stored in a file and loaded in the header when the action is run.
%%(css)
.easier {font-family:verdana;color:green}
====The PHP Code (Required)====
Every action is expected to have at least one line of code and a version number set in the config section.
The format is (lowercase action name without spaces)_version => '#'.
You can specify an unlimited number of config settings (one per line).
====Informing the Installer (Required)====
A mention of ""InstallableAction"" is required for the Installer to include your action in the list. You can hide it in an HTML comment with the following line of code:
""<!-- InstallableAction -->""
CategoryTemplate


Revision [14724]

The oldest known version of this page was created on 2006-06-28 17:07:52 by FishPete [first version. not tested yet!]
Valid XHTML :: Valid CSS: :: Powered by WikkaWiki