<?php if (!defined('PmWiki')) exit(); /* Copyright 2004 Ilya Zverev (zverik@int.spb.ru) You can redistribute this file and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This file enables concurrent editing of pages in PmWiki. Tested with PmWiki 1.0.8. Simply copy this file into the 'local/' subdirectory or some other suitable place and then do include_once('local/concur.php'); Note that this module replaces standart 'edit' action, what may lead to problems with other modules which do the same thing. It is recommended to add following lines into your skin .css-file: #concurrent { border: 1px dotted gray; margin-top: 5px; margin-bottom: 5px; } #concurrent .concurtitle { background: #F0F0F0; display: block; font-size: x-small; } History: [cur] - first version */ ## Insert a proxy that will note concurrent editings $HandleActions['edit'] = 'HandleConcurrentEdit'; SDV($MergeLineWidth, 40); SDV($ConcurrentEditFmt, "<h3 class='wikimessage'>$[The page text has been changed while you were editing it.] ".FmtWikiLink('',"{{PmWiki/ConcurrentEditing}}",'(?)')."</h3>"); $DoubleBrackets['/^-ce-a-.+$/'] = "<div id='concurrent'><b class='concurtitle'>".XL('added:')."</b>"; $DoubleBrackets['/^-ce-d-.+$/'] = "<div id='concurrent'><b class='concurtitle'>".XL('deleted:')."</b>"; $DoubleBrackets['/^-ce-c-.+$/'] = "<div id='concurrent'><b class='concurtitle'>".XL('changed from:')."</b>"; $DoubleBrackets['/^-ce-t-.+$/'] = "<b class='concurtitle'>".XL('to:')."</b>"; $DoubleBrackets['/^-ce-f-.+$/'] = "</div>"; function HandleConcurrentEdit($pagename) { global $restore,$preview,$HandleActions,$Text, $HandleEditFmt,$PageStartFmt,$PageEditFmt,$PagePreviewFmt,$PageEndFmt,$EditMessageFmt, $DiffClassMinor,$PatchFunction, $EditLastRev, $ConcurrentEditFmt; $page = RetrieveAuthPage($pagename,"edit"); if( $page ) { $EditLastRev = $page['rev']; ## Change the edit form to include the hidden time field ## Note the regexp! $PageEditFmt = preg_replace('/(?=\<input type=\'hidden\')/', "<input type='hidden' name='startedit' value='\$EditLastRev' />", $PageEditFmt, 1); } if (@$_POST['post']) { $PreEditRev = @$_REQUEST['startedit']; if( !isset($PreEditRev) || !isset($EditLastRev) || ($PreEditRev >= $EditLastRev) ) { $handle = $HandleActions['post']; return $handle($pagename); } // somebody have modified page text while we were editing it $concur = 'Concur'; $EditMessageFmt .= $ConcurrentEditFmt; } // the rest is copy-pasted from pmwiki.php 1:1 if (!$page) { Abort("?cannot edit $pagename"); } SetPageVars($pagename,$page,"Edit $pagename"); if ($restore && $PatchFunction) { $text = $PatchFunction($page,$restore); } else if ($preview) { $text = stripmagic($_POST['text']); } // except this line: else if ($concur) { $text = MergeWithPage(str_replace("\r","",stripmagic($_POST['text'])), $page['text']); } else { $text = $page['text']; } $Text = $text; $DiffClassMinor = ''; if (@$_POST['diffclass']=='minor') $DiffClassMinor="checked='checked'"; SDV($HandleEditFmt,array(&$PageStartFmt, &$PageEditFmt, &$PagePreviewFmt, &$PageEndFmt)); PrintFmt($pagename,$HandleEditFmt); } // Does some kind of a merge function. // It simply does diff and inserts results into a page // offering user to apply changes, removing informational // lines. function MergeWithPage($newtext, $oldtext) { global $DiffFunction, $MergeLineWidth; $MergeAddHeader = str_pad(' '.XL('added:'), $MergeLineWidth, '-', STR_PAD_LEFT); $MergeDeleteHeader = str_pad(' '.XL('removed:'), $MergeLineWidth, '-', STR_PAD_LEFT); $MergeChangeFromHeader = str_pad(' '.XL('changed from:'), $MergeLineWidth, '-', STR_PAD_LEFT); $MergeChangeToHeader = str_pad(' '.XL('to:'), $MergeLineWidth, '-', STR_PAD_LEFT); $MergeFooter = str_repeat('-', $MergeLineWidth); $diff = $DiffFunction($oldtext, $newtext); # echo '<pre>'.$diff.'</pre>'; $d = explode("\n", $diff); $t = explode("\n", $oldtext); // initializing line offsets array //$o = array_fill(0, count($t)+1, 0); $o = array(); for($i=0;$i<=count($t);$i++) $o[] = $i; // now applying changes... in our way $insend = 0; foreach($d as $x) { if (preg_match('/^(\\d+)(?:,(\\d+))?([adc])(\\d+)(?:,(\\d+))?/',$x,$match)) { if($insend>0) { array_splice($t,$o[$insend],0,'-ce-f-'.$MergeFooter); for($i=$insend;$i<count($o);$i++) $o[$i]++; } $a1 = $a2 = $match[1]; if ($match[2]) $a2=$match[2]; $b1 = $b2 = $match[4]; if ($match[5]) $b2=$match[5]; $dista = $a2-$a1+1; $distb = $b2-$b1+1; if ($match[3]=='d') { //array_splice($t,$b1,$dista); array_splice($t,$o[$b1],0,'-ce-d-'.$MergeDeleteHeader); for($i=$b1;$i<count($o);$i++) $o[$i] += $dista+1; $insend = $b1; } if ($match[3]=='c') { //array_splice($t,$b1-1,$a2-$a1+1); array_splice($t,$o[$b1-1],0,'-ce-c-'.$MergeChangeFromHeader); for($i=$b1-1;$i<count($o);$i++) $o[$i] += $dista+1; array_splice($t,$o[$b1-1],0,'-ce-t-'.$MergeChangeToHeader); for($i=$b1-1;$i<count($o);$i++) $o[$i]++; $insend = $b2; } if ($match[3]=='a') { array_splice($t,$o[$b1-1],0,'-ce-a-'.$MergeAddHeader); for($i=$b1-1;$i<count($o);$i++) $o[$i]++; $insend = $b2; } continue; } if (preg_match('/^> (.*)$/',$x,$match)) { array_splice($t,$o[$b1-1],0,$match[1]); for($i=$b1-1; $i<count($o)-1;$i++) $o[$i+1] = $o[$i]+1; $b1++; $o[] = end($o)+1; } } if($insend>0) { array_splice($t,$o[$insend],0,'-ce-f-'.$MergeFooter); for($i=$insend;$i<count($o);$i++) $o[$i]++; } # for($i=4;$i<16;$i++) $t[$o[$i]] = ($i+1).' '.$t[$o[$i]]; return implode("\n",$t); } ?>