Merge branch 'master' of https://github.com/easysoft/zentaopms
This commit is contained in:
+1
-1
@@ -31,7 +31,7 @@ $config->requestFix = '-'; // The divider in the url when PATH_IN
|
||||
$config->moduleVar = 'm'; // requestType=GET: the module var name.
|
||||
$config->methodVar = 'f'; // requestType=GET: the method var name.
|
||||
$config->viewVar = 't'; // requestType=GET: the view var name.
|
||||
$config->sessionVar = 'sid'; // requestType=GET: the session var name.
|
||||
$config->sessionVar = 'zentaosid'; // requestType=GET: the session var name.
|
||||
$config->allowedTags = '<p><span><h1><h2><h3><h4><h5><em><u><strong><br><ol><ul><li><img><a><b><font><hr><pre><div><table><td><th><tr><tbody><embed><style>';
|
||||
$config->accountRule = '|^[a-zA-Z0-9_]{1}[a-zA-Z0-9_\.]{1,}[a-zA-Z0-9_]{1}$|';
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE `zt_branch` ADD `order` smallint unsigned NOT NULL AFTER `name`;
|
||||
@@ -1801,11 +1801,8 @@ class baseRouter
|
||||
{
|
||||
foreach($lang->db->custom[$moduleName] as $section => $fields)
|
||||
{
|
||||
foreach($fields as $key => $value)
|
||||
{
|
||||
unset($lang->{$moduleName}->{$section}[$key]);
|
||||
$lang->{$moduleName}->{$section}[$key] = $value;
|
||||
}
|
||||
unset($lang->{$moduleName}->{$section});
|
||||
foreach($fields as $key => $value) $lang->{$moduleName}->{$section}[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -231,6 +231,16 @@ class actionModel extends model
|
||||
$title = $this->dao->select('title')->from(TABLE_PRODUCTPLAN)->where('id')->eq($action->extra)->fetch('title');
|
||||
if($title) $action->extra = html::a(helper::createLink('productplan', 'view', "planID=$action->extra"), $title);
|
||||
}
|
||||
elseif($actionName == 'linked2build')
|
||||
{
|
||||
$name = $this->dao->select('name')->from(TABLE_BUILD)->where('id')->eq($action->extra)->fetch('name');
|
||||
if($name) $action->extra = html::a(helper::createLink('build', 'view', "builID=$action->extra&type={$action->objectType}"), $name);
|
||||
}
|
||||
elseif($actionName == 'linked2release')
|
||||
{
|
||||
$name = $this->dao->select('name')->from(TABLE_RELEASE)->where('id')->eq($action->extra)->fetch('name');
|
||||
if($name) $action->extra = html::a(helper::createLink('release', 'view', "releaseID=$action->extra&type={$action->objectType}"), $name);
|
||||
}
|
||||
elseif($actionName == 'moved')
|
||||
{
|
||||
$name = $this->dao->select('name')->from(TABLE_PROJECT)->where('id')->eq($action->extra)->fetch('name');
|
||||
@@ -245,6 +255,16 @@ class actionModel extends model
|
||||
$name = $this->dao->select('name')->from(TABLE_PROJECT)->where('id')->eq($action->extra)->fetch('name');
|
||||
if($name) $action->extra = html::a(helper::createLink('project', 'story', "projectID=$action->extra"), "#$action->extra " . $name);
|
||||
}
|
||||
elseif($actionName == 'unlinkedfrombuild')
|
||||
{
|
||||
$name = $this->dao->select('name')->from(TABLE_BUILD)->where('id')->eq($action->extra)->fetch('name');
|
||||
if($name) $action->extra = html::a(helper::createLink('build', 'view', "builID=$action->extra&type={$action->objectType}"), $name);
|
||||
}
|
||||
elseif($actionName == 'unlinkedfromrelease')
|
||||
{
|
||||
$name = $this->dao->select('name')->from(TABLE_RELEASE)->where('id')->eq($action->extra)->fetch('name');
|
||||
if($name) $action->extra = html::a(helper::createLink('release', 'view', "releaseID=$action->extra&type={$action->objectType}"), $name);
|
||||
}
|
||||
elseif($actionName == 'unlinkedfromplan')
|
||||
{
|
||||
$title = $this->dao->select('title')->from(TABLE_PRODUCTPLAN)->where('id')->eq($action->extra)->fetch('title');
|
||||
|
||||
@@ -38,6 +38,17 @@ class branch extends control
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort branch.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function sort()
|
||||
{
|
||||
$this->branch->sort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax get drop menu.
|
||||
*
|
||||
@@ -89,10 +100,11 @@ class branch extends control
|
||||
*/
|
||||
public function delete($branchID, $confirm = 'no')
|
||||
{
|
||||
$this->app->loadLang('product');
|
||||
$productType = $this->branch->getProductType($branchID);
|
||||
if(!$this->branch->checkBranchData($branchID)) die(js::alert(str_replace('@branch@', $this->lang->product->branchName[$productType], $this->lang->branch->canNotDelete)));
|
||||
if($confirm == 'no')
|
||||
{
|
||||
$this->app->loadLang('product');
|
||||
$productType = $this->branch->getProductType($branchID);
|
||||
die(js::confirm(str_replace('@branch@', $this->lang->product->branchName[$productType], $this->lang->branch->confirmDelete), inlink('delete', "branchID=$branchID&confirm=yes")));
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +1,4 @@
|
||||
#branches .input-group{margin-bottom:5px; width:100%}
|
||||
#branches .input-group, #newbranches .input-group{margin-bottom:5px; width:100%}
|
||||
#branches .sort-handler{cursor: move}
|
||||
#branches .input-group.drag-shadow{z-index:5;}
|
||||
#branches .input-group.drag-row{opacity:0;}
|
||||
|
||||
@@ -1,11 +1,28 @@
|
||||
function addItem()
|
||||
function addItem(obj)
|
||||
{
|
||||
var $inputgroup = $('#branches .input-group:last');
|
||||
$('#branches').append($inputgroup.clone()).find('.input-group:last').find('input').val('');
|
||||
var $inputgroup = $(obj).closest('.input-group').clone();
|
||||
$inputgroup.find('input').val('');
|
||||
$(obj).closest('.input-group').after($inputgroup);
|
||||
}
|
||||
|
||||
function deleteItem(obj)
|
||||
{
|
||||
if($(obj).closest('#branches').find("input[id^='newbranch']").size() <= 1) return;
|
||||
if($(obj).closest('#newbranches').find("input[id^='newbranch']").size() <= 1) return;
|
||||
$(obj).closest('.input-group').remove();
|
||||
}
|
||||
|
||||
$(function()
|
||||
{
|
||||
$('#branches').sortable(
|
||||
{
|
||||
selector: '.input-group',
|
||||
dragCssClass: 'drag-row',
|
||||
trigger: $('#branches').find('.sort-handler').length ? '.sort-handler' : null,
|
||||
finish: function(e)
|
||||
{
|
||||
var list = '';
|
||||
$('#branches').find('.input-group').each(function(){list += $(this).attr('data-id') + ',';});
|
||||
$.post(createLink('branch', 'sort'), {'branches' : list});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,4 +6,5 @@ $lang->branch->delete = 'Delete Branch';
|
||||
$lang->branch->manageTitle = '%s Management';
|
||||
$lang->branch->all = 'All';
|
||||
|
||||
$lang->branch->confirmDelete = '@branch@ Delete will affect @branch@ related Story、Module、Planning、Release、Bug、Case, etc. Please think before you delete this @branch@.';
|
||||
$lang->branch->confirmDelete = 'Are you sure delete this @branch@?';
|
||||
$lang->branch->canNotDelete = 'It has data in @branch@, can not deleted.';
|
||||
|
||||
@@ -6,4 +6,5 @@ $lang->branch->delete = '分支删除';
|
||||
$lang->branch->manageTitle = '%s管理';
|
||||
$lang->branch->all = '所有';
|
||||
|
||||
$lang->branch->confirmDelete = '@branch@删除,会影响关联该@branch@的需求、模块、计划、发布、Bug、用例等等,请慎重考虑。是否删除该@branch@';
|
||||
$lang->branch->confirmDelete = '是否删除该@branch@?';
|
||||
$lang->branch->canNotDelete = '该@branch@下已经有数据,不能删除!';
|
||||
|
||||
+39
-4
@@ -39,7 +39,7 @@ class branchModel extends model
|
||||
*/
|
||||
public function getPairs($productID, $params = '')
|
||||
{
|
||||
$branches = $this->dao->select('*')->from(TABLE_BRANCH)->where('product')->eq($productID)->andWhere('deleted')->eq(0)->orderBy('id_asc')->fetchPairs('id', 'name');
|
||||
$branches = $this->dao->select('*')->from(TABLE_BRANCH)->where('product')->eq($productID)->andWhere('deleted')->eq(0)->orderBy('`order`')->fetchPairs('id', 'name');
|
||||
if(strpos($params, 'noempty') === false)
|
||||
{
|
||||
$product = $this->loadModel('product')->getById($productID);
|
||||
@@ -68,10 +68,10 @@ class branchModel extends model
|
||||
if($oldBranches[$branchID] != $branch) $this->dao->update(TABLE_BRANCH)->set('name')->eq($branch)->where('id')->eq($branchID)->exec();
|
||||
}
|
||||
}
|
||||
foreach($data->newbranch as $branch)
|
||||
foreach($data->newbranch as $i => $branch)
|
||||
{
|
||||
if(empty($branch)) continue;
|
||||
$this->dao->insert(TABLE_BRANCH)->set('name')->eq($branch)->set('product')->eq($productID)->exec();
|
||||
$this->dao->insert(TABLE_BRANCH)->set('name')->eq($branch)->set('product')->eq($productID)->set('`order`')->eq(count($data->branch) + $i + 1)->exec();
|
||||
}
|
||||
|
||||
return dao::isError();
|
||||
@@ -87,7 +87,7 @@ class branchModel extends model
|
||||
*/
|
||||
public function getByProducts($products, $params = '')
|
||||
{
|
||||
$branches = $this->dao->select('*')->from(TABLE_BRANCH)->where('product')->in($products)->andWhere('deleted')->eq(0)->fetchAll();
|
||||
$branches = $this->dao->select('*')->from(TABLE_BRANCH)->where('product')->in($products)->andWhere('deleted')->eq(0)->orderBy('`order`')->fetchAll();
|
||||
$products = $this->loadModel('product')->getByIdList($products);
|
||||
|
||||
$branchGroups = array();
|
||||
@@ -121,4 +121,39 @@ class branchModel extends model
|
||||
->where('t1.id')->eq($branchID)
|
||||
->fetch('type');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort branch.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function sort()
|
||||
{
|
||||
$data = fixer::input('post')->get();
|
||||
$branches = trim($data->branches, ',');
|
||||
foreach(explode(',', $branches) as $order => $branchID)
|
||||
{
|
||||
$this->dao->update(TABLE_BRANCH)->set('`order`')->eq($order)->where('id')->eq($branchID)->exec();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check branch data.
|
||||
*
|
||||
* @param int $branchID
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function checkBranchData($branchID)
|
||||
{
|
||||
$module = $this->dao->select('id')->from(TABLE_MODULE)->where('branch')->eq($branchID)->limit(1)->fetch();
|
||||
$story = $this->dao->select('id')->from(TABLE_STORY)->where('branch')->eq($branchID)->andWhere('deleted')->eq(0)->limit(1)->fetch();
|
||||
$plan = $this->dao->select('id')->from(TABLE_PRODUCTPLAN)->where('branch')->eq($branchID)->andWhere('deleted')->eq(0)->limit(1)->fetch();
|
||||
$bug = $this->dao->select('id')->from(TABLE_BUG)->where('branch')->eq($branchID)->andWhere('deleted')->eq(0)->limit(1)->fetch();
|
||||
$case = $this->dao->select('id')->from(TABLE_CASE)->where('branch')->eq($branchID)->andWhere('deleted')->eq(0)->limit(1)->fetch();
|
||||
$release = $this->dao->select('id')->from(TABLE_RELEASE)->where('branch')->eq($branchID)->andWhere('deleted')->eq(0)->limit(1)->fetch();
|
||||
$build = $this->dao->select('id')->from(TABLE_BUILD)->where('branch')->eq($branchID)->andWhere('deleted')->eq(0)->limit(1)->fetch();
|
||||
return empty($module) and empty($story) and empty($bug) and empty($case) and empty($release) and empty($build) and empty($plan);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,12 +22,22 @@
|
||||
<td class="w-300px">
|
||||
<div id='branches'>
|
||||
<?php foreach($branches as $branchID => $branch):?>
|
||||
<div class='input-group'><?php echo html::input("branch[$branchID]", $branch, "class='form-control'")?></div>
|
||||
<div class='input-group' data-id='<?php echo $branchID?>'>
|
||||
<?php echo html::input("branch[$branchID]", $branch, "class='form-control'")?>
|
||||
<?php if(common::hasPriv('branch', 'sort')):?>
|
||||
<span class='input-group-addon sort-handler'><a><i class='icon icon-move'></i></a></span>
|
||||
<?php endif;?>
|
||||
<?php if(common::hasPriv('branch', 'delete')):?>
|
||||
<span class='input-group-addon'><?php echo html::a(inlink('delete', "branchID=$branchID"), "<i class='icon icon-remove'></i>", 'hiddenwin')?></span>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
<?php endforeach;?>
|
||||
</div>
|
||||
<div id='newbranches'>
|
||||
<?php for($i = 0; $i < 2; $i++):?>
|
||||
<div class='input-group'>
|
||||
<?php echo html::input("newbranch[]", '', "class='form-control'")?>
|
||||
<span class='input-group-addon'><a href='javascript:;' onclick='addItem()'><i class='icon icon-plus'></i></a></span>
|
||||
<span class='input-group-addon'><a href='javascript:;' onclick='addItem(this)'><i class='icon icon-plus'></i></a></span>
|
||||
<span class='input-group-addon'><a href='javascript:;' onclick='deleteItem(this)'><i class='icon icon-remove'></i></a></span>
|
||||
</div>
|
||||
<?php endfor;?>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
$config->bug = new stdClass();
|
||||
$config->bug->batchCreate = 10;
|
||||
$config->bug->longlife = 7;
|
||||
|
||||
$config->bug->create = new stdclass();
|
||||
$config->bug->edit = new stdclass();
|
||||
|
||||
@@ -755,6 +755,7 @@ class bug extends control
|
||||
}
|
||||
}
|
||||
if($type == 'product') die(js::locate($this->createLink('bug', 'browse', "productID=$projectID")));
|
||||
if($type == 'my') die(js::locate($this->createLink('my', 'bug')));
|
||||
die(js::locate($this->createLink('project', 'bug', "projectID=$projectID")));
|
||||
}
|
||||
|
||||
|
||||
@@ -28,9 +28,12 @@
|
||||
#keywordsAddonLabel:before {content: '空'; color: transparent}
|
||||
|
||||
#contactListGroup .input-group-btn > .btn {margin-left: -1px!important;}
|
||||
#contactListGroup .chosen-container-single a {border-left-width: 0px;}
|
||||
|
||||
.chosen-container {max-width: 533px;}
|
||||
|
||||
.minw-80px {min-width: 80px;}
|
||||
|
||||
.colorpicker.input-group-btn > .btn {border-right: none}
|
||||
|
||||
#branch {border-left-width: 0px;}
|
||||
|
||||
+11
-10
@@ -207,8 +207,6 @@ $lang->bug->browserList['other'] = 'Other';
|
||||
$lang->bug->typeList[''] = '';
|
||||
$lang->bug->typeList['codeerror'] = 'Code Error';
|
||||
$lang->bug->typeList['interface'] = 'Interface Optimization';
|
||||
$lang->bug->typeList['designchange'] = 'Design Change';
|
||||
$lang->bug->typeList['newfeature'] = 'New Feature';
|
||||
$lang->bug->typeList['designdefect'] = 'Design Defect';
|
||||
$lang->bug->typeList['config'] = 'Config';
|
||||
$lang->bug->typeList['install'] = 'Install/Deploy';
|
||||
@@ -216,7 +214,6 @@ $lang->bug->typeList['security'] = 'Security';
|
||||
$lang->bug->typeList['performance'] = 'Performance';
|
||||
$lang->bug->typeList['standard'] = 'Standard';
|
||||
$lang->bug->typeList['automation'] = 'Testing Script';
|
||||
$lang->bug->typeList['trackthings'] = 'Issue Tracking';
|
||||
$lang->bug->typeList['others'] = 'Other';
|
||||
|
||||
$lang->bug->statusList[''] = '';
|
||||
@@ -331,13 +328,17 @@ $lang->bug->report->bugHistories->graph->xAxisName = 'Handling Steps';
|
||||
|
||||
/* 操作记录。*/
|
||||
$lang->bug->action = new stdclass();
|
||||
$lang->bug->action->resolved = array('main' => '$date, solved by <strong>$actor</strong> and the solution is <strong>$extra</strong> $appendLink.', 'extra' => 'resolutionList');
|
||||
$lang->bug->action->tostory = array('main' => '$date, transferred by <strong>$actor</strong> to <strong>Story</strong> with ID <strong>$extra</strong>.');
|
||||
$lang->bug->action->totask = array('main' => '$date, imported by <strong>$actor</strong> as <strong>Task</strong> with ID <strong>$extra</strong>.');
|
||||
$lang->bug->action->linked2plan = array('main' => '$date, linked by <strong>$actor</strong> to Planning <strong>$extra</strong>.');
|
||||
$lang->bug->action->unlinkedfromplan = array('main' => '$date, deleted by <strong>$actor</strong> from Planning <strong>$extra</strong>.');
|
||||
$lang->bug->action->linkrelatedbug = array('main' => '$date, related by <strong>$actor</strong> to Bug <strong>$extra</strong>.');
|
||||
$lang->bug->action->unlinkrelatedbug = array('main' => '$date, removed by <strong>$actor</strong> from Bug <strong>$extra</strong>.');
|
||||
$lang->bug->action->resolved = array('main' => '$date, solved by <strong>$actor</strong> and the solution is <strong>$extra</strong> $appendLink.', 'extra' => 'resolutionList');
|
||||
$lang->bug->action->tostory = array('main' => '$date, transferred by <strong>$actor</strong> to <strong>Story</strong> with ID <strong>$extra</strong>.');
|
||||
$lang->bug->action->totask = array('main' => '$date, imported by <strong>$actor</strong> as <strong>Task</strong> with ID <strong>$extra</strong>.');
|
||||
$lang->bug->action->linked2plan = array('main' => '$date, linked by <strong>$actor</strong> to Planning <strong>$extra</strong>.');
|
||||
$lang->bug->action->unlinkedfromplan = array('main' => '$date, deleted by <strong>$actor</strong> from Planning <strong>$extra</strong>.');
|
||||
$lang->bug->action->linked2build = array('main' => '$date, linked by <strong>$actor</strong> to Build <strong>$extra</strong>.');
|
||||
$lang->bug->action->unlinkedfrombuild = array('main' => '$date, removed by <strong>$actor</strong> from Build <strong>$extra</strong>.');
|
||||
$lang->bug->action->linked2release = array('main' => '$date, linked by <strong>$actor</strong> to Release <strong>$extra</strong>.');
|
||||
$lang->bug->action->unlinkedfromrelease = array('main' => '$date, removed by <strong>$actor</strong> from Release <strong>$extra</strong>.');
|
||||
$lang->bug->action->linkrelatedbug = array('main' => '$date, related by <strong>$actor</strong> to Bug <strong>$extra</strong>.');
|
||||
$lang->bug->action->unlinkrelatedbug = array('main' => '$date, removed by <strong>$actor</strong> from Bug <strong>$extra</strong>.');
|
||||
|
||||
$lang->bug->placeholder = new stdclass();
|
||||
$lang->bug->placeholder->chooseBuilds = 'Choose Build...';
|
||||
|
||||
+11
-10
@@ -207,8 +207,6 @@ $lang->bug->browserList['other'] = '其他';
|
||||
$lang->bug->typeList[''] = '';
|
||||
$lang->bug->typeList['codeerror'] = '代码错误';
|
||||
$lang->bug->typeList['interface'] = '界面优化';
|
||||
$lang->bug->typeList['designchange'] = '设计变更';
|
||||
$lang->bug->typeList['newfeature'] = '新增需求';
|
||||
$lang->bug->typeList['designdefect'] = '设计缺陷';
|
||||
$lang->bug->typeList['config'] = '配置相关';
|
||||
$lang->bug->typeList['install'] = '安装部署';
|
||||
@@ -216,7 +214,6 @@ $lang->bug->typeList['security'] = '安全相关';
|
||||
$lang->bug->typeList['performance'] = '性能问题';
|
||||
$lang->bug->typeList['standard'] = '标准规范';
|
||||
$lang->bug->typeList['automation'] = '测试脚本';
|
||||
$lang->bug->typeList['trackthings'] = '事务跟踪';
|
||||
$lang->bug->typeList['others'] = '其他';
|
||||
|
||||
$lang->bug->statusList[''] = '';
|
||||
@@ -331,13 +328,17 @@ $lang->bug->report->bugHistories->graph->xAxisName = '处理步骤';
|
||||
|
||||
/* 操作记录。*/
|
||||
$lang->bug->action = new stdclass();
|
||||
$lang->bug->action->resolved = array('main' => '$date, 由 <strong>$actor</strong> 解决,方案为 <strong>$extra</strong> $appendLink。', 'extra' => 'resolutionList');
|
||||
$lang->bug->action->tostory = array('main' => '$date, 由 <strong>$actor</strong> 转为<strong>需求</strong>,编号为 <strong>$extra</strong>。');
|
||||
$lang->bug->action->totask = array('main' => '$date, 由 <strong>$actor</strong> 导入为<strong>任务</strong>,编号为 <strong>$extra</strong>。');
|
||||
$lang->bug->action->linked2plan = array('main' => '$date, 由 <strong>$actor</strong> 关联到计划 <strong>$extra</strong>。');
|
||||
$lang->bug->action->unlinkedfromplan = array('main' => '$date, 由 <strong>$actor</strong> 从计划 <strong>$extra</strong> 移除。');
|
||||
$lang->bug->action->linkrelatedbug = array('main' => '$date, 由 <strong>$actor</strong> 关联相关Bug <strong>$extra</strong>。');
|
||||
$lang->bug->action->unlinkrelatedbug = array('main' => '$date, 由 <strong>$actor</strong> 移除相关Bug <strong>$extra</strong>。');
|
||||
$lang->bug->action->resolved = array('main' => '$date, 由 <strong>$actor</strong> 解决,方案为 <strong>$extra</strong> $appendLink。', 'extra' => 'resolutionList');
|
||||
$lang->bug->action->tostory = array('main' => '$date, 由 <strong>$actor</strong> 转为<strong>需求</strong>,编号为 <strong>$extra</strong>。');
|
||||
$lang->bug->action->totask = array('main' => '$date, 由 <strong>$actor</strong> 导入为<strong>任务</strong>,编号为 <strong>$extra</strong>。');
|
||||
$lang->bug->action->linked2plan = array('main' => '$date, 由 <strong>$actor</strong> 关联到计划 <strong>$extra</strong>。');
|
||||
$lang->bug->action->unlinkedfromplan = array('main' => '$date, 由 <strong>$actor</strong> 从计划 <strong>$extra</strong> 移除。');
|
||||
$lang->bug->action->linked2build = array('main' => '$date, 由 <strong>$actor</strong> 关联到版本 <strong>$extra</strong>。');
|
||||
$lang->bug->action->unlinkedfrombuild = array('main' => '$date, 由 <strong>$actor</strong> 从版本 <strong>$extra</strong> 移除。');
|
||||
$lang->bug->action->linked2release = array('main' => '$date, 由 <strong>$actor</strong> 关联到发布 <strong>$extra</strong>。');
|
||||
$lang->bug->action->unlinkedfromrelease = array('main' => '$date, 由 <strong>$actor</strong> 从发布 <strong>$extra</strong> 移除。');
|
||||
$lang->bug->action->linkrelatedbug = array('main' => '$date, 由 <strong>$actor</strong> 关联相关Bug <strong>$extra</strong>。');
|
||||
$lang->bug->action->unlinkrelatedbug = array('main' => '$date, 由 <strong>$actor</strong> 移除相关Bug <strong>$extra</strong>。');
|
||||
|
||||
$lang->bug->placeholder = new stdclass();
|
||||
$lang->bug->placeholder->chooseBuilds = '选择相关版本...';
|
||||
|
||||
@@ -1222,7 +1222,7 @@ class bugModel extends model
|
||||
*/
|
||||
public function getStoryBugs($storyID)
|
||||
{
|
||||
return $this->dao->select('id, title, type, status, assignedTo, resolvedBy, resolution')
|
||||
return $this->dao->select('id, title, pri, type, status, assignedTo, resolvedBy, resolution')
|
||||
->from(TABLE_BUG)
|
||||
->where('story')->eq((int)$storyID)
|
||||
->andWhere('deleted')->eq(0)
|
||||
@@ -1842,11 +1842,12 @@ class bugModel extends model
|
||||
*/
|
||||
public function getByLonglifebugs($productID, $branch, $modules, $projects, $orderBy, $pager)
|
||||
{
|
||||
return $this->dao->findByLastEditedDate("<", date(DT_DATE1, strtotime('-7 days')))->from(TABLE_BUG)->andWhere('product')->eq($productID)
|
||||
$lastEditedDate = date(DT_DATE1, time() - $this->config->bug->longlife * 24 * 3600);
|
||||
return $this->dao->findByLastEditedDate("<", $lastEditedDate)->from(TABLE_BUG)->andWhere('product')->eq($productID)
|
||||
->andWhere('project')->in(array_keys($projects))
|
||||
->beginIF($branch)->andWhere('branch')->in($branch)->fi()
|
||||
->beginIF($modules)->andWhere('module')->in($modules)->fi()
|
||||
->andWhere('openedDate')->lt(date(DT_DATE1,strtotime('-7 days')))
|
||||
->andWhere('openedDate')->lt($lastEditedDate)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->andWhere('status')->ne('closed')->orderBy($orderBy)->page($pager)->fetchAll();
|
||||
}
|
||||
@@ -2114,13 +2115,13 @@ class bugModel extends model
|
||||
echo $bug->activatedCount;
|
||||
break;
|
||||
case 'openedBy':
|
||||
echo zget($users, $bug->openedBy, $bug->openedBy);
|
||||
echo zget($users, $bug->openedBy);
|
||||
break;
|
||||
case 'openedDate':
|
||||
echo substr($bug->openedDate, 5, 11);
|
||||
break;
|
||||
case 'openedBuild':
|
||||
foreach(explode(',', $bug->openedBuild) as $build) echo zget($builds, $build, $build) . '<br />';
|
||||
foreach(explode(',', $bug->openedBuild) as $build) echo zget($builds, $build) . '<br />';
|
||||
break;
|
||||
case 'assignedTo':
|
||||
echo zget($users, $bug->assignedTo, $bug->assignedTo);
|
||||
@@ -2132,7 +2133,7 @@ class bugModel extends model
|
||||
echo zget($users, $bug->resolvedBy, $bug->resolvedBy);
|
||||
break;
|
||||
case 'resolution':
|
||||
echo $this->lang->bug->resolutionList[$bug->resolution];
|
||||
echo zget($this->lang->bug->resolutionList, $bug->resolution);
|
||||
break;
|
||||
case 'resolvedDate':
|
||||
echo substr($bug->resolvedDate, 5, 11);
|
||||
@@ -2141,7 +2142,7 @@ class bugModel extends model
|
||||
echo $bug->resolvedBuild;
|
||||
break;
|
||||
case 'closedBy':
|
||||
echo zget($users, $bug->closedBy, $bug->closedBy);
|
||||
echo zget($users, $bug->closedBy);
|
||||
break;
|
||||
case 'lastEditedDate':
|
||||
echo substr($bug->lastEditedDate, 5, 11);
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
|
||||
<td <?php if($bug->assignedTo == $this->app->user->account) echo 'class="red"';?>><?php echo zget($users, $bug->assignedTo, $bug->assignedTo);?></td>
|
||||
<td><?php echo zget($users, $bug->resolvedBy, $bug->resolvedBy)?></td>
|
||||
<td><?php echo $lang->bug->resolutionList[$bug->resolution];?></td>
|
||||
<td><?php echo zget($lang->bug->resolutionList, $bug->resolution);?></td>
|
||||
|
||||
<?php if($this->cookie->windowWidth >= $this->config->wideSize):?>
|
||||
<td><?php echo substr($bug->resolvedDate, 5, 11)?></td>
|
||||
|
||||
@@ -289,6 +289,10 @@ class buildModel extends model
|
||||
|
||||
$build->stories .= ',' . join(',', $this->post->stories);
|
||||
$this->dao->update(TABLE_BUILD)->set('stories')->eq($build->stories)->where('id')->eq((int)$buildID)->exec();
|
||||
foreach($this->post->stories as $storyID)
|
||||
{
|
||||
$this->loadModel('action')->create('story', $storyID, 'linked2build', '', $buildID);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -304,6 +308,7 @@ class buildModel extends model
|
||||
$build = $this->getByID($buildID);
|
||||
$build->stories = trim(str_replace(",$storyID,", ',', ",$build->stories,"), ',');
|
||||
$this->dao->update(TABLE_BUILD)->set('stories')->eq($build->stories)->where('id')->eq((int)$buildID)->exec();
|
||||
$this->loadModel('action')->create('story', $storyID, 'unlinkedfrombuild', '', $buildID);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -323,6 +328,10 @@ class buildModel extends model
|
||||
foreach($storyList as $storyID) $build->stories = str_replace(",$storyID,", ',', $build->stories);
|
||||
$build->stories = trim($build->stories, ',');
|
||||
$this->dao->update(TABLE_BUILD)->set('stories')->eq($build->stories)->where('id')->eq((int)$buildID)->exec();
|
||||
foreach($this->post->unlinkStories as $unlinkStoryID)
|
||||
{
|
||||
$this->loadModel('action')->create('story', $unlinkStoryID, 'unlinkedfrombuild', '', $buildID);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -339,6 +348,10 @@ class buildModel extends model
|
||||
$build->bugs .= ',' . join(',', $this->post->bugs);
|
||||
$this->updateLinkedBug($build);
|
||||
$this->dao->update(TABLE_BUILD)->set('bugs')->eq($build->bugs)->where('id')->eq((int)$buildID)->exec();
|
||||
foreach($this->post->bugs as $bugID)
|
||||
{
|
||||
$this->loadModel('action')->create('bug', $bugID, 'linked2build', '', $buildID);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -354,6 +367,7 @@ class buildModel extends model
|
||||
$build = $this->getByID($buildID);
|
||||
$build->bugs = trim(str_replace(",$bugID,", ',', ",$build->bugs,"), ',');
|
||||
$this->dao->update(TABLE_BUILD)->set('bugs')->eq($build->bugs)->where('id')->eq((int)$buildID)->exec();
|
||||
$this->loadModel('action')->create('bug', $bugID, 'unlinkedfrombuild', '', $buildID);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -374,5 +388,9 @@ class buildModel extends model
|
||||
foreach($bugList as $bugID) $build->bugs = str_replace(",$bugID,", ',', $build->bugs);
|
||||
$build->bugs = trim($build->bugs, ',');
|
||||
$this->dao->update(TABLE_BUILD)->set('bugs')->eq($build->bugs)->where('id')->eq((int)$buildID)->exec();
|
||||
foreach($this->post->unlinkBugs as $unlinkBugID)
|
||||
{
|
||||
$this->loadModel('action')->create('bug', $unlinkBugID, 'unlinkedfrombuild', '', $buildID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,9 +304,8 @@ $lang->admin = new stdclass();
|
||||
$lang->admin->menu = new stdclass();
|
||||
$lang->admin->menu->index = array('link' => 'Homepage|admin|index');
|
||||
$lang->admin->menu->extension = array('link' => 'Extension|extension|browse', 'subModule' => 'extension');
|
||||
$lang->admin->menu->custom = array('link' => 'Custom|custom|index', 'subModule' => 'custom');
|
||||
$lang->admin->menu->custom = array('link' => 'Custom|custom|set', 'subModule' => 'custom');
|
||||
$lang->admin->menu->mail = array('link' => 'Email|mail|index', 'subModule' => 'mail');
|
||||
$lang->admin->menu->convert = array('link' => 'Import|convert|index', 'subModule' => 'convert');
|
||||
$lang->admin->menu->backup = array('link' => 'Backup|backup|index', 'subModule' => 'backup');
|
||||
$lang->admin->menu->safe = array('link' => 'Security|admin|safe', 'alias' => 'checkweak');
|
||||
$lang->admin->menu->cron = array('link' => 'Cron|cron|index', 'subModule' => 'cron');
|
||||
|
||||
@@ -304,9 +304,8 @@ $lang->admin = new stdclass();
|
||||
$lang->admin->menu = new stdclass();
|
||||
$lang->admin->menu->index = array('link' => '首页|admin|index');
|
||||
$lang->admin->menu->extension = array('link' => '插件|extension|browse', 'subModule' => 'extension');
|
||||
$lang->admin->menu->custom = array('link' => '自定义|custom|index', 'subModule' => 'custom');
|
||||
$lang->admin->menu->custom = array('link' => '自定义|custom|set', 'subModule' => 'custom');
|
||||
$lang->admin->menu->mail = array('link' => '发信|mail|index', 'subModule' => 'mail');
|
||||
$lang->admin->menu->convert = array('link' => '导入|convert|index', 'subModule' => 'convert');
|
||||
$lang->admin->menu->backup = array('link' => '备份|backup|index', 'subModule' => 'backup');
|
||||
$lang->admin->menu->safe = array('link' => '安全|admin|safe', 'alias' => 'checkweak');
|
||||
$lang->admin->menu->cron = array('link' => '计划任务|cron|index', 'subModule' => 'cron');
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?php
|
||||
$config->custom = new stdClass();
|
||||
$config->custom->canAdd['story'] = 'reasonList,reviewResultList,sourceList,priList';
|
||||
$config->custom->canAdd['task'] = 'priList,typeList';
|
||||
$config->custom->canAdd['task'] = 'priList,typeList,reasonList';
|
||||
$config->custom->canAdd['bug'] = 'priList,severityList,osList,browserList,typeList,resolutionList';
|
||||
$config->custom->canAdd['testcase'] = 'priList,typeList,stageList';
|
||||
$config->custom->canAdd['testcase'] = 'priList,typeList,stageList,resultList,statusList';
|
||||
$config->custom->canAdd['testtask'] = 'priList';
|
||||
$config->custom->canAdd['todo'] = 'priList,typeList';
|
||||
$config->custom->canAdd['user'] = 'roleList';
|
||||
|
||||
@@ -37,8 +37,7 @@ class custom extends control
|
||||
$currentLang = $this->app->getClientLang();
|
||||
|
||||
$this->app->loadLang($module);
|
||||
$this->app->loadConfig('story');
|
||||
$fieldList = $this->lang->$module->$field;
|
||||
$fieldList = zget($this->lang->$module, $field, '');
|
||||
|
||||
if($module == 'bug' and $field == 'typeList')
|
||||
{
|
||||
@@ -46,12 +45,35 @@ class custom extends control
|
||||
unset($fieldList['newfeature']);
|
||||
unset($fieldList['trackthings']);
|
||||
}
|
||||
if($module == 'story' && $field == 'review')
|
||||
{
|
||||
$this->app->loadConfig('story');
|
||||
$this->view->users = $this->loadModel('user')->getPairs('nodeleted|noclosed');
|
||||
$this->view->needReview = zget($this->config->story, 'needReview', 1);
|
||||
$this->view->forceReview = zget($this->config->story, 'forceReview', '');
|
||||
}
|
||||
if($module == 'task' && $field == 'hours')
|
||||
{
|
||||
$this->app->loadConfig('project');
|
||||
$this->view->weekend = $this->config->project->weekend;
|
||||
$this->view->workhours = $this->config->project->defaultWorkhours;
|
||||
}
|
||||
if($module == 'bug' && $field == 'longlife')
|
||||
{
|
||||
$this->app->loadConfig('bug');
|
||||
$this->view->longlife = $this->config->bug->longlife;
|
||||
}
|
||||
|
||||
if(!empty($_POST))
|
||||
{
|
||||
if($module == 'story' && $field == 'review')
|
||||
{
|
||||
$this->loadModel('setting')->setItem('system.story.needReview', fixer::input('post')->get()->needReview);
|
||||
$data = fixer::input('post')->join('forceReview', ',')->get();
|
||||
$this->loadModel('setting')->setItems('system.story', $data);
|
||||
}
|
||||
elseif($module == 'task' && $field == 'hours')
|
||||
{
|
||||
$this->loadModel('setting')->setItems('system.project', fixer::input('post')->get());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -60,8 +82,8 @@ class custom extends control
|
||||
foreach($_POST['keys'] as $index => $key)
|
||||
{
|
||||
$value = $_POST['values'][$index];
|
||||
if(!$value or !$key) continue;
|
||||
$system = $_POST['systems'][$index];
|
||||
if(!$system and (!$value or !$key)) continue;
|
||||
|
||||
/* the length of role is 20, check it when save. */
|
||||
if($module == 'user' and $field == 'roleList' and strlen($key) > 20) die(js::alert($this->lang->custom->notice->userRole));
|
||||
@@ -93,7 +115,6 @@ class custom extends control
|
||||
$this->view->title = $this->lang->custom->common . $this->lang->colon . $this->lang->$module->common;
|
||||
$this->view->position[] = $this->lang->custom->common;
|
||||
$this->view->position[] = $this->lang->$module->common;
|
||||
$this->view->needReview = $this->config->story->needReview;
|
||||
$this->view->fieldList = $fieldList;
|
||||
$this->view->dbFields = $dbFields;
|
||||
$this->view->field = $field;
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
.alert-block{border-top:1px solid #ddd;}
|
||||
|
||||
@@ -31,6 +31,7 @@ $lang->custom->task->fields['priList'] = '优先级';
|
||||
$lang->custom->task->fields['typeList'] = '类型';
|
||||
$lang->custom->task->fields['reasonList'] = '关闭原因';
|
||||
$lang->custom->task->fields['statusList'] = '状态';
|
||||
$lang->custom->task->fields['hours'] = '工时';
|
||||
|
||||
$lang->custom->bug = new stdClass();
|
||||
$lang->custom->bug->fields['priList'] = '优先级';
|
||||
@@ -40,6 +41,7 @@ $lang->custom->bug->fields['browserList'] = '浏览器';
|
||||
$lang->custom->bug->fields['typeList'] = '类型';
|
||||
$lang->custom->bug->fields['resolutionList'] = '解决方案';
|
||||
$lang->custom->bug->fields['statusList'] = '状态';
|
||||
$lang->custom->bug->fields['longlife'] = '久未处理天数';
|
||||
|
||||
$lang->custom->testcase = new stdClass();
|
||||
$lang->custom->testcase->fields['priList'] = '优先级';
|
||||
@@ -67,15 +69,24 @@ $lang->custom->allLang = '适用所有语言';
|
||||
$lang->custom->confirmRestore = '是否要恢复默认配置?';
|
||||
|
||||
$lang->custom->notice = new stdclass();
|
||||
$lang->custom->notice->userRole = '键的长度必须小于20个字符!';
|
||||
$lang->custom->notice->userRole = '键的长度必须小于20个字符!';
|
||||
$lang->custom->notice->canNotAdd = '该项值已经在禅道中固定,不能添加新值';
|
||||
$lang->custom->notice->forceReview = '指定人提交的需求必须评审。';
|
||||
$lang->custom->notice->longlife = 'Bug列表页面的久未处理标签中,列出设置天数之前未处理的Bug。';
|
||||
$lang->custom->notice->indexPage['product'] = "从8.2版本起增加了产品主页视图,是否默认进入产品主页?";
|
||||
$lang->custom->notice->indexPage['project'] = "从8.2版本起增加了项目主页视图,是否默认进入项目主页?";
|
||||
$lang->custom->notice->indexPage['qa'] = "从8.2版本起增加了测试主页视图,是否默认进入测试主页?";
|
||||
|
||||
$lang->custom->storyReview = '评审流程';
|
||||
$lang->custom->forceReview = '强制评审';
|
||||
$lang->custom->reviewList[1] = '开启';
|
||||
$lang->custom->reviewList[0] = '关闭';
|
||||
|
||||
$lang->custom->workingHours = '每天可用工时';
|
||||
$lang->custom->weekend = '周休';
|
||||
$lang->custom->weekendList[2] = '双休';
|
||||
$lang->custom->weekendList[1] = '单休';
|
||||
|
||||
$lang->custom->productProject = new stdclass();
|
||||
$lang->custom->productProject->relation['0_0'] = '产品 - 项目';
|
||||
$lang->custom->productProject->relation['0_1'] = '产品 - 迭代';
|
||||
|
||||
@@ -193,7 +193,8 @@ class customModel extends model
|
||||
/* Merge fileMenu and customMenu. */
|
||||
foreach($customMenuMap as $name => $item)
|
||||
{
|
||||
if(!isset($allMenu->$name))$allMenu->$name = $item;
|
||||
if(is_object($allMenu) and !isset($allMenu->$name))$allMenu->$name = $item;
|
||||
if(is_array($allMenu) and !isset($allMenu[$name]))$allMenu[$name] = $item;
|
||||
}
|
||||
|
||||
foreach($allMenu as $name => $item)
|
||||
|
||||
@@ -29,19 +29,18 @@
|
||||
<div class='main'>
|
||||
<form method='post' class='form-condensed' target='hiddenwin'>
|
||||
<table class='table table-form'>
|
||||
<tr><th class='w-100px'><?php echo $lang->custom->select;?></th><th></th><th></th></tr>
|
||||
<?php $checkedKey = isset($config->custom->productProject) ? $config->custom->productProject : '0_0' ?>
|
||||
<?php foreach($lang->custom->productProject->relation as $key => $value):?>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td class='w-300px'>
|
||||
<label class="radio-inline"><input type="radio" name="productProject" value="<?php echo $key?>"<?php echo $key == $checkedKey ? " checked='checked'" : ''?> id="productProject<?php echo $key;?>"><?php echo $value;?></label>
|
||||
<th class='w-150px text-top'><?php echo $lang->custom->select;?></th>
|
||||
<?php $checkedKey = isset($config->custom->productProject) ? $config->custom->productProject : '0_0' ?>
|
||||
<td>
|
||||
<?php foreach($lang->custom->productProject->relation as $key => $value):?>
|
||||
<p><label class="radio-inline"><input type="radio" name="productProject" value="<?php echo $key?>"<?php echo $key == $checkedKey ? " checked='checked'" : ''?> id="productProject<?php echo $key;?>"><?php echo $value;?></label></p>
|
||||
<?php endforeach;?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach;?>
|
||||
<tr><td></td><td><?php echo html::submitButton()?></td></tr>
|
||||
<tr>
|
||||
<td colspan='3' class='pd-0'>
|
||||
<td colspan='2' class='pd-0'>
|
||||
<div class='alert alert-info alert-block'><strong><?php echo $lang->custom->productProject->notice?></strong></div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -48,33 +48,72 @@ EOT;
|
||||
</div>
|
||||
<div class='side'>
|
||||
<div class='list-group'>
|
||||
<?php
|
||||
<?php
|
||||
foreach($lang->custom->{$module}->fields as $key => $value)
|
||||
{
|
||||
echo "<li class='list-group-item' id='{$key}Tab'>" . html::a(inlink('set', "module=$module&field=$key"), $value) . "</li>";
|
||||
}
|
||||
?>
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<div class='main'>
|
||||
<form method='post' class='form-condensed' target='hiddenwin'>
|
||||
<div class='panel panel-sm'>
|
||||
<div class='panel-heading'>
|
||||
<strong><?php echo $lang->custom->object[$module] . ' >> ' . $lang->custom->$module->fields[$field]?></strong>
|
||||
<strong><?php echo $lang->custom->object[$module] . $lang->arrow . $lang->custom->$module->fields[$field]?></strong>
|
||||
</div>
|
||||
<?php if($field == 'review'):?>
|
||||
<table class='table table-borderless mw-600px'>
|
||||
<?php if($module == 'story' and $field == 'review'):?>
|
||||
<table class='table table-form mw-800px'>
|
||||
<tr>
|
||||
<td><?php echo $lang->custom->storyReview;?></td>
|
||||
<th class='w-80px'><?php echo $lang->custom->storyReview;?></th>
|
||||
<td><?php echo html::radio('needReview', $lang->custom->reviewList, $needReview);?></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->custom->forceReview;?></th>
|
||||
<td><?php echo html::select('forceReview[]', $users, $forceReview, "class='form-control chosen' multiple");?></td>
|
||||
<td class='w-180px'><?php echo $lang->custom->notice->forceReview;?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><?php echo html::submitButton();?></td>
|
||||
</tr>
|
||||
</table>
|
||||
<?php elseif($module == 'task' and $field == 'hours'):?>
|
||||
<table class='table table-form mw-600px'>
|
||||
<tr>
|
||||
<th class='w-150px'><?php echo $lang->custom->workingHours;?></th>
|
||||
<td><?php echo html::input('defaultWorkhours', $workhours, "class='form-control w-80px'");?></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->custom->weekend;?></th>
|
||||
<td><?php echo html::radio('weekend', $lang->custom->weekendList, $weekend);?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><?php echo html::submitButton();?></td>
|
||||
</tr>
|
||||
</table>
|
||||
<?php elseif($module == 'bug' and $field == 'longlife'):?>
|
||||
<table class='table table-form mw-600px'>
|
||||
<tr>
|
||||
<th class='w-100px'><?php echo $lang->custom->bug->fields['longlife'];?></th>
|
||||
<td class='w-100px'>
|
||||
<div class='input-group'>
|
||||
<?php echo html::input('longlife', $longlife, "class='form-control'");?>
|
||||
<span class='input-group-addon'><?php echo $lang->day?></span>
|
||||
</div>
|
||||
</td>
|
||||
<td><?php echo html::submitButton();?></td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class='alert alert-info alert-block'><?php echo $lang->custom->notice->longlife;?></div>
|
||||
<?php else:?>
|
||||
<table class='table table-borderless active-disabled table-condensed mw-600px'>
|
||||
<table class='table table-form active-disabled table-condensed mw-600px'>
|
||||
<tr class='text-center'>
|
||||
<th class='w-120px'><?php echo $lang->custom->key;?></th>
|
||||
<th><?php echo $lang->custom->value;?></th>
|
||||
<td class='w-120px'><strong><?php echo $lang->custom->key;?></strong></td>
|
||||
<td><strong><?php echo $lang->custom->value;?></strong></td>
|
||||
<?php if($canAdd):?><th class='w-40px'></th><?php endif;?>
|
||||
</tr>
|
||||
<?php foreach($fieldList as $key => $value):?>
|
||||
@@ -87,7 +126,7 @@ EOT;
|
||||
<?php if($canAdd):?>
|
||||
<td class='text-left w-100px'>
|
||||
<a href='javascript:void()' class='btn-icon' onclick='addItem(this)'><i class='icon-plus'></i></a>
|
||||
<?php if(!$system):?><a href='javascript:void()' onclick='delItem(this)' class='btn-icon'><i class='icon-remove'></i></a><?php endif;?>
|
||||
<a href='javascript:void()' onclick='delItem(this)' class='btn-icon'><i class='icon-remove'></i></a>
|
||||
</td>
|
||||
<?php endif;?>
|
||||
</tr>
|
||||
@@ -103,6 +142,9 @@ EOT;
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<?php if(!$canAdd):?>
|
||||
<div class='alert alert-warning alert-block'><?php echo $lang->custom->notice->canNotAdd;?></div>
|
||||
<?php endif;?>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -123,6 +123,16 @@ class datatableModel extends model
|
||||
{
|
||||
echo $this->lang->actions;
|
||||
}
|
||||
elseif($id == 'progess')
|
||||
{
|
||||
$this->app->loadLang('task');
|
||||
echo $this->lang->task->progess;
|
||||
}
|
||||
elseif($id == 'taskCount' or $id == 'bugCount' or $id == 'caseCount')
|
||||
{
|
||||
$this->app->loadLang('story');
|
||||
echo $this->lang->story->$id;
|
||||
}
|
||||
else
|
||||
{
|
||||
common::printOrderLink($id, $orderBy, $vars, $col->title);
|
||||
|
||||
@@ -100,8 +100,7 @@ $lang->doc->errorEditSystemDoc = "System Doc Lib needs no modifications.";
|
||||
$lang->doc->errorEmptyProduct = "No {$lang->productCommon}. Document cannot be created.";
|
||||
$lang->doc->errorEmptyProject = "No {$lang->projectCommon}. Document cannot be created.";
|
||||
$lang->doc->errorMainSysLib = "Can not delete this library.";
|
||||
$lang->doc->accessDenied = "Access to library denied!";
|
||||
$lang->doc->noMatched = "No library including '%s' can be found.";
|
||||
$lang->doc->accessDenied = "Access denied!";
|
||||
$lang->doc->versionNotFount = 'The document is not exist in this version.';
|
||||
|
||||
$lang->doc->placeholder = new stdclass();
|
||||
|
||||
@@ -100,8 +100,7 @@ $lang->doc->errorEditSystemDoc = "系统文档库无需修改。";
|
||||
$lang->doc->errorEmptyProduct = "没有{$lang->productCommon},无法创建文档";
|
||||
$lang->doc->errorEmptyProject = "没有{$lang->projectCommon},无法创建文档";
|
||||
$lang->doc->errorMainSysLib = "该系统文档库不能删除!";
|
||||
$lang->doc->accessDenied = "您没有权限访问该文档库!";
|
||||
$lang->doc->noMatched = '找不到包含"%s"的文档库';
|
||||
$lang->doc->accessDenied = "您没有权限访问!";
|
||||
$lang->doc->versionNotFount = '该版本文档不存在';
|
||||
|
||||
$lang->doc->placeholder = new stdclass();
|
||||
|
||||
@@ -45,7 +45,7 @@ class docModel extends model
|
||||
foreach($libs as $lib)
|
||||
{
|
||||
if($lib->product) $productIdList[] = $lib->product;
|
||||
if($lib->project) $productIdList[] = $lib->project;
|
||||
if($lib->project) $projectIdList[] = $lib->project;
|
||||
}
|
||||
}
|
||||
$products = $productIdList ? $this->dao->select('id,name')->from(TABLE_PRODUCT)->where('id')->in($productIdList)->fetchPairs('id', 'name') : array();
|
||||
@@ -312,7 +312,12 @@ class docModel extends model
|
||||
public function getById($docID, $version = 0, $setImgSize = false)
|
||||
{
|
||||
$doc = $this->dao->select('*')->from(TABLE_DOC)->where('id')->eq((int)$docID)->fetch();
|
||||
if(!$doc or !$this->checkPriv($doc)) return false;
|
||||
if(!$doc) return false;
|
||||
if(!$this->checkPriv($doc))
|
||||
{
|
||||
echo(js::alert($this->lang->doc->accessDenied));
|
||||
die(js::locate('back'));
|
||||
}
|
||||
$version = $version ? $version : $doc->version;
|
||||
$docContent = $this->dao->select('*')->from(TABLE_DOCCONTENT)->where('doc')->eq($doc->id)->andWhere('version')->eq($version)->fetch();
|
||||
|
||||
|
||||
@@ -36,6 +36,28 @@ function downloadFile(fileID)
|
||||
{
|
||||
$fileTitle = "<li class='list-group-item'><i class='icon-file-text text-muted icon'></i> " . $file->title .'.' . $file->extension;
|
||||
echo html::a($this->createLink('file', 'download', "fileID=$file->id") . $sessionString, $fileTitle, '_blank', "onclick='return downloadFile($file->id)'");
|
||||
|
||||
/* Show size info. */
|
||||
if($file->size < 1024)
|
||||
{
|
||||
echo "<span>(" . $file->size . 'B' . ")</span>";
|
||||
}
|
||||
elseif($file->size < 1024 * 1024)
|
||||
{
|
||||
$file->size = round($file->size / 1024, 2);
|
||||
echo "<span>(" . $file->size . 'K' . ")</span>";
|
||||
}
|
||||
elseif($file->size < 1024 * 1024 * 1024)
|
||||
{
|
||||
$file->size = round($file->size / (1024 * 1024), 2);
|
||||
echo "<span>(" . $file->size . 'M' . ")</span>";
|
||||
}
|
||||
else
|
||||
{
|
||||
$file->size = round($file->size / (1024 * 1024 * 1024), 2);
|
||||
echo "<span>(" . $file->size . 'G' . ")</span>";
|
||||
}
|
||||
|
||||
echo "<span class='right-icon'>";
|
||||
common::printLink('file', 'edit', "fileID=$file->id", "<i class='icon-pencil'></i>", '', "class='edit btn-icon' title='{$lang->file->edit}'");
|
||||
if(common::hasPriv('file', 'delete')) echo html::a('###', "<i class='icon-remove'></i>", '', "class='btn-icon' onclick='deleteFile($file->id)' title='$lang->delete'");
|
||||
|
||||
@@ -1,11 +1,3 @@
|
||||
function setNoChecked()
|
||||
{
|
||||
var noCheckValue = '';
|
||||
$(':checkbox').each(function(){
|
||||
if(!$(this).attr('checked') && $(this).next('span').attr('id') != undefined) noCheckValue = noCheckValue + ',' + $(this).next('span').attr('id');
|
||||
})
|
||||
$('#noChecked').val(noCheckValue);
|
||||
}
|
||||
function toggleProduct()
|
||||
{
|
||||
$('#productBox').toggle($('#product').prop("checked"));
|
||||
@@ -27,4 +19,13 @@ $(function()
|
||||
{
|
||||
toggleProduct();
|
||||
toggleProject();
|
||||
$('.group-item :checkbox[name^="actions"]').change(function()
|
||||
{
|
||||
var allChecked = true;
|
||||
$('.group-item :checkbox[name^="actions"]').each(function()
|
||||
{
|
||||
if(!$(this).prop('checked')) allChecked = false;
|
||||
})
|
||||
$('input:checkbox[name^="allchecker"]').prop('checked', allChecked);
|
||||
})
|
||||
})
|
||||
|
||||
@@ -266,8 +266,7 @@ class groupModel extends model
|
||||
public function updateView($groupID)
|
||||
{
|
||||
$actions = $this->post->actions;
|
||||
if(!isset($actions['views']['product']) and isset($actions['products'])) unset($actions['products']);
|
||||
if(!isset($actions['views']['project']) and isset($actions['projects'])) unset($actions['projects']);
|
||||
if(isset($_POST['allchecker']))$actions['views'] = array();
|
||||
|
||||
$actions = empty($actions) ? '' : json_encode($actions);
|
||||
$this->dao->update(TABLE_GROUP)->set('acl')->eq($actions)->where('id')->eq($groupID)->exec();
|
||||
|
||||
@@ -11,6 +11,13 @@
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<div id='titlebar'>
|
||||
<div class='heading'>
|
||||
<span class='prefix' title='GROUP'><?php echo html::icon($lang->icons['group']);?> <strong><?php echo $group->id;?></strong></span>
|
||||
<strong><?php echo $group->name;?></strong>
|
||||
<small class='text-muted'> <?php echo $lang->group->manageView;?></small>
|
||||
</div>
|
||||
</div>
|
||||
<form class='form-condensed' method='post' target='hiddenwin'>
|
||||
<table class='table table-form'>
|
||||
<tr>
|
||||
@@ -24,19 +31,19 @@
|
||||
<?php $moduleName = strip_tags($moduleName);?>
|
||||
<div class='group-item'>
|
||||
<label class='priv' for='<?php echo $module?>'>
|
||||
<input type='checkbox' id='<?php echo $module?>' name='actions[views][<?php echo strtolower($module);?>]' value='<?php echo $module;?>' <?php if(isset($group->acl['views'][$module])) echo "checked";?> />
|
||||
<input type='checkbox' id='<?php echo $module?>' name='actions[views][<?php echo strtolower($module);?>]' value='<?php echo $module;?>' <?php if(isset($group->acl['views'][$module]) or empty($group->acl['views'])) echo "checked";?> />
|
||||
<?php echo $moduleName;?>
|
||||
</label>
|
||||
</div>
|
||||
<?php endforeach;?>
|
||||
<div class='group-item'>
|
||||
<label class='priv' for='allchecker'>
|
||||
<input type="checkbox" id='allchecker' name="allchecker[]" onclick="selectAll(this, '', 'checkbox')">
|
||||
<input type="checkbox" id='allchecker' name="allchecker" onclick="selectAll(this, '', 'checkbox')" <?php if(empty($group->acl['views'])) echo "checked";?> />
|
||||
<?php echo $lang->selectAll?>
|
||||
</label>
|
||||
</div>
|
||||
</td>
|
||||
<td><?php echo $lang->group->noticeVisit?></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr id='productBox' style='display:none'>
|
||||
<th class='text-right'><?php echo $lang->group->productList?></th>
|
||||
|
||||
@@ -58,6 +58,6 @@ include '../../common/view/header.html.php';
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
<div class='alert alert-info alert-block'><?php printf($lang->mail->sendCloudHelp, common::hasPriv('mail', 'sendcloudUser') ? inlink('sendcloudUser') : '#')?></div>
|
||||
<div class='alert alert-info alert-block' style='border-top:1px solid #ddd'><?php printf($lang->mail->sendCloudHelp, common::hasPriv('mail', 'sendcloudUser') ? inlink('sendcloudUser') : '#')?></div>
|
||||
</div>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
|
||||
@@ -141,7 +141,7 @@ class misc extends control
|
||||
public function qrCode()
|
||||
{
|
||||
$loginAPI = common::getSysURL() . $this->config->webRoot;
|
||||
$session = $this->loadModel('user')->isLogon() ? '?sid=' . session_id() : '';
|
||||
$session = $this->loadModel('user')->isLogon() ? '?' . $this->config->sessionVar . '=' . session_id() : '';
|
||||
|
||||
if(!extension_loaded('gd'))
|
||||
{
|
||||
|
||||
+12
-11
@@ -194,17 +194,18 @@ class my extends control
|
||||
$this->session->set('bugIDs', $bugIDs . ',');
|
||||
|
||||
/* assign. */
|
||||
$this->view->title = $this->lang->my->common . $this->lang->colon . $this->lang->my->bug;
|
||||
$this->view->position[] = $this->lang->my->bug;
|
||||
$this->view->bugs = $bugs;
|
||||
$this->view->users = $this->user->getPairs('noletter');
|
||||
$this->view->tabID = 'bug';
|
||||
$this->view->type = $type;
|
||||
$this->view->recTotal = $recTotal;
|
||||
$this->view->recPerPage = $recPerPage;
|
||||
$this->view->pageID = $pageID;
|
||||
$this->view->orderBy = $orderBy;
|
||||
$this->view->pager = $pager;
|
||||
$this->view->title = $this->lang->my->common . $this->lang->colon . $this->lang->my->bug;
|
||||
$this->view->position[] = $this->lang->my->bug;
|
||||
$this->view->bugs = $bugs;
|
||||
$this->view->users = $this->user->getPairs('noletter');
|
||||
$this->view->memberPairs = $this->user->getPairs('noletter|nodeleted');
|
||||
$this->view->tabID = 'bug';
|
||||
$this->view->type = $type;
|
||||
$this->view->recTotal = $recTotal;
|
||||
$this->view->recPerPage = $recPerPage;
|
||||
$this->view->pageID = $pageID;
|
||||
$this->view->orderBy = $orderBy;
|
||||
$this->view->pager = $pager;
|
||||
|
||||
$this->display();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
.dropdown-menu.with-search {padding-bottom: 34px; min-width: 150px; overflow: hidden; max-height: 305px}
|
||||
.dropdown-menu > .menu-search {padding: 0; position: absolute; z-index: 0; bottom: 0; left: 0; right: 0}
|
||||
.dropdown-menu > .menu-search .input-group {width:100%;}
|
||||
.dropdown-menu > .menu-search .input-group-addon {position: absolute; right: 10px; top: 0; z-index: 10; background: none; border: none; color: #666}
|
||||
|
||||
@@ -9,4 +9,20 @@ $(function()
|
||||
if($('table.tablesorter').closest('form').size() > 0) fixedTfootAction($('table.tablesorter').closest('form'));
|
||||
/* Fixed table header */
|
||||
if($('table.tablesorter').size() > 0) fixedTheadOfList($('table.tablesorter:first'));
|
||||
|
||||
$('.dropdown-menu .with-search .menu-search').click(function(e)
|
||||
{
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
}).on('keyup change paste', 'input', function()
|
||||
{
|
||||
var val = $(this).val().toLowerCase();
|
||||
var $options = $(this).closest('ul.dropdown-menu.with-search').find('.option');
|
||||
if(val == '') return $options.removeClass('hide');
|
||||
$options.each(function()
|
||||
{
|
||||
var $option = $(this);
|
||||
$option.toggleClass('hide', $option.text().toString().toLowerCase().indexOf(val) < 0 && $option.data('key').toString().toLowerCase().indexOf(val) < 0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -70,15 +70,54 @@
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan='10'>
|
||||
<?php if($bugs):?>
|
||||
<div class='table-actions clearfix'>
|
||||
<?php
|
||||
if($bugs and $canBatchEdit)
|
||||
{
|
||||
<?php echo html::selectButton();?>
|
||||
<div class='btn-group dropup'>
|
||||
<?php
|
||||
$actionLink = $this->createLink('bug', 'batchEdit');
|
||||
echo html::selectButton() . html::commonButton($lang->edit, "onclick=\"setFormAction('$actionLink')\"");
|
||||
}
|
||||
?>
|
||||
$misc = common::hasPriv('bug', 'batchEdit') ? "onclick=\"setFormAction('$actionLink')\"" : "disabled='disabled'";
|
||||
echo html::commonButton($lang->edit, $misc);
|
||||
?>
|
||||
<button type='button' class='btn dropdown-toggle' data-toggle='dropdown'><span class='caret'></span></button>
|
||||
<ul class='dropdown-menu'>
|
||||
<?php
|
||||
$class = "class='disabled'";
|
||||
$actionLink = $this->createLink('bug', 'batchConfirm');
|
||||
$misc = common::hasPriv('bug', 'batchConfirm') ? "onclick=\"setFormAction('$actionLink','hiddenwin')\"" : $class;
|
||||
if($misc) echo "<li>" . html::a('javascript:;', $lang->bug->confirmBug, '', $misc) . "</li>";
|
||||
|
||||
$actionLink = $this->createLink('bug', 'batchClose');
|
||||
$misc = common::hasPriv('bug', 'batchClose') ? "onclick=\"setFormAction('$actionLink','hiddenwin')\"" : $class;
|
||||
if($misc) echo "<li>" . html::a('javascript:;', $lang->bug->close, '', $misc) . "</li>";
|
||||
|
||||
$canBatchAssignTo = common::hasPriv('bug', 'batchAssignTo');
|
||||
if($canBatchAssignTo && count($bugs))
|
||||
{
|
||||
$withSearch = count($memberPairs) > 10;
|
||||
$actionLink = $this->createLink('bug', 'batchAssignTo', "productID=0&type=my");
|
||||
echo html::select('assignedTo', $memberPairs, '', 'class="hidden"');
|
||||
echo "<li class='dropdown-submenu'>";
|
||||
echo html::a('javascript::', $lang->bug->assignedTo, 'id="assignItem"');
|
||||
echo "<ul class='dropdown-menu" . ($withSearch ? ' with-search':'') . "'>";
|
||||
foreach ($memberPairs as $key => $value)
|
||||
{
|
||||
if(empty($key)) continue;
|
||||
echo "<li class='option' data-key='$key'>" . html::a("javascript:$(\".table-actions #assignedTo\").val(\"$key\");setFormAction(\"$actionLink\")", $value, '', '') . '</li>';
|
||||
}
|
||||
if($withSearch) echo "<li class='menu-search'><div class='input-group input-group-sm'><input type='text' class='form-control' placeholder=''><span class='input-group-addon'><i class='icon-search'></i></span></div></li>";
|
||||
echo "</ul>";
|
||||
echo "</li>";
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "<li>" . html::a('javascript:;', $lang->bug->assignedTo, '', $class);
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
<?php $pager->show();?>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -75,25 +75,89 @@
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan='10'>
|
||||
<?php if(count($stories)):?>
|
||||
<div class='table-actions clearfix'>
|
||||
<?php
|
||||
if(count($stories))
|
||||
{
|
||||
if($canBatchEdit or $canBatchRun) echo html::selectButton();
|
||||
|
||||
if($canBatchEdit)
|
||||
{
|
||||
$actionLink = $this->createLink('story', 'batchEdit');
|
||||
echo html::commonButton($lang->edit, "onclick=\"setFormAction('$actionLink')\"");
|
||||
}
|
||||
if($canBatchClose and $type != 'closedBy')
|
||||
{
|
||||
$actionLink = $this->createLink('story', 'batchClose');
|
||||
echo html::commonButton($lang->close, "onclick=\"setFormAction('$actionLink')\"");
|
||||
}
|
||||
}
|
||||
?>
|
||||
<?php echo html::selectButton();?>
|
||||
<div class='btn-group dropup'>
|
||||
<?php
|
||||
$actionLink = $this->createLink('story', 'batchEdit');
|
||||
$misc = $canBatchEdit ? "onclick=\"setFormAction('$actionLink')\"" : "disabled='disabled'";
|
||||
echo html::commonButton($lang->edit, $misc);
|
||||
?>
|
||||
<button type='button' class='btn dropdown-toggle' data-toggle='dropdown'><span class='caret'></span></button>
|
||||
<ul class='dropdown-menu'>
|
||||
<?php
|
||||
$class = "class='disabled'";
|
||||
$actionLink = $this->createLink('story', 'batchClose');
|
||||
$misc = ($canBatchClose and $type != 'closedBy') ? "onclick=\"setFormAction('$actionLink','hiddenwin')\"" : $class;
|
||||
if($misc) echo "<li>" . html::a('javascript:;', $lang->close, '', $misc) . "</li>";
|
||||
|
||||
if(common::hasPriv('story', 'batchReview'))
|
||||
{
|
||||
echo "<li class='dropdown-submenu'>";
|
||||
echo html::a('javascript:;', $lang->story->review, '', "id='reviewItem'");
|
||||
echo "<ul class='dropdown-menu'>";
|
||||
unset($lang->story->reviewResultList['']);
|
||||
unset($lang->story->reviewResultList['revert']);
|
||||
foreach($lang->story->reviewResultList as $key => $result)
|
||||
{
|
||||
$actionLink = $this->createLink('story', 'batchReview', "result=$key");
|
||||
if($key == 'reject')
|
||||
{
|
||||
echo "<li class='dropdown-submenu'>";
|
||||
echo html::a('#', $result, '', "id='rejectItem'");
|
||||
echo "<ul class='dropdown-menu'>";
|
||||
unset($lang->story->reasonList['']);
|
||||
unset($lang->story->reasonList['subdivided']);
|
||||
unset($lang->story->reasonList['duplicate']);
|
||||
|
||||
foreach($lang->story->reasonList as $key => $reason)
|
||||
{
|
||||
$actionLink = $this->createLink('story', 'batchReview', "result=reject&reason=$key");
|
||||
echo "<li>";
|
||||
echo html::a('#', $reason, '', "onclick=\"setFormAction('$actionLink','hiddenwin')\"");
|
||||
echo "</li>";
|
||||
}
|
||||
echo '</ul></li>';
|
||||
}
|
||||
else
|
||||
{
|
||||
echo '<li>' . html::a('#', $result, '', "onclick=\"setFormAction('$actionLink','hiddenwin')\"") . '</li>';
|
||||
}
|
||||
}
|
||||
echo '</ul></li>';
|
||||
}
|
||||
else
|
||||
{
|
||||
echo '<li>' . html::a('javascript:;', $lang->story->review, '', $class) . '</li>';
|
||||
}
|
||||
|
||||
if(common::hasPriv('story', 'batchAssignTo'))
|
||||
{
|
||||
$withSearch = count($users) > 10;
|
||||
$actionLink = $this->createLink('story', 'batchAssignTo');
|
||||
echo html::select('assignedTo', $users, '', 'class="hidden"');
|
||||
echo "<li class='dropdown-submenu'>";
|
||||
echo html::a('javascript::', $lang->story->assignedTo, '', 'id="assignItem"');
|
||||
echo "<ul class='dropdown-menu" . ($withSearch ? ' with-search':'') . "'>";
|
||||
foreach ($users as $key => $value)
|
||||
{
|
||||
if(empty($key) or $key == 'closed') continue;
|
||||
echo "<li class='option' data-key='$key'>" . html::a("javascript:$(\".table-actions #assignedTo\").val(\"$key\");setFormAction(\"$actionLink\")", $value, '', '') . '</li>';
|
||||
}
|
||||
if($withSearch) echo "<li class='menu-search'><div class='input-group input-group-sm'><input type='text' class='form-control' placeholder=''><span class='input-group-addon'><i class='icon-search'></i></span></div></li>";
|
||||
echo "</ul>";
|
||||
echo "</li>";
|
||||
}
|
||||
else
|
||||
{
|
||||
echo '<li>' . html::a('javascript:;', $lang->story->assignedTo, '', $class) . '</li>';
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
<?php $pager->show();?>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -89,7 +89,7 @@ $lang->product->statusList['normal'] = 'Normal';
|
||||
$lang->product->statusList['closed'] = 'Closed';
|
||||
|
||||
$lang->product->aclList['open'] = "Default({$lang->productCommon} with View permission can access to it)";
|
||||
$lang->product->aclList['private'] = "Private{$lang->productCommon}({$lang->projectCommon}team members only)";
|
||||
$lang->product->aclList['private'] = "Private {$lang->productCommon}({$lang->productCommon} of pesponsible person and {$lang->projectCommon} team members only)";
|
||||
$lang->product->aclList['custom'] = 'Custom(Team members and Whitelisr members have access to it.)';
|
||||
|
||||
$lang->product->storySummary = " <strong>%s</strong> Story in total on this page, <strong>%s</strong> man-hour estimated. Case coverage is <strong>%s</strong>.";
|
||||
@@ -104,5 +104,5 @@ $lang->product->featureBar['browse']['closedbyme'] = $lang->product->closedByM
|
||||
$lang->product->featureBar['browse']['draftstory'] = $lang->product->draftStory;
|
||||
$lang->product->featureBar['browse']['activestory'] = $lang->product->activeStory;
|
||||
$lang->product->featureBar['browse']['changedstory'] = $lang->product->changedStory;
|
||||
$lang->product->featureBar['browse']['willclose'] = $lang->product->willOff;
|
||||
$lang->product->featureBar['browse']['willclose'] = $lang->product->willClose;
|
||||
$lang->product->featureBar['browse']['closedstory'] = $lang->product->closedStory;
|
||||
|
||||
@@ -89,7 +89,7 @@ $lang->product->statusList['normal'] = '正常';
|
||||
$lang->product->statusList['closed'] = '结束';
|
||||
|
||||
$lang->product->aclList['open'] = "默认设置(有{$lang->productCommon}视图权限,即可访问)";
|
||||
$lang->product->aclList['private'] = "私有{$lang->productCommon}(只有{$lang->projectCommon}团队成员才能访问)";
|
||||
$lang->product->aclList['private'] = "私有{$lang->productCommon}(只有{$lang->productCommon}相关负责人和{$lang->projectCommon}团队成员才能访问)";
|
||||
$lang->product->aclList['custom'] = '自定义白名单(团队成员和白名单的成员可以访问)';
|
||||
|
||||
$lang->product->storySummary = "本页共 <strong>%s</strong> 个需求,预计 <strong>%s</strong> 个工时,用例覆盖率<strong>%s</strong>。";
|
||||
|
||||
@@ -23,7 +23,7 @@ extract($widths);
|
||||
<tbody>
|
||||
<?php foreach($stories as $story):?>
|
||||
<tr class='text-center' data-id='<?php echo $story->id?>'>
|
||||
<?php foreach($setting as $key => $value) $this->story->printCell($value, $story, $users, $branches, $storyStages, $modulePairs);?>
|
||||
<?php foreach($setting as $key => $value) $this->story->printCell($value, $story, $users, $branches, $storyStages, $modulePairs, $storyTasks, $storyBugs, $storyCases);?>
|
||||
</tr>
|
||||
<?php endforeach;?>
|
||||
</tbody>
|
||||
|
||||
@@ -83,16 +83,25 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->product->type;?></th>
|
||||
<td><?php echo $lang->product->typeList[$product->type];?></td><td></td>
|
||||
<td><?php echo $lang->product->typeList[$product->type];?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->product->status;?></th>
|
||||
<td class='product-<?php echo $product->status?>'><?php echo $lang->product->statusList[$product->status];?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->story->openedBy?></th>
|
||||
<td><?php echo zget($users, $product->createdBy);?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->story->openedDate?></th>
|
||||
<td><?php echo $product->createdDate;?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->product->acl;?></th>
|
||||
<td><?php echo $lang->product->aclList[$product->acl];?></td>
|
||||
</tr>
|
||||
<?php if($product->acl == 'custom'):?>
|
||||
<tr>
|
||||
<th><?php echo $lang->product->whitelist;?></th>
|
||||
<td>
|
||||
@@ -101,15 +110,8 @@
|
||||
foreach($whitelist as $groupID) if(isset($groups[$groupID])) echo $groups[$groupID] . ' ';
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->story->openedBy?></th>
|
||||
<td><?php echo zget($users, $product->createdBy);?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->story->openedDate?></th>
|
||||
<td><?php echo $product->createdDate;?></td>
|
||||
</tr>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
</table>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
|
||||
@@ -230,7 +230,7 @@ class productplan extends control
|
||||
$this->view->actions = $this->loadModel('action')->getList('productplan', $planID);
|
||||
$this->view->users = $this->loadModel('user')->getPairs('noletter');
|
||||
$this->view->plans = $this->productplan->getPairs($plan->product, $plan->branch);
|
||||
$this->view->modules = array('0' => '/') + $this->loadModel('tree')->getModulePairs($plan->product, 'story');
|
||||
$this->view->modules = $this->loadModel('tree')->getOptionMenu($plan->product);
|
||||
$this->view->type = $type;
|
||||
$this->view->orderBy = $orderBy;
|
||||
$this->view->link = $link;
|
||||
@@ -320,6 +320,7 @@ class productplan extends control
|
||||
$this->view->plans = $this->dao->select('id, end')->from(TABLE_PRODUCTPLAN)->fetchPairs();
|
||||
$this->view->users = $this->loadModel('user')->getPairs('noletter');
|
||||
$this->view->browseType = $browseType;
|
||||
$this->view->modules = $this->loadModel('tree')->getOptionMenu($plan->product);
|
||||
$this->view->param = $param;
|
||||
$this->view->orderBy = $orderBy;
|
||||
$this->display();
|
||||
|
||||
@@ -25,6 +25,7 @@ include '../../common/view/tablesorter.html.php';
|
||||
<th class='w-pri'> <?php echo $lang->priAB;?></th>
|
||||
<th class='w-200px'> <?php echo $lang->story->plan;?></th>
|
||||
<th> <?php echo $lang->story->title;?></th>
|
||||
<th class='w-80px'> <?php echo $lang->story->module;?></th>
|
||||
<th class='w-user'> <?php echo $lang->openedByAB;?></th>
|
||||
<th class='w-user'> <?php echo $lang->assignedToAB;?></th>
|
||||
<th class='w-30px'> <?php echo $lang->story->estimateAB;?></th>
|
||||
@@ -43,6 +44,7 @@ include '../../common/view/tablesorter.html.php';
|
||||
<td><span class='<?php echo 'pri' . zget($lang->story->priList, $story->pri, $story->pri);?>'><?php echo zget($lang->story->priList, $story->pri, $story->pri)?></span></td>
|
||||
<td><?php echo $story->planTitle;?></td>
|
||||
<td class='text-left nobr' title='<?php echo $story->title?>'><?php echo html::a($this->createLink('story', 'view', "storyID=$story->id"), $story->title);?></td>
|
||||
<td title='<?php echo $modules[$story->module]?>'><?php echo $modules[$story->module];?></td>
|
||||
<td><?php echo zget($users, $story->openedBy);?></td>
|
||||
<td><?php echo zget($users, $story->assignedTo);?></td>
|
||||
<td><?php echo $story->estimate;?></td>
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
</td>
|
||||
<td><span class='<?php echo 'pri' . zget($lang->story->priList, $story->pri, $story->pri)?>'><?php echo zget($lang->story->priList, $story->pri, $story->pri);?></span></td>
|
||||
<td class='text-left nobr' title='<?php echo $story->title?>'><?php echo html::a($viewLink , $story->title);?></td>
|
||||
<td><?php echo $modules[$story->module];?></td>
|
||||
<td class='text-left'><?php echo $modules[$story->module];?></td>
|
||||
<td><?php echo zget($users, $story->openedBy);?></td>
|
||||
<td><?php echo zget($users, $story->assignedTo);?></td>
|
||||
<td><?php echo $story->estimate;?></td>
|
||||
@@ -123,35 +123,163 @@
|
||||
<tr>
|
||||
<td colspan='9'>
|
||||
<div class='table-actions clearfix'>
|
||||
<?php
|
||||
if(count($planStories) and ($canBatchUnlink or $canBatchChangePlan))
|
||||
{
|
||||
echo html::selectButton();
|
||||
echo "<div class='btn-group dropup'>";
|
||||
$actionLink = inlink('batchUnlinkStory', "planID=$plan->id&orderBy=$orderBy");
|
||||
echo html::commonButton($lang->productplan->unlinkStory, ($canBatchUnlink ? '' : 'disabled') . "onclick=\"setFormAction('$actionLink', '', this)\"");
|
||||
echo "<button type='button' class='btn dropdown-toggle' data-toggle='dropdown'><span class='caret'></span></button>";
|
||||
echo "<ul class='dropdown-menu'>";
|
||||
echo "<li class='dropdown-submenu'>";
|
||||
echo html::a('javascript:;', $lang->story->planAB, '', "id='changePlan' " . ($canBatchChangePlan ? '' : "class='disabled'"));
|
||||
if($canBatchChangePlan)
|
||||
<?php if(count($planStories)):?>
|
||||
<?php echo html::selectButton();?>
|
||||
<?php
|
||||
$disabled = $canBatchUnlink ? '' : "disabled='disabled'";
|
||||
$actionLink = inlink('batchUnlinkStory', "planID=$plan->id&orderBy=$orderBy");
|
||||
?>
|
||||
<div class='btn-group dropup'>
|
||||
<?php echo html::commonButton($lang->productplan->unlinkStory, ($canBatchUnlink ? '' : 'disabled') . "onclick=\"setFormAction('$actionLink', '', this)\"");?>
|
||||
<button type='button' class='btn dropdown-toggle' data-toggle='dropdown'><span class='caret'></span></button>
|
||||
<ul class='dropdown-menu'>
|
||||
<?php
|
||||
$class = "class='disabled'";
|
||||
|
||||
$canBatchEdit = common::hasPriv('story', 'batchEdit');
|
||||
$actionLink = $this->createLink('story', 'batchEdit', "productID=$plan->product&projectID=0&branch=$branch");
|
||||
$misc = $canBatchEdit ? "onclick=\"setFormAction('$actionLink', '', this)\"" : $class;
|
||||
echo "<li>" . html::a('#', $lang->edit, '', $misc) . "</li>";
|
||||
|
||||
if(common::hasPriv('story', 'batchReview'))
|
||||
{
|
||||
echo "<li class='dropdown-submenu'>";
|
||||
echo html::a('javascript:;', $lang->story->review, '', "id='reviewItem'");
|
||||
echo "<ul class='dropdown-menu'>";
|
||||
unset($lang->story->reviewResultList['']);
|
||||
unset($lang->story->reviewResultList['revert']);
|
||||
foreach($lang->story->reviewResultList as $key => $result)
|
||||
{
|
||||
$actionLink = $this->createLink('story', 'batchReview', "result=$key");
|
||||
if($key == 'reject')
|
||||
{
|
||||
echo "<li class='dropdown-submenu'>";
|
||||
echo html::a('#', $result, '', "id='rejectItem'");
|
||||
echo "<ul class='dropdown-menu'>";
|
||||
unset($lang->story->reasonList['']);
|
||||
unset($lang->story->reasonList['subdivided']);
|
||||
unset($lang->story->reasonList['duplicate']);
|
||||
|
||||
foreach($lang->story->reasonList as $key => $reason)
|
||||
{
|
||||
$actionLink = $this->createLink('story', 'batchReview', "result=reject&reason=$key");
|
||||
echo "<li>";
|
||||
echo html::a('#', $reason, '', "onclick=\"setFormAction('$actionLink','hiddenwin', this)\"");
|
||||
echo "</li>";
|
||||
}
|
||||
echo '</ul></li>';
|
||||
}
|
||||
else
|
||||
{
|
||||
echo '<li>' . html::a('#', $result, '', "onclick=\"setFormAction('$actionLink','hiddenwin', this)\"") . '</li>';
|
||||
}
|
||||
}
|
||||
echo '</ul></li>';
|
||||
}
|
||||
else
|
||||
{
|
||||
echo '<li>' . html::a('javascript:;', $lang->story->review, '', $class) . '</li>';
|
||||
}
|
||||
|
||||
if(common::hasPriv('story', 'batchChangeBranch') and $this->session->currentProductType != 'normal')
|
||||
{
|
||||
$withSearch = count($branches) > 8;
|
||||
echo "<li class='dropdown-submenu'>";
|
||||
echo html::a('javascript:;', $lang->product->branchName[$this->session->currentProductType], '', "id='branchItem'");
|
||||
echo "<ul class='dropdown-menu" . ($withSearch ? ' with-search':'') . "'>";
|
||||
foreach($branches as $branchID => $branchName)
|
||||
{
|
||||
$actionLink = $this->createLink('story', 'batchChangeBranch', "branchID=$branchID");
|
||||
echo "<li class='option' data-key='$branchID'>" . html::a('#', $branchName, '', "onclick=\"setFormAction('$actionLink', 'hiddenwin', this)\"") . "</li>";
|
||||
}
|
||||
if($withSearch) echo "<li class='menu-search'><div class='input-group input-group-sm'><input type='text' class='form-control' placeholder=''><span class='input-group-addon'><i class='icon-search'></i></span></div></li>";
|
||||
echo '</ul></li>';
|
||||
}
|
||||
|
||||
if(common::hasPriv('story', 'batchChangeModule'))
|
||||
{
|
||||
$withSearch = count($modules) > 8;
|
||||
echo "<li class='dropdown-submenu'>";
|
||||
echo html::a('javascript:;', $lang->story->moduleAB, '', "id='moduleItem'");
|
||||
echo "<ul class='dropdown-menu" . ($withSearch ? ' with-search':'') . "'>";
|
||||
foreach($modules as $moduleId => $module)
|
||||
{
|
||||
$actionLink = $this->createLink('story', 'batchChangeModule', "moduleID=$moduleId");
|
||||
echo "<li class='option' data-key='$moduleID'>" . html::a('#', $module, '', "onclick=\"setFormAction('$actionLink','hiddenwin', this)\"") . "</li>";
|
||||
}
|
||||
if($withSearch) echo "<li class='menu-search'><div class='input-group input-group-sm'><input type='text' class='form-control' placeholder=''><span class='input-group-addon'><i class='icon-search'></i></span></div></li>";
|
||||
echo '</ul></li>';
|
||||
}
|
||||
else
|
||||
{
|
||||
echo '<li>' . html::a('javascript:;', $lang->story->moduleAB, '', $class) . '</li>';
|
||||
}
|
||||
|
||||
if(common::hasPriv('story', 'batchChangePlan'))
|
||||
{
|
||||
unset($plans['']);
|
||||
unset($plans[$plan->id]);
|
||||
$plans = array(0 => $lang->null) + $plans;
|
||||
$withSearch = count($plans) > 10;
|
||||
$withSearch = count($plans) > 8;
|
||||
echo "<li class='dropdown-submenu'>";
|
||||
echo html::a('javascript:;', $lang->story->planAB, '', "id='planItem'");
|
||||
echo "<ul class='dropdown-menu" . ($withSearch ? ' with-search':'') . "'>";
|
||||
foreach($plans as $planID => $planName)
|
||||
{
|
||||
$actionLink = $this->createLink('story', 'batchChangePlan', "planID=$planID&oldPlanID=$plan->id");
|
||||
echo "<li class='option' data-key='$planID'>" . html::a('#', $planName, '', "onclick=\"setFormAction('$actionLink', 'hiddenwin', this)\"") . "</li>";
|
||||
echo "<li class='option' data-key='$planID'>" . html::a('#', $planName, '', "onclick=\"setFormAction('$actionLink','hiddenwin', this)\"") . "</li>";
|
||||
}
|
||||
if($withSearch) echo "<li class='menu-search'><div class='input-group input-group-sm'><input type='text' class='form-control' placeholder=''><span class='input-group-addon'><i class='icon-search'></i></span></div></li>";
|
||||
echo '</ul>';
|
||||
echo '</ul></li>';
|
||||
}
|
||||
echo '</li></ul></div>';
|
||||
}
|
||||
?>
|
||||
else
|
||||
{
|
||||
echo '<li>' . html::a('javascript:;', $lang->story->planAB, '', $class) . '</li>';
|
||||
}
|
||||
|
||||
if(common::hasPriv('story', 'batchChangeStage'))
|
||||
{
|
||||
echo "<li class='dropdown-submenu'>";
|
||||
echo html::a('javascript:;', $lang->story->stageAB, '', "id='stageItem'");
|
||||
echo "<ul class='dropdown-menu'>";
|
||||
$lang->story->stageList[''] = $lang->null;
|
||||
foreach($lang->story->stageList as $key => $stage)
|
||||
{
|
||||
$actionLink = $this->createLink('story', 'batchChangeStage', "stage=$key");
|
||||
echo "<li>" . html::a('#', $stage, '', "onclick=\"setFormAction('$actionLink','hiddenwin', this)\"") . "</li>";
|
||||
}
|
||||
echo '</ul></li>';
|
||||
}
|
||||
else
|
||||
{
|
||||
echo '<li>' . html::a('javascript:;', $lang->story->stageAB, '', $class) . '</li>';
|
||||
}
|
||||
|
||||
if(common::hasPriv('story', 'batchAssignTo'))
|
||||
{
|
||||
$withSearch = count($users) > 10;
|
||||
$actionLink = $this->createLink('story', 'batchAssignTo', "productID=$plan->product");
|
||||
echo html::select('assignedTo', $users, '', 'class="hidden"');
|
||||
echo "<li class='dropdown-submenu'>";
|
||||
echo html::a('javascript::', $lang->story->assignedTo, '', 'id="assignItem"');
|
||||
echo "<ul class='dropdown-menu" . ($withSearch ? ' with-search':'') . "'>";
|
||||
foreach ($users as $key => $value)
|
||||
{
|
||||
if(empty($key) or $key == 'closed') continue;
|
||||
echo "<li class='option' data-key='$key'>" . html::a("javascript:$(\".table-actions #assignedTo\").val(\"$key\");setFormAction(\"$actionLink\")", $value, '', '') . '</li>';
|
||||
}
|
||||
if($withSearch) echo "<li class='menu-search'><div class='input-group input-group-sm'><input type='text' class='form-control' placeholder=''><span class='input-group-addon'><i class='icon-search'></i></span></div></li>";
|
||||
echo "</ul>";
|
||||
echo "</li>";
|
||||
}
|
||||
else
|
||||
{
|
||||
echo '<li>' . html::a('javascript:;', $lang->story->assignedTo, '', $class) . '</li>';
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
<div class='text'><?php echo $summary;?></div>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
@@ -3,6 +3,7 @@ $config->project = new stdclass();
|
||||
$config->project->defaultWorkhours = '7.0';
|
||||
$config->project->orderBy = 'isDone,status,order_desc';
|
||||
$config->project->maxBurnDay = '31';
|
||||
$config->project->weekend = '2';
|
||||
|
||||
global $lang, $app;
|
||||
$app->loadLang('task');
|
||||
|
||||
@@ -537,6 +537,7 @@ class project extends control
|
||||
/* Append id for secend sort. */
|
||||
$sort = $this->loadModel('common')->appendOrder($orderBy);
|
||||
|
||||
$queryID = ($type == 'bySearch') ? (int)$param : 0;
|
||||
$project = $this->commonAction($projectID);
|
||||
|
||||
/* Load pager. */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#productsBox {padding: 20px;}
|
||||
#productsBox > .col-sm-4 {padding: 8px 15px; border:1px solid #ddd;margin-bottom:5px; width:32%; margin-right:8px;}
|
||||
#productsBox > .col-sm-4 label {display:block; cursor: pointer;}
|
||||
#productsBox > .col-sm-4:hover {background: #f1f1f1; cursor: pointer;}
|
||||
#productsBox > .col-sm-4.checked, #productsBox > .col-sm-4.checked:hover {background: #E5FFE6; border: 1px solid #229F24;}
|
||||
.row {padding: 20px;}
|
||||
#productsBox .row > .col-sm-4 {padding: 8px 15px; border:1px solid #ddd;margin-bottom:5px; width:32%; margin-right:8px;}
|
||||
#productsBox .row > .col-sm-4 label {display:block; cursor: pointer;}
|
||||
#productsBox .row > .col-sm-4:hover {background: #f1f1f1; cursor: pointer;}
|
||||
#productsBox .row > .col-sm-4.checked, #productsBox .row > .col-sm-4.checked:hover {background: #E5FFE6; border: 1px solid #229F24;}
|
||||
.col-sm-4+.col-sm-4 {margin-left: 0;}
|
||||
|
||||
@@ -44,7 +44,7 @@ function computeDaysDelta(date1, date2)
|
||||
weekEnds = 0;
|
||||
for(i = 0; i < delta; i++)
|
||||
{
|
||||
if(date1.getDay() == 0 || date1.getDay() == 6) weekEnds ++;
|
||||
if((weekend == 2 && date1.getDay() == 6) || date1.getDay() == 0) weekEnds ++;
|
||||
date1 = date1.valueOf();
|
||||
date1 += 1000 * 60 * 60 * 24;
|
||||
date1 = new Date(date1);
|
||||
|
||||
@@ -110,6 +110,8 @@ $lang->project->doc = 'Doc';
|
||||
$lang->project->manageProducts = 'Link ' . $lang->productCommon;
|
||||
$lang->project->linkStory = 'Link Story';
|
||||
$lang->project->unlinkStoryTasks = 'Unlinked Task';
|
||||
$lang->project->linkedProducts = 'Linked products';
|
||||
$lang->project->unlinkedProducts = 'Unlinked products';
|
||||
$lang->project->view = "Info";
|
||||
$lang->project->create = "Add";
|
||||
$lang->project->copy = "Copy {$lang->projectCommon}";
|
||||
|
||||
@@ -110,6 +110,8 @@ $lang->project->doc = '文档列表';
|
||||
$lang->project->manageProducts = '关联' . $lang->productCommon;
|
||||
$lang->project->linkStory = '关联需求';
|
||||
$lang->project->unlinkStoryTasks = '未关联需求任务';
|
||||
$lang->project->linkedProducts = '已关联';
|
||||
$lang->project->unlinkedProducts = '未关联';
|
||||
$lang->project->view = "{$lang->projectCommon}概况";
|
||||
$lang->project->create = "添加{$lang->projectCommon}";
|
||||
$lang->project->copy = "复制{$lang->projectCommon}";
|
||||
|
||||
+14
-18
@@ -1886,45 +1886,41 @@ class projectModel extends model
|
||||
public function getDateList($begin, $end, $type, $interval = '', $format = 'm/d/Y')
|
||||
{
|
||||
$begin = strtotime($begin);
|
||||
$end = strtotime($end);
|
||||
$end = strtotime($end) + 24 * 3600;
|
||||
|
||||
$beginWeekDay = date('w', $begin);
|
||||
$days = ($end - $begin) / 3600 / 24;
|
||||
if($type == 'noweekend')
|
||||
{
|
||||
$mod = $days % 7;
|
||||
$days = $days - floor($days / 7) * 2;
|
||||
$days = $mod == 6 ? $days - 1 : $days;
|
||||
$allDays = $days;
|
||||
$weekDay = $beginWeekDay;
|
||||
for($i = 0; $i < $allDays; $i++, $weekDay++)
|
||||
{
|
||||
$weekDay = $weekDay % 7;
|
||||
if(($this->config->project->weekend == 2 and $weekDay == 6) or $weekDay == 0) $days--;
|
||||
}
|
||||
}
|
||||
|
||||
if(!$interval) $interval = floor($days / $this->config->project->maxBurnDay);
|
||||
|
||||
$dateList = array();
|
||||
$date = $begin;
|
||||
$spaces = (int)$interval;
|
||||
$counter = $spaces;
|
||||
while($date <= $end)
|
||||
$weekDay = $beginWeekDay;
|
||||
for($date = $begin; $date <= $end; $date += 24 * 3600, $weekDay++)
|
||||
{
|
||||
/* Remove weekend when type is noweekend.*/
|
||||
if($type == 'noweekend')
|
||||
{
|
||||
$weekDay = date('w', $date);
|
||||
if($weekDay == 6 or $weekDay == 0)
|
||||
{
|
||||
$date += 24 * 3600;
|
||||
continue;
|
||||
}
|
||||
$weekDay = $weekDay % 7;
|
||||
if(($this->config->project->weekend == 2 and $weekDay == 6) or $weekDay == 0) continue;
|
||||
}
|
||||
|
||||
$counter ++;
|
||||
if($counter <= $spaces)
|
||||
{
|
||||
$date += 24 * 3600;
|
||||
continue;
|
||||
}
|
||||
if($counter <= $spaces) continue;
|
||||
|
||||
$counter = 0;
|
||||
$dateList[] = date($format, $date);
|
||||
$date += 24 * 3600;
|
||||
}
|
||||
|
||||
return array($dateList, $interval);
|
||||
|
||||
@@ -78,4 +78,5 @@ $minWidth = (count($visibleFields) > 5) ? 'w-150px' : '';
|
||||
</form>
|
||||
<?php $customLink = $this->createLink('custom', 'ajaxSaveCustomFields', 'module=project§ion=custom&key=batchEditFields')?>
|
||||
<?php include '../../common/view/customfield.html.php';?>
|
||||
<?php js::set('weekend', $config->project->weekend);?>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
|
||||
@@ -159,4 +159,5 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php js::set('weekend', $config->project->weekend);?>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
|
||||
@@ -140,4 +140,5 @@
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
<?php js::set('weekend', $config->project->weekend);?>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
|
||||
@@ -17,28 +17,55 @@
|
||||
<?php echo html::icon($lang->icons['product']);?> <?php echo $lang->project->manageProducts;?>
|
||||
</div>
|
||||
</div>
|
||||
<form class='form-condensed' method='post'>
|
||||
<div id='productsBox' class='row'>
|
||||
<?php foreach($allProducts as $productID => $productName):?>
|
||||
<?php $checked = isset($linkedProducts[$productID]) ? 'checked' : ''; ?>
|
||||
<div class='col-sm-4 <?php echo $checked?>'>
|
||||
<?php if(isset($branchGroups[$productID])) echo "<div class='col-sm-6' style='padding-left:0px'>"?>
|
||||
<label for='<?php echo 'products'. $productID?>';>
|
||||
<?php echo "<input type='checkbox' name='products[$productID]' value='$productID' $checked id='products{$productID}'> $productName";?>
|
||||
</label>
|
||||
<?php
|
||||
if(isset($branchGroups[$productID]))
|
||||
{
|
||||
echo "</div><div class='col-sm-6'>";
|
||||
echo html::select("branch[$productID]", $branchGroups[$productID], $checked ? $linkedProducts[$productID]->branch : '', "class='from-control chosen'");
|
||||
echo '</div>';
|
||||
}
|
||||
?>
|
||||
<form id='productsBox' class='form-condensed' method='post'>
|
||||
<fieldset>
|
||||
<legend><?php echo $lang->project->linkedProducts;?></legend>
|
||||
<div class='row'>
|
||||
<?php foreach($allProducts as $productID => $productName):?>
|
||||
<?php if(isset($linkedProducts[$productID])):?>
|
||||
<?php $checked = 'checked';?>
|
||||
<div class='col-sm-4 <?php echo $checked?>'>
|
||||
<?php if(isset($branchGroups[$productID])) echo "<div class='col-sm-6' style='padding-left:0px'>"?>
|
||||
<label for='<?php echo 'products'. $productID?>';>
|
||||
<?php echo "<input type='checkbox' name='products[$productID]' value='$productID' $checked id='products{$productID}'> $productName";?>
|
||||
</label>
|
||||
<?php
|
||||
if(isset($branchGroups[$productID]))
|
||||
{
|
||||
echo "</div><div class='col-sm-6'>";
|
||||
echo html::select("branch[$productID]", $branchGroups[$productID], $linkedProducts[$productID]->branch, "class='from-control chosen'");
|
||||
echo '</div>';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php unset($allProducts[$productID]);?>
|
||||
<?php endif;?>
|
||||
<?php endforeach;?>
|
||||
</div>
|
||||
<?php endforeach;?>
|
||||
<?php echo html::hidden("post", 'post');?>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend><?php echo $lang->project->unlinkedProducts;?></legend>
|
||||
<div class='row'>
|
||||
<?php foreach($allProducts as $productID => $productName):?>
|
||||
<div class='col-sm-4'>
|
||||
<?php if(isset($branchGroups[$productID])) echo "<div class='col-sm-6' style='padding-left:0px'>"?>
|
||||
<label for='<?php echo 'products'. $productID?>';>
|
||||
<?php echo "<input type='checkbox' name='products[$productID]' value='$productID' id='products{$productID}'> $productName";?>
|
||||
</label>
|
||||
<?php
|
||||
if(isset($branchGroups[$productID]))
|
||||
{
|
||||
echo "</div><div class='col-sm-6'>";
|
||||
echo html::select("branch[$productID]", $branchGroups[$productID], '', "class='from-control chosen'");
|
||||
echo '</div>';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php endforeach;?>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div class="text-center">
|
||||
<?php echo html::hidden("post", 'post');?>
|
||||
<?php echo html::submitButton();?>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -63,4 +63,5 @@
|
||||
</form>
|
||||
<div class='main'><?php include '../../common/view/action.html.php';?></div>
|
||||
</div>
|
||||
<?php js::set('weekend', $config->project->weekend);?>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
|
||||
@@ -58,6 +58,15 @@
|
||||
<legend><?php echo $lang->project->desc;?></legend>
|
||||
<div class='content'><?php echo $project->desc;?></div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend><?php echo $lang->project->otherInfo?></legend>
|
||||
<table class='table table-data table-condensed table-borderless'>
|
||||
<tr>
|
||||
<th class='w-80px'><?php echo $lang->project->lblStats;?></th>
|
||||
<td><?php printf($lang->project->stats, $project->totalHours, $project->totalEstimate, $project->totalConsumed, $project->totalLeft, 10)?></td>
|
||||
</tr>
|
||||
</table>
|
||||
</fieldset>
|
||||
<?php include '../../common/view/action.html.php';?>
|
||||
<div class='actions'> <?php if(!$project->deleted) echo $actionLinks;?></div>
|
||||
</div>
|
||||
@@ -134,6 +143,7 @@
|
||||
<th><?php echo $lang->project->acl;?></th>
|
||||
<td><?php echo $lang->project->aclList[$project->acl];?></td>
|
||||
</tr>
|
||||
<?php if($project->acl == 'custom'):?>
|
||||
<tr>
|
||||
<th><?php echo $lang->project->whitelist;?></th>
|
||||
<td>
|
||||
@@ -143,15 +153,7 @@
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend><?php echo $lang->project->otherInfo?></legend>
|
||||
<table class='table table-data table-condensed table-borderless'>
|
||||
<tr>
|
||||
<th class='w-80px'><?php echo $lang->project->lblStats;?></th>
|
||||
<td><?php printf($lang->project->stats, $project->totalHours, $project->totalEstimate, $project->totalConsumed, $project->totalLeft, 10)?></td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
</table>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
@@ -196,7 +196,11 @@ class releaseModel extends model
|
||||
if($release->stories)
|
||||
{
|
||||
$this->loadModel('story');
|
||||
foreach($this->post->stories as $storyID) $this->story->setStage($storyID);
|
||||
foreach($this->post->stories as $storyID)
|
||||
{
|
||||
$this->story->setStage($storyID);
|
||||
$this->loadModel('action')->create('story', $storyID, 'linked2release', '', $releaseID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,6 +217,7 @@ class releaseModel extends model
|
||||
$release = $this->getByID($releaseID);
|
||||
$release->stories = trim(str_replace(",$storyID,", ',', ",$release->stories,"), ',');
|
||||
$this->dao->update(TABLE_RELEASE)->set('stories')->eq($release->stories)->where('id')->eq((int)$releaseID)->exec();
|
||||
$this->loadModel('action')->create('story', $storyID, 'unlinkedfromrelease', '', $releaseID);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -232,6 +237,10 @@ class releaseModel extends model
|
||||
foreach($storyList as $storyID) $release->stories = str_replace(",$storyID,", ',', $release->stories);
|
||||
$release->stories = trim($release->stories, ',');
|
||||
$this->dao->update(TABLE_RELEASE)->set('stories')->eq($release->stories)->where('id')->eq((int)$releaseID)->exec();
|
||||
foreach($this->post->unlinkStories as $unlinkStoryID)
|
||||
{
|
||||
$this->loadModel('action')->create('story', $unlinkStoryID, 'unlinkedfromrelease', '', $releaseID);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -248,6 +257,10 @@ class releaseModel extends model
|
||||
$field = $type == 'bug' ? 'bugs' : 'leftBugs';
|
||||
$release->$field .= ',' . join(',', $this->post->bugs);
|
||||
$this->dao->update(TABLE_RELEASE)->set($field)->eq($release->$field)->where('id')->eq((int)$releaseID)->exec();
|
||||
foreach($this->post->bugs as $bugID)
|
||||
{
|
||||
$this->loadModel('action')->create('bug', $bugID, 'linked2release', '', $releaseID);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -264,6 +277,7 @@ class releaseModel extends model
|
||||
$field = $type == 'bug' ? 'bugs' : 'leftBugs';
|
||||
$release->{$field} = trim(str_replace(",$bugID,", ',', ",{$release->$field},"), ',');
|
||||
$this->dao->update(TABLE_RELEASE)->set($field)->eq($release->$field)->where('id')->eq((int)$releaseID)->exec();
|
||||
$this->loadModel('action')->create('bug', $bugID, 'unlinkedfromrelease', '', $releaseID);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -285,6 +299,10 @@ class releaseModel extends model
|
||||
foreach($bugList as $bugID) $release->$field = str_replace(",$bugID,", ',', $release->$field);
|
||||
$release->$field = trim($release->$field, ',');
|
||||
$this->dao->update(TABLE_RELEASE)->set($field)->eq($release->$field)->where('id')->eq((int)$releaseID)->exec();
|
||||
foreach($this->post->unlinkBugs as $unlinkBugID)
|
||||
{
|
||||
$this->loadModel('action')->create('bug', $unlinkBugID, 'unlinkedfromrelease', '', $releaseID);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -113,7 +113,7 @@ class report extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function workload($begin = '', $end = '', $days = 0, $workday = 7, $dept = 0)
|
||||
public function workload($begin = '', $end = '', $days = 0, $workday = 0, $dept = 0)
|
||||
{
|
||||
if($_POST)
|
||||
{
|
||||
@@ -125,13 +125,22 @@ class report extends control
|
||||
$workday = $data->workday;
|
||||
}
|
||||
|
||||
$begin = $begin ? date('Y-m-d', strtotime($begin)) : date('Y-m-d', strtotime('now'));
|
||||
$end = $end ? date('Y-m-d', strtotime($end)) : date('Y-m-d', strtotime('+1 week'));
|
||||
$this->app->loadConfig('project');
|
||||
$begin = $begin ? strtotime($begin) : time();
|
||||
$end = $end ? strtotime($end) : time() + (7 * 24 * 3600);
|
||||
$end += 24 * 2600;
|
||||
$beginWeekDay = date('w', $begin);
|
||||
$begin = date('Y-m-d', $begin);
|
||||
$end = date('Y-m-d', $end);
|
||||
|
||||
if(!$days)
|
||||
if(empty($workday))$workday = $this->config->project->defaultWorkhours;
|
||||
$diffDays = helper::diffDate($end, $begin);
|
||||
$weekDay = $beginWeekDay;
|
||||
$days = $diffDays;
|
||||
for($i = 0; $i < $diffDays; $i++,$weekDay++)
|
||||
{
|
||||
$diffDays = helper::diffDate($end, $begin);
|
||||
$days = round($diffDays - ($diffDays / 7 * 2));
|
||||
$weekDay = $weekDay % 7;
|
||||
if(($this->config->project->weekend == 2 and $weekDay == 6) or $weekDay == 0) $days --;
|
||||
}
|
||||
|
||||
$this->view->title = $this->lang->report->workload;
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<table class='table table-condensed table-striped table-bordered tablesorter table-fixed active-disabled' id="workload">
|
||||
<table class='table table-condensed table-striped table-bordered table-fixed active-disabled' id="workload">
|
||||
<thead>
|
||||
<tr class='colhead'>
|
||||
<th><?php echo $lang->report->user;?></th>
|
||||
|
||||
@@ -89,6 +89,21 @@ $config->story->datatable->fieldList['stage']['fixed'] = 'no';
|
||||
$config->story->datatable->fieldList['stage']['width'] = '90';
|
||||
$config->story->datatable->fieldList['stage']['required'] = 'no';
|
||||
|
||||
$config->story->datatable->fieldList['taskCount']['title'] = 'taskCount';
|
||||
$config->story->datatable->fieldList['taskCount']['fixed'] = 'no';
|
||||
$config->story->datatable->fieldList['taskCount']['width'] = '90';
|
||||
$config->story->datatable->fieldList['taskCount']['required'] = 'no';
|
||||
|
||||
$config->story->datatable->fieldList['bugCount']['title'] = 'bugCount';
|
||||
$config->story->datatable->fieldList['bugCount']['fixed'] = 'no';
|
||||
$config->story->datatable->fieldList['bugCount']['width'] = '90';
|
||||
$config->story->datatable->fieldList['bugCount']['required'] = 'no';
|
||||
|
||||
$config->story->datatable->fieldList['caseCount']['title'] = 'caseCount';
|
||||
$config->story->datatable->fieldList['caseCount']['fixed'] = 'no';
|
||||
$config->story->datatable->fieldList['caseCount']['width'] = '90';
|
||||
$config->story->datatable->fieldList['caseCount']['required'] = 'no';
|
||||
|
||||
$config->story->datatable->fieldList['openedBy']['title'] = 'openedByAB';
|
||||
$config->story->datatable->fieldList['openedBy']['fixed'] = 'no';
|
||||
$config->story->datatable->fieldList['openedBy']['width'] = '80';
|
||||
|
||||
@@ -192,6 +192,7 @@ class story extends control
|
||||
$this->view->keywords = $keywords;
|
||||
$this->view->mailto = $mailto;
|
||||
$this->view->needReview = ($this->app->user->account == $product->PO || $projectID > 0 || $this->config->story->needReview == 0) ? "checked='checked'" : "";
|
||||
if($this->story->checkForceReview()) $this->view->needReview = '';
|
||||
|
||||
$this->display();
|
||||
}
|
||||
@@ -277,6 +278,7 @@ class story extends control
|
||||
$this->view->branch = $branch;
|
||||
$this->view->branches = $this->loadModel('branch')->getPairs($productID);
|
||||
$this->view->needReview = ($this->app->user->account == $product->PO || $this->config->story->needReview == 0) ? 0 : 1;
|
||||
if($this->story->checkForceReview()) $this->view->needReview = 1;
|
||||
|
||||
$this->display();
|
||||
}
|
||||
@@ -492,6 +494,7 @@ class story extends control
|
||||
$this->view->users = $this->user->getPairs('nodeleted|pofirst', $this->view->story->assignedTo);
|
||||
$this->view->position[] = $this->lang->story->change;
|
||||
$this->view->needReview = ($this->app->user->account == $this->view->product->PO || $this->config->story->needReview == 0) ? "checked='checked'" : "";
|
||||
if($this->story->checkForceReview()) $this->view->needReview = '';
|
||||
$this->display();
|
||||
}
|
||||
|
||||
@@ -944,8 +947,9 @@ class story extends control
|
||||
public function cases($storyID)
|
||||
{
|
||||
$this->loadModel('testcase');
|
||||
$this->view->cases = $this->testcase->getStoryCases($storyID);
|
||||
$this->view->users = $this->user->getPairs('noletter');
|
||||
$this->view->cases = $this->testcase->getStoryCases($storyID);
|
||||
$this->view->users = $this->user->getPairs('noletter');
|
||||
$this->view->resultList = array('' => '') + $this->lang->testcase->resultList;
|
||||
$this->display();
|
||||
}
|
||||
|
||||
@@ -1082,7 +1086,7 @@ class story extends control
|
||||
*/
|
||||
public function ajaxGetProjectStories($projectID, $productID = 0, $branch = 0, $moduleID = 0, $storyID = 0, $number = '', $type= 'full')
|
||||
{
|
||||
if($moduleID)
|
||||
if($moduleID)
|
||||
{
|
||||
$moduleID = $this->loadModel('tree')->getStoryModule($moduleID);
|
||||
$moduleID = $this->tree->getAllChildID($moduleID);
|
||||
|
||||
@@ -17,3 +17,6 @@ select {border:1px solid #ccc}
|
||||
.w-230px{width:230px;}
|
||||
|
||||
.colorpicker.input-group-btn > .btn {border-right: none}
|
||||
|
||||
#branch {border-left-width: 0px}
|
||||
#mailtoGroup .chosen-container-single a {border-left-width: 0px}
|
||||
|
||||
@@ -24,6 +24,8 @@ $lang->story->delete = "Delete";
|
||||
$lang->story->view = "Story Details";
|
||||
$lang->story->tasks = "Linked Task";
|
||||
$lang->story->taskCount = 'Tasks';
|
||||
$lang->story->bugCount = 'Bugs';
|
||||
$lang->story->caseCount = 'Testcases';
|
||||
$lang->story->taskCountAB = 'Tasks';
|
||||
$lang->story->bugCountAB = 'Bugs';
|
||||
$lang->story->caseCountAB = 'Cases';
|
||||
@@ -31,6 +33,7 @@ $lang->story->linkStory = 'Link Story';
|
||||
$lang->story->unlinkStory = 'Unlink Story';
|
||||
$lang->story->export = "Export Data";
|
||||
$lang->story->zeroCase = "Zero Case";
|
||||
$lang->story->zeroTask = "Zero Task";
|
||||
$lang->story->reportChart = "Report";
|
||||
$lang->story->batchChangePlan = "Batch Change Planning";
|
||||
$lang->story->batchChangeBranch = "Batch Change Branch";
|
||||
@@ -188,10 +191,14 @@ $lang->story->form->file = 'Files. If there are Story related files, please
|
||||
$lang->story->action = new stdclass();
|
||||
$lang->story->action->reviewed = array('main' => '$date, recorded by <strong>$actor</strong>. Review result is <strong>$extra</strong>.', 'extra' => 'reviewResultList');
|
||||
$lang->story->action->closed = array('main' => '$date, closed by <strong>$actor</strong>. The reasion is <strong>$extra</strong> $appendLink.', 'extra' => 'reasonList');
|
||||
$lang->story->action->linked2plan = array('main' => '$date, linked by <strong>$actor</strong> to Planning <strong>$extra</strong>');
|
||||
$lang->story->action->unlinkedfromplan = array('main' => '$date, removed by <strong>$actor</strong> from Planning <strong>$extra</strong>.');
|
||||
$lang->story->action->linked2project = array('main' => '$date, linked by <strong>$actor</strong> to ' . $lang->projectCommon . ' <strong>$extra</strong>.');
|
||||
$lang->story->action->unlinkedfromproject = array('main' => '$date, removed by <strong>$actor</strong> from ' . $lang->projectCommon . ' <strong>$extra</strong>.');
|
||||
$lang->story->action->linked2plan = array('main' => '$date, linked by <strong>$actor</strong> to Planning <strong>$extra</strong>');
|
||||
$lang->story->action->unlinkedfromplan = array('main' => '$date, removed by <strong>$actor</strong> from Planning <strong>$extra</strong>.');
|
||||
$lang->story->action->linked2project = array('main' => '$date, linked by <strong>$actor</strong> to ' . $lang->projectCommon . ' <strong>$extra</strong>.');
|
||||
$lang->story->action->unlinkedfromproject = array('main' => '$date, removed by <strong>$actor</strong> from ' . $lang->projectCommon . ' <strong>$extra</strong>.');
|
||||
$lang->story->action->linked2build = array('main' => '$date, linked by <strong>$actor</strong> to Build <strong>$extra</strong>');
|
||||
$lang->story->action->unlinkedfrombuild = array('main' => '$date, removed by <strong>$actor</strong> from Build <strong>$extra</strong>.');
|
||||
$lang->story->action->linked2release = array('main' => '$date, linked by <strong>$actor</strong> to Release <strong>$extra</strong>');
|
||||
$lang->story->action->unlinkedfromrelease = array('main' => '$date, removed by <strong>$actor</strong> from Release <strong>$extra</strong>.');
|
||||
$lang->story->action->linkrelatedstory = array('main' => '$date, linked by <strong>$actor</strong> to Story <strong>$extra</strong>.');
|
||||
$lang->story->action->subdividestory = array('main' => '$date, subdivided by <strong>$actor</strong> to Story <strong>$extra</strong>.');
|
||||
$lang->story->action->unlinkrelatedstory = array('main' => '$date, removed by <strong>$actor</strong> from Story <strong>$extra</strong>.');
|
||||
|
||||
@@ -24,6 +24,8 @@ $lang->story->delete = "删除";
|
||||
$lang->story->view = "需求详情";
|
||||
$lang->story->tasks = "相关任务";
|
||||
$lang->story->taskCount = '任务数';
|
||||
$lang->story->bugCount = 'Bug数';
|
||||
$lang->story->caseCount = '用例数';
|
||||
$lang->story->taskCountAB = '任';
|
||||
$lang->story->bugCountAB = 'Bug';
|
||||
$lang->story->caseCountAB = '用';
|
||||
@@ -31,6 +33,7 @@ $lang->story->linkStory = '关联需求';
|
||||
$lang->story->unlinkStory = '移除相关需求';
|
||||
$lang->story->export = "导出数据";
|
||||
$lang->story->zeroCase = "零用例需求";
|
||||
$lang->story->zeroTask = "零任务需求";
|
||||
$lang->story->reportChart = "统计报表";
|
||||
$lang->story->batchChangePlan = "批量修改计划";
|
||||
$lang->story->batchChangeBranch = "批量修改分支";
|
||||
@@ -188,10 +191,14 @@ $lang->story->form->file = '附件,如果该需求有相关文件,请
|
||||
$lang->story->action = new stdclass();
|
||||
$lang->story->action->reviewed = array('main' => '$date, 由 <strong>$actor</strong> 记录评审结果,结果为 <strong>$extra</strong>。', 'extra' => 'reviewResultList');
|
||||
$lang->story->action->closed = array('main' => '$date, 由 <strong>$actor</strong> 关闭,原因为 <strong>$extra</strong> $appendLink。', 'extra' => 'reasonList');
|
||||
$lang->story->action->linked2plan = array('main' => '$date, 由 <strong>$actor</strong> 关联到计划 <strong>$extra</strong>。');
|
||||
$lang->story->action->unlinkedfromplan = array('main' => '$date, 由 <strong>$actor</strong> 从计划 <strong>$extra</strong> 移除。');
|
||||
$lang->story->action->linked2project = array('main' => '$date, 由 <strong>$actor</strong> 关联到' . $lang->projectCommon . ' <strong>$extra</strong>。');
|
||||
$lang->story->action->unlinkedfromproject = array('main' => '$date, 由 <strong>$actor</strong> 从' . $lang->projectCommon . ' <strong>$extra</strong> 移除。');
|
||||
$lang->story->action->linked2plan = array('main' => '$date, 由 <strong>$actor</strong> 关联到计划 <strong>$extra</strong>。');
|
||||
$lang->story->action->unlinkedfromplan = array('main' => '$date, 由 <strong>$actor</strong> 从计划 <strong>$extra</strong> 移除。');
|
||||
$lang->story->action->linked2project = array('main' => '$date, 由 <strong>$actor</strong> 关联到' . $lang->projectCommon . ' <strong>$extra</strong>。');
|
||||
$lang->story->action->unlinkedfromproject = array('main' => '$date, 由 <strong>$actor</strong> 从' . $lang->projectCommon . ' <strong>$extra</strong> 移除。');
|
||||
$lang->story->action->linked2build = array('main' => '$date, 由 <strong>$actor</strong> 关联到版本 <strong>$extra</strong>。');
|
||||
$lang->story->action->unlinkedfrombuild = array('main' => '$date, 由 <strong>$actor</strong> 从版本 <strong>$extra</strong> 移除。');
|
||||
$lang->story->action->linked2release = array('main' => '$date, 由 <strong>$actor</strong> 关联到发布 <strong>$extra</strong>。');
|
||||
$lang->story->action->unlinkedfromrelease = array('main' => '$date, 由 <strong>$actor</strong> 从发布 <strong>$extra</strong> 移除。');
|
||||
$lang->story->action->linkrelatedstory = array('main' => '$date, 由 <strong>$actor</strong> 关联相关需求 <strong>$extra</strong>。');
|
||||
$lang->story->action->subdividestory = array('main' => '$date, 由 <strong>$actor</strong> 细分为需求 <strong>$extra</strong>。');
|
||||
$lang->story->action->unlinkrelatedstory = array('main' => '$date, 由 <strong>$actor</strong> 移除相关需求 <strong>$extra</strong>。');
|
||||
|
||||
+35
-2
@@ -165,6 +165,7 @@ class storyModel extends model
|
||||
$result = $this->loadModel('common')->removeDuplicate('story', $story, "product={$story->product}");
|
||||
if($result['stop']) return array('status' => 'exists', 'id' => $result['duplicate']);
|
||||
|
||||
if($this->checkForceReview()) $story->status = 'draft';
|
||||
$story = $this->loadModel('file')->processEditor($story, $this->config->story->editor->create['id'], $this->post->uid);
|
||||
$this->dao->insert(TABLE_STORY)->data($story, 'spec,verify')->autoCheck()->batchCheck($this->config->story->create->requiredFields, 'notempty')->exec();
|
||||
if(!dao::isError())
|
||||
@@ -265,6 +266,7 @@ class storyModel extends model
|
||||
|
||||
if(isset($stories->uploadImage)) $this->loadModel('file');
|
||||
|
||||
$forceReview = $this->checkForceReview();
|
||||
for($i = 0; $i < $batchNum; $i++)
|
||||
{
|
||||
if(!empty($stories->title[$i]))
|
||||
@@ -277,7 +279,7 @@ class storyModel extends model
|
||||
$data->source = $stories->source[$i];
|
||||
$data->pri = $stories->pri[$i];
|
||||
$data->estimate = $stories->estimate[$i];
|
||||
$data->status = $stories->needReview[$i] == 0 ? 'active' : 'draft';
|
||||
$data->status = ($stories->needReview[$i] == 0 and !$forceReview) ? 'active' : 'draft';
|
||||
$data->keywords = $stories->keywords[$i];
|
||||
$data->product = $productID;
|
||||
$data->branch = $branch;
|
||||
@@ -394,6 +396,7 @@ class storyModel extends model
|
||||
->stripTags($this->config->story->editor->change['id'], $this->config->allowedTags)
|
||||
->remove('files,labels,comment,needNotReview,uid')
|
||||
->get();
|
||||
if($this->checkForceReview()) $story->status = 'changed';
|
||||
$story = $this->loadModel('file')->processEditor($story, $this->config->story->editor->change['id'], $this->post->uid);
|
||||
$this->dao->update(TABLE_STORY)->data($story, 'spec,verify')
|
||||
->autoCheck()
|
||||
@@ -2152,10 +2155,14 @@ class storyModel extends model
|
||||
* @param array $users
|
||||
* @param array $branches
|
||||
* @param array $storyStages
|
||||
* @param array $modulePairs
|
||||
* @param array $storyTasks
|
||||
* @param array $storyBugs
|
||||
* @param array $storyCases
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function printCell($col, $story, $users, $branches, $storyStages, $modulePairs = array())
|
||||
public function printCell($col, $story, $users, $branches, $storyStages, $modulePairs = array(), $storyTasks, $storyBugs, $storyCases)
|
||||
{
|
||||
$storyLink = helper::createLink('story', 'view', "storyID=$story->id");
|
||||
$account = $this->app->user->account;
|
||||
@@ -2214,6 +2221,18 @@ class storyModel extends model
|
||||
echo "</div>";
|
||||
}
|
||||
break;
|
||||
case 'taskCount':
|
||||
$tasksLink = helper::createLink('story', 'tasks', "storyID=$story->id");
|
||||
$storyTasks[$story->id] > 0 ? print(html::a($tasksLink, $storyTasks[$story->id], '', 'class="iframe"')) : print(0);
|
||||
break;
|
||||
case 'bugCount':
|
||||
$bugsLink = helper::createLink('story', 'bugs', "storyID=$story->id");
|
||||
$storyBugs[$story->id] > 0 ? print(html::a($bugsLink, $storyBugs[$story->id], '', 'class="iframe"')) : print(0);
|
||||
break;
|
||||
case 'caseCount':
|
||||
$casesLink = helper::createLink('story', 'cases', "storyID=$story->id");
|
||||
$storyCases[$story->id] > 0 ? print(html::a($casesLink, $storyCases[$story->id], '', 'class="iframe"')) : print(0);
|
||||
break;
|
||||
case 'openedBy':
|
||||
echo zget($users, $story->openedBy, $story->openedBy);
|
||||
break;
|
||||
@@ -2273,4 +2292,18 @@ class storyModel extends model
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check force review for user.
|
||||
*
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function checkForceReview()
|
||||
{
|
||||
$forceReview = false;
|
||||
if(!empty($this->config->story->forceReview)) $forceReview = strpos(",{$this->config->story->forceReview},", ",{$this->app->user->account},") !== false;
|
||||
|
||||
return $forceReview;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,6 +89,11 @@ $config->task->datatable->fieldList['left']['fixed'] = 'no';
|
||||
$config->task->datatable->fieldList['left']['width'] = '40';
|
||||
$config->task->datatable->fieldList['left']['required'] = 'no';
|
||||
|
||||
$config->task->datatable->fieldList['progess']['title'] = 'progess';
|
||||
$config->task->datatable->fieldList['progess']['fixed'] = 'no';
|
||||
$config->task->datatable->fieldList['progess']['width'] = '40';
|
||||
$config->task->datatable->fieldList['progess']['required'] = 'no';
|
||||
|
||||
$config->task->datatable->fieldList['deadline']['title'] = 'deadlineAB';
|
||||
$config->task->datatable->fieldList['deadline']['fixed'] = 'no';
|
||||
$config->task->datatable->fieldList['deadline']['width'] = '70';
|
||||
|
||||
@@ -199,14 +199,15 @@ class task extends control
|
||||
$position[] = $this->lang->task->common;
|
||||
$position[] = $this->lang->task->batchCreate;
|
||||
|
||||
$this->view->title = $title;
|
||||
$this->view->position = $position;
|
||||
$this->view->project = $project;
|
||||
$this->view->stories = $stories;
|
||||
$this->view->modules = $modules;
|
||||
$this->view->storyID = $storyID;
|
||||
$this->view->story = $this->loadModel('story')->getByID($storyID);
|
||||
$this->view->members = $members;
|
||||
$this->view->title = $title;
|
||||
$this->view->position = $position;
|
||||
$this->view->project = $project;
|
||||
$this->view->stories = $stories;
|
||||
$this->view->modules = $modules;
|
||||
$this->view->storyID = $storyID;
|
||||
$this->view->story = $this->story->getByID($storyID);
|
||||
$this->view->storyTasks = $this->task->getStoryTaskCounts(array_keys($stories), $projectID);
|
||||
$this->view->members = $members;
|
||||
$this->display();
|
||||
}
|
||||
|
||||
|
||||
@@ -7,3 +7,8 @@
|
||||
.chosen-container[id^="story"] {width: 200px;}
|
||||
.chosen-container[id^="story"] .chosen-drop {min-width: 450px;!important}
|
||||
.chosen-container[id^="module"] .chosen-drop {min-width: 400px;!important}
|
||||
|
||||
#zeroTaskStory{background-color: #fafafa; color: #808080; padding: 5px 8px; text-align: center; margin-left: 10px; border: 1px solid #ddd; }
|
||||
#zeroTaskStory .icon{display:none;}
|
||||
#zeroTaskStory.zeroTask {background-color: #114f8e; color: #fff; border-color: #114f8e; }
|
||||
#zeroTaskStory.zeroTask .icon{display:inline;}
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
#mailto + .chosen-container-multi .chosen-choices {border-top-left-radius: 0; border-bottom-left-radius: 0}
|
||||
|
||||
#mailtoGroup .input-group-btn > .btn {margin-left: -1px!important;}
|
||||
#mailtoGroup .chosen-container-single a {border-left-width: 0px;}
|
||||
|
||||
.chosen-container {max-width: 980px}
|
||||
|
||||
.minw-80px {min-width: 80px;}
|
||||
.minw-60px {min-width: 60px;}
|
||||
.minw-80px {min-width: 120px;}
|
||||
.minw-60px {min-width: 50px;}
|
||||
|
||||
|
||||
@@ -12,8 +12,20 @@ function setStories(moduleID, projectID, num)
|
||||
var storyID = $('#story' + num).val();
|
||||
if(!stories) stories = '<select id="story' + num + '" name="story[' + num + ']" class="form-control"></select>';
|
||||
$('#story' + num).replaceWith(stories);
|
||||
if(moduleID == 0) $('#story' + num).append("<option value='ditto'>" + ditto + "</option>")
|
||||
if(moduleID == 0) $('#story' + num).append("<option value='ditto'>" + ditto + "</option>");
|
||||
$('#story' + num).val(storyID);
|
||||
if($('#zeroTaskStory').hasClass('zeroTask'))
|
||||
{
|
||||
$('#story' + num).find('option').each(function()
|
||||
{
|
||||
value = $(this).attr('value');
|
||||
if(value != 'ditto' && storyTasks[value] > 0)
|
||||
{
|
||||
$(this).hide();
|
||||
if(storyID == value) $('#story' + num).val('');
|
||||
}
|
||||
})
|
||||
}
|
||||
$("#story" + num + "_chosen").remove();
|
||||
$("#story" + num).chosen(defaultChosenOptions);
|
||||
});
|
||||
@@ -44,6 +56,38 @@ function setStoryRelated(num)
|
||||
}
|
||||
}
|
||||
|
||||
/* Toggle zero task story. */
|
||||
function toggleZeroTaskStory()
|
||||
{
|
||||
if($('#zeroTaskStory').hasClass('zeroTask'))
|
||||
{
|
||||
$('#zeroTaskStory').removeClass('zeroTask');
|
||||
zeroTask = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#zeroTaskStory').addClass('zeroTask');
|
||||
zeroTask = true;
|
||||
}
|
||||
$.cookie('zeroTask', zeroTask, {expires:config.cookieLife, path:config.webRoot});
|
||||
$('select[name^="story"]').each(function()
|
||||
{
|
||||
selectVal = $(this).val();
|
||||
$(this).find('option').each(function()
|
||||
{
|
||||
value = $(this).attr('value');
|
||||
$(this).show();
|
||||
if(value != 'ditto' && storyTasks[value] > 0 && zeroTask)
|
||||
{
|
||||
$(this).hide();
|
||||
if(selectVal == value) selectVal = '';
|
||||
}
|
||||
})
|
||||
$(this).val(selectVal);
|
||||
$(this).trigger("chosen:updated");
|
||||
})
|
||||
}
|
||||
|
||||
$(document).on('click', '.chosen-with-drop', function()
|
||||
{
|
||||
var select = $(this).prev('select');
|
||||
@@ -94,4 +138,5 @@ $(function()
|
||||
/* Adjust width for ie chosen width. */
|
||||
$('#module0_chosen').width($('#module1_chosen').width());
|
||||
$('#story0_chosen').width($('#story1_chosen').width());
|
||||
if($.cookie('zeroTask') == 'true') toggleZeroTaskStory();
|
||||
})
|
||||
|
||||
@@ -93,6 +93,19 @@ function setAfter()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load stories.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function loadStories(projectID)
|
||||
{
|
||||
moduleID = $('#module').val();
|
||||
setStories(moduleID, projectID);
|
||||
}
|
||||
|
||||
/**
|
||||
* load stories of module.
|
||||
*
|
||||
|
||||
@@ -90,6 +90,8 @@ $lang->task->editEstimate = 'Edit Man-Hour';
|
||||
$lang->task->deleteEstimate = 'Delete Man-Hour';
|
||||
$lang->task->colorTag = 'Color Tag';
|
||||
$lang->task->files = 'Files';
|
||||
$lang->task->hasConsumed = 'Has Consumed';
|
||||
$lang->task->thisConsume = 'This Consumption';
|
||||
|
||||
$lang->task->ditto = 'Ditto';
|
||||
$lang->task->dittoNotice = "This Task does not belong to the Project as the previous one does!";
|
||||
@@ -146,6 +148,7 @@ $lang->task->remindBug = "This Task is converted from a Bug. Do you
|
||||
$lang->task->confirmChangeProject = "If you change {$lang->projectCommon}, the related Module, Story and Assignor will be changed. Do you want to do it?";
|
||||
$lang->task->confirmFinish = '"Estimated reamin hour" is 0. Do you want to change the Status to "Done"?';
|
||||
$lang->task->confirmRecord = '"Remain hour" is 0. Do you want to set Task as "Done"?';
|
||||
$lang->task->noticeLinkStory = "No story to be linked, you can %s for this project, then %s";
|
||||
$lang->task->noticeSaveRecord = 'Your man-hour is not saved. Please save it first.';
|
||||
$lang->task->commentActions = '%s. %s, commented by <strong>%s</strong>.';
|
||||
|
||||
|
||||
@@ -90,6 +90,8 @@ $lang->task->editEstimate = '编辑工时';
|
||||
$lang->task->deleteEstimate = '删除工时';
|
||||
$lang->task->colorTag = '颜色标签';
|
||||
$lang->task->files = '附件';
|
||||
$lang->task->hasConsumed = '已消耗';
|
||||
$lang->task->thisConsume = '本次消耗';
|
||||
|
||||
$lang->task->ditto = '同上';
|
||||
$lang->task->dittoNotice = "该任务与上一任务不属于同一项目!";
|
||||
@@ -146,6 +148,7 @@ $lang->task->remindBug = "该任务为Bug转化得到,是否更新
|
||||
$lang->task->confirmChangeProject = "修改{$lang->projectCommon}会导致相应的所属模块、相关需求和指派人发生变化,确定吗?";
|
||||
$lang->task->confirmFinish = '"预计剩余"为0,确认将任务状态改为"已完成"吗?';
|
||||
$lang->task->confirmRecord = '"剩余"为0,任务将标记为"已完成",您确定吗?';
|
||||
$lang->task->noticeLinkStory = "没有可关联的相关需求,您可以为当前项目%s,然后%s";
|
||||
$lang->task->noticeSaveRecord = '您有尚未保存的工时记录,请先将其保存。';
|
||||
$lang->task->commentActions = '%s. %s, 由 <strong>%s</strong> 添加备注。';
|
||||
|
||||
|
||||
+10
-6
@@ -645,7 +645,6 @@ class taskModel extends model
|
||||
public function finish($taskID)
|
||||
{
|
||||
$oldTask = $this->getById($taskID);
|
||||
if($this->post->consumed < $oldTask->consumed) die(js::error($this->lang->task->error->consumedSmall));
|
||||
$now = helper::now();
|
||||
$task = fixer::input('post')
|
||||
->setDefault('left', 0)
|
||||
@@ -654,22 +653,24 @@ class taskModel extends model
|
||||
->setDefault('status', 'done')
|
||||
->setDefault('finishedBy, lastEditedBy', $this->app->user->account)
|
||||
->setDefault('finishedDate, lastEditedDate', $now)
|
||||
->remove('comment,files,labels')
|
||||
->remove('comment,files,labels,thisConsume')
|
||||
->get();
|
||||
if($task->finishedDate == substr($now, 0, 10)) $task->finishedDate = $now;
|
||||
if(!isset($task->consumed)) $task->consumed = $oldTask->consumed + $this->post->thisConsume;
|
||||
|
||||
if(!is_numeric($task->consumed)) die(js::error($this->lang->task->error->consumedNumber));
|
||||
|
||||
/* Record consumed and left. */
|
||||
$consumed = $task->consumed - $oldTask->consumed;
|
||||
$consumed = $task->consumed - $oldTask->consumed;
|
||||
if($consumed < 0) die(js::error($this->lang->task->error->consumedSmall));
|
||||
$estimate = fixer::input('post')
|
||||
->setDefault('account', $this->app->user->account)
|
||||
->setDefault('task', $taskID)
|
||||
->setDefault('date', date(DT_DATE1))
|
||||
->setDefault('left', 0)
|
||||
->remove('finishedDate,comment,assignedTo,files,labels')
|
||||
->remove('finishedDate,comment,assignedTo,files,labels,consumed,thisConsume')
|
||||
->get();
|
||||
$estimate->consumed = $estimate->consumed - $oldTask->consumed;
|
||||
$estimate->consumed = $consumed;
|
||||
if($estimate->consumed) $this->addTaskEstimate($estimate);
|
||||
|
||||
$this->dao->update(TABLE_TASK)->data($task)
|
||||
@@ -990,7 +991,7 @@ class taskModel extends model
|
||||
*/
|
||||
public function getStoryTasks($storyID, $projectID = 0)
|
||||
{
|
||||
return $this->dao->select('id, name, assignedTo, status, estimate, consumed, `left`')
|
||||
return $this->dao->select('id, name, assignedTo, pri, status, estimate, consumed, `left`')
|
||||
->from(TABLE_TASK)
|
||||
->where('story')->eq((int)$storyID)
|
||||
->andWhere('deleted')->eq(0)
|
||||
@@ -1623,6 +1624,9 @@ class taskModel extends model
|
||||
case 'left':
|
||||
echo round($task->left, 1);
|
||||
break;
|
||||
case 'progess':
|
||||
echo $task->progess . '%';
|
||||
break;
|
||||
case 'deadline':
|
||||
if(substr($task->deadline, 0, 4) > 0) echo substr($task->deadline, 5, 6);
|
||||
break;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
<div class='heading'>
|
||||
<span class='prefix'><?php echo html::icon($lang->icons['task']);?></span>
|
||||
<strong><small class='text-muted'><?php echo html::icon($lang->icons['batchCreate']);?></small> <?php echo $lang->task->batchCreate . $lang->task->common;?></strong>
|
||||
<span><small><a href='javascript:toggleZeroTaskStory();' id='zeroTaskStory'><?php echo $lang->story->zeroTask;?><i class='icon icon-remove'></i></a></small></span>
|
||||
<div class='actions'>
|
||||
<?php echo html::commonButton($lang->pasteText, "data-toggle='myModal'")?>
|
||||
<button type="button" class="btn btn-default" data-toggle="customModal"><i class='icon icon-cog'></i> </button>
|
||||
@@ -126,6 +127,7 @@ foreach(explode(',', $showFields) as $field)
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php js::set('storyTasks', $storyTasks);?>
|
||||
<?php js::set('mainField', 'name');?>
|
||||
<?php js::set('ditto', $lang->task->ditto);?>
|
||||
<?php $customLink = $this->createLink('custom', 'ajaxSaveCustomFields', 'module=task§ion=custom&key=batchCreateFields')?>
|
||||
|
||||
@@ -47,8 +47,12 @@
|
||||
<th><?php echo $lang->task->story;?></th>
|
||||
<td colspan='3'>
|
||||
<div class='input-group'>
|
||||
<?php if(empty($stories)):?>
|
||||
<span id='story'><?php printf($lang->task->noticeLinkStory, html::a($this->createLink('project', 'linkStory', "projectID=$project->id"), $lang->project->linkStory, '_blank'), html::a("javascript:loadStories($project->id)", $lang->refresh));?></span>
|
||||
<?php else:?>
|
||||
<?php echo html::select('story', $stories, $task->story, "class='form-control chosen' onchange='setStoryRelated();'");?>
|
||||
<span class='input-group-btn' id='preview'><a href='#' class='btn iframe'><?php echo $lang->preview;?></a></span>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -110,12 +114,12 @@
|
||||
<tr>
|
||||
<th><?php echo $lang->task->desc;?></th>
|
||||
<td colspan='3'><?php echo html::textarea('desc', $task->desc, "rows='10' class='form-control'");?></td>
|
||||
</tr>
|
||||
<?php
|
||||
$hiddenEstStarted = strpos(",$showFields,", ',estStarted,') === false;
|
||||
$hiddenDeadline = strpos(",$showFields,", ',deadline,') === false;
|
||||
$hiddenMailto = strpos(",$showFields,", ',mailto,') === false;
|
||||
?>
|
||||
</tr>
|
||||
<?php
|
||||
$hiddenEstStarted = strpos(",$showFields,", ',estStarted,') === false;
|
||||
$hiddenDeadline = strpos(",$showFields,", ',deadline,') === false;
|
||||
$hiddenMailto = strpos(",$showFields,", ',mailto,') === false;
|
||||
?>
|
||||
<?php if(!$hiddenEstStarted or !$hiddenDeadline or !$hiddenMailto):?>
|
||||
<tr>
|
||||
<th><?php echo ($hiddenEstStarted and $hiddenDeadline) ? $lang->task->mailto : $lang->task->datePlan;?></th>
|
||||
|
||||
@@ -23,8 +23,12 @@
|
||||
<form class='form-condensed' method='post' enctype='multipart/form-data' target='hiddenwin'>
|
||||
<table class='table table-form'>
|
||||
<tr>
|
||||
<th class='w-80px'><?php echo $lang->task->consumed;?></th>
|
||||
<td class='w-p25-f'><div class='input-group'><?php echo html::input('consumed', $task->consumed, "class='form-control'");?> <span class='input-group-addon'><?php echo $lang->task->hour;?></span></div></td><td></td>
|
||||
<th class='w-80px'><?php echo $lang->task->hasConsumed;?></th>
|
||||
<td class='w-p25-f'> <?php echo $task->consumed;?> <?php echo $lang->workingHour;?></td><td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->task->thisConsume;?></th>
|
||||
<td><div class='input-group'><?php echo html::input('thisConsume', 0, "class='form-control'");?> <span class='input-group-addon'><?php echo $lang->task->hour;?></span></div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->task->assignedTo;?></th>
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<td class='w-p25-f'><div class='datepicker-wrapper datepicker-date'><?php echo html::input('realStarted', $task->realStarted == '0000-00-00' ? helper::today() : $task->realStarted, "class='form-control form-date'");?></div></td><td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->task->consumed;?></th>
|
||||
<th><?php echo $lang->task->thisConsume;?></th>
|
||||
<td><div class='input-group'><?php echo html::input('consumed', $task->consumed, "class='form-control'");?> <span class='input-group-addon'><?php echo $lang->task->hour;?></span></div></td><td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
@@ -33,3 +33,5 @@
|
||||
.minw-80px {min-width: 80px;}
|
||||
|
||||
.colorpicker.input-group-btn > .btn {border-right: none}
|
||||
|
||||
#branch {border-left-width: 0px;}
|
||||
|
||||
@@ -391,7 +391,7 @@ class testcaseModel extends model
|
||||
*/
|
||||
public function getStoryCases($storyID)
|
||||
{
|
||||
return $this->dao->select('id, title, type, status, lastRunner, lastRunDate, lastRunResult')
|
||||
return $this->dao->select('id, title, pri, type, status, lastRunner, lastRunDate, lastRunResult')
|
||||
->from(TABLE_CASE)
|
||||
->where('story')->eq((int)$storyID)
|
||||
->andWhere('deleted')->eq(0)
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
#mailtoGroup .input-group-btn > .btn {margin-left: -1px!important;}
|
||||
#mailtoGroup .chosen-container-single a {border-left-width: 0px;}
|
||||
|
||||
+9
-12
@@ -820,35 +820,32 @@ class user extends control
|
||||
{
|
||||
if(!isset($_SESSION['resetFileName']))
|
||||
{
|
||||
$resetFileName = $this->app->getBasePath() . 'www' . DIRECTORY_SEPARATOR . uniqid('reset_') . '.txt';
|
||||
$resetFileName = $this->app->getBasePath() . 'tmp' . DIRECTORY_SEPARATOR . uniqid('reset_') . '.txt';
|
||||
$this->session->set('resetFileName', $resetFileName);
|
||||
}
|
||||
|
||||
$resetFileName = $this->session->resetFileName;
|
||||
$this->view->title = $this->lang->user->resetPassword;
|
||||
|
||||
$status = '';
|
||||
if(!file_exists($resetFileName) or (time() - filemtime($resetFileName)) > 60 * 2) $status = 'createFile';
|
||||
$needCreateFile = false;
|
||||
if(!file_exists($resetFileName) or (time() - filemtime($resetFileName)) > 60 * 2) $needCreateFile = true;
|
||||
|
||||
if($_POST)
|
||||
{
|
||||
if($status == 'createFile') die(js::reload('parent'));
|
||||
if($needCreateFile) die(js::reload('parent'));
|
||||
|
||||
$result = $this->user->resetPassword();
|
||||
if(dao::isError()) die(js::error(dao::getError()));
|
||||
if(!$result) die(js::alert($this->lang->user->resetFail));
|
||||
|
||||
echo js::alert($this->lang->user->resetSuccess);
|
||||
die(js::locate(inlink('logout'), 'parent'));
|
||||
$referer = $this->server->http_host . $this->createLink('index', 'index');
|
||||
$referer = helper::safe64Encode($referer);
|
||||
die(js::locate(inlink('logout', $referer), 'parent'));
|
||||
}
|
||||
|
||||
if($status == 'createFile')
|
||||
{
|
||||
$this->view->status = $status;
|
||||
die($this->display());
|
||||
}
|
||||
|
||||
$this->view->status = 'reset';
|
||||
$this->view->status = 'reset';
|
||||
$this->view->needCreateFile = $needCreateFile;
|
||||
$this->display();
|
||||
}
|
||||
|
||||
|
||||
@@ -158,8 +158,8 @@ $lang->user->contacts->or = ' or ';
|
||||
|
||||
$lang->user->resetFail = "Reset failed. Please check the account";
|
||||
$lang->user->resetSuccess = "Password reset! Please use your new password to login.";
|
||||
$lang->user->noticeResetFile = "<h5>For security reason, your Administrator account has to be verified.</h5>
|
||||
<h5>Please login into your Zentao host and create the %s file.</h5>
|
||||
$lang->user->noticeResetFile = "<h5>If you are not Administrator, please contact Administrator to reset your password.</h5>
|
||||
<h5>If you are, please login into your Zentao host and create the %s file.</h5>
|
||||
<p>Note:</p>
|
||||
<ol>
|
||||
<li>Keep the ok.txt empty.</li>
|
||||
|
||||
@@ -158,8 +158,8 @@ $lang->user->contacts->or = ' 或者 ';
|
||||
|
||||
$lang->user->resetFail = "重置密码失败,检查用户名是否存在!";
|
||||
$lang->user->resetSuccess = "重置密码成功,请用新密码登录。";
|
||||
$lang->user->noticeResetFile = '<h5>为了安全起见,系统需要确认您的管理员身份</h5>
|
||||
<h5>请登录禅道所在的服务器,创建%s文件。</h5>
|
||||
$lang->user->noticeResetFile = '<h5>普通用户请联系管理员重置密码</h5>
|
||||
<h5>管理员请登录禅道所在的服务器,创建%s文件。</h5>
|
||||
<p>注意:</p>
|
||||
<ol>
|
||||
<li>文件内容为空。</li>
|
||||
|
||||
@@ -11,40 +11,48 @@
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.lite.html.php';?>
|
||||
<?php if($status == 'createFile'):?>
|
||||
<?php if($needCreateFile):?>
|
||||
<div class='container mw-700px' style='margin-top:100px;'>
|
||||
<div class='panel-body'>
|
||||
<?php printf($lang->user->noticeResetFile, $this->session->resetFileName);?>
|
||||
<div class='panel'>
|
||||
<div class='panel-heading'>
|
||||
<strong><?php echo $lang->user->resetPassword?></strong>
|
||||
</div>
|
||||
<div class='panel-body'>
|
||||
<div class='alert alert-info'>
|
||||
<?php printf($lang->user->noticeResetFile, $this->session->resetFileName);?>
|
||||
</div>
|
||||
<p><?php echo html::a(inlink('reset'), $this->lang->refresh, '', "class='btn'")?></p>
|
||||
</div>
|
||||
</div>
|
||||
<p><?php echo html::a(inlink('reset'), $this->lang->refresh, '', "class='btn'")?></p>
|
||||
</div>
|
||||
<?php elseif($status == 'reset'):?>
|
||||
<div class='container mw-500px' style='margin-top:50px;'>
|
||||
<div class='panel'>
|
||||
<div class='panel-heading'>
|
||||
<strong><?php echo $lang->user->resetPassword?></strong>
|
||||
</div>
|
||||
<form method='post' target='hiddenwin'>
|
||||
<table class='table table-form'>
|
||||
<tr>
|
||||
<th><?php echo $lang->user->account?></th>
|
||||
<td><?php echo html::input('account', '', "class='form-control'")?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->user->password?></th>
|
||||
<td><?php echo html::password('password1', '', "class='form-control'")?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->user->password2?></th>
|
||||
<td><?php echo html::password('password2', '', "class='form-control'")?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th></th>
|
||||
<td><?php echo html::submitButton()?></td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
<div class='panel'>
|
||||
<div class='panel-heading'>
|
||||
<strong><?php echo $lang->user->resetPassword?></strong>
|
||||
</div>
|
||||
<form method='post' target='hiddenwin'>
|
||||
<table class='table table-form'>
|
||||
<tr>
|
||||
<th><?php echo $lang->user->account?></th>
|
||||
<td><?php echo html::input('account', '', "class='form-control'")?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<input type='password' style="display:none"> <!-- Disable input password by browser automatically. -->
|
||||
<th><?php echo $lang->user->password?></th>
|
||||
<td><?php echo html::password('password1', '', "class='form-control'")?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->user->password2?></th>
|
||||
<td><?php echo html::password('password2', '', "class='form-control'")?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th></th>
|
||||
<td><?php echo html::submitButton()?></td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
<?php include '../../common/view/footer.lite.html.php';?>
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
;(function()
|
||||
{
|
||||
// CommonJS
|
||||
SyntaxHighlighter = SyntaxHighlighter || (typeof require !== 'undefined'? require('shCore').SyntaxHighlighter : null);
|
||||
|
||||
function Brush()
|
||||
{
|
||||
// Created by Peter Atoria @ http://iAtoria.com
|
||||
|
||||
var inits = 'class interface function package';
|
||||
|
||||
var keywords = '-Infinity ...rest Array as AS3 Boolean break case catch const continue Date decodeURI ' +
|
||||
'decodeURIComponent default delete do dynamic each else encodeURI encodeURIComponent escape ' +
|
||||
'extends false final finally flash_proxy for get if implements import in include Infinity ' +
|
||||
'instanceof int internal is isFinite isNaN isXMLName label namespace NaN native new null ' +
|
||||
'Null Number Object object_proxy override parseFloat parseInt private protected public ' +
|
||||
'return set static String super switch this throw true try typeof uint undefined unescape ' +
|
||||
'use void while with'
|
||||
;
|
||||
|
||||
this.regexList = [
|
||||
{ regex: SyntaxHighlighter.regexLib.singleLineCComments, css: 'comments' }, // one line comments
|
||||
{ regex: SyntaxHighlighter.regexLib.multiLineCComments, css: 'comments' }, // multiline comments
|
||||
{ regex: SyntaxHighlighter.regexLib.doubleQuotedString, css: 'string' }, // double quoted strings
|
||||
{ regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' }, // single quoted strings
|
||||
{ regex: /\b([\d]+(\.[\d]+)?|0x[a-f0-9]+)\b/gi, css: 'value' }, // numbers
|
||||
{ regex: new RegExp(this.getKeywords(inits), 'gm'), css: 'color3' }, // initializations
|
||||
{ regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' }, // keywords
|
||||
{ regex: new RegExp('var', 'gm'), css: 'variable' }, // variable
|
||||
{ regex: new RegExp('trace', 'gm'), css: 'color1' } // trace
|
||||
];
|
||||
|
||||
this.forHtmlScript(SyntaxHighlighter.regexLib.scriptScriptTags);
|
||||
};
|
||||
|
||||
Brush.prototype = new SyntaxHighlighter.Highlighter();
|
||||
Brush.aliases = ['actionscript3', 'as3'];
|
||||
|
||||
SyntaxHighlighter.brushes.AS3 = Brush;
|
||||
|
||||
// CommonJS
|
||||
typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
|
||||
})();
|
||||
@@ -0,0 +1,84 @@
|
||||
;(function()
|
||||
{
|
||||
// CommonJS
|
||||
SyntaxHighlighter = SyntaxHighlighter || (typeof require !== 'undefined'? require('shCore').SyntaxHighlighter : null);
|
||||
|
||||
function Brush()
|
||||
{
|
||||
// AppleScript brush by David Chambers
|
||||
// http://davidchambersdesign.com/
|
||||
var keywords = 'after before beginning continue copy each end every from return get global in local named of set some that the then times to where whose with without';
|
||||
var ordinals = 'first second third fourth fifth sixth seventh eighth ninth tenth last front back middle';
|
||||
var specials = 'activate add alias ask attachment boolean class constant delete duplicate empty exists id integer list make message modal modified new no pi properties quit real record remove rest result reveal reverse run running save string word yes';
|
||||
|
||||
this.regexList = [
|
||||
|
||||
{ regex: /(--|#).*$/gm,
|
||||
css: 'comments' },
|
||||
|
||||
{ regex: /\(\*(?:[\s\S]*?\(\*[\s\S]*?\*\))*[\s\S]*?\*\)/gm, // support nested comments
|
||||
css: 'comments' },
|
||||
|
||||
{ regex: /"[\s\S]*?"/gm,
|
||||
css: 'string' },
|
||||
|
||||
{ regex: /(?:,|:|¬|'s\b|\(|\)|\{|\}|«|\b\w*»)/g, // operators
|
||||
css: 'color1' },
|
||||
|
||||
{ regex: /(-)?(\d)+(\.(\d)?)?(E\+(\d)+)?/g, // numbers
|
||||
css: 'color1' },
|
||||
|
||||
{ regex: /(?:&(amp;|gt;|lt;)?|=|� |>|<|≥|>=|≤|<=|\*|\+|-|\/|÷|\^)/g,
|
||||
css: 'color2' },
|
||||
|
||||
{ regex: /\b(?:and|as|div|mod|not|or|return(?!\s&)(ing)?|equals|(is(n't| not)? )?equal( to)?|does(n't| not) equal|(is(n't| not)? )?(greater|less) than( or equal( to)?)?|(comes|does(n't| not) come) (after|before)|is(n't| not)?( in)? (back|front) of|is(n't| not)? behind|is(n't| not)?( (in|contained by))?|does(n't| not) contain|contain(s)?|(start|begin|end)(s)? with|((but|end) )?(consider|ignor)ing|prop(erty)?|(a )?ref(erence)?( to)?|repeat (until|while|with)|((end|exit) )?repeat|((else|end) )?if|else|(end )?(script|tell|try)|(on )?error|(put )?into|(of )?(it|me)|its|my|with (timeout( of)?|transaction)|end (timeout|transaction))\b/g,
|
||||
css: 'keyword' },
|
||||
|
||||
{ regex: /\b\d+(st|nd|rd|th)\b/g, // ordinals
|
||||
css: 'keyword' },
|
||||
|
||||
{ regex: /\b(?:about|above|against|around|at|below|beneath|beside|between|by|(apart|aside) from|(instead|out) of|into|on(to)?|over|since|thr(ough|u)|under)\b/g,
|
||||
css: 'color3' },
|
||||
|
||||
{ regex: /\b(?:adding folder items to|after receiving|clipboard info|set the clipboard to|(the )?clipboard|entire contents|document( (edited|file|nib name))?|file( (name|type))?|(info )?for|giving up after|(name )?extension|return(ed)?|second(?! item)(s)?|list (disks|folder)|(Unicode )?text|(disk )?item(s)?|((current|list) )?view|((container|key) )?window|case|diacriticals|hyphens|numeric strings|punctuation|white space|folder creation|application(s( folder)?| (processes|scripts position|support))?|((desktop )?(pictures )?|(documents|downloads|favorites|home|keychain|library|movies|music|public|scripts|sites|system|users|utilities|workflows) )folder|desktop|Folder Action scripts|font(s| panel)?|help|internet plugins|modem scripts|(system )?preferences|printer descriptions|scripting (additions|components)|shared (documents|libraries)|startup (disk|items)|temporary items|trash|on server|in AppleTalk zone|((as|long|short) )?user name|user (ID|locale)|(with )?password|in (bundle( with identifier)?|directory)|(close|open for) access|read|write( permission)?|(g|s)et eof|starting at|hidden( answer)?|open(ed| (location|untitled))?|error (handling|reporting)|administrator privileges|altering line endings|get volume settings|(alert|boot|input|mount|output|set) volume|output muted|(fax|random )?number|round(ing)?|up|down|toward zero|to nearest|as taught in school|system (attribute|info)|((AppleScript( Studio)?|system) )?version|(home )?directory|(IPv4|primary Ethernet) address|CPU (type|speed)|physical memory|time (stamp|to GMT)|replacing|ASCII (character|number)|localized string|from table|offset|summarize|beep|delay|say|(empty|multiple) selections allowed|(of|preferred) type|invisibles|showing( package contents)?|editable URL|(File|FTP|News|Media|Web) [Ss]ervers|Telnet hosts|Directory services|Remote applications|waiting until completion|saving( (in|to))?|path (for|to( (((current|frontmost) )?application|resource))?)|(background|RGB) color|(OK|cancel) button name|cancel button|button(s)?|cubic ((centi)?met(re|er)s|yards|feet|inches)|square ((kilo)?met(re|er)s|miles|yards|feet)|(centi|kilo)?met(re|er)s|miles|yards|feet|inches|lit(re|er)s|gallons|quarts|(kilo)?grams|ounces|pounds|degrees (Celsius|Fahrenheit|Kelvin)|print( (dialog|settings))?|clos(e(able)?|ing)|(de)?miniaturized|miniaturizable|zoom(ed|able)|attribute run|action (method|property|title)|phone|email|((start|end)ing|home) page|((birth|creation|current|custom|modification) )?date|((((phonetic )?(first|last|middle))|computer|host|maiden|related) |nick)?name|aim|icq|jabber|msn|yahoo|address(es)?|save addressbook|should enable action|city|country( code)?|formatte(r|d address)|(palette )?label|state|street|zip|AIM [Hh]andle(s)?|my card|select(ion| all)?|unsaved|(alpha )?value|entr(y|ies)|(ICQ|Jabber|MSN) handle|person|people|company|department|icon image|job title|note|organization|suffix|vcard|url|copies|collating|pages (across|down)|request print time|target( printer)?|((GUI Scripting|Script menu) )?enabled|show Computer scripts|(de)?activated|awake from nib|became (key|main)|call method|of (class|object)|center|clicked toolbar item|closed|for document|exposed|(can )?hide|idle|keyboard (down|up)|event( (number|type))?|launch(ed)?|load (image|movie|nib|sound)|owner|log|mouse (down|dragged|entered|exited|moved|up)|move|column|localization|resource|script|register|drag (info|types)|resigned (active|key|main)|resiz(e(d)?|able)|right mouse (down|dragged|up)|scroll wheel|(at )?index|should (close|open( untitled)?|quit( after last window closed)?|zoom)|((proposed|screen) )?bounds|show(n)?|behind|in front of|size (mode|to fit)|update(d| toolbar item)?|was (hidden|miniaturized)|will (become active|close|finish launching|hide|miniaturize|move|open|quit|(resign )?active|((maximum|minimum|proposed) )?size|show|zoom)|bundle|data source|movie|pasteboard|sound|tool(bar| tip)|(color|open|save) panel|coordinate system|frontmost|main( (bundle|menu|window))?|((services|(excluded from )?windows) )?menu|((executable|frameworks|resource|scripts|shared (frameworks|support)) )?path|(selected item )?identifier|data|content(s| view)?|character(s)?|click count|(command|control|option|shift) key down|context|delta (x|y|z)|key( code)?|location|pressure|unmodified characters|types|(first )?responder|playing|(allowed|selectable) identifiers|allows customization|(auto saves )?configuration|visible|image( name)?|menu form representation|tag|user(-| )defaults|associated file name|(auto|needs) display|current field editor|floating|has (resize indicator|shadow)|hides when deactivated|level|minimized (image|title)|opaque|position|release when closed|sheet|title(d)?)\b/g,
|
||||
css: 'color4' },
|
||||
|
||||
{ regex: /\b(?:tracks|paragraph|text item(s)?)\b/g,
|
||||
css: 'classes' },
|
||||
|
||||
{ regex: /\b(?:AppleScript|album|video kind|grouping|length|text item delimiters|quoted form|POSIX path(?= of))\b/g,
|
||||
css: 'properties' },
|
||||
|
||||
{ regex: /\b(?:run|exists|count)\b/g,
|
||||
css: 'commandNames' },
|
||||
|
||||
{ regex: /\b(?:POSIX (file|path))\b/g,
|
||||
css: 'additionClasses' },
|
||||
|
||||
{ regex: /\b(?:message|with (data|icon( (caution|note|stop))?|parameter(s)?|prompt|properties|seed|title)|regexp|string result|using( delimiters)?|default (answer|button|color|country code|entr(y|ies)|identifiers|items|name|location|script editor))\b/g,
|
||||
css: 'additionParameterNames' },
|
||||
|
||||
{ regex: /\b(?:display(ing| (alert|dialog|mode))?|choose( ((remote )?application|color|folder|from list|URL))?|(do( shell)?|load|run|store) script|re_compile|find text)\b/g,
|
||||
css: 'additionCommandNames' },
|
||||
|
||||
{ regex: /\b(?:xxx)\b/g,
|
||||
css: 'parameterNames' },
|
||||
|
||||
{ regex: /\b(?:true|false|none)\b/g,
|
||||
css: 'enumeratedValues' },
|
||||
|
||||
|
||||
{ regex: new RegExp(this.getKeywords(specials), 'gm'), css: 'color3' },
|
||||
{ regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' },
|
||||
{ regex: new RegExp(this.getKeywords(ordinals), 'gm'), css: 'keyword' }
|
||||
];
|
||||
};
|
||||
|
||||
Brush.prototype = new SyntaxHighlighter.Highlighter();
|
||||
Brush.aliases = ['applescript'];
|
||||
|
||||
SyntaxHighlighter.brushes.AppleScript = Brush;
|
||||
|
||||
// CommonJS
|
||||
typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
|
||||
})();
|
||||
@@ -0,0 +1,39 @@
|
||||
;(function()
|
||||
{
|
||||
// CommonJS
|
||||
SyntaxHighlighter = SyntaxHighlighter || (typeof require !== 'undefined'? require('shCore').SyntaxHighlighter : null);
|
||||
|
||||
function Brush()
|
||||
{
|
||||
var keywords = 'abs addr and ansichar ansistring array as asm begin boolean byte cardinal ' +
|
||||
'case char class comp const constructor currency destructor div do double ' +
|
||||
'downto else end except exports extended false file finalization finally ' +
|
||||
'for function goto if implementation in inherited int64 initialization ' +
|
||||
'integer interface is label library longint longword mod nil not object ' +
|
||||
'of on or packed pansichar pansistring pchar pcurrency pdatetime pextended ' +
|
||||
'pint64 pointer private procedure program property pshortstring pstring ' +
|
||||
'pvariant pwidechar pwidestring protected public published raise real real48 ' +
|
||||
'record repeat set shl shortint shortstring shr single smallint string then ' +
|
||||
'threadvar to true try type unit until uses val var varirnt while widechar ' +
|
||||
'widestring with word write writeln xor';
|
||||
|
||||
this.regexList = [
|
||||
{ regex: /\(\*[\s\S]*?\*\)/gm, css: 'comments' }, // multiline comments (* *)
|
||||
{ regex: /{(?!\$)[\s\S]*?}/gm, css: 'comments' }, // multiline comments { }
|
||||
{ regex: SyntaxHighlighter.regexLib.singleLineCComments, css: 'comments' }, // one line
|
||||
{ regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' }, // strings
|
||||
{ regex: /\{\$[a-zA-Z]+ .+\}/g, css: 'color1' }, // compiler Directives and Region tags
|
||||
{ regex: /\b[\d\.]+\b/g, css: 'value' }, // numbers 12345
|
||||
{ regex: /\$[a-zA-Z0-9]+\b/g, css: 'value' }, // numbers $F5D3
|
||||
{ regex: new RegExp(this.getKeywords(keywords), 'gmi'), css: 'keyword' } // keyword
|
||||
];
|
||||
};
|
||||
|
||||
Brush.prototype = new SyntaxHighlighter.Highlighter();
|
||||
Brush.aliases = ['delphi', 'pascal', 'pas'];
|
||||
|
||||
SyntaxHighlighter.brushes.Delphi = Brush;
|
||||
|
||||
// CommonJS
|
||||
typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
|
||||
})();
|
||||
@@ -0,0 +1,25 @@
|
||||
;(function()
|
||||
{
|
||||
// CommonJS
|
||||
SyntaxHighlighter = SyntaxHighlighter || (typeof require !== 'undefined'? require('shCore').SyntaxHighlighter : null);
|
||||
|
||||
function Brush()
|
||||
{
|
||||
this.regexList = [
|
||||
{ regex: /^\+\+\+ .*$/gm, css: 'color2' }, // new file
|
||||
{ regex: /^\-\-\- .*$/gm, css: 'color2' }, // old file
|
||||
{ regex: /^\s.*$/gm, css: 'color1' }, // unchanged
|
||||
{ regex: /^@@.*@@.*$/gm, css: 'variable' }, // location
|
||||
{ regex: /^\+.*$/gm, css: 'string' }, // additions
|
||||
{ regex: /^\-.*$/gm, css: 'color3' } // deletions
|
||||
];
|
||||
};
|
||||
|
||||
Brush.prototype = new SyntaxHighlighter.Highlighter();
|
||||
Brush.aliases = ['diff', 'patch'];
|
||||
|
||||
SyntaxHighlighter.brushes.Diff = Brush;
|
||||
|
||||
// CommonJS
|
||||
typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
|
||||
})();
|
||||
@@ -0,0 +1,36 @@
|
||||
;(function()
|
||||
{
|
||||
// CommonJS
|
||||
SyntaxHighlighter = SyntaxHighlighter || (typeof require !== 'undefined'? require('shCore').SyntaxHighlighter : null);
|
||||
|
||||
function Brush()
|
||||
{
|
||||
// Contributed by Jean-Lou Dupont
|
||||
// http://jldupont.blogspot.com/2009/06/erlang-syntax-highlighter.html
|
||||
|
||||
// According to: http://erlang.org/doc/reference_manual/introduction.html#1.5
|
||||
var keywords = 'after and andalso band begin bnot bor bsl bsr bxor '+
|
||||
'case catch cond div end fun if let not of or orelse '+
|
||||
'query receive rem try when xor'+
|
||||
// additional
|
||||
' module export import define';
|
||||
|
||||
this.regexList = [
|
||||
{ regex: new RegExp("[A-Z][A-Za-z0-9_]+", 'g'), css: 'constants' },
|
||||
{ regex: new RegExp("\\%.+", 'gm'), css: 'comments' },
|
||||
{ regex: new RegExp("\\?[A-Za-z0-9_]+", 'g'), css: 'preprocessor' },
|
||||
{ regex: new RegExp("[a-z0-9_]+:[a-z0-9_]+", 'g'), css: 'functions' },
|
||||
{ regex: SyntaxHighlighter.regexLib.doubleQuotedString, css: 'string' },
|
||||
{ regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' },
|
||||
{ regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' }
|
||||
];
|
||||
};
|
||||
|
||||
Brush.prototype = new SyntaxHighlighter.Highlighter();
|
||||
Brush.aliases = ['erl', 'erlang'];
|
||||
|
||||
SyntaxHighlighter.brushes.Erlang = Brush;
|
||||
|
||||
// CommonJS
|
||||
typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
|
||||
})();
|
||||
@@ -0,0 +1,51 @@
|
||||
;(function()
|
||||
{
|
||||
// CommonJS
|
||||
SyntaxHighlighter = SyntaxHighlighter || (typeof require !== 'undefined'? require('shCore').SyntaxHighlighter : null);
|
||||
|
||||
function Brush()
|
||||
{
|
||||
// Contributed by Andres Almiray
|
||||
// http://jroller.com/aalmiray/entry/nice_source_code_syntax_highlighter
|
||||
|
||||
var keywords = 'as assert break case catch class continue def default do else extends finally ' +
|
||||
'if in implements import instanceof interface new package property return switch ' +
|
||||
'throw throws try while public protected private static';
|
||||
var types = 'void boolean byte char short int long float double';
|
||||
var constants = 'null';
|
||||
var methods = 'allProperties count get size '+
|
||||
'collect each eachProperty eachPropertyName eachWithIndex find findAll ' +
|
||||
'findIndexOf grep inject max min reverseEach sort ' +
|
||||
'asImmutable asSynchronized flatten intersect join pop reverse subMap toList ' +
|
||||
'padRight padLeft contains eachMatch toCharacter toLong toUrl tokenize ' +
|
||||
'eachFile eachFileRecurse eachB yte eachLine readBytes readLine getText ' +
|
||||
'splitEachLine withReader append encodeBase64 decodeBase64 filterLine ' +
|
||||
'transformChar transformLine withOutputStream withPrintWriter withStream ' +
|
||||
'withStreams withWriter withWriterAppend write writeLine '+
|
||||
'dump inspect invokeMethod print println step times upto use waitForOrKill '+
|
||||
'getText';
|
||||
|
||||
this.regexList = [
|
||||
{ regex: SyntaxHighlighter.regexLib.singleLineCComments, css: 'comments' }, // one line comments
|
||||
{ regex: SyntaxHighlighter.regexLib.multiLineCComments, css: 'comments' }, // multiline comments
|
||||
{ regex: SyntaxHighlighter.regexLib.doubleQuotedString, css: 'string' }, // strings
|
||||
{ regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' }, // strings
|
||||
{ regex: /""".*"""/g, css: 'string' }, // GStrings
|
||||
{ regex: new RegExp('\\b([\\d]+(\\.[\\d]+)?|0x[a-f0-9]+)\\b', 'gi'), css: 'value' }, // numbers
|
||||
{ regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' }, // goovy keyword
|
||||
{ regex: new RegExp(this.getKeywords(types), 'gm'), css: 'color1' }, // goovy/java type
|
||||
{ regex: new RegExp(this.getKeywords(constants), 'gm'), css: 'constants' }, // constants
|
||||
{ regex: new RegExp(this.getKeywords(methods), 'gm'), css: 'functions' } // methods
|
||||
];
|
||||
|
||||
this.forHtmlScript(SyntaxHighlighter.regexLib.aspScriptTags);
|
||||
}
|
||||
|
||||
Brush.prototype = new SyntaxHighlighter.Highlighter();
|
||||
Brush.aliases = ['groovy'];
|
||||
|
||||
SyntaxHighlighter.brushes.Groovy = Brush;
|
||||
|
||||
// CommonJS
|
||||
typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
|
||||
})();
|
||||
@@ -0,0 +1,83 @@
|
||||
;(function()
|
||||
{
|
||||
// CommonJS
|
||||
SyntaxHighlighter = SyntaxHighlighter || (typeof require !== 'undefined'? require('shCore').SyntaxHighlighter : null);
|
||||
|
||||
function Brush()
|
||||
{
|
||||
function getKeywordsCSS(str)
|
||||
{
|
||||
return '\\b([a-z_]|)' + str.replace(/ /g, '(?=:)\\b|\\b([a-z_\\*]|\\*|)') + '(?=:)\\b';
|
||||
};
|
||||
|
||||
function getValuesCSS(str)
|
||||
{
|
||||
return '\\b' + str.replace(/ /g, '(?!-)(?!:)\\b|\\b()') + '\:\\b';
|
||||
};
|
||||
|
||||
function getKeywordsPrependedBy(keywords, by)
|
||||
{
|
||||
return '(?:' + keywords.replace(/^\s+|\s+$/g, '').replace(/\s+/g, '|' + by + '\\b').replace(/^/, by + '\\b') + ')\\b';
|
||||
}
|
||||
|
||||
var keywords = 'ascent azimuth background-attachment background-color background-image background-position ' +
|
||||
'background-repeat background baseline bbox border-collapse border-color border-spacing border-style border-top ' +
|
||||
'border-right border-bottom border-left border-top-color border-right-color border-bottom-color border-left-color ' +
|
||||
'border-top-style border-right-style border-bottom-style border-left-style border-top-width border-right-width ' +
|
||||
'border-bottom-width border-left-width border-width border bottom cap-height caption-side centerline clear clip color ' +
|
||||
'content counter-increment counter-reset cue-after cue-before cue cursor definition-src descent direction display ' +
|
||||
'elevation empty-cells float font-size-adjust font-family font-size font-stretch font-style font-variant font-weight font ' +
|
||||
'height left letter-spacing line-height list-style-image list-style-position list-style-type list-style margin-top ' +
|
||||
'margin-right margin-bottom margin-left margin marker-offset marks mathline max-height max-width min-height min-width orphans ' +
|
||||
'outline-color outline-style outline-width outline overflow padding-top padding-right padding-bottom padding-left padding page ' +
|
||||
'page-break-after page-break-before page-break-inside pause pause-after pause-before pitch pitch-range play-during position ' +
|
||||
'quotes right richness size slope src speak-header speak-numeral speak-punctuation speak speech-rate stemh stemv stress ' +
|
||||
'table-layout text-align top text-decoration text-indent text-shadow text-transform unicode-bidi unicode-range units-per-em ' +
|
||||
'vertical-align visibility voice-family volume white-space widows width widths word-spacing x-height z-index zoom';
|
||||
|
||||
var values = 'above absolute all always aqua armenian attr aural auto avoid baseline behind below bidi-override black blink block blue bold bolder '+
|
||||
'both bottom braille capitalize caption center center-left center-right circle close-quote code collapse compact condensed '+
|
||||
'continuous counter counters crop cross crosshair cursive dashed decimal decimal-leading-zero digits disc dotted double '+
|
||||
'embed embossed e-resize expanded extra-condensed extra-expanded fantasy far-left far-right fast faster fixed format fuchsia '+
|
||||
'gray green groove handheld hebrew help hidden hide high higher icon inline-table inline inset inside invert italic '+
|
||||
'justify landscape large larger left-side left leftwards level lighter lime line-through list-item local loud lower-alpha '+
|
||||
'lowercase lower-greek lower-latin lower-roman lower low ltr marker maroon medium message-box middle mix move narrower '+
|
||||
'navy ne-resize no-close-quote none no-open-quote no-repeat normal nowrap n-resize nw-resize oblique olive once open-quote outset '+
|
||||
'outside overline pointer portrait pre print projection purple red relative repeat repeat-x repeat-y rgb ridge right right-side '+
|
||||
'rightwards rtl run-in screen scroll semi-condensed semi-expanded separate se-resize show silent silver slower slow '+
|
||||
'small small-caps small-caption smaller soft solid speech spell-out square s-resize static status-bar sub super sw-resize '+
|
||||
'table-caption table-cell table-column table-column-group table-footer-group table-header-group table-row table-row-group teal '+
|
||||
'text-bottom text-top thick thin top transparent tty tv ultra-condensed ultra-expanded underline upper-alpha uppercase upper-latin '+
|
||||
'upper-roman url visible wait white wider w-resize x-fast x-high x-large x-loud x-low x-slow x-small x-soft xx-large xx-small yellow';
|
||||
|
||||
var fonts = '[mM]onospace [tT]ahoma [vV]erdana [aA]rial [hH]elvetica [sS]ans-serif [sS]erif [cC]ourier mono sans serif';
|
||||
|
||||
var statements = 'important default';
|
||||
var preprocessor = 'import extend debug warn if else for while mixin function include content media';
|
||||
|
||||
var r = SyntaxHighlighter.regexLib;
|
||||
|
||||
this.regexList = [
|
||||
{ regex: r.multiLineCComments, css: 'comments' }, // multiline comments
|
||||
{ regex: r.singleLineCComments, css: 'comments' }, // singleline comments
|
||||
{ regex: r.doubleQuotedString, css: 'string' }, // double quoted strings
|
||||
{ regex: r.singleQuotedString, css: 'string' }, // single quoted strings
|
||||
{ regex: /\#[a-fA-F0-9]{3,6}/g, css: 'value' }, // html colors
|
||||
{ regex: /\b(-?\d+)(\.\d+)?(px|em|rem|pt|\:|\%|)\b/g, css: 'value' }, // sizes
|
||||
{ regex: /\$[\w-]+/g, css: 'variable' }, // variables
|
||||
{ regex: new RegExp(getKeywordsPrependedBy(statements, '!'), 'g'), css: 'color3' }, // statements
|
||||
{ regex: new RegExp(getKeywordsPrependedBy(preprocessor, '@'), 'g'), css: 'preprocessor' }, // preprocessor
|
||||
{ regex: new RegExp(getKeywordsCSS(keywords), 'gm'), css: 'keyword' }, // keywords
|
||||
{ regex: new RegExp(getValuesCSS(values), 'g'), css: 'value' }, // values
|
||||
{ regex: new RegExp(this.getKeywords(fonts), 'g'), css: 'color1' } // fonts
|
||||
];
|
||||
};
|
||||
|
||||
Brush.prototype = new SyntaxHighlighter.Highlighter();
|
||||
Brush.aliases = ['sass', 'scss'];
|
||||
|
||||
SyntaxHighlighter.brushes.Sass = Brush;
|
||||
|
||||
// CommonJS
|
||||
typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
|
||||
})();
|
||||
@@ -0,0 +1,35 @@
|
||||
;(function()
|
||||
{
|
||||
// CommonJS
|
||||
SyntaxHighlighter = SyntaxHighlighter || (typeof require !== 'undefined'? require('shCore').SyntaxHighlighter : null);
|
||||
|
||||
function Brush()
|
||||
{
|
||||
// Contributed by Yegor Jbanov and David Bernard.
|
||||
|
||||
var keywords = 'val sealed case def true trait implicit forSome import match object null finally super ' +
|
||||
'override try lazy for var catch throw type extends class while with new final yield abstract ' +
|
||||
'else do if return protected private this package false';
|
||||
|
||||
var keyops = '[_:=><%#@]+';
|
||||
|
||||
this.regexList = [
|
||||
{ regex: SyntaxHighlighter.regexLib.singleLineCComments, css: 'comments' }, // one line comments
|
||||
{ regex: SyntaxHighlighter.regexLib.multiLineCComments, css: 'comments' }, // multiline comments
|
||||
{ regex: SyntaxHighlighter.regexLib.multiLineSingleQuotedString, css: 'string' }, // multi-line strings
|
||||
{ regex: SyntaxHighlighter.regexLib.multiLineDoubleQuotedString, css: 'string' }, // double-quoted string
|
||||
{ regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' }, // strings
|
||||
{ regex: /0x[a-f0-9]+|\d+(\.\d+)?/gi, css: 'value' }, // numbers
|
||||
{ regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' }, // keywords
|
||||
{ regex: new RegExp(keyops, 'gm'), css: 'keyword' } // scala keyword
|
||||
];
|
||||
}
|
||||
|
||||
Brush.prototype = new SyntaxHighlighter.Highlighter();
|
||||
Brush.aliases = ['scala'];
|
||||
|
||||
SyntaxHighlighter.brushes.Scala = Brush;
|
||||
|
||||
// CommonJS
|
||||
typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
|
||||
})();
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user