* finish task #2663.
This commit is contained in:
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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
@@ -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';
|
||||
|
||||
@@ -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 = '相应的链接地址';
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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';?>
|
||||
@@ -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');
|
||||
|
||||
Reference in New Issue
Block a user