* finish task #2663.

This commit is contained in:
wangyidong
2016-10-28 09:28:04 +08:00
parent 9a83ebe44a
commit 94bdc95038
7 changed files with 391 additions and 5 deletions
+73
View File
@@ -423,6 +423,79 @@ class doc extends control
$this->display();
}
/**
* Diff doc.
*
* @param int $docID
* @param int $newVersion
* @param int $oldVersion
* @access public
* @return void
*/
public function diff($docID, $newVersion, $oldVersion = '')
{
if(empty($oldVersion)) $oldVersion = $newVersion - 1;
if(empty($oldVersion) or empty($newVersion)) die(js::error($this->lang->doc->versionNotFound) . js::locate('back'));
$newDoc = $this->doc->getById($docID, $newVersion, true);
$oldDoc = $this->doc->getById($docID, $oldVersion, true);
if(!$newDoc) die(js::error($this->lang->notFound) . js::locate('back'));
/* Merge files in doc. */
$dbOldDocFiles = $this->dao->select('files')->from(TABLE_DOCCONTENT)->where('doc')->eq($docID)->andWhere('version')->eq($oldVersion)->fetch('files');
$dbOldDocFiles = explode(',', $dbOldDocFiles);
sort($dbOldDocFiles);
$oldDocFiles = array();
foreach($dbOldDocFiles as $fileID)
{
$file = isset($oldDoc->files[$fileID]) ? $oldDoc->files[$fileID] : '';
$oldDocFiles[$fileID] = 'File #' . $fileID;
if($file) $oldDocFiles[$fileID] .= ' ' . $file->title . '.' . $file->extension;
}
$oldDoc->files = join("\n", $oldDocFiles);
$dbNewDocFiles = $this->dao->select('files')->from(TABLE_DOCCONTENT)->where('doc')->eq($docID)->andWhere('version')->eq($newVersion)->fetch('files');
$dbNewDocFiles = explode(',', $dbNewDocFiles);
sort($dbNewDocFiles);
$newDocFiles = array();
foreach($dbNewDocFiles as $fileID)
{
$file = isset($newDoc->files[$fileID]) ? $newDoc->files[$fileID] : '';
$newDocFiles[$fileID] = 'File #' . $fileID;
if($file) $newDocFiles[$fileID] .= ' ' . $file->title . '.' . $file->extension;
}
$newDoc->files = join("\n", $newDocFiles);
/* Get diff. */
$diff = new stdclass();
$diff->content = $this->doc->diff($oldDoc->content, $newDoc->content);
$diff->digest = $this->doc->diff($oldDoc->digest, $newDoc->digest);
$diff->files = $this->doc->diff($oldDoc->files, $newDoc->files);
/* Check priv when lib is product or project. */
$lib = $this->doc->getLibByID($newDoc->lib);
$type = $lib->product ? 'product' : ($lib->project ? 'project' : 'custom');
$this->libs = $this->doc->getLibs($type);
/* Set menu. */
$this->doc->setMenu($this->libs, $newDoc->lib, $type);
$this->view->title = "DOC #$newDoc->id $newDoc->title - " . $this->libs[$newDoc->lib];
$this->view->position[] = html::a($this->createLink('doc', 'browse', "libID=$newDoc->lib"), $this->libs[$newDoc->lib]);
$this->view->position[] = $this->lang->doc->view;
$this->view->newDoc = $newDoc;
$this->view->oldDoc = $oldDoc;
$this->view->docID = $docID;
$this->view->lib = $lib;
$this->view->type = $type;
$this->view->newVersion = $newVersion;
$this->view->oldVersion = $oldVersion;
$this->view->diff = $diff;
$this->display();
}
/**
* Delete a doc.
*
+11
View File
@@ -0,0 +1,11 @@
table.alldiff th{width:70px;border-right:1px solid #ddd;}
table.table.alldiff td:last-child{padding:0px;}
table.table.diff {border:none}
table.alldiff table.table.diff td{border:none;}
table.alldiff table.table.diff .num{border-right:1px solid #ddd; text-align:right; width:20px;}
table.alldiff table.table.diff .oldLine{border-right:1px solid #ddd;}
table.table.diff td.newLine{padding:3px;}
table.table.diff td.oldLine{padding:3px;}
table.table.diff td.line{padding-left:20px;}
table.table.diff td.diffline.newLine{background: #8eff8e}
table.table.diff td.diffline.oldLine{background: #f6b2b2}
+37 -5
View File
@@ -28,12 +28,17 @@ $lang->doc->addedBy = 'Added by';
$lang->doc->addedDate = 'Added date';
$lang->doc->editedBy = 'Edited by';
$lang->doc->editedDate = 'Edited date';
$lang->doc->version = 'Version';
$lang->doc->basicInfo = 'Basic Info';
$lang->doc->deleted = 'Deleted';
$lang->doc->fileObject = 'File object';
$lang->doc->whiteList = 'White list';
$lang->doc->contentType = 'Doc type';
$lang->doc->moduleDoc = 'By module';
$lang->doc->searchDoc = 'By search';
//$lang->doc->allDoc = 'All document';
$lang->doc->allDoc = 'All doc';
$lang->doc->openedByMe = 'Added by me';
/* Actions. */
$lang->doc->index = 'Index';
@@ -42,33 +47,60 @@ $lang->doc->edit = 'Edit doc';
$lang->doc->delete = 'Delete doc';
$lang->doc->browse = 'Browse doc';
$lang->doc->view = 'View doc';
$lang->doc->diff = 'Diff';
$lang->doc->manageType = 'Manage type';
$lang->doc->addType = 'Add type';
$lang->doc->libName = 'Library name';
$lang->doc->libType = 'Library type';
$lang->doc->custom = 'Custom library';
$lang->doc->createLib = 'Create library';
$lang->doc->editLib = 'Edit library';
$lang->doc->deleteLib = 'Delete library';
$lang->doc->fixedMenu = 'Fixed in Menu';
$lang->doc->removeMenu = 'Move from menu';
/* Browse tabs. */
$lang->doc->allProduct = "All {$lang->productCommon}s";
$lang->doc->allProject = "All {$lang->projectCommon}s";
$lang->doc->libTypeList['product'] = "{$lang->productCommon} doc";
$lang->doc->libTypeList['project'] = "{$lang->projectCommon} doc";
$lang->doc->libTypeList['custom'] = 'Custom library';
$lang->doc->systemLibs['product'] = "{$lang->productCommon} doc";
$lang->doc->systemLibs['project'] = "{$lang->projectCommon} doc";
$lang->doc->types['file'] = 'File';
$lang->doc->types['url'] = 'Link';
$lang->doc->types['text'] = 'Html';
$lang->doc->aclList['public'] = 'Public';
$lang->doc->aclList['custom'] = 'Custom';
$lang->doc->aclList['private'] = 'Private';
$lang->doc->contentTypeList['html'] = 'HTML';
$lang->doc->contentTypeList['markdown'] = 'MarkDown';
$lang->doc->browseType = 'Browse type';
$lang->doc->browseTypeList['list'] = 'List';
$lang->doc->browseTypeList['menu'] = 'Menu';
$lang->doc->browseTypeList['tree'] = 'Tree';
$lang->doc->confirmDelete = "Are you sure to delete this doc?";
$lang->doc->confirmDeleteLib = " Are you sure to delete this doc library?";
$lang->doc->errorEditSystemDoc = "System doc library needn't edit";
$lang->doc->errorEmptyProduct = "{$lang->productCommon} is empty, can not create doc.";
$lang->doc->errorEmptyProject = "{$lang->projectCommon} is empty, can not create doc.";
$lang->doc->errorEmptySysLib = "Do not delete all library in system library";
$lang->doc->accessDenied = "Access to this library denied.";
$lang->doc->noMatched = "No matched library including '%s'";
$lang->doc->versionNotFount = 'Do not found doc in this version';
$lang->doc->placeholder = new stdclass();
$lang->doc->placeholder->url = 'url';
$lang->doclib = new stdclass();
$lang->doclib->name = 'Library Name';
$lang->doclib->name = 'Library Name';
$lang->doclib->control = 'Control';
$lang->doclib->acl = 'Power';
$lang->doclib->group = 'Group';
$lang->doclib->user = 'User';
$lang->doclib->files = 'Files';
$lang->doclib->all = 'All library';
+2
View File
@@ -47,6 +47,7 @@ $lang->doc->edit = '编辑文档';
$lang->doc->delete = '删除文档';
$lang->doc->browse = '文档列表';
$lang->doc->view = '文档详情';
$lang->doc->diff = '对比';
$lang->doc->manageType = '维护分类';
$lang->doc->addType = '增加分类';
@@ -90,6 +91,7 @@ $lang->doc->errorEmptyProject = "没有{$lang->projectCommon},无法创建文
$lang->doc->errorEmptySysLib = "系统文档库不能全部删除!";
$lang->doc->accessDenied = "您没有权限访问该文档库!";
$lang->doc->noMatched = '找不到包含"%s"的文档库';
$lang->doc->versionNotFount = '该版本文档不存在';
$lang->doc->placeholder = new stdclass();
$lang->doc->placeholder->url = '相应的链接地址';
+161
View File
@@ -279,6 +279,7 @@ class docModel extends model
$this->dao->update(TABLE_DOC)->set('version')->eq($doc->version)->where('id')->eq($doc->id)->exec();
}
$doc->title = isset($docContent->title) ? $docContent->title : '';
$doc->digest = isset($docContent->digest) ? $docContent->digest : '';
$doc->content = isset($docContent->content) ? $docContent->content : '';
$doc->type = isset($docContent->type) ? $docContent->type : '';
@@ -893,4 +894,164 @@ class docModel extends model
$node->actions = false;
return $node;
}
/**
* Diff doc.
*
* @param string $text1
* @param string $text2
* @access public
* @return array
*/
public function diff($text1, $text2)
{
$text1 = explode("\n", trim($text1));
$text2 = explode("\n", trim($text2));
$text1Len = count($text1);
$text2Len = count($text2);
$trace = array();
$trace[-1] = array_fill(-1, $text2Len + 1, +1);
$lcs0 = array_fill(-1, $text2Len + 1, 0);
$lcs1[-1] = 0;
foreach($text1 as $line)
{
$temp = array();
$temp[-1] = -1;
for($i = 0; $i < $text2Len; $i++)
{
if($line == $text2[$i])
{
$lcs1[$i] = $lcs0[$i - 1] + 1;
$temp[$i] = 0;
}
elseif($lcs0[$i] > $lcs1[$i - 1])
{
$lcs1[$i] = $lcs0[$i];
$temp[$i] = -1;
}
else
{
$lcs1[$i] = $lcs1[$i - 1];
$temp[$i] = +1;
}
}
array_push($trace, $temp);
$temp = $lcs1;
$lcs1 = $lcs0;
$lcs0 = $temp;
}
$same = 0;
$out = false;
$ret = array();
for($i = $text1Len - 1, $j = $text2Len - 1; $i != -1 || $j != -1;)
{
if($trace[$i][$j] == 0)
{
$same++;
if($out && $same > 0)
{
$outbegina = $i + $same;
$outbeginb = $j + $same;
for($k = $i + $same - 1; $k >= $outbegina; $k--) array_push($ret, array('cmd' => ' ', 'dat' => $text1[$k]));
$dat = array($outbegina, $outenda - $outbegina + 1, $outbeginb, $outendb - $outbeginb + 1);
array_push($ret, array('cmd' => '@', 'dat'=> $dat));
$out = false;
}
$i--;
$j--;
}
else
{
if(!$out)
{
$same = min($same, 0);
$out = true;
$outenda = $i + $same;
$outendb = $j + $same;
}
for($k = $i + $same; $k > $i; $k--) array_push($ret, array('cmd' => ' ', 'dat' => $text1[$k]));
$same = 0;
if($trace[$i][$j] == -1)
{
array_push($ret, array('cmd' => '-', 'dat' => $text1[$i]));
$i--;
}
else
{
array_push($ret, array('cmd' => '+', 'dat' => $text2[$j]));
$j--;
}
}
}
if($out)
{
$outbegina = max(0, $same);
$outbeginb = max(0, $same);
for($k = $same - 1; $k >= $outbegina; $k--) array_push($ret, array('cmd' => ' ', 'dat' => $text1[$k]));
$dat = array($outbegina, $outenda - $outbegina + 1, $outbeginb, $outendb - $outbeginb + 1);
array_push($ret, array('cmd' => '@', 'dat'=> $dat));
}
$diffs = array_reverse($ret);
if(empty($diffs)) return array();
$processedDiff = array();
foreach($diffs as $i => $diff)
{
if($diff['cmd'] == '@')
{
$max = max($diff['dat'][1], $diff['dat'][3]);
for($number = 0; $number < $max; $number++)
{
$oldLineNO = $diff['dat'][0] + $number;
$newLineNO = $diff['dat'][2] + $number;
$oldLine = '';
$newLine = '';
if($diff['dat'][1] > 0 and $diff['dat'][1] >= $number + 1) $oldLine = $diffs[$i + $number + 1]['dat'];
if($diff['dat'][3] > 0 and $diff['dat'][3] >= $number + 1) $newLine = $diffs[$i + $number + 1 + $diff['dat'][1]]['dat'];
$processedDiff['old'][$oldLineNO] = $oldLine;
$processedDiff['new'][$newLineNO] = $newLine;
}
}
}
return $processedDiff;
}
/**
* Get line number by diff.
*
* @param array $diff
* @param int $i
* @param int $lineNO
* @access public
* @return array
*/
public function getLineNumber($diff, $i, $lineNO)
{
$action = '';
if(isset($diff[$i]))
{
if(empty($diff[$i]))
{
$showNumber = '';
$action = '';
}
else
{
$showNumber = $lineNO + 1;
$action = 'diff';
}
}
else
{
$showNumber = $lineNO + 1;
$action = '';
}
return array($showNumber, $action, 'number' => $showNumber, 'action' => $action);
}
}
+94
View File
@@ -0,0 +1,94 @@
<?php
/**
* The view of doc module of ZenTaoPMS.
*
* @copyright Copyright 2009-2015 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Jia Fu <fujia@cnezsoft.com>
* @package doc
* @version $Id: view.html.php 975 2010-07-29 03:30:25Z jajacn@126.com $
* @link http://www.zentao.net
*/
?>
<?php include '../../common/view/header.html.php';?>
<div id='titlebar'>
<div class='heading'>
<span class='prefix' title='DOC'><?php echo html::icon($lang->icons['doc']);?> <strong><?php echo $docID;?></strong></span>
<strong><?php echo $newDoc->title;?></strong>
<span><?php echo " #" . $oldVersion . ' : ' . $newVersion?></span>
<?php if($newDoc->deleted):?>
<span class='label label-danger'><?php echo $lang->doc->deleted;?></span>
<?php endif; ?>
</div>
<div class='actions'><?php html::backButton(); ?></div>
</div>
<div class='row-table'>
<table class='table table-data alldiff'>
<?php if($oldDoc->title != $newDoc->title):?>
<tr>
<th><?php $lang->doc->title?></th>
<td><?php echo $oldDoc->title?></td>
<td><?php echo $newDoc->title?></td>
</tr>
<?php endif;?>
<?php foreach($diff as $field => $diffLines):?>
<?php if(empty($diffLines)) continue;?>
<tr>
<th><?php echo $lang->doc->$field?></th>
<td colspan='2'>
<table class='diff table table-data table-hover table-condensed'>
<?php
$oldLines = explode("\n", htmlspecialchars(trim($oldDoc->$field)));
$newLines = explode("\n", htmlspecialchars(trim($newDoc->$field)));
$lines = max(count($oldLines), count($newLines));
$oldLineNO = 0;
$newLineNO = 0;
?>
<?php for($i = 0; $i < $lines; $i++):?>
<tr>
<?php
list($showNumber, $action) = $this->doc->getLineNumber($diffLines['old'], $i, $oldLineNO);
$showLine = '';
if($showNumber)
{
$showLine = $oldLines[$oldLineNO];
$oldLineNO ++;
}
elseif(isset($oldLines[$oldLineNO]) and empty($oldLines[$oldLineNO]))
{
$showNumber = $oldLineNO + 1;
$oldLineNO ++;
if(isset($diffLines['old'][$i])) $action = 'diff';
}
if($action) $showLine = "<i class='icon icon-minus'></i> " . $showLine;
?>
<td class='oldNO num'><?php echo $showNumber?></td>
<td class='oldLine <?php echo $action?>line'><?php echo $showLine?></td>
<?php
list($showNumber, $action) = $this->doc->getLineNumber($diffLines['new'], $i, $newLineNO);
$showLine = '';
if($showNumber)
{
$showLine = $newLines[$newLineNO];
$newLineNO ++;
}
elseif(isset($newLines[$newLineNO]) and empty($newLines[$newLineNO]))
{
$showNumber = $newLineNO + 1;
$newLineNO ++;
if(isset($diffLines['new'][$i])) $action = 'diff';
}
if($action) $showLine = "<i class='icon icon-plus'></i> " . $showLine;
?>
<td class='newNO num'><?php echo $showNumber?></td>
<td class='newLine <?php echo $action?>line'><?php echo $showLine?></td>
</tr>
<?php endfor;?>
</table>
</td>
</tr>
<?php endforeach;?>
</table>
</div>
<?php js::set('type', $type)?>
<?php include '../../common/view/footer.html.php';?>
+13
View File
@@ -41,6 +41,19 @@
if(!$doc->deleted)
{
ob_start();
if($doc->version > 1 and common::hasPriv('doc', 'diff'))
{
echo "<div class='btn-group'>";
echo "<button data-toggle='dropdown' type='button' class='btn dropdown-toggle'>{$lang->doc->diff} <span class='caret'></span></button>";
echo "<ul class='dropdown-menu'>";
for($i = $doc->version; $i >= 1; $i --)
{
if($i == $version) continue;
echo '<li>' . html::a(inlink('diff', "docID=$doc->id&newVersion=$version&version=$i"), '#' . $i) . '</li>';
}
echo "</ul>";
echo "</div>";
}
echo "<div class='btn-group'>";
common::printIcon('doc', 'edit', $params);
common::printIcon('doc', 'delete', $params, '', 'button', '', 'hiddenwin');