diff options
author | Klap-in <klapinklapin@gmail.com> | 2013-01-27 22:02:47 +0100 |
---|---|---|
committer | Klap-in <klapinklapin@gmail.com> | 2013-01-27 22:02:47 +0100 |
commit | f9528c0c7accd2da60f16864555b4982b940a1a0 (patch) | |
tree | 148637afadd0ce2f906424f137c36e6beea1fecc /inc | |
parent | 1a40fc9935bd06a440a844e081e4bfce5fce2932 (diff) | |
download | rpg-f9528c0c7accd2da60f16864555b4982b940a1a0.tar.gz rpg-f9528c0c7accd2da60f16864555b4982b940a1a0.tar.bz2 |
Added diff navigation
Navigation links to move to previous edit before revision in left column or next/last edit after revision in right column.
Diffstat (limited to 'inc')
-rw-r--r-- | inc/changelog.php | 213 | ||||
-rw-r--r-- | inc/html.php | 47 | ||||
-rw-r--r-- | inc/lang/en/lang.php | 4 | ||||
-rw-r--r-- | inc/lang/nl/lang.php | 4 |
4 files changed, 267 insertions, 1 deletions
diff --git a/inc/changelog.php b/inc/changelog.php index 9768fea51..e25c3144e 100644 --- a/inc/changelog.php +++ b/inc/changelog.php @@ -543,4 +543,217 @@ function getRevisions($id, $first, $num, $chunk_size=8192, $media=false) { return $revs; } +/** + * Get the nth revision left or right handside for a specific page id + * and revision (timestamp). For large changelog files, only the chunk containing the + * reference revision $rev is read and sometimes a next chunck. + * + * Adjacent changelog lines are optimistically parsed and cached to speed up + * consecutive calls to getRevisionInfo. + * + * @author Gerrit Uitslag <klapinklapin@gmail.com> + * + * based on getRevisionInfo by + * @author Ben Coburn <btcoburn@silicodon.net> + * @author Kate Arzamastseva <pshns@ukr.net> + * + * @param string $id pageid + * @param int $rev revision timestamp used as startdate (doesn't need to be revisionnumber) + * @param int $direction give position of returned revision with respect to $rev; positive=next, negative=prev + * @param int $chunk_size maximum block size + * @param bool $media + * @return bool|string + */ +function getRelativeRevision($id, $rev, $direction, $chunk_size = 8192, $media = false) { + global $cache_revinfo; + global $INFO; + $cache =& $cache_revinfo; + if(!isset($cache[$id])) { + $cache[$id] = array(); + } + $rev = max($rev, 0); + + //no direction given or last rev, so no follow-up + if(!$direction || ($direction > 0 && $rev == $INFO['meta']['last_change']['date'])) { + return false; + } + + if($media) { + $file = mediaMetaFN($id, '.changes'); + } else { + $file = metaFN($id, '.changes'); + } + if(!@file_exists($file)) { + return false; + } + + //get $lines from changelog + $lines = array(); + $fp = null; + $tail = 0; + $head = 0; + $eof = 0; + if(filesize($file) < $chunk_size || $chunk_size == 0) { + // read whole file + $uses_chuncks = false; + $lines = file($file); + if($lines === false) { + return false; + } + } else { + // read by chunk + $uses_chuncks = true; + $fp = fopen($file, 'rb'); // "file pointer" + if($fp === false) { + return false; + } //error + $head = 0; + fseek($fp, 0, SEEK_END); //set file position indicator 0 byte from end. + $tail = ftell($fp); //return current position of pointer as integer + $eof = $tail; + $finger = 0; + $finger_rev = 0; + + // find chunk + while($tail - $head > $chunk_size) { + $finger = $head + floor(($tail - $head) / 2.0); + $finger = getNewlinepointer($fp, $finger); + $tmp = fgets($fp); // then read at that location + $tmp = parseChangelogLine($tmp); + $finger_rev = $tmp['date']; + if($finger == $head || $finger == $tail) { + break; + } + if($finger_rev > $rev) { + $tail = $finger; + } else { + $head = $finger; + } + } + + if($tail - $head < 1) { + // cound not find chunk, assume requested rev is missing + fclose($fp); + return false; + } + + $lines = readChunk($fp, $head, $tail); + } + + // look for revisions later then $rev, when founded count till the wanted revision is reached + // also parse and cache changelog lines that pass + $revcounter = 0; + $relrev = false; + $tmp = array(); + $checkotherchunck = true; //always runs once + while(!$relrev && $checkotherchunck) { + + if($direction > 0) { + foreach($lines as $value) { + $tmp = parseChangelogLine($value); + if($tmp !== false) { + $cache[$id][$tmp['date']] = $tmp; + //look for revs older then reference $rev and select $direction-th one + if($tmp['date'] > $rev) { + $revcounter++; + if($revcounter == $direction) { + $relrev = $tmp['date']; + } + } + } + } + } else { + //parse in reverse order + for($i = count($lines) - 1; $i >= 0; $i--) { + $tmp = parseChangelogLine($lines[$i]); + if($tmp !== false) { + $cache[$id][$tmp['date']] = $tmp; + //look for revs older then reference $rev and select $direction-th one + if($tmp['date'] < $rev) { + $revcounter++; + if($revcounter == abs($direction)) { + $relrev = $tmp['date']; + } + } + } + } + } + + //true when $rev is found, but not the wanted follow-up. + $checkotherchunck = $uses_chuncks + && ($tmp['date'] == $rev || ($revcounter > 0 && !$relrev)) + && !feof($fp); + + if($checkotherchunck) { + if($direction > 0) { + //get interval of next chunck, smaller than $chunck_size + $head = $tail; + $lookpointer = true; + $tail = $head + floor($chunk_size * (2 / 3)); + while($lookpointer) { + $tail = min($tail, $eof); + $tail = getNewlinepointer($fp, $tail); + $lookpointer = $tail - $head > $chunk_size; + if($lookpointer) { + $tail = $head + floor(($tail - $head) / 2); + } + } + } else { + $tail = $head; + $head = max($tail - $chunk_size, 0); + $head = getNewlinepointer($fp, $head); + } + + //load next chunck + $lines = readChunk($fp, $head, $tail); + } + } + if($uses_chuncks) { + fclose($fp); + } + if($relrev == $INFO['meta']['last_change']['date']) { + return 'current'; + } + return $relrev; +} + +/** + * Read chunk and return array with lines of given chunck. + * Has no check if $head and $tail are really at a new line + * + * @param $fp resource filepointer + * @param $head int start point chunck + * @param $tail int end point chunck + * @return array lines read from chunck + */ +function readChunk($fp, $head, $tail) { + $chunk = ''; + $chunk_size = max($tail - $head, 0); // found chunk size + $got = 0; + fseek($fp, $head); + while($got < $chunk_size && !feof($fp)) { + $tmp = @fread($fp, max($chunk_size - $got, 0)); + if($tmp === false) { + break; + } //error state + $got += strlen($tmp); + $chunk .= $tmp; + } + $lines = explode("\n", $chunk); + array_pop($lines); // remove trailing newline + return $lines; +} + +/** + * Set pointer to first new line after $finger and return its position + * + * @param $fp resource filepointer + * @param $finger int a pointer + * @return int pointer + */ +function getNewlinepointer($fp, $finger) { + fseek($fp, $finger); + fgets($fp); // slip the finger forward to a new line + return ftell($fp); +} diff --git a/inc/html.php b/inc/html.php index 5c1c75cf6..9d344a05f 100644 --- a/inc/html.php +++ b/inc/html.php @@ -1151,6 +1151,18 @@ function html_diff($text='',$intro=true,$type=null){ } $r_text = rawWiki($ID,$r_rev); + //look for previous/next revision + if($r_rev) { + $next_rev = getRelativeRevision($ID, $r_rev, 1); + } else { + $next_rev = false; + } + if($l_rev) { + $prev_rev = getRelativeRevision($ID, $l_rev, -1); + } else { + $prev_rev = false; + } + list($l_head, $r_head, $l_minor, $r_minor) = html_diff_head($l_rev, $r_rev); } @@ -1191,7 +1203,40 @@ function html_diff($text='',$intro=true,$type=null){ 'rev2[1]' => $r_rev, 'difftype' => $type, )); - ptln('<p><a class="wikilink1" href="'.$diffurl.'">'.$lang['difflink'].'</a></p>'); + ptln('<p><a class="wikilink1" href="'.$diffurl.'">'.$lang['difflink'].'</a><br />'); + if($prev_rev){ + $diffurlprev = wl($ID, array( + 'do' => 'diff', + 'rev2[0]' => $prev_rev, + 'rev2[1]' => $l_rev, + 'difftype' => $type, + )); + ptln('<a class="wikilink1" href="'.$diffurlprev.'">← '.$lang['diffpreviousedit'].'</a> - '); + } + $recenturl = wl($ID, array( + 'do' => 'revisions' + )); + ptln('<a class="wikilink1" href="'.$recenturl.'">'.$lang['overviewrevs'].'</a>'); + if($next_rev){ + if($next_rev=='current') { + $diffurlnextparam = array( + 'do' => 'diff', + 'rev' => $r_rev, + 'difftype' => $type, + ); + $navnexttitle = $lang['difflastedit']; + } else { + $diffurlnextparam = array( + 'do' => 'diff', + 'rev2[0]' => $r_rev, + 'rev2[1]' => $next_rev, + 'difftype' => $type, + ); + $navnexttitle = $lang['diffnextedit']; + } + ptln(' - <a class="wikilink1" href="'.wl($ID, $diffurlnextparam).'">'.$navnexttitle.' →</a>'); + } + ptln('</p>'); ptln('</div>'); } ?> diff --git a/inc/lang/en/lang.php b/inc/lang/en/lang.php index 144faf4e1..92d352097 100644 --- a/inc/lang/en/lang.php +++ b/inc/lang/en/lang.php @@ -184,6 +184,10 @@ $lang['difflink'] = 'Link to this comparison view'; $lang['diff_type'] = 'View differences:'; $lang['diff_inline'] = 'Inline'; $lang['diff_side'] = 'Side by Side'; +$lang['diffpreviousedit'] = 'Previous edit'; +$lang['diffnextedit'] = 'Next edit'; +$lang['difflastedit'] = 'Last edit'; +$lang['overviewrevs'] = 'Overview of revisions'; $lang['line'] = 'Line'; $lang['breadcrumb'] = 'Trace'; $lang['youarehere'] = 'You are here'; diff --git a/inc/lang/nl/lang.php b/inc/lang/nl/lang.php index 0241eab2f..2fe536f31 100644 --- a/inc/lang/nl/lang.php +++ b/inc/lang/nl/lang.php @@ -185,6 +185,10 @@ $lang['difflink'] = 'Link naar deze vergelijking'; $lang['diff_type'] = 'Bekijk verschillen:'; $lang['diff_inline'] = 'Inline'; $lang['diff_side'] = 'Zij aan zij'; +$lang['diffpreviousedit'] = 'Vorige bewerking'; +$lang['diffnextedit'] = 'Volgende bewerking'; +$lang['difflastedit'] = 'Laatste bewerking'; +$lang['overviewrevs'] = 'Overzicht van revisies'; $lang['line'] = 'Regel'; $lang['breadcrumb'] = 'Spoor'; $lang['youarehere'] = 'Je bent hier'; |