diff --git a/VERSION b/VERSION
index 9341e7602b..b82244ff8c 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-10.0.stable
+10.1.stable
diff --git a/config/config.php b/config/config.php
index 037ff1caec..b8e9bcd87a 100644
--- a/config/config.php
+++ b/config/config.php
@@ -16,7 +16,7 @@ if(!class_exists('config')){class config{}}
if(!function_exists('getWebRoot')){function getWebRoot(){}}
/* 基本设置。Basic settings. */
-$config->version = '10.0'; // ZenTaoPHP的版本。 The version of ZenTaoPHP. Don't change it.
+$config->version = '10.1'; // ZenTaoPHP的版本。 The version of ZenTaoPHP. Don't change it.
$config->charset = 'UTF-8'; // ZenTaoPHP的编码。 The encoding of ZenTaoPHP.
$config->cookieLife = time() + 2592000; // Cookie的生存时间。The cookie life time.
$config->timezone = 'Asia/Shanghai'; // 时区设置。 The time zone setting, for more see http://www.php.net/manual/en/timezones.php.
diff --git a/doc/CHANGELOG b/doc/CHANGELOG
index 19ea984146..2f1386f4d9 100644
--- a/doc/CHANGELOG
+++ b/doc/CHANGELOG
@@ -1,3 +1,158 @@
+2018-07-11 10.1
+完成的需求
+3068 需求关联相关需求字段时,选择需求后页面没有及时刷新。
+3067 项目需求列表页面调整创建需求和关联需求按钮的位置。
+3066 项目任务列表可以直接点击进入
+3065 优化各个视图首页区块中滚动条的位置和样式
+3064 调整编辑器和详情页面P标签的行距,精简,保持一致。
+3058 检查zt_webhookdatas表是否还需要,如果不需要,去掉
+3037 多人任务只能线性执行
+3036 调整待办列表中操作按钮
+3035 调整首页指派给我区块中待办的查询逻辑
+3034 父任务删除,子任务一起删除
+3033 父任务的起止日期根据子任务的起止日期变化
+3031 后台自定义必填项,如果是系统原来默认的必填项,不出现在编辑的下拉列表里,即不允许编辑
+3027 创建需求列出的计划规则修改
+3025 数据库表索引再过一遍,有些加了没用上
+3015 导出设置,选中某个已存模板,下方模板名称不显示。点删除时,不大清楚删除的是哪个模板
+3012 创建任务,如果是多人类型的任务,设置团队的时候目前只能设置6个,考虑增加添加按钮,排序换成拖拽的
+2935 文档库和文档的权限分开进行检查
+2910 下个版本升级时把项目状态是done的改为closed
+2857 需求和bug的所属模块改为后台可以去掉必填
+2835 导出用例结果的时候,不管状态。有实际情况数据就导出。
+2820 子任务详情,标题中的父任务,做成链接。
+2818 把任务列表自定义显示字段中的“完成”改成“完成日期”
+
+修复的Bug
+1990 需求以重复原因关闭之后,再修改关闭原因无法将重复需求字段置空
+1989 测试单关联用例页面,搜索,选择搜索字段,搜索框数据没有变化
+1988 操作栏存在换行显示的问题
+1987 登录后跳转的网址不对
+1986 发信功能,收到的邮件,邮件标题跳转链接错误
+1984 所有产品和所有项目页面,对产品和项目排序不生效
+1981 组织-权限 有一个没有对号的汉字展示
+1978 部分模块拖动排序显示有问题
+1977 添加待办不填写待办名称,没有提示必填项
+1975 批量添加bug多项录入卡死
+1971 文档模块下面富文本编辑器选择SQL会变形
+1966 产品的模块显示位置错误
+1965 创建任务,抄送给下拉显示不完整
+1964 项目按计划关联需求时会把草稿状态的需求关联进来
+1963 markdown无法正常录入数据
+1962 富文本编辑器的图片空间功能异常
+1961 测试单-关联用例 缺少 按照bug关联 用例的功能
+1958 项目主页任务统计与实际不符
+1951 10.0.beta产品计划关联缺陷列表,不能按查询条件过滤数据
+1950 长名称的产品,需要优化测试单首页样式
+1948 任务管理模式下,文档里产品相关内容需要隐藏
+1944 产品需求里生成报表,下拉时会出现所有表头的表格
+1942 项目-任务,按分组查看任务时,父子任务会统计负责任务工时总和
+1941 创建周期性待办,新建的待办和周期待办的创建人不一致
+1935 bug标题过长时,点击解决bug,会遮挡下方信息
+1924 文档库创建文档链接跳转不对
+1921 多人任务创建后点击编辑然后保存无法保存
+1920 产品-项目:项目过多,加一个总数给用户预知
+1919 产品-概况:最新动态模块中,对重要信息待处理(以蓝色的点重点突出)
+1918 文档-产品:文档的产品详情页有页码行
+1917 文档-文档主页:在左边的文档导航部分,产品名过长
+1913 组织-权限,视图维护设置可以访问的产品或项目无效
+1908 修改日志无法滚动
+1903 产品批量编辑与概况显示不一致
+1884 任务列表工时统计显示不友好
+1873 需求单独分解任务 列表页面的任务数不会变化
+1870 文档同时编辑没有提示
+1846 详情页面,先删除再取消,再点击编辑,然后点返回,谷歌和safari浏览器会提醒是否要删除该任务
+1829 燃尽图模块的图例,位置有一点挤
+1575 测试-bug 简单表格自定义字段比较多的时候排版有问题
+1561 单独创建用户的时候对邮件地址没有进行验证
+1560 用例步骤和预期高度样式显示不友好
+1559 测试报告中点击用例标题显示最新用例版本内容,不是测试单执行的用例版本内容
+1558 多人任务任务点完成时,会自动添加一条工时记录
+1557 套件关联用例问题
+1555 使用markdown创建文档时>会被过滤
+1554 附件名称长显示不美观
+1548 测试单模块显示错误
+1542 访问控制分组白名单显示优化
+1541 项目-版本 关联需求显示阶段不一致
+1540 10.0版本批量创建任务和需求,页面加载慢。
+1532 项目-版本,编辑已上传的附件名称,历史记录显示超出浏览器页面
+1985 任务标题过长,完成、关闭、激活任务页面标题会遮挡下方信息
+1983 在安装禅道,生成配置文件,检查requestType是否可以使用PATH_INFO方式的时候,检查不起作用
+1982 计划列表的描述没有换行
+1980 产品类型为多平台或多分支类型,产品下的需求所属阶段信息显示不出来
+1979 组织-用户列表 职位栏换行
+1976 升级成功页面,然之协同logo显示不全
+1973 优化名字很长时的文档页面
+1972 保存提交操作没有增加防止重复点击的设置
+1970 一键安装包zbox.php代码问题
+1968 我的地盘,欢迎总览区块,任务已延期数量统计不准确
+1967 非强制评审用户,对草稿状态的需求进行变更,需求状态还是显示为草稿
+1960 需求阶段规则完善
+1957 测试用例导入csv文件,预期和步骤以英文引号结尾无法导入
+1956 产品创建方法代码优化
+1955 创建项目时如果关联计划,项目能创建成功但是页面没有跳转,并且计划没有关联上
+1954 统计-测试-bug创建表,数据没有正常显示
+1947 集成然之,自动跳回然之功能打开,用例执行失败转bug,用例步骤不会自动带到bug中
+1943 需求变更确认按钮点击无反应
+1940 测试用例导出csv文件,实际情况字段内容没有导出
+1939 创建多人任务时不维护预计工时,用户点击完成,任务状态会变为已完成
+1938 测试-bug,编辑bug,选择所属项目后,解决版本只能选择这个项目下的版本
+1936 修改config/config.php文件后缀名白名单,pcblib格式文件上传后后缀名重复
+1930 测试-bug,按抄送给字段进行搜索,没有数据
+1929 需求查看功能异常
+1927 需求分组子任务工时重复计算
+1926 项目-需求 无法关联需求
+1925 维护产品线页面点击返回无效
+1923 需求标题列表和详情页面显示不一致
+1922 附件上传目录只读时ajaxForm无法正常提交
+1916 文档的视图切换按钮只在搜索结果页出现,其他页面没有
+1915 文档-项目:Google浏览器中,点击“项目”,文档左边的导航部分会消失
+1912 10.0 bug列表自定义字段无法设置
+1911 bug详情页面无法显示完整长版本名称
+1910 module/project/control.php代码错误
+1909 我的地盘项目状态与详情页面不一致
+1907 修复这里面的安全漏洞
+1897 项目-团队中,受限用户选择是,用户还是可以创建任务
+1895 邮件中设置的发信人和收到邮件时的发信人不一致
+1894 产品-概况页面,历史记录记录的是最新动态中的信息
+1893 测试-测试单删除后,还可以搜索到
+1892 周期待办编辑保存后会创建不符合要求的待办
+1891 任务分解子任务,不填写任务名称也可以保存
+1890 添加子任务没有必填项提醒
+1889 计划关联bug默认进来的未关联bug数量显示不对
+1888 组织-权限,权限维护,取消产品计划-关联需求权限,产品-计划下需求无法排序
+1887 点击模块不显示子任务
+1880 子任务收起会被勾选
+1874 批量修改需求阶段不生效
+1872 多人任务第二个人员无法记录工时
+1871 优化创建用户页面密码验证失败的提示
+1585 升级成功的页面,然之协同的logo显示不完整
+1582 待办关闭后,指派人还是之前指派的用户
+1581 zbox服务不能正常重启
+1556 看板上拖动任务没有按预期工作
+1553 调整任务指派时剩余工时字段的逻辑
+1552 关联需求,搜索是否需要显示删除的需求。
+1551 国际版绑定禅道官网逻辑错误
+1547 批量添加用户,职位显示为必填,实际职位非必填字段
+1546 英文版文档首页%s
+1544 周期待办的创建人会显示所有成员中的一个
+1534 项目-概况的 关联计划 无法修改
+1533 钉钉机器人中发的链接点击无法访问
+1530 测试报告(测试管理工具)提示需要关联项目
+1528 平台页面无法切换产品
+1527 用户源码包安装检测的session目录读写权限不准
+1526 禅道更新到 9.8.x后速度变慢cpu占用率增高
+1522 禅道附件图片无法下载预览
+1521 受限用户可以删除任何能看到的附件
+1520 列表页面排序功能异常
+1519 所有项目排序功能异常
+1512 新建产品,维护产品线,点刷新显示为维护模块
+1506 升级结果页面,然之协同的logo没显示完整
+1501 项目关联的产品多,显示样式需优化。
+1496 员工负载表显示错位
+1492 创建项目页面关联计划,计划下的需求不会关联到项目中
+1491 任务列表,点击表头进行排序,对子任务不起作用
+
2018-04-03 9.8.3.stable
完成的需求
2872 把用户的入职日期属性展示出来
diff --git a/framework/helper.class.php b/framework/helper.class.php
index e54e60d459..af58e010ca 100644
--- a/framework/helper.class.php
+++ b/framework/helper.class.php
@@ -162,3 +162,18 @@ function formatTime($time, $format = '')
if($format) return date($format, strtotime($time));
return trim($time);
}
+
+/**
+ * Fix for session error.
+ *
+ * @param int $class
+ * @access protected
+ * @return void
+ */
+function __autoload($class)
+{
+ if(!class_exists($class))
+ {
+ if($class == 'post_max_size' or $class == 'max_input_vars') eval('class ' . $class . ' {};');
+ }
+}
diff --git a/lib/snoopy/snoopy.class.php b/lib/snoopy/snoopy.class.php
index e83e283ddb..d5d7c2ce76 100644
--- a/lib/snoopy/snoopy.class.php
+++ b/lib/snoopy/snoopy.class.php
@@ -1068,7 +1068,7 @@ class Snoopy
$headers[] = "API-RemoteIP: " . $_SERVER['REMOTE_ADDR'];
curl_setopt($curl, CURLOPT_URL, $URI);
- curl_setopt($curl, CURLOPT_HTTPHEADER, $headers );
+ curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLINFO_HEADER_OUT, TRUE);
if(!empty($body))
{
@@ -1082,6 +1082,21 @@ class Snoopy
$result_headers = curl_getinfo($curl);
curl_close($curl);
+ global $app;
+ $logFile = $app->getLogRoot() . 'saas.' . date('Ymd') . '.log.php';
+ if(!file_exists($logFile)) file_put_contents($logFile, '');
+
+ $fh = @fopen($logFile, 'a');
+ if($fh)
+ {
+ fwrite($fh, date('Ymd H:i:s') . ": " . $app->getURI() . "\n");
+ fwrite($fh, "url: " . $URI . "\n");
+ if(!empty($data)) fwrite($fh, "data: " . print_r($body, true) . "\n");
+ fwrite($fh, "results:" . print_r($results, true) . "\n");
+ if(!empty($return)) fwrite($fh, "errors: " . $return . "\n");
+ fclose($fh);
+ }
+
$this->_redirectaddr = false;
$this->response_code = $result_headers['http_code'];
if(!empty($result_headers['redirect_url']))$this->_redirectaddr = $result_headers['redirect_url'];
diff --git a/module/block/lang/zh-tw.php b/module/block/lang/zh-tw.php
index a62f02bd04..8a4f399770 100644
--- a/module/block/lang/zh-tw.php
+++ b/module/block/lang/zh-tw.php
@@ -15,6 +15,7 @@ $lang->block->name = '區塊名稱';
$lang->block->style = '外觀';
$lang->block->grid = '位置';
$lang->block->color = '顏色';
+$lang->block->reset = '恢復預設';
$lang->block->account = '所屬用戶';
$lang->block->module = '所屬模組';
@@ -52,6 +53,8 @@ $lang->block->createBlock = '添加區塊';
$lang->block->editBlock = '編輯區塊';
$lang->block->ordersSaved = '排序已保存';
$lang->block->confirmRemoveBlock = '確定移除區塊嗎?';
+$lang->block->noticeNewBlock = '10.0版本以後各個視圖主頁提供了全新的視圖,您要啟用新的視圖佈局嗎?';
+$lang->block->confirmReset = '是否恢復預設佈局';
$lang->block->closeForever = '永久關閉';
$lang->block->confirmClose = '確定永久關閉該區塊嗎?關閉後所有人都將無法使用該區塊,可以在後台自定義中打開。';
$lang->block->remove = '移除';
diff --git a/module/block/model.php b/module/block/model.php
index 82f3f233eb..6bfa893c47 100644
--- a/module/block/model.php
+++ b/module/block/model.php
@@ -160,11 +160,11 @@ class blockModel extends model
$projects = $this->loadModel('project')->getPairs();
$products = $this->loadModel('product')->getPairs();
- $data['tasks'] = (int)$this->dao->select('count(*) AS count')->from(TABLE_TASK)->where('assignedTo')->eq($this->app->user->account)->fetch('count');
- $data['bugs'] = (int)$this->dao->select('count(*) AS count')->from(TABLE_BUG)->where('assignedTo')->eq($this->app->user->account)->fetch('count');
- $data['stories'] = (int)$this->dao->select('count(*) AS count')->from(TABLE_STORY)->where('assignedTo')->eq($this->app->user->account)->fetch('count');
- $data['projects'] = (int)$this->dao->select('count(*) AS count')->from(TABLE_PROJECT)->where('id')->in(array_keys($projects))->andWhere("(status='wait' or status='doing')")->fetch('count');
- $data['products'] = (int)$this->dao->select('count(*) AS count')->from(TABLE_PRODUCT)->where('status')->ne('closed')->andWhere('id')->in(array_keys($products))->fetch('count');
+ $data['tasks'] = (int)$this->dao->select('count(*) AS count')->from(TABLE_TASK)->where('assignedTo')->eq($this->app->user->account)->andWhere('deleted')->eq(0)->fetch('count');
+ $data['bugs'] = (int)$this->dao->select('count(*) AS count')->from(TABLE_BUG)->where('assignedTo')->eq($this->app->user->account)->andWhere('deleted')->eq(0)->fetch('count');
+ $data['stories'] = (int)$this->dao->select('count(*) AS count')->from(TABLE_STORY)->where('assignedTo')->eq($this->app->user->account)->andWhere('deleted')->eq(0)->fetch('count');
+ $data['projects'] = (int)$this->dao->select('count(*) AS count')->from(TABLE_PROJECT)->where('id')->in(array_keys($projects))->andWhere("(status='wait' or status='doing')")->andWhere('deleted')->eq(0)->fetch('count');
+ $data['products'] = (int)$this->dao->select('count(*) AS count')->from(TABLE_PRODUCT)->where('status')->ne('closed')->andWhere('id')->in(array_keys($products))->andWhere('deleted')->eq(0)->fetch('count');
$today = date('Y-m-d');
$data['delayTask'] = (int)$this->dao->select('count(*) AS count')->from(TABLE_TASK)
@@ -172,17 +172,20 @@ class blockModel extends model
->andWhere('status')->in('wait,doing')
->andWhere('deadline')->ne('0000-00-00')
->andWhere('deadline')->lt($today)
+ ->andWhere('deleted')->eq(0)
->fetch('count');
$data['delayBug'] = (int)$this->dao->select('count(*) AS count')->from(TABLE_BUG)
->where('assignedTo')->eq($this->app->user->account)
->andWhere('status')->eq('active')
->andWhere('deadline')->ne('0000-00-00')
->andWhere('deadline')->lt($today)
+ ->andWhere('deleted')->eq(0)
->fetch('count');
$data['delayProject'] = (int)$this->dao->select('count(*) AS count')->from(TABLE_PROJECT)
->where('id')->in(array_keys($projects))
->andWhere('status')->in('wait,doing')
->andWhere('end')->lt($today)
+ ->andWhere('deleted')->eq(0)
->fetch('count');
return $data;
diff --git a/module/bug/control.php b/module/bug/control.php
index 187e6b3c7a..027540e689 100644
--- a/module/bug/control.php
+++ b/module/bug/control.php
@@ -482,7 +482,7 @@ class bug extends control
}
/* Set custom. */
- $product = $this->product->getById($productID);
+ $product = $this->product->getById($productID);
foreach(explode(',', $this->config->bug->list->customBatchCreateFields) as $field)
{
if($product->type != 'normal') $customFields[$product->type] = $this->lang->product->branchName[$product->type];
diff --git a/module/bug/js/batchcreate.js b/module/bug/js/batchcreate.js
index 91cfc514d4..6c359ba21b 100644
--- a/module/bug/js/batchcreate.js
+++ b/module/bug/js/batchcreate.js
@@ -23,7 +23,7 @@ function setBranchRelated(branchID, productID, num)
if(!modules) modules = '';
$('#modules' + num).replaceWith(modules);
$("#modules" + num + "_chosen").remove();
- $("#modules" + num).chosen(defaultChosenOptions);
+ $("#modules" + num).chosen();
});
projectLink = createLink('product', 'ajaxGetProjects', 'productID=' + productID + '&projectID=0&branch=' + branchID + '&num=' + num);
@@ -32,7 +32,7 @@ function setBranchRelated(branchID, productID, num)
if(!projects) projects = '';
$('#projects' + num).replaceWith(projects);
$("#projects" + num + "_chosen").remove();
- $("#projects" + num).chosen(defaultChosenOptions);
+ $("#projects" + num).chosen();
});
buildLink = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + "&varName=openedBuilds&build=&branch=" + branchID + "&index=" + num);
@@ -63,7 +63,7 @@ function setOpenedBuilds(link, index)
$('#buildBox' + index + ' select').addClass('select-1');
$('#buildBox' + index + ' select').attr('name','openedBuilds[' + index + '][]');
$('#buildBox' + index + ' select').attr('id','openedBuilds' + index);
- $('#buildBox' + index + ' select').chosen(defaultChosenOptions);
+ $('#buildBox' + index + ' select').chosen();
index++;
if($('#projects' + index).val() != 'ditto') break;
diff --git a/module/bug/js/browse.js b/module/bug/js/browse.js
index c48f4edd06..5bd584904b 100644
--- a/module/bug/js/browse.js
+++ b/module/bug/js/browse.js
@@ -4,7 +4,15 @@ $(function()
if(flow == 'onlyTest')
{
- $('#subNavbar > .nav > li[data-id=' + browseType + ']').addClass('active');
+ $('#subNavbar > .nav li[data-id=' + browseType + ']').addClass('active');
+ var $more = $('#subNavbar > .nav > li[data-id=more]');
+ if($more.find('.dropdown-menu').children().length)
+ {
+ $more.find('.dropdown-menu').children().each(function()
+ {
+ if($(this).hasClass('active')) $more.addClass('active');
+ });
+ }
var navWidth = $('#subNavbar > .nav').width();
var leftWidth = 0;
diff --git a/module/bug/js/common.js b/module/bug/js/common.js
index 9e565e87a2..35fc894ff7 100644
--- a/module/bug/js/common.js
+++ b/module/bug/js/common.js
@@ -21,7 +21,7 @@ $(function()
if(page == 'create' || page == 'edit' || page == 'assignedto' || page == 'confirmbug')
{
oldProductID = $('#product').val();
- $("#story, #task, #mailto").chosen(defaultChosenOptions);
+ $("#story, #task, #mailto").chosen();
}
if(window.flow != 'full')
@@ -57,7 +57,7 @@ function loadAll(productID)
{
$('#product').val(oldProductID);//Revert old product id if confirm is no.
$('#product').trigger("chosen:updated");
- $('#product').chosen(defaultChosenOptions);
+ $('#product').chosen();
return true;
}
@@ -66,7 +66,7 @@ function loadAll(productID)
else
{
$('#taskIdBox').innerHTML = ''; // Reset the task.
- $('#task').chosen(defaultChosenOptions);
+ $('#task').chosen();
loadProductBranches(productID)
loadProductModules(productID);
loadProductProjects(productID);
@@ -85,7 +85,7 @@ function loadAll(productID)
function loadBranch()
{
$('#taskIdBox').innerHTML = ''; // Reset the task.
- $('#task').chosen(defaultChosenOptions);
+ $('#task').chosen();
productID = $('#product').val();
loadProductModules(productID);
loadProductProjects(productID);
@@ -106,7 +106,7 @@ function loadAllBuilds(that)
{
oldResolvedBuild = $('#resolvedBuild').val() ? $('#resolvedBuild').val() : 0;
link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=resolvedBuild&build=' + oldResolvedBuild + '&branch=0&index=0&type=all');
- $('#resolvedBuildBox').load(link, function(){$(this).find('select').chosen(defaultChosenOptions)});
+ $('#resolvedBuildBox').load(link, function(){$(this).find('select').chosen()});
}
else
{
@@ -141,19 +141,19 @@ function loadAllProjectBuilds(projectID, productID)
{
oldOpenedBuild = $('#openedBuild').val() ? $('#openedBuild').val() : 0;
link = createLink('build', 'ajaxGetProjectBuilds', 'projectID=' + projectID + '&productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + '&branch=' + branch + '&index=0&needCreate=true&type=all');
- $('#buildBox').load(link, function(){ notice(); $('#openedBuild').chosen(defaultChosenOptions);});
+ $('#buildBox').load(link, function(){ notice(); $('#openedBuild').chosen();});
}
if(page == 'edit')
{
if(buildBox == 'openedBuildBox')
{
link = createLink('build', 'ajaxGetProjectBuilds', 'projectID=' + projectID + '&productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + '&branch=' + branch + '&index=0&needCreate=true&type=all');
- $('#openedBuildBox').load(link, function(){$(this).find('select').chosen(defaultChosenOptions)});
+ $('#openedBuildBox').load(link, function(){$(this).find('select').chosen()});
}
if(buildBox == 'resolvedBuildBox')
{
link = createLink('build', 'ajaxGetProjectBuilds', 'projectID=' + projectID + '&productID=' + productID + '&varName=resolvedBuild&build=' + oldResolvedBuild + '&branch=0&index=0&needCreate=true&type=all');
- $('#resolvedBuildBox').load(link, function(){$(this).find('select').chosen(defaultChosenOptions)});
+ $('#resolvedBuildBox').load(link, function(){$(this).find('select').chosen()});
}
}
}
@@ -172,19 +172,19 @@ function loadAllProductBuilds(productID)
if(page == 'create')
{
link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + '&branch=' + branch + '&index=0&type=all');
- $('#buildBox').load(link, function(){ notice(); $('#openedBuild').chosen(defaultChosenOptions);});
+ $('#buildBox').load(link, function(){ notice(); $('#openedBuild').chosen();});
}
if(page == 'edit')
{
if(buildBox == 'openedBuildBox')
{
link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + '&branch=' + branch + '&index=0&type=all');
- $('#openedBuildBox').load(link, function(){$(this).find('select').chosen(defaultChosenOptions)});
+ $('#openedBuildBox').load(link, function(){$(this).find('select').chosen()});
}
if(buildBox == 'resolvedBuildBox')
{
link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=resolvedBuild&build=' + oldResolvedBuild + '&branch=0&index=0&type=all');
- $('#resolvedBuildBox').load(link, function(){$(this).find('select').chosen(defaultChosenOptions)});
+ $('#resolvedBuildBox').load(link, function(){$(this).find('select').chosen()});
}
}
}
@@ -203,7 +203,7 @@ function loadProductModules(productID)
link = createLink('tree', 'ajaxGetOptionMenu', 'productID=' + productID + '&viewtype=bug&branch=' + branch + '&rootModuleID=0&returnType=html&fieldID=&needManage=true');
$('#moduleIdBox').load(link, function()
{
- $(this).find('select').chosen(defaultChosenOptions)
+ $(this).find('select').chosen()
});
}
@@ -219,7 +219,7 @@ function loadProductStories(productID)
branch = $('#branch').val();
if(typeof(branch) == 'undefined') branch = 0;
link = createLink('story', 'ajaxGetProductStories', 'productID=' + productID + '&branch=' + branch + '&moduleId=0&storyID=' + oldStoryID);
- $('#storyIdBox').load(link, function(){$('#story').chosen(defaultChosenOptions);});
+ $('#storyIdBox').load(link, function(){$('#story').chosen();});
}
/**
@@ -234,7 +234,7 @@ function loadProductProjects(productID)
branch = $('#branch').val();
if(typeof(branch) == 'undefined') branch = 0;
link = createLink('product', 'ajaxGetProjects', 'productID=' + productID + '&projectID=' + oldProjectID + '&branch=' + branch);
- $('#projectIdBox').load(link, function(){$(this).find('select').chosen(defaultChosenOptions)});
+ $('#projectIdBox').load(link, function(){$(this).find('select').chosen()});
}
/**
@@ -249,7 +249,7 @@ function loadProductplans(productID)
branch = $('#branch').val();
if(typeof(branch) == 'undefined') branch = 0;
link = createLink('productplan', 'ajaxGetProductplans', 'productID=' + productID + '&branch=' + branch);
- $('#planIdBox').load(link, function(){$(this).find('select').chosen(defaultChosenOptions)});
+ $('#planIdBox').load(link, function(){$(this).find('select').chosen()});
}
/**
@@ -267,13 +267,13 @@ function loadProductBuilds(productID)
if(page == 'create')
{
- $('#buildBox').load(link, function(){ notice(); $('#openedBuild').chosen(defaultChosenOptions);});
+ $('#buildBox').load(link, function(){ notice(); $('#openedBuild').chosen();});
}
else
{
- $('#openedBuildBox').load(link, function(){$(this).find('select').chosen(defaultChosenOptions)});
+ $('#openedBuildBox').load(link, function(){$(this).find('select').chosen()});
link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=resolvedBuild&build=' + oldResolvedBuild + '&branch=' + branch);
- $('#resolvedBuildBox').load(link, function(){$(this).find('select').chosen(defaultChosenOptions)});
+ $('#resolvedBuildBox').load(link, function(){$(this).find('select').chosen()});
}
}
@@ -311,7 +311,7 @@ function loadProjectRelated(projectID)
function loadProjectTasks(projectID)
{
link = createLink('task', 'ajaxGetProjectTasks', 'projectID=' + projectID + '&taskID=' + oldTaskID);
- $('#taskIdBox').load(link, function(){$('#task').chosen(defaultChosenOptions);});
+ $('#taskIdBox').load(link, function(){$('#task').chosen();});
}
/**
@@ -326,7 +326,7 @@ function loadProjectStories(projectID)
branch = $('#branch').val();
if(typeof(branch) == 'undefined') branch = 0;
link = createLink('story', 'ajaxGetProjectStories', 'projectID=' + projectID + '&productID=' + $('#product').val() + '&branch=' + branch + '&moduleID=0&storyID=' + oldStoryID);
- $('#storyIdBox').load(link, function(){$('#story').chosen(defaultChosenOptions);});
+ $('#storyIdBox').load(link, function(){$('#story').chosen();});
}
/**
@@ -346,15 +346,15 @@ function loadProjectBuilds(projectID)
if(page == 'create')
{
link = createLink('build', 'ajaxGetProjectBuilds', 'projectID=' + projectID + '&productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + "&branch=" + branch + "&index=0&needCreate=true");
- $('#buildBox').load(link, function(){ notice(); $('#openedBuild').chosen(defaultChosenOptions);});
+ $('#buildBox').load(link, function(){ notice(); $('#openedBuild').chosen();});
}
else
{
link = createLink('build', 'ajaxGetProjectBuilds', 'projectID=' + projectID + '&productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + '&branch=' + branch);
- $('#openedBuildBox').load(link, function(){$(this).find('select').chosen(defaultChosenOptions)});
+ $('#openedBuildBox').load(link, function(){$(this).find('select').chosen()});
link = createLink('build', 'ajaxGetProjectBuilds', 'projectID=' + projectID + '&productID=' + productID + '&varName=resolvedBuild&build=' + oldResolvedBuild + '&branch=' + branch);
- $('#resolvedBuildBox').load(link, function(){$(this).find('select').chosen(defaultChosenOptions)});
+ $('#resolvedBuildBox').load(link, function(){$(this).find('select').chosen()});
}
}
@@ -376,7 +376,7 @@ function setStories(moduleID, productID)
if(!stories) stories = '';
$('#story').replaceWith(stories);
$('#story_chosen').remove();
- $("#story").chosen(defaultChosenOptions);
+ $("#story").chosen();
});
}
@@ -410,7 +410,7 @@ function loadProductBranches(productID)
function loadAssignedTo(projectID)
{
link = createLink('bug', 'ajaxLoadAssignedTo', 'projectID=' + projectID + '&selectedUser=' + $('#assignedTo').val());
- $('#assignedToBox').load(link, function(){$('#assignedTo').chosen(defaultChosenOptions);});
+ $('#assignedToBox').load(link, function(){$('#assignedTo').chosen();});
}
/**
diff --git a/module/bug/js/create.js b/module/bug/js/create.js
index ef4c921464..8416c0e8b8 100644
--- a/module/bug/js/create.js
+++ b/module/bug/js/create.js
@@ -29,7 +29,7 @@ function loadAllUsers()
function loadProjectTeamMembers(productID)
{
var link = createLink('bug', 'ajaxLoadProjectTeamMembers', 'productID=' + productID + '&selectedUser=' + $('#assignedTo').val());
- $('#assignedToBox').load(link, function(){$('#assignedTo').chosen(defaultChosenOptions);});
+ $('#assignedToBox').load(link, function(){$('#assignedTo').chosen();});
}
/**
diff --git a/module/bug/model.php b/module/bug/model.php
index 7405d1673e..9290177b28 100644
--- a/module/bug/model.php
+++ b/module/bug/model.php
@@ -101,39 +101,26 @@ class bugModel extends model
$replace['productID'] = $productID;
$replace['branch'] = $branch;
$replace['param'] = $moduleID;
+
+ /* Replace for dropdown submenu. */
+ if(isset($this->lang->bug->subMenu->$key))
+ {
+ $subMenu = common::createSubMenu($this->lang->bug->subMenu->$key, $replace);
+
+ /* Avoid the menu shaking when change it by js. */
+ if(isset($subMenu[$browseType]))
+ {
+ $currentSubMenu = $subMenu[$browseType];
+ $this->lang->bug->menu->more['link'] = "$currentSubMenu->text|" . implode('|', $currentSubMenu->link);
+ }
+
+ if(!empty($subMenu)) $this->lang->bug->menu->{$key}['subMenu'] = $subMenu;
+ }
+
+ if($this->app->getMethodName() != 'view') $this->lang->bug->menu->bysearch = " {$this->lang->bug->byQuery}";
}
common::setMenuVars($this->lang->bug->menu, $key, $replace);
}
- if($this->config->global->flow != 'full')
- {
- $tmpMenu = (array)$this->lang->bug->menu;
- $moreMenu = array_slice($tmpMenu, -6);
- $tmpMenu = array_slice($tmpMenu, 0, count($tmpMenu) - 6);
- if($moreMenu)
- {
- $moreKey = 'more';
- $moreLabel = $this->lang->more;
- if(isset($this->lang->bug->moreSelects[$browseType]))
- {
- $moreKey = $browseType;
- $moreLabel = $this->lang->bug->moreSelects[$browseType];
- }
- $more = "{$moreLabel}";
- $more .= "
';
- $tmpMenu[$moreKey] = $more;
- }
- if($this->app->getMethodName() != 'view') $tmpMenu['bysearch'] = " {$this->lang->bug->byQuery}";
- $this->lang->bug->menu = (object)$tmpMenu;
- }
}
/**
diff --git a/module/common/lang/en.php b/module/common/lang/en.php
index 73be22bebe..316c57d4be 100644
--- a/module/common/lang/en.php
+++ b/module/common/lang/en.php
@@ -229,13 +229,13 @@ $lang->release->menu = $lang->product->menu;
$lang->project = new stdclass();
$lang->project->menu = new stdclass();
-$lang->project->menu->list = array('link' => '%s', 'subModule' => 'task,grouptask,tree', 'alias' => 'grouptask,importtask,importbug,tree');
+$lang->project->menu->list = array('link' => 'Task List|project|task|projectID=%s', 'subModule' => 'task,grouptask,tree', 'alias' => 'grouptask,importtask,importbug,tree', 'class' => 'dropdown dropdown-hover');
$lang->project->menu->kanban = array('link' => 'Kanban|project|kanban|projectID=%s');
$lang->project->menu->burn = array('link' => 'Burn|project|burn|projectID=%s');
$lang->project->menu->story = array('link' => 'Story|project|story|projectID=%s', 'subModule' => 'story', 'alias' => 'linkstory,storykanban');
-$lang->project->menu->qa = array('link' => '%s', 'subModule' => 'bug,build,testtask');
+$lang->project->menu->qa = array('link' => 'Bug|project|bug|projectID=%s', 'subModule' => 'bug,build,testtask', 'alias' => 'build,testtask', 'class' => 'dropdown dropdown-hover');
$lang->project->menu->doc = array('link' => 'Doc|doc|objectLibs|type=project&objectID=%s&from=project', 'subModule' => 'doc');
-$lang->project->menu->action = array('link' => '%s');
+$lang->project->menu->action = array('link' => 'Dynamic|project|dynamic|projectID=%s', 'subModule' => 'dynamic', 'class' => 'dropdown dropdown-hover');
$lang->project->menu->product = $lang->productCommon . '|project|manageproducts|projectID=%s';
$lang->project->menu->team = array('link' => 'Team|project|team|projectID=%s', 'alias' => 'managemembers');
$lang->project->menu->view = array('link' => 'Overview|project|view|projectID=%s', 'alias' => 'edit,start,suspend,putoff,close');
@@ -723,12 +723,16 @@ if(isset($config->global->flow) and $config->global->flow == 'onlyTest')
$lang->bug->menu->resolvedbyme = 'ResolvedByMe|bug|browse|productID=%s&branch=%s&browseType=resolvedbyme¶m=%s';
$lang->bug->menu->toclosed = 'ToBeClosed|bug|browse|productID=%s&branch=%s&browseType=toclosed¶m=%s';
$lang->bug->menu->unresolved = 'Unresolved|bug|browse|productID=%s&branch=%s&browseType=unresolved¶m=%s';
- $lang->bug->menu->unconfirmed = 'Unconfirmed|bug|browse|productID=%s&branch=%s&browseType=unconfirmed¶m=%s';
- $lang->bug->menu->assigntonull = 'Unassigned|bug|browse|productID=%s&branch=%s&browseType=assigntonull¶m=%s';
- $lang->bug->menu->longlifebugs = 'Pending|bug|browse|productID=%s&branch=%s&browseType=longlifebugs¶m=%s';
- $lang->bug->menu->postponedbugs = 'PostPoned|bug|browse|productID=%s&branch=%s&browseType=postponedbugs¶m=%s';
- $lang->bug->menu->overduebugs = 'Overdue|bug|browse|productID=%s&branch=%s&browseType=overduebugs¶m=%s';
- $lang->bug->menu->needconfirm = 'NeedConfirm|bug|browse|productID=%s&branch=%s&browseType=needconfirm¶m=%s';
+ $lang->bug->menu->more = array('link' => 'More|bug|browse|productID=%s&branch=%s&browseType=unconfirmed¶m=%s', 'class' => 'dropdown dropdown-hover');
+
+ $lang->bug->subMenu = new stdclass();
+ $lang->bug->subMenu->more = new stdclass();
+ $lang->bug->subMenu->more->unconfirmed = 'Unconfirmed|bug|browse|productID=%s&branch=%s&browseType=unconfirmed¶m=%s';
+ $lang->bug->subMenu->more->assigntonull = 'Unassigned|bug|browse|productID=%s&branch=%s&browseType=assigntonull¶m=%s';
+ $lang->bug->subMenu->more->longlifebugs = 'Pending|bug|browse|productID=%s&branch=%s&browseType=longlifebugs¶m=%s';
+ $lang->bug->subMenu->more->postponedbugs = 'PostPoned|bug|browse|productID=%s&branch=%s&browseType=postponedbugs¶m=%s';
+ $lang->bug->subMenu->more->overduebugs = 'Overdue|bug|browse|productID=%s&branch=%s&browseType=overduebugs¶m=%s';
+ $lang->bug->subMenu->more->needconfirm = 'NeedConfirm|bug|browse|productID=%s&branch=%s&browseType=needconfirm¶m=%s';
$lang->bug->menuOrder[5] = 'product';
$lang->bug->menuOrder[10] = 'all';
@@ -747,9 +751,13 @@ if(isset($config->global->flow) and $config->global->flow == 'onlyTest')
/* Adjust sub menu of testcase. */
$lang->testcase->menu = new stdclass();
- $lang->testcase->menu->all = 'All|testcase|browse|productID=%s&branch=%s&browseType=all';
- $lang->testcase->menu->wait = 'Wait|testcase|browse|productID=%s&branch=%s&browseType=wait';
- $lang->testcase->menu->suite = array('link' => '%s', 'fixed' => true);
+ $lang->testcase->menu->all = 'All|testcase|browse|productID=%s&branch=%s&browseType=all';
+ $lang->testcase->menu->wait = 'Wait|testcase|browse|productID=%s&branch=%s&browseType=wait';
+ $lang->testcase->menu->bysuite = array('link' => 'Test Suite|testsuite|create|productID=%s', 'class' => 'dropdown dropdown-hover');
+
+ $lang->testcase->subMenu = new stdclass();
+ $lang->testcase->subMenu->bysuite = new stdclass();
+ $lang->testcase->subMenu->bysuite->create = 'Create Suite|testsuite|create|productID=%s';
$lang->testcase->menuOrder[5] = 'product';
$lang->testcase->menuOrder[10] = 'all';
diff --git a/module/common/lang/zh-cn.php b/module/common/lang/zh-cn.php
index acb0ce8ed2..28f0cbfaec 100644
--- a/module/common/lang/zh-cn.php
+++ b/module/common/lang/zh-cn.php
@@ -229,16 +229,16 @@ $lang->release->menu = $lang->product->menu;
$lang->project = new stdclass();
$lang->project->menu = new stdclass();
-$lang->project->menu->list = array('link' => '%s', 'subModule' => 'task,grouptask,tree', 'alias' => 'grouptask,importtask,importbug,tree');
-$lang->project->menu->kanban = array('link' => '看板|project|kanban|projectID=%s');
-$lang->project->menu->burn = array('link' => '燃尽图|project|burn|projectID=%s');
-$lang->project->menu->story = array('link' => '需求|project|story|projectID=%s', 'subModule' => 'story', 'alias' => 'linkstory,storykanban');
-$lang->project->menu->qa = array('link' => '%s', 'subModule' => 'bug,build,testtask');
-$lang->project->menu->doc = array('link' => '文档|doc|objectLibs|type=project&objectID=%s&from=project', 'subModule' => 'doc');
-$lang->project->menu->action = array('link' => '%s');
-$lang->project->menu->product = $lang->productCommon . '|project|manageproducts|projectID=%s';
-$lang->project->menu->team = array('link' => '团队|project|team|projectID=%s', 'alias' => 'managemembers');
-$lang->project->menu->view = array('link' => '概况|project|view|projectID=%s', 'alias' => 'edit,start,suspend,putoff,close');
+$lang->project->menu->list = array('link' => '任务列表|project|task|projectID=%s', 'subModule' => 'task,grouptask,tree', 'alias' => 'grouptask,importtask,importbug,tree', 'class' => 'dropdown dropdown-hover');
+$lang->project->menu->kanban = array('link' => '看板|project|kanban|projectID=%s');
+$lang->project->menu->burn = array('link' => '燃尽图|project|burn|projectID=%s');
+$lang->project->menu->story = array('link' => '需求|project|story|projectID=%s', 'subModule' => 'story', 'alias' => 'linkstory,storykanban');
+$lang->project->menu->qa = array('link' => 'Bug|project|bug|projectID=%s', 'subModule' => 'bug,build,testtask', 'alias' => 'build,testtask', 'class' => 'dropdown dropdown-hover');
+$lang->project->menu->doc = array('link' => '文档|doc|objectLibs|type=project&objectID=%s&from=project', 'subModule' => 'doc');
+$lang->project->menu->action = array('link' => '动态|project|dynamic|projectID=%s', 'subModule' => 'dynamic', 'class' => 'dropdown dropdown-hover');
+$lang->project->menu->product = $lang->productCommon . '|project|manageproducts|projectID=%s';
+$lang->project->menu->team = array('link' => '团队|project|team|projectID=%s', 'alias' => 'managemembers');
+$lang->project->menu->view = array('link' => '概况|project|view|projectID=%s', 'alias' => 'edit,start,suspend,putoff,close');
$lang->project->subMenu = new stdclass();
$lang->project->subMenu->list = new stdclass();
@@ -723,12 +723,16 @@ if(isset($config->global->flow) and $config->global->flow == 'onlyTest')
$lang->bug->menu->resolvedbyme = '由我解决|bug|browse|productID=%s&branch=%s&browseType=resolvedbyme¶m=%s';
$lang->bug->menu->toclosed = '待关闭|bug|browse|productID=%s&branch=%s&browseType=toclosed¶m=%s';
$lang->bug->menu->unresolved = '未解决|bug|browse|productID=%s&branch=%s&browseType=unresolved¶m=%s';
- $lang->bug->menu->unconfirmed = '未确认|bug|browse|productID=%s&branch=%s&browseType=unconfirmed¶m=%s';
- $lang->bug->menu->assigntonull = '未指派|bug|browse|productID=%s&branch=%s&browseType=assigntonull¶m=%s';
- $lang->bug->menu->longlifebugs = '久未处理|bug|browse|productID=%s&branch=%s&browseType=longlifebugs¶m=%s';
- $lang->bug->menu->postponedbugs = '被延期|bug|browse|productID=%s&branch=%s&browseType=postponedbugs¶m=%s';
- $lang->bug->menu->overduebugs = '过期Bug|bug|browse|productID=%s&branch=%s&browseType=overduebugs¶m=%s';
- $lang->bug->menu->needconfirm = '需求变动|bug|browse|productID=%s&branch=%s&browseType=needconfirm¶m=%s';
+ $lang->bug->menu->more = array('link' => '更多|bug|browse|productID=%s&branch=%s&browseType=unconfirmed¶m=%s', 'class' => 'dropdown dropdown-hover');
+
+ $lang->bug->subMenu = new stdclass();
+ $lang->bug->subMenu->more = new stdclass();
+ $lang->bug->subMenu->more->unconfirmed = '未确认|bug|browse|productID=%s&branch=%s&browseType=unconfirmed¶m=%s';
+ $lang->bug->subMenu->more->assigntonull = '未指派|bug|browse|productID=%s&branch=%s&browseType=assigntonull¶m=%s';
+ $lang->bug->subMenu->more->longlifebugs = '久未处理|bug|browse|productID=%s&branch=%s&browseType=longlifebugs¶m=%s';
+ $lang->bug->subMenu->more->postponedbugs = '被延期|bug|browse|productID=%s&branch=%s&browseType=postponedbugs¶m=%s';
+ $lang->bug->subMenu->more->overduebugs = '过期Bug|bug|browse|productID=%s&branch=%s&browseType=overduebugs¶m=%s';
+ $lang->bug->subMenu->more->needconfirm = '需求变动|bug|browse|productID=%s&branch=%s&browseType=needconfirm¶m=%s';
$lang->bug->menuOrder[5] = 'product';
$lang->bug->menuOrder[10] = 'all';
@@ -747,9 +751,13 @@ if(isset($config->global->flow) and $config->global->flow == 'onlyTest')
/* Adjust sub menu of testcase. */
$lang->testcase->menu = new stdclass();
- $lang->testcase->menu->all = '所有|testcase|browse|productID=%s&branch=%s&browseType=all';
- $lang->testcase->menu->wait = '待评审|testcase|browse|productID=%s&branch=%s&browseType=wait';
- $lang->testcase->menu->suite = array('link' => '%s', 'fixed' => true);
+ $lang->testcase->menu->all = '所有|testcase|browse|productID=%s&branch=%s&browseType=all';
+ $lang->testcase->menu->wait = '待评审|testcase|browse|productID=%s&branch=%s&browseType=wait';
+ $lang->testcase->menu->bysuite = array('link' => '套件|testsuite|create|productID=%s', 'class' => 'dropdown dropdown-hover');
+
+ $lang->testcase->subMenu = new stdclass();
+ $lang->testcase->subMenu->bysuite = new stdclass();
+ $lang->testcase->subMenu->bysuite->create = '建套件|testsuite|create|productID=%s';
$lang->testcase->menuOrder[5] = 'product';
$lang->testcase->menuOrder[10] = 'all';
diff --git a/module/common/lang/zh-tw.php b/module/common/lang/zh-tw.php
index 58ba92753b..aaf98cd0e2 100644
--- a/module/common/lang/zh-tw.php
+++ b/module/common/lang/zh-tw.php
@@ -229,16 +229,16 @@ $lang->release->menu = $lang->product->menu;
$lang->project = new stdclass();
$lang->project->menu = new stdclass();
-$lang->project->menu->list = array('link' => '%s', 'subModule' => 'task,grouptask,tree', 'alias' => 'grouptask,importtask,importbug,tree');
-$lang->project->menu->kanban = array('link' => '看板|project|kanban|projectID=%s');
-$lang->project->menu->burn = array('link' => '燃盡圖|project|burn|projectID=%s');
-$lang->project->menu->story = array('link' => '需求|project|story|projectID=%s', 'subModule' => 'story', 'alias' => 'linkstory,storykanban');
-$lang->project->menu->qa = array('link' => '%s', 'subModule' => 'bug,build,testtask');
-$lang->project->menu->doc = array('link' => '文檔|doc|objectLibs|type=project&objectID=%s&from=project', 'subModule' => 'doc');
-$lang->project->menu->action = array('link' => '%s');
-$lang->project->menu->product = $lang->productCommon . '|project|manageproducts|projectID=%s';
-$lang->project->menu->team = array('link' => '團隊|project|team|projectID=%s', 'alias' => 'managemembers');
-$lang->project->menu->view = array('link' => '概況|project|view|projectID=%s', 'alias' => 'edit,start,suspend,putoff,close');
+$lang->project->menu->list = array('link' => '任務列表|project|task|projectID=%s', 'subModule' => 'task,grouptask,tree', 'alias' => 'grouptask,importtask,importbug,tree', 'class' => 'dropdown dropdown-hover');
+$lang->project->menu->kanban = array('link' => '看板|project|kanban|projectID=%s');
+$lang->project->menu->burn = array('link' => '燃盡圖|project|burn|projectID=%s');
+$lang->project->menu->story = array('link' => '需求|project|story|projectID=%s', 'subModule' => 'story', 'alias' => 'linkstory,storykanban');
+$lang->project->menu->qa = array('link' => 'Bug|project|bug|projectID=%s', 'subModule' => 'bug,build,testtask', 'alias' => 'build,testtask', 'class' => 'dropdown dropdown-hover');
+$lang->project->menu->doc = array('link' => '文檔|doc|objectLibs|type=project&objectID=%s&from=project', 'subModule' => 'doc');
+$lang->project->menu->action = array('link' => '動態|project|dynamic|projectID=%s', 'subModule' => 'dynamic', 'class' => 'dropdown dropdown-hover');
+$lang->project->menu->product = $lang->productCommon . '|project|manageproducts|projectID=%s';
+$lang->project->menu->team = array('link' => '團隊|project|team|projectID=%s', 'alias' => 'managemembers');
+$lang->project->menu->view = array('link' => '概況|project|view|projectID=%s', 'alias' => 'edit,start,suspend,putoff,close');
$lang->project->subMenu = new stdclass();
$lang->project->subMenu->list = new stdclass();
@@ -723,12 +723,16 @@ if(isset($config->global->flow) and $config->global->flow == 'onlyTest')
$lang->bug->menu->resolvedbyme = '由我解決|bug|browse|productID=%s&branch=%s&browseType=resolvedbyme¶m=%s';
$lang->bug->menu->toclosed = '待關閉|bug|browse|productID=%s&branch=%s&browseType=toclosed¶m=%s';
$lang->bug->menu->unresolved = '未解決|bug|browse|productID=%s&branch=%s&browseType=unresolved¶m=%s';
- $lang->bug->menu->unconfirmed = '未確認|bug|browse|productID=%s&branch=%s&browseType=unconfirmed¶m=%s';
- $lang->bug->menu->assigntonull = '未指派|bug|browse|productID=%s&branch=%s&browseType=assigntonull¶m=%s';
- $lang->bug->menu->longlifebugs = '久未處理|bug|browse|productID=%s&branch=%s&browseType=longlifebugs¶m=%s';
- $lang->bug->menu->postponedbugs = '被延期|bug|browse|productID=%s&branch=%s&browseType=postponedbugs¶m=%s';
- $lang->bug->menu->overduebugs = '過期Bug|bug|browse|productID=%s&branch=%s&browseType=overduebugs¶m=%s';
- $lang->bug->menu->needconfirm = '需求變動|bug|browse|productID=%s&branch=%s&browseType=needconfirm¶m=%s';
+ $lang->bug->menu->more = array('link' => '更多|bug|browse|productID=%s&branch=%s&browseType=unconfirmed¶m=%s', 'class' => 'dropdown dropdown-hover');
+
+ $lang->bug->subMenu = new stdclass();
+ $lang->bug->subMenu->more = new stdclass();
+ $lang->bug->subMenu->more->unconfirmed = '未確認|bug|browse|productID=%s&branch=%s&browseType=unconfirmed¶m=%s';
+ $lang->bug->subMenu->more->assigntonull = '未指派|bug|browse|productID=%s&branch=%s&browseType=assigntonull¶m=%s';
+ $lang->bug->subMenu->more->longlifebugs = '久未處理|bug|browse|productID=%s&branch=%s&browseType=longlifebugs¶m=%s';
+ $lang->bug->subMenu->more->postponedbugs = '被延期|bug|browse|productID=%s&branch=%s&browseType=postponedbugs¶m=%s';
+ $lang->bug->subMenu->more->overduebugs = '過期Bug|bug|browse|productID=%s&branch=%s&browseType=overduebugs¶m=%s';
+ $lang->bug->subMenu->more->needconfirm = '需求變動|bug|browse|productID=%s&branch=%s&browseType=needconfirm¶m=%s';
$lang->bug->menuOrder[5] = 'product';
$lang->bug->menuOrder[10] = 'all';
@@ -747,9 +751,13 @@ if(isset($config->global->flow) and $config->global->flow == 'onlyTest')
/* Adjust sub menu of testcase. */
$lang->testcase->menu = new stdclass();
- $lang->testcase->menu->all = '所有|testcase|browse|productID=%s&branch=%s&browseType=all';
- $lang->testcase->menu->wait = '待評審|testcase|browse|productID=%s&branch=%s&browseType=wait';
- $lang->testcase->menu->suite = array('link' => '%s', 'fixed' => true);
+ $lang->testcase->menu->all = '所有|testcase|browse|productID=%s&branch=%s&browseType=all';
+ $lang->testcase->menu->wait = '待評審|testcase|browse|productID=%s&branch=%s&browseType=wait';
+ $lang->testcase->menu->bysuite = array('link' => '套件|testsuite|create|productID=%s', 'class' => 'dropdown dropdown-hover');
+
+ $lang->testcase->subMenu = new stdclass();
+ $lang->testcase->subMenu->bysuite = new stdclass();
+ $lang->testcase->subMenu->bysuite->create = '建套件|testsuite|create|productID=%s';
$lang->testcase->menuOrder[5] = 'product';
$lang->testcase->menuOrder[10] = 'all';
diff --git a/module/common/model.php b/module/common/model.php
index bf625a0a04..c164a9fba2 100644
--- a/module/common/model.php
+++ b/module/common/model.php
@@ -349,6 +349,40 @@ class commonModel extends model
return $link;
}
+ /**
+ * Create sub menu by settings in lang files.
+ *
+ * @param array $items
+ * @param mixed $replace
+ * @static
+ * @access public
+ * @return array
+ */
+ public static function createSubMenu($items, $replace)
+ {
+ $subMenu = array();
+ foreach($items as $subMenuKey => $subMenuLink)
+ {
+ if(isset($subMenuLink['link'])) $subMenuLink = $subMenuLink['link'];
+ $subMenuLink = vsprintf($subMenuLink, $replace);
+ list($subMenuName, $subMenuModule, $subMenuMethod, $subMenuParams) = explode('|', $subMenuLink);
+
+ $link = array();
+ $link['module'] = $subMenuModule;
+ $link['method'] = $subMenuMethod;
+ $link['vars'] = $subMenuParams;
+
+ $menu = new stdclass();
+ $menu->name = $subMenuKey;
+ $menu->link = $link;
+ $menu->text = $subMenuName;
+ $menu->hidden = false;
+ $subMenu[$subMenuKey] = $menu;
+ }
+
+ return $subMenu;
+ }
+
/**
* Print the main menu.
*
@@ -468,7 +502,7 @@ class commonModel extends model
echo $isMobile ? '' : "\n";
if(isset($lang->menugroup->$moduleName)) $moduleName = $lang->menugroup->$moduleName;
- /* Cycling to print every sub menus. */
+ /* Cycling to print every sub menu. */
foreach($menu as $menuItem)
{
if(isset($lang->$moduleName->dividerMenu) and strpos($lang->$moduleName->dividerMenu, ",{$menuItem->name},") !== false) echo "";
@@ -505,7 +539,56 @@ class commonModel extends model
if($currentModule == 'testsuite' && $currentMethod == 'library') $active = '';
}
- $menuItemHtml = "- " . html::a($link, $menuItem->text, $target) . "
\n";
+ $label = $menuItem->text;
+ $subMenu = '';
+ /* Print sub menus. */
+ if(isset($menuItem->subMenu))
+ {
+ $firstLink = '';
+ $firstLabel = '';
+ foreach($menuItem->subMenu as $subMenuItem)
+ {
+ if($subMenuItem->hidden) continue;
+
+ $subActive = '';
+ $subModule = '';
+ $subMethod = '';
+ $subParams = '';
+ $subLabel = $subMenuItem->text;
+ if(isset($subMenuItem->link['module'])) $subModule = $subMenuItem->link['module'];
+ if(isset($subMenuItem->link['method'])) $subMethod = $subMenuItem->link['method'];
+ if(isset($subMenuItem->link['vars'])) $subParams = $subMenuItem->link['vars'];
+
+ $subLink = helper::createLink($subModule, $subMethod, $subParams);
+
+ if($config->global->flow != 'onlyTest' && $currentModule == strtolower($subModule) && $currentMethod == strtolower($subMethod)) $subActive = 'active';
+
+ $subMenu .= "- " . html::a($subLink, $subLabel) . '
';
+
+ if(!$firstLink) $firstLink = $subLink;
+ if(!$firstLabel) $firstLabel = $subLabel;
+ }
+
+ if(!$firstLink or !$firstLabel) continue;
+
+ if($config->global->flow == 'onlyTest')
+ {
+ $link = $firstLink;
+ }
+ else
+ {
+ $link = $firstLink;
+ $label = $firstLabel;
+ }
+
+ if($subMenu)
+ {
+ $label .= "";
+ $subMenu = "";
+ }
+ }
+
+ $menuItemHtml = "- " . html::a($link, $label, $target) . $subMenu . "
\n";
if($isMobile) $menuItemHtml = html::a($link, $menuItem->text, $target, "class='$class $active'") . "\n";
echo $menuItemHtml;
}
@@ -1326,7 +1409,7 @@ EOD;
if(strpos(",{$limitedProjects},", ",$objectID,") !== false) $limitedProject = true;
if(empty($app->user->rights['rights']['my']['limited']) && !$limitedProject) return true;
}
-
+ if(empty($app->user->rights['rights']['my']['limited'])) return true;
if(!is_null($method) && strpos($method, 'batch') === 0) return false;
if(!is_null($method) && strpos($method, 'link') === 0) return false;
diff --git a/module/common/view/chosen.html.php b/module/common/view/chosen.html.php
index d858549e5d..73bcf4f74d 100755
--- a/module/common/view/chosen.html.php
+++ b/module/common/view/chosen.html.php
@@ -4,6 +4,6 @@ var chooseUsersToMail = 'chooseUsersToMail;?>';
$(document).ready(function()
{
$("#mailto").attr('data-placeholder', chooseUsersToMail);
- $("#mailto, #productID").chosen($.defaultChosenOptions).on('chosen:showing_dropdown');
+ $("#mailto, #productID").chosen();
});
diff --git a/module/custom/css/ajaxmenu.css b/module/custom/css/ajaxmenu.css
index b9fd5075b5..1ed14b18df 100644
--- a/module/custom/css/ajaxmenu.css
+++ b/module/custom/css/ajaxmenu.css
@@ -12,5 +12,5 @@
#menuEditor li > a .item-hidden-icon {display: none; margin-left: 3px;}
#menuEditor .dropdown-menu > li > a .item-hidden-icon {margin-left: 10px;}
#menuEditor li.menu-hidden > a .item-hidden-icon {display: inline-block;}
-#menuEditor .nav > li.menu-hidden > a {opacity: .7; border: 1px dashed #ddd; background: rgba(0,0,0,.1); margin: 0 2px;}
+#menuEditor .nav > li.menu-hidden > a {border: 1px dashed #ddd; background: rgba(0,0,0,.1); margin: 0 2px;}
#menuEditor .nav > li.menu-hidden > a > .dropdown{display: inline-block;}
diff --git a/module/custom/js/ajaxmenu.js b/module/custom/js/ajaxmenu.js
index 92a936973e..30f2e24004 100644
--- a/module/custom/js/ajaxmenu.js
+++ b/module/custom/js/ajaxmenu.js
@@ -45,9 +45,34 @@ $(function()
if(!item.text || item.fixed) return;
var $a = $('').append(item.text);
$a.data('menu', item).append('');
- $('').attr('data-id', item.name).toggleClass('right', item.float === 'right').toggleClass('menu-hidden', !!item.hidden).append($a).appendTo($nav);
- var $dropmenu = $a.find('.dropdown-menu').empty();
- return $dropmenu.remove(); // Disable custom submenu, full function see https://github.com/easysoft/zentaopms/blob/c7fdbddfc074ddd7ddf539b1d3b5f108ab13ec7b/module/custom/js/ajaxmenu.js
+ var hidden = !!item.hidden;
+ if(item.subMenu)
+ {
+ hidden = true;
+ $a.addClass('dropdown dropdown-hover').append("");
+ var $dropmenu = $a.find('.dropdown-menu');
+ $.each(item.subMenu, function(subIdx, subItem)
+ {
+ subItem.order = subIdx + 1;
+ var $subA = $('').append(subItem.text);
+ $subA.data('menu', subItem).append('');
+ $('').attr('data-id', subItem.name).toggleClass('right', subItem.float === 'right').toggleClass('menu-hidden', !!subItem.hidden).append($subA).appendTo($dropmenu);
+
+ hidden = subItem.hidden && hidden;
+ });
+ var $aInner = $a.children('a');
+ if ($aInner.length)
+ {
+ $aInner.replaceWith($('' + $aInner.text() + ' '));
+ $a.addClass('dropdown-hover');
+ }
+ if(!$dropmenu.children().length)
+ {
+ $a.removeClass('dropdown dropdown-hover').find('.caret').remove();
+ $dropmenu.remove();
+ }
+ }
+ $('').attr('data-id', item.name).toggleClass('right', item.float === 'right').toggleClass('menu-hidden', hidden).append($a).appendTo($nav);
});
$nav.sortable({finish: function(e)
{
@@ -113,17 +138,19 @@ $(function()
var data = {name: item.name, order: parseInt(item.order)};
if(item.hidden) data.hidden = true;
if(item.float) data.float = item.float;
- dataList.push(data);
- if (item.subMenu)
+ if(item.subMenu)
{
+ var subMenu = [];
$.each(item.subMenu, function(sIdx, subItem)
{
var subData = {name: subItem.name, order: parseInt(subItem.order)};
if(subItem.hidden) subData.hidden = true;
if(subItem.float) subData.float = subItem.float;
- dataList.push(subData);
+ subMenu.push(subData);
});
+ data.subMenu = subMenu;
}
+ dataList.push(data);
});
return dataList;
};
@@ -200,9 +227,11 @@ $(function()
}
}).on('click', '.nav>li>a,.dropdown-menu>li>a', function(e)
{
- var $a = $(this);
- var item = $a.data('menu');
- if (!item) return;
+ var $a = $(this);
+ var item = $a.data('menu');
+ if(!item) return;
+ if($a.find('.dropdown-menu').length) return;
+
var $menu = $a.closest('nav');
var moduleName = item.link && item.link['module'] ? item.link['module'] : item.name;
var methodName = item.link && item.link['method'] ? item.link['method'] : '';
@@ -213,6 +242,19 @@ $(function()
methodName = item.name;
}
$a.parent().toggleClass('menu-hidden', item.hidden);
+
+ /* Update parent menu by sub menu. */
+ if($a.parent().parent().hasClass('dropdown-menu'))
+ {
+ var hidden = true;
+ $a.parent().parent().children().each(function()
+ {
+ hidden = $(this).hasClass('menu-hidden') && hidden;
+ });
+
+ $a.parent().parent().parent().parent().toggleClass('menu-hidden', hidden);
+ }
+
updateConfig($menu);
e.stopPropagation();
});
diff --git a/module/custom/model.php b/module/custom/model.php
index 7963d8a248..4d1f576faa 100644
--- a/module/custom/model.php
+++ b/module/custom/model.php
@@ -140,11 +140,11 @@ class customModel extends model
public static function setMenuByConfig($allMenu, $customMenu, $module = '')
{
global $app, $lang, $config;
- $menu = array();
- $menuModuleName = $module;
- $order = 1;
- $customMenuMap = array();
- $isTutorialMode = commonModel::isTutorialMode();
+ $menu = array();
+ $menuModuleName = $module;
+ $order = 1;
+ $customMenuMap = array();
+ $isTutorialMode = commonModel::isTutorialMode();
if($customMenu)
{
@@ -201,8 +201,8 @@ class customModel extends model
/* Merge fileMenu and customMenu. */
foreach($customMenuMap as $name => $item)
{
- if(is_object($allMenu) and !isset($allMenu->$name))$allMenu->$name = $item;
- if(is_array($allMenu) and !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)
@@ -249,13 +249,32 @@ class customModel extends model
}
$hidden = isset($customMenuMap[$name]) && isset($customMenuMap[$name]->hidden) && $customMenuMap[$name]->hidden;
+
+ if(isset($item['subMenu']))
+ {
+ foreach($item['subMenu'] as $subItem)
+ {
+ if(isset($subItem->link['module']) && isset($subItem->link['method']))
+ {
+ $subItem->hidden = !common::hasPriv($subItem->link['module'], $subItem->link['method']);
+ }
+ }
+ if(isset($customMenuMap[$name]->subMenu))
+ {
+ foreach($customMenuMap[$name]->subMenu as $subItem)
+ {
+ if(isset($subItem->hidden) && isset($item['subMenu'][$subItem->name])) $item['subMenu'][$subItem->name]->hidden = $subItem->hidden;
+ }
+ }
+ }
+
if(strpos($name, 'QUERY') === 0 and !isset($customMenuMap[$name])) $hidden = true;
$menuItem = new stdclass();
- $menuItem->name = $name;
- $menuItem->link = $itemLink;
- $menuItem->text = $label;
- $menuItem->order = (isset($customMenuMap[$name]) && isset($customMenuMap[$name]->order) ? $customMenuMap[$name]->order : $order++);
+ $menuItem->name = $name;
+ $menuItem->link = $itemLink;
+ $menuItem->text = $label;
+ $menuItem->order = (isset($customMenuMap[$name]) && isset($customMenuMap[$name]->order) ? $customMenuMap[$name]->order : $order++);
if($hidden) $menuItem->hidden = $hidden;
if($class) $menuItem->class = $class;
if($subModule)$menuItem->subModule = $subModule;
diff --git a/module/custom/view/required.html.php b/module/custom/view/required.html.php
index 6264aca9b0..031cbf4b68 100644
--- a/module/custom/view/required.html.php
+++ b/module/custom/view/required.html.php
@@ -39,6 +39,8 @@
custom->getFormFields($moduleName, $method);
+ if($moduleName == 'doc' and $method == 'createlib') $method = 'createLib';
+ if($moduleName == 'doc' and $method == 'editlib') $method = 'editLib';
if($moduleName == 'testsuite' and $method == 'createlib') $method = 'createLib';
if($moduleName == 'testsuite' and $method == 'createcase')
{
diff --git a/module/dev/lang/zh-tw.php b/module/dev/lang/zh-tw.php
index b7001d72b8..65da631b39 100644
--- a/module/dev/lang/zh-tw.php
+++ b/module/dev/lang/zh-tw.php
@@ -82,7 +82,6 @@ $lang->dev->tableList['testsuite'] = '測試套件';
$lang->dev->tableList['tree'] = '模組關係';
$lang->dev->tableList['upgrade'] = '更新';
$lang->dev->tableList['cron'] = '定時任務';
-$lang->dev->tableList['mailqueue'] = '郵件隊列';
$lang->dev->tableList['datatable'] = '數據表格';
$lang->dev->tableList['block'] = '區塊';
$lang->dev->tableList['branch'] = '平台/分支';
@@ -93,7 +92,6 @@ $lang->dev->tableList['suitecase'] = '套件用例';
$lang->dev->tableList['score'] = '積分';
$lang->dev->tableList['entry'] = '應用';
$lang->dev->tableList['webhook'] = 'WebHook';
-$lang->dev->tableList['webhookdatas'] = 'WebHook數據';
$lang->dev->tableList['log'] = '介面日誌';
$lang->dev->tableList['message'] = '消息';
$lang->dev->tableList['notify'] = '通知';
diff --git a/module/doc/js/common.js b/module/doc/js/common.js
index e2e3e42572..07de94e6ba 100644
--- a/module/doc/js/common.js
+++ b/module/doc/js/common.js
@@ -1,7 +1,7 @@
function loadModules(libID)
{
link = createLink('doc', 'ajaxGetModules', 'libID=' + libID);
- $('#moduleBox').load(link, function(){$('#moduleBox').find('select').chosen(defaultChosenOptions)});
+ $('#moduleBox').load(link, function(){$('#moduleBox').find('select').chosen()});
}
function toggleAcl(acl)
diff --git a/module/doc/model.php b/module/doc/model.php
index 3a504b49b3..33ffe6bfda 100644
--- a/module/doc/model.php
+++ b/module/doc/model.php
@@ -35,11 +35,16 @@ class docModel extends model
if($libID)
{
$lib = $this->getLibById($libID);
- if($this->checkPriv($lib))
+ if(!$this->checkPrivLib($lib))
{
- $type = $lib->product ? 'product' : 'custom';
- $type = $lib->project ? 'project' : $type;
+ echo(js::alert($this->lang->doc->accessDenied));
+ $loginLink = $this->config->requestType == 'GET' ? "?{$this->config->moduleVar}=user&{$this->config->methodVar}=login" : "user{$this->config->requestFix}login";
+ if(strpos($this->server->http_referer, $loginLink) !== false) die(js::locate(inlink('index')));
+ die(js::locate('back'));
}
+
+ $type = $lib->product ? 'product' : 'custom';
+ $type = $lib->project ? 'project' : $type;
}
$mainLib = $type == 'custom' ? $this->lang->doc->customAB : $mainLib;
@@ -191,7 +196,7 @@ class docModel extends model
* @access public
* @return array
*/
- public function getLibs($type = '')
+ public function getLibs($type = '', $extra = '')
{
if($type == 'product' or $type == 'project')
{
@@ -215,11 +220,49 @@ class docModel extends model
$libPairs = array();
while($lib = $stmt->fetch())
{
- if($this->checkPriv($lib)) $libPairs[$lib->id] = $lib->name;
+ if($this->checkPrivLib($lib, $extra)) $libPairs[$lib->id] = $lib->name;
}
return $libPairs;
}
+ /**
+ * Get grant libs by doc.
+ *
+ * @access public
+ * @return array
+ */
+ public function getPrivLibsByDoc()
+ {
+ static $libs;
+ if($libs === null)
+ {
+ $libs = array();
+ $stmt = $this->dao->select('lib,groups,users')->from(TABLE_DOC)->where('acl')->ne('open')->andWhere("(groups != '' or users != '')")->query();
+
+ $account = ",{$this->app->user->account},";
+ $userGroups = $this->app->user->groups;
+ while($lib = $stmt->fetch())
+ {
+ if(strpos(",$lib->users,", $account) !== false)
+ {
+ $libs[$lib->lib] = $lib->lib;
+ }
+ else
+ {
+ foreach($userGroups as $groupID)
+ {
+ if(strpos(",$lib->groups,", ",$groupID,") !== false)
+ {
+ $libs[$lib->lib] = $lib->lib;
+ break;
+ }
+ }
+ }
+ }
+ }
+ return $libs;
+ }
+
/**
* Create a library.
*
@@ -377,7 +420,7 @@ class docModel extends model
->fetchAll('id');
foreach($docs as $docID => $doc)
{
- if(!$this->checkPriv($doc)) unset($docs[$docID]);
+ if(!$this->checkPrivDoc($doc)) unset($docs[$docID]);
}
$docs = $this->dao->select('*')->from(TABLE_DOC)
->where('id')->in(array_keys($docs))
@@ -481,7 +524,7 @@ class docModel extends model
$docIdList = array();
while($doc = $stmt->fetch())
{
- if($this->checkPriv($doc)) $docIdList[$doc->id] = $doc->id;
+ if($this->checkPrivDoc($doc)) $docIdList[$doc->id] = $doc->id;
}
return $docIdList;
}
@@ -498,7 +541,7 @@ class docModel extends model
{
$doc = $this->dao->select('*')->from(TABLE_DOC)->where('id')->eq((int)$docID)->fetch();
if(!$doc) return false;
- if(!$this->checkPriv($doc))
+ if(!$this->checkPrivDoc($doc))
{
echo(js::alert($this->lang->doc->accessDenied));
$loginLink = $this->config->requestType == 'GET' ? "?{$this->config->moduleVar}=user&{$this->config->methodVar}=login" : "user{$this->config->requestFix}login";
@@ -803,13 +846,14 @@ class docModel extends model
}
/**
- * Check priv.
+ * Check priv for lib.
*
* @param object $object
+ * @param string $extra
* @access public
* @return bool
*/
- public function checkPriv($object, $type = 'lib')
+ public function checkPrivLib($object, $extra = '')
{
if($this->app->user->admin) return true;
@@ -817,29 +861,26 @@ class docModel extends model
if(!empty($object->product) and !empty($acls['products']) and !in_array($object->product, $acls['products'])) return false;
if(!empty($object->project) and !empty($acls['projects']) and !in_array($object->project, $acls['projects'])) return false;
- if(isset($object->lib))
- {
- static $libs;
- if(empty($libs)) $libs = $this->getLibs('all');
- if(!isset($libs[$object->lib])) return false;
- }
-
if($object->acl == 'open') return true;
$account = ',' . $this->app->user->account . ',';
if(isset($object->addedBy) and $object->addedBy == $this->app->user->account) return true;
- if($object->acl == 'private' and strpos(",$object->users,", $account) !== false) return true;
+ if(strpos(",$object->users,", $account) !== false) return true;
if($object->acl == 'custom')
{
- if(strpos(",$object->users,", $account) !== false) return true;
-
$userGroups = $this->app->user->groups;
foreach($userGroups as $groupID)
{
if(strpos(",$object->groups,", ",$groupID,") !== false) return true;
}
}
- if(isset($object->lib)) return false;
+
+ if(strpos($extra, 'notdoc') === false)
+ {
+ static $extraDocLibs;
+ if($extraDocLibs === null) $extraDocLibs = $this->getPrivLibsByDoc();
+ if(isset($extraDocLibs[$object->id])) return true;
+ }
if($object->project)
{
@@ -858,6 +899,42 @@ class docModel extends model
return false;
}
+ /**
+ * Check priv for doc.
+ *
+ * @param object $object
+ * @access public
+ * @return bool
+ */
+ public function checkPrivDoc($object)
+ {
+ if($this->app->user->admin) return true;
+
+ static $extraDocLibs;
+ if($extraDocLibs === null) $extraDocLibs = $this->getPrivLibsByDoc();
+
+ static $libs;
+ if($libs === null) $libs = $this->getLibs('all', 'notdoc');
+ if(isset($libs[$object->lib]) and isset($extraDocLibs[$object->lib])) unset($extraDocLibs[$object->lib]);
+ if(!isset($libs[$object->lib]) and !isset($extraDocLibs[$object->lib])) return false;
+
+ if($object->acl == 'open' and !isset($extraDocLibs[$object->lib])) return true;
+
+ $account = ',' . $this->app->user->account . ',';
+ if(isset($object->addedBy) and $object->addedBy == $this->app->user->account) return true;
+ if(strpos(",$object->users,", $account) !== false) return true;
+ if($object->acl == 'custom')
+ {
+ $userGroups = $this->app->user->groups;
+ foreach($userGroups as $groupID)
+ {
+ if(strpos(",$object->groups,", ",$groupID,") !== false) return true;
+ }
+ }
+
+ return false;
+ }
+
/**
* Get all libs by type.
*
@@ -1017,7 +1094,7 @@ class docModel extends model
{
if($limit && $i > $limit) break;
$key = ($type == 'product' or $type == 'project') ? $type : 'id';
- if($this->checkPriv($docLib) and !isset($libs[$docLib->$key]))
+ if($this->checkPrivLib($docLib) and !isset($libs[$docLib->$key]))
{
$libs[$docLib->$key] = $docLib->name;
$i++;
@@ -1062,7 +1139,7 @@ class docModel extends model
{
foreach($libs as $lib)
{
- if($this->checkPriv($lib)) $buildGroups[$objectID][$lib->id] = $lib->name;
+ if($this->checkPrivLib($lib)) $buildGroups[$objectID][$lib->id] = $lib->name;
}
if($type == 'product' and isset($hasProject[$objectID]) and common::hasPriv('doc', 'allLibs')) $buildGroups[$objectID]['project'] = $this->lang->doclib->project;
if(common::hasPriv('doc', 'showFiles')) $buildGroups[$objectID]['files'] = $this->lang->doclib->files;
@@ -1104,7 +1181,7 @@ class docModel extends model
$libs = array();
foreach($objectLibs as $lib)
{
- if($this->checkPriv($lib)) $libs[$lib->id] = $lib;
+ if($this->checkPrivLib($lib)) $libs[$lib->id] = $lib;
}
$itemCounts = $this->statLibCounts(array_keys($libs));
@@ -1154,7 +1231,7 @@ class docModel extends model
$docCounts = array();
foreach($docs as $doc)
{
- if(!$this->checkPriv($doc)) continue;
+ if(!$this->checkPrivDoc($doc)) continue;
if(!isset($docCounts[$doc->lib])) $docCounts[$doc->lib] = 0;
$docCounts[$doc->lib] ++;
}
@@ -1272,7 +1349,7 @@ class docModel extends model
$docGroups = array();
foreach($docs as $doc)
{
- if($this->checkPriv($doc)) $docGroups[$doc->module][$doc->id] = $doc;
+ if($this->checkPrivDoc($doc)) $docGroups[$doc->module][$doc->id] = $doc;
}
}
@@ -1326,7 +1403,7 @@ class docModel extends model
if(empty($libID)) return '';
$lib = $this->getLibById($libID);
- if(!$this->checkPriv($lib))
+ if(!$this->checkPrivLib($lib))
{
echo(js::alert($this->lang->doc->accessDenied));
$loginLink = $this->config->requestType == 'GET' ? "?{$this->config->moduleVar}=user&{$this->config->methodVar}=login" : "user{$this->config->requestFix}login";
diff --git a/module/file/view/export.html.php b/module/file/view/export.html.php
index 6fc3f3241f..cb5119547d 100644
--- a/module/file/view/export.html.php
+++ b/module/file/view/export.html.php
@@ -66,7 +66,7 @@ function saveTemplate()
var defaultValue = $('#tplBox #template').val();
$('#tplBox').html(data);
if(data.indexOf('alert') >= 0) $('#tplBox #template').val(defaultValue);
- $("#tplBox #template").chosen(defaultChosenOptions).on('chosen:showing_dropdown', function()
+ $("#tplBox #template").chosen().on('chosen:showing_dropdown', function()
{
var $this = $(this);
var $chosen = $this.next('.chosen-container').removeClass('chosen-up');
diff --git a/module/install/lang/zh-cn.php b/module/install/lang/zh-cn.php
index 8e6b3303bc..c813bb19ec 100644
--- a/module/install/lang/zh-cn.php
+++ b/module/install/lang/zh-cn.php
@@ -35,6 +35,7 @@ $lang->install->links = <<http://www.zentao.net/ask/
新浪微博:http://weibo.com/easysoft
+
您现在正在安装的版本是 %s。
EOT;
diff --git a/module/install/lang/zh-tw.php b/module/install/lang/zh-tw.php
index e3e441e2d5..f111342644 100644
--- a/module/install/lang/zh-tw.php
+++ b/module/install/lang/zh-tw.php
@@ -35,6 +35,7 @@ $lang->install->links = <<http://www.zentao.net/ask/
新浪微博:http://weibo.com/easysoft
+
您現在正在安裝的版本是 %s。
EOT;
diff --git a/module/product/css/browse.css b/module/product/css/browse.css
index e6c75dc9b9..015f56d6cb 100644
--- a/module/product/css/browse.css
+++ b/module/product/css/browse.css
@@ -14,5 +14,3 @@
.popoverStage .icon-caret-down{position:absolute;}
a.removeModule{color:#ddd}
a.removeModule:hover{color:red}
-
-tbody > tr > td > .btn-icon {margin-right: 3px;}
diff --git a/module/product/js/create.js b/module/product/js/create.js
index de766375f5..b478c4fc3f 100644
--- a/module/product/js/create.js
+++ b/module/product/js/create.js
@@ -10,6 +10,6 @@ function loadProductLines(rootID)
link = createLink('tree', 'ajaxGetOptionMenu', 'rootID=' + rootID + '&viewtype=line' + '&branch=0' + '&rootModuleID=0&returnType=html&fieldID=&needManage=true');
$('#lineIdBox').load(link, function()
{
- $(this).find('select').chosen(defaultChosenOptions)
+ $(this).find('select').chosen()
});
}
diff --git a/module/product/lang/zh-tw.php b/module/product/lang/zh-tw.php
index 7c0b468147..a055673da9 100644
--- a/module/product/lang/zh-tw.php
+++ b/module/product/lang/zh-tw.php
@@ -116,8 +116,8 @@ $lang->product->aclList['open'] = "預設設置(有{$lang->productCommon}視
$lang->product->aclList['private'] = "私有{$lang->productCommon}(只有{$lang->productCommon}相關負責人和{$lang->projectCommon}團隊成員才能訪問)";
$lang->product->aclList['custom'] = '自定義白名單(團隊成員和白名單的成員可以訪問)';
-$lang->product->storySummary = "本頁共 %s 個需求,預計 %s 個工時,用例覆蓋率%s。";
-$lang->product->checkedSummary = "選中 %total% 個需求,預計 %estimate% 個工時,用例覆蓋率%rate%。";
+$lang->product->storySummary = "本頁共 %s 個需求,預計 %s 個工時,用例覆蓋率 %s。";
+$lang->product->checkedSummary = "選中 %total% 個需求,預計 %estimate% 個工時,用例覆蓋率 %rate%。";
$lang->product->noModule = '您現在還沒有模組信息
請維護產品模組
';
$lang->product->noProduct = '暫時沒有產品。';
$lang->product->noMatched = '找不到包含"%s"的' . $lang->productCommon;
diff --git a/module/productplan/control.php b/module/productplan/control.php
index dd80eb90e6..22bd866bf7 100644
--- a/module/productplan/control.php
+++ b/module/productplan/control.php
@@ -253,7 +253,7 @@ class productplan extends control
{
$stories = array();
$order = explode(',', $plan->order);
- if(strpos($orderBy, 'asc') !== false) $order = array_reverse($order, true);
+ if(strpos($orderBy, 'desc') !== false) $order = array_reverse($order, true);
foreach($order as $id)
{
if(empty($id)) continue;
diff --git a/module/productplan/view/browse.html.php b/module/productplan/view/browse.html.php
index 2ad8f26266..7a6a80df67 100644
--- a/module/productplan/view/browse.html.php
+++ b/module/productplan/view/browse.html.php
@@ -98,8 +98,7 @@
if(common::hasPriv('productplan', 'delete', $plan))
{
- $deleteURL = $this->createLink('productplan', 'delete', "planID=$plan->id&confirm=yes");
- echo html::a("javascript:ajaxDelete(\"$deleteURL\",\"productplanList\",confirmDelete)", '', '', "class='btn btn-icon' title='{$lang->productplan->delete}'");
+ common::printIcon('productplan', 'delete', "planID=$plan->id", $plan, '', '', 'hiddenwin');
}
?>
diff --git a/module/productplan/view/view.html.php b/module/productplan/view/view.html.php
index 3c896024fa..cc401bdff8 100644
--- a/module/productplan/view/view.html.php
+++ b/module/productplan/view/view.html.php
@@ -11,6 +11,7 @@
*/
?>
+
productplan->confirmUnlinkStory)?>
productplan->confirmUnlinkBug)?>
id);?>
@@ -114,7 +115,7 @@
actions?> |
-
+
diff --git a/module/project/control.php b/module/project/control.php
index 2f9cd23c93..19f82dd774 100644
--- a/module/project/control.php
+++ b/module/project/control.php
@@ -2308,13 +2308,24 @@ class project extends control
public function importPlanStories($projectID, $planID)
{
$planStories = $planProducts = array();
- $planStory = $this->loadModel('story')->getPlanStories($planID, 'changed,active,reviewing');
+ $planStory = $this->loadModel('story')->getPlanStories($planID);
if(!empty($planStory))
{
+ $count = 0;
+ foreach($planStory as $id => $story)
+ {
+ if($story->status == 'draft')
+ {
+ $count++;
+ unset($planStory[$id]);
+ continue;
+ }
+ $planProducts[$story->id] = $story->product;
+ }
$planStories = array_keys($planStory);
- foreach($planStory as $story) $planProducts[$story->id] = $story->product;
$this->project->linkStory($projectID, $planStories, $planProducts);
}
+ if($count != 0) die(js::confirm(sprintf($this->lang->project->haveDraft, $count), $this->createLink('project', 'story', "projectID=$projectID")));
die(js::locate(helper::createLink('project', 'story', 'projectID=' . $projectID), 'parent'));
}
diff --git a/module/project/css/task.css b/module/project/css/task.css
index e69de29bb2..e30b6a07e9 100644
--- a/module/project/css/task.css
+++ b/module/project/css/task.css
@@ -0,0 +1 @@
+td.delayed{background: #e84e0f!important; color: white;}
diff --git a/module/project/js/common.js b/module/project/js/common.js
index db6009f509..2d953b531c 100644
--- a/module/project/js/common.js
+++ b/module/project/js/common.js
@@ -182,7 +182,7 @@ function loadPlans(product, branchID)
if(data)
{
if($("div#plan" + index).size() == 0) $("#plansBox .row").append('');
- $("div#plan" + index).width($(product).closest('.col-sm-4').width()).html(data).find('select').attr('name', 'plans[' + productID + ']').attr('id', 'plans' + productID).chosen();
+ $("div#plan" + index).html(data).find('select').attr('name', 'plans[' + productID + ']').attr('id', 'plans' + productID).chosen();
adjustPlanBoxMargin();
}
diff --git a/module/project/js/kanban.js b/module/project/js/kanban.js
index 01057745c7..e12431b191 100644
--- a/module/project/js/kanban.js
+++ b/module/project/js/kanban.js
@@ -100,7 +100,6 @@ $(function()
shown: function(){$('.modal-iframe').addClass('with-titlebar').data('cancel-reload', true)},
hidden: refresh
});
- return true;
}
return false;
};
diff --git a/module/project/lang/en.php b/module/project/lang/en.php
index 93e30b51e3..2e74245187 100644
--- a/module/project/lang/en.php
+++ b/module/project/lang/en.php
@@ -209,6 +209,7 @@ $lang->project->batchWBS = "Batch Decompose";
$lang->project->howToUpdateBurn = "Help ";
$lang->project->whyNoStories = "No Story can be linked. Please check whether there is Story in {$lang->projectCommon} linked {$lang->productCommon} and make sure it has been reviewed.";
$lang->project->productStories = "{$lang->projectCommon} linked story is the subeset of {$lang->productCommon}, which can only be linked after review. Please Link Story。";
+$lang->project->haveDraft = "There are %s draft stories can't be linked.";
$lang->project->doneProjects = 'Done';
$lang->project->selectDept = 'Select Department';
$lang->project->selectDeptTitle = 'Select Department';
diff --git a/module/project/lang/zh-cn.php b/module/project/lang/zh-cn.php
index 73053d872b..bb1c550bcc 100644
--- a/module/project/lang/zh-cn.php
+++ b/module/project/lang/zh-cn.php
@@ -209,6 +209,7 @@ $lang->project->batchWBS = "批量分解";
$lang->project->howToUpdateBurn = "帮助 ";
$lang->project->whyNoStories = "看起来没有需求可以关联。请检查下{$lang->projectCommon}关联的{$lang->productCommon}中有没有需求,而且要确保它们已经审核通过。";
$lang->project->productStories = "{$lang->projectCommon}关联的需求是{$lang->productCommon}需求的子集,并且只有评审通过的需求才能关联。请关联需求。";
+$lang->project->haveDraft = "有%s条草稿状态的需求无法关联到该{$lang->projectCommon}";
$lang->project->doneProjects = '已结束';
$lang->project->selectDept = '选择部门';
$lang->project->selectDeptTitle = '选择一个部门的成员';
diff --git a/module/project/lang/zh-tw.php b/module/project/lang/zh-tw.php
index 26a3e703f1..8e5e866b80 100644
--- a/module/project/lang/zh-tw.php
+++ b/module/project/lang/zh-tw.php
@@ -145,6 +145,8 @@ $lang->project->importPlanStories = '按計劃關聯需求';
$lang->project->importBug = '導入Bug';
$lang->project->updateOrder = '排序';
$lang->project->tree = '樹狀圖';
+$lang->project->treeTask = '只看任務';
+$lang->project->treeStory = '只看需求';
$lang->project->storyKanban = '需求看板';
$lang->project->storySort = '需求排序';
$lang->project->importPlanStory = '創建' . $lang->projectCommon . '成功!\n是否導入計劃關聯的相關需求?';
@@ -207,6 +209,7 @@ $lang->project->batchWBS = "批量分解";
$lang->project->howToUpdateBurn = "幫助 ";
$lang->project->whyNoStories = "看起來沒有需求可以關聯。請檢查下{$lang->projectCommon}關聯的{$lang->productCommon}中有沒有需求,而且要確保它們已經審核通過。";
$lang->project->productStories = "{$lang->projectCommon}關聯的需求是{$lang->productCommon}需求的子集,並且只有評審通過的需求才能關聯。請關聯需求。";
+$lang->project->haveDraft = "有%s條草稿狀態的需求無法關聯到該{$lang->projectCommon}";
$lang->project->doneProjects = '已結束';
$lang->project->selectDept = '選擇部門';
$lang->project->selectDeptTitle = '選擇一個部門的成員';
diff --git a/module/project/model.php b/module/project/model.php
index c30c78b17e..fe6e80b10e 100644
--- a/module/project/model.php
+++ b/module/project/model.php
@@ -141,65 +141,15 @@ class projectModel extends model
foreach($this->lang->project->menu as $key => $menu)
{
- $replace = $projectID;
+ common::setMenuVars($this->lang->project->menu, $key, $projectID);
/* Replace for dropdown submenu. */
if(isset($this->lang->project->subMenu->$key))
{
- $index = 0;
- $firstLink = '';
- $dropTitle = '';
- $hasActive = false;
- $subMenu = array();
- $replace = "';
- $replace = "$dropTitle " . $replace;
-
- $this->lang->project->menu->{$key}['class'] = 'dropdown dropdown-hover';
- if($hasActive) $this->lang->project->menu->{$key}['class'] .= ' active';
+ $subMenu = common::createSubMenu($this->lang->project->subMenu->$key, $projectID);
if(!empty($subMenu)) $this->lang->project->menu->{$key}['subMenu'] = $subMenu;
}
- common::setMenuVars($this->lang->project->menu, $key, $replace);
}
}
@@ -1645,15 +1595,26 @@ class projectModel extends model
{
foreach($plans as $planID => $productID)
{
- $planStory = $this->loadModel('story')->getPlanStories($planID, 'active');
+ $planStory = $this->loadModel('story')->getPlanStories($planID);
if(!empty($planStory))
{
+ $count = 0;
+ foreach($planStory as $id => $story)
+ {
+ if($story->status == 'draft')
+ {
+ $count++;
+ unset($planStory[$id]);
+ continue;
+ }
+ $planProducts[$story->id] = $story->product;
+ }
$planStories = array_merge($planStories, array_keys($planStory));
- foreach($planStory as $story) $planProducts[$story->id] = $story->product;
}
}
}
$this->linkStory($projectID, $planStories, $planProducts);
+ if($count != 0) die(js::confirm(sprintf($this->lang->project->haveDraft, $count), helper::createLink('project', 'create', "projectID=$projectID")));
}
/**
diff --git a/module/project/view/build.html.php b/module/project/view/build.html.php
index 2b95cc8255..ea59456c24 100644
--- a/module/project/view/build.html.php
+++ b/module/project/view/build.html.php
@@ -87,8 +87,7 @@
common::printIcon('build', 'edit', "buildID=$build->id", $build, 'list');
if(common::hasPriv('build', 'delete', $build))
{
- $deleteURL = $this->createLink('build', 'delete', "buildID=$build->id&confirm=yes");
- echo html::a("javascript:ajaxDelete(\"$deleteURL\",\"buildList\",confirmDelete)", '', '', "class='btn' title='{$lang->build->delete}'");
+ common::printIcon('build', 'delete', "buildID=$build->id", $build, '', '', 'hiddenwin');
}
?>
diff --git a/module/project/view/edit.html.php b/module/project/view/edit.html.php
index 3fbf7b4483..8ee356120b 100644
--- a/module/project/view/edit.html.php
+++ b/module/project/view/edit.html.php
@@ -137,9 +137,11 @@
project->linkPlan;?> |
+
id, array(0 => ''));?>
- id . "]", $plans, $product->plan, "class='form-control chosen'");?>
+ id . "]", $plans, $product->plan, "class='form-control chosen'");?>
+
|
diff --git a/module/project/view/view.html.php b/module/project/view/view.html.php
index b4adbbe2a6..f6d4e12bc1 100644
--- a/module/project/view/view.html.php
+++ b/module/project/view/view.html.php
@@ -203,7 +203,7 @@
- totalHours ? round($project->totalConsumed / $project->totalHours, 3) * 100 : 0;?>
+ totalConsumed + $project->totalLeft) ? round($project->totalConsumed / ($project->totalConsumed + $project->totalLeft), 3) * 100 : 0;?>
projectCommon . $lang->project->progress;?> percent;?>
@@ -226,7 +226,7 @@
project->totalDays;?> |
days;?> |
project->totalLeft;?> |
- totalLeft;?> |
+ totalLeft . $lang->project->workHour;?> |
|
| project->totalHours;?> |
diff --git a/module/release/view/browse.html.php b/module/release/view/browse.html.php
index 10caf0919e..cc2d4b5443 100644
--- a/module/release/view/browse.html.php
+++ b/module/release/view/browse.html.php
@@ -77,8 +77,7 @@
common::printIcon('release', 'edit', "release=$release->id", $release, 'list');
if(common::hasPriv('release', 'delete', $release))
{
- $deleteURL = $this->createLink('release', 'delete', "releaseID=$release->id&confirm=yes");
- echo html::a("javascript:ajaxDelete(\"$deleteURL\",\"releaseList\",confirmDelete)", '', '', "class='btn' title='{$lang->release->delete}'");
+ common::printIcon('release', 'delete', "releaseID=$release->id", $release, '', '', 'hiddenwin');
}
?>
diff --git a/module/search/lang/zh-tw.php b/module/search/lang/zh-tw.php
index 5a9e95dc55..4709ae98b4 100644
--- a/module/search/lang/zh-tw.php
+++ b/module/search/lang/zh-tw.php
@@ -24,6 +24,7 @@ $lang->search->select = '需求/任務篩選';
$lang->search->me = '自己';
$lang->search->noQuery = '還沒有保存查詢!';
$lang->search->onMenuBar = '顯示在菜單欄';
+$lang->search->custom = '自定義';
$lang->search->account = '用戶名';
$lang->search->module = '模組';
diff --git a/module/story/js/batchedit.js b/module/story/js/batchedit.js
index d4906bf19a..b4fff1bb6b 100644
--- a/module/story/js/batchedit.js
+++ b/module/story/js/batchedit.js
@@ -31,11 +31,11 @@ function loadBranches(product, branch, storyID)
if(!branch) branch = 0;
moduleLink = createLink('tree', 'ajaxGetOptionMenu', 'productID=' + product + '&viewtype=story&branch=' + branch + '&rootModuleID=0&returnType=html&fieldID=' + storyID);
- $('#modules' + storyID).parent('td').load(moduleLink, function(){$('#modules' + storyID).chosen(defaultChosenOptions);});
+ $('#modules' + storyID).parent('td').load(moduleLink, function(){$('#modules' + storyID).chosen();});
planID = $('#plans' + storyID).val();
planLink = createLink('product', 'ajaxGetPlans', 'productID=' + product + '&branch=' + branch + '&planID=' + planID + '&fieldID=' + storyID);
- $('#plans' + storyID).parent('td').load(planLink, function(){$('#plans' + storyID).chosen(defaultChosenOptions);});
+ $('#plans' + storyID).parent('td').load(planLink, function(){$('#plans' + storyID).chosen();});
}
$(function()
diff --git a/module/story/model.php b/module/story/model.php
index bdddb3f696..dc0ce05950 100644
--- a/module/story/model.php
+++ b/module/story/model.php
@@ -274,8 +274,6 @@ class storyModel extends model
$stories->plan[$i] = $plan;
$stories->pri[$i] = (int)$pri;
$stories->source[$i] = $source;
-
- if(!empty($stories->title[$i]) && empty($stories->module[$i])) die(js::alert(sprintf($this->lang->error->notempty, $this->lang->story->module)));
}
if(isset($stories->uploadImage)) $this->loadModel('file');
diff --git a/module/story/view/batchcreate.html.php b/module/story/view/batchcreate.html.php
index 82aa831bbc..aa9926481b 100644
--- a/module/story/view/batchcreate.html.php
+++ b/module/story/view/batchcreate.html.php
@@ -46,7 +46,7 @@
| idAB;?> |
'>product->branch;?> |
- story->module;?> |
+ story->module;?> |
'>story->plan;?> |
story->title;?> |
'>story->spec;?> |
diff --git a/module/story/view/review.html.php b/module/story/view/review.html.php
index 4f5435cf03..3e01190381 100644
--- a/module/story/view/review.html.php
+++ b/module/story/view/review.html.php
@@ -32,7 +32,7 @@ var assignedTo = 'lastEditedBy ? print($story->lastEditedBy) : pri
| story->reviewResult;?> |
- story->reviewResultList, '', 'class=form-control onchange="switchShow(this.value)"');?> | |
+ story->reviewResultList, '', 'class=form-control onchange="switchShow(this.value)"');?> | |
| story->rejectedReason;?> |
diff --git a/module/task/js/batchcreate.js b/module/task/js/batchcreate.js
index 4a470912b6..57097f3bb5 100755
--- a/module/task/js/batchcreate.js
+++ b/module/task/js/batchcreate.js
@@ -1,6 +1,3 @@
-/* Remove width in defaultChosenOptions. */
-delete defaultChosenOptions.width;
-
/* Remove 'ditto' in first row. */
$(function()
{
@@ -32,7 +29,7 @@ function setStories(moduleID, projectID, num)
})
}
$("#story" + num + "_chosen").remove();
- $("#story" + num).chosen(defaultChosenOptions);
+ $("#story" + num).chosen();
});
}
diff --git a/module/task/js/common.js b/module/task/js/common.js
index e69de29bb2..4fb3b9b7b7 100644
--- a/module/task/js/common.js
+++ b/module/task/js/common.js
@@ -0,0 +1,51 @@
+function adjustSortBtn()
+{
+ $('.btn-move-up:first').addClass('disabled').attr('disabled', 'disabled');
+ $('.btn-move-down:last').addClass('disabled').attr('disabled', 'disabled');
+}
+
+$('.btn-move-up, .btn-move-down').click(function()
+{
+ var $this = $(this);
+ if($this.hasClass('btn-move-up'))
+ {
+ $(this).parents('tr').prev().before($(this).parents('tr'));
+ }
+ else
+ {
+ $this.parents('tr').next().after($(this).parents('tr'));
+ }
+ $('.btn-move-up, .btn-move-down').removeClass('disabled').removeAttr('disabled');
+
+ adjustSortBtn();
+});
+
+function adjustSortBtn()
+{
+ $('.btn-move-up:first').addClass('disabled').attr('disabled', 'disabled');
+ $('.btn-move-down:last').addClass('disabled').attr('disabled', 'disabled');
+}
+
+$('#modalTeam .btn').click(function()
+{
+ var team = '';
+ var time = 0;
+ $('[name*=team]').each(function()
+ {
+ if($(this).find('option:selected').text() != '')
+ {
+ team += ' ' + $(this).find('option:selected').text();
+ }
+
+ estimate = parseFloat($(this).parents('td').next('td').find('[name*=teamEstimate]').val());
+ if(!isNaN(estimate))
+ {
+ time += estimate;
+ }
+
+ $('#teamMember').val(team);
+ $('#estimate').val(time);
+ })
+});
+
+//end
diff --git a/module/task/js/edit.js b/module/task/js/edit.js
index b457c91982..b680d1f535 100644
--- a/module/task/js/edit.js
+++ b/module/task/js/edit.js
@@ -1,6 +1,6 @@
$(function()
{
- $("#story, #mailto").chosen(defaultChosenOptions);
+ $("#story, #mailto").chosen();
$('.record-estimate-toggle').modalTrigger({width:900, type:'iframe', afterHide: function(){parent.location.href=parent.location.href;}});
})
@@ -41,7 +41,7 @@ function loadAll(projectID)
function loadModuleMenu(projectID)
{
var link = createLink('tree', 'ajaxGetOptionMenu', 'rootID=' + projectID + '&viewtype=task');
- $('#moduleIdBox').load(link, function(){$('#module').chosen(defaultChosenOptions);});
+ $('#moduleIdBox').load(link, function(){$('#module').chosen();});
}
/**
@@ -54,7 +54,7 @@ function loadModuleMenu(projectID)
function loadProjectStories(projectID)
{
var link = createLink('story', 'ajaxGetProjectStories', 'projectID=' + projectID + '&productID=0&branch=0&moduleID=0&storyID=' + oldStoryID);
- $('#storyIdBox').load(link, function(){$('#story').chosen(defaultChosenOptions);});
+ $('#storyIdBox').load(link, function(){$('#story').chosen();});
}
/**
@@ -67,7 +67,7 @@ function loadProjectStories(projectID)
function loadProjectMembers(projectID)
{
var link = createLink('project', 'ajaxGetMembers', 'projectID=' + projectID + '&assignedTo=' + oldAssignedTo);
- $('#assignedToIdBox').load(link, function(){$('#assignedToIdBox').find('select').chosen(defaultChosenOptions)});
+ $('#assignedToIdBox').load(link, function(){$('#assignedToIdBox').find('select').chosen()});
}
/* empty function. */
diff --git a/module/task/lang/zh-tw.php b/module/task/lang/zh-tw.php
index 30aecf7827..9ee6a81bfe 100644
--- a/module/task/lang/zh-tw.php
+++ b/module/task/lang/zh-tw.php
@@ -183,6 +183,7 @@ $lang->task->error->left = '請填寫"剩餘"';
$lang->task->error->work = '"備註"必須小於%d個字元';
$lang->task->error->skipClose = '任務:%s 不是“已完成”或“已取消”狀態,確定要關閉嗎?';
$lang->task->error->consumed = '任務:%s工時不能小於0,忽略該任務工時的改動';
+$lang->task->error->assignedTo = '當前狀態的多人任務不能指派給任務團隊外的成員。';
/* Report. */
$lang->task->report = new stdclass();
diff --git a/module/task/view/view.html.php b/module/task/view/view.html.php
index 8761407221..1143e5082a 100644
--- a/module/task/view/view.html.php
+++ b/module/task/view/view.html.php
@@ -222,7 +222,7 @@
mailto));
- if(empty($mainto))
+ if(empty($mailto))
{
echo $lang->noData;
}
diff --git a/module/testcase/js/batchcreate.js b/module/testcase/js/batchcreate.js
index a7adc7a3e0..6ce0166461 100644
--- a/module/testcase/js/batchcreate.js
+++ b/module/testcase/js/batchcreate.js
@@ -101,6 +101,6 @@ function setModules(branchID, productID, num)
if(!modules) modules = '';
$('#module' + num).replaceWith(modules);
$("#module" + num + "_chosen").remove();
- $("#module" + num).chosen(defaultChosenOptions);
+ $("#module" + num).chosen();
});
}
diff --git a/module/testcase/js/batchedit.js b/module/testcase/js/batchedit.js
index 0e616280eb..e9747337f4 100644
--- a/module/testcase/js/batchedit.js
+++ b/module/testcase/js/batchedit.js
@@ -31,7 +31,7 @@ function loadBranches(product, branch, caseID)
if(!branch) branch = 0;
moduleLink = createLink('tree', 'ajaxGetOptionMenu', 'productID=' + product + '&viewtype=case&branch=' + branch + '&rootModuleID=0&returnType=html&fieldID=' + caseID + '&needManage=true');
- $('#modules' + caseID).parent('td').load(moduleLink, function(){$('#modules' + caseID).chosen(defaultChosenOptions);})
+ $('#modules' + caseID).parent('td').load(moduleLink, function(){$('#modules' + caseID).chosen();})
}
$(function()
diff --git a/module/testcase/js/browse.js b/module/testcase/js/browse.js
index 692513e229..de31393cc4 100644
--- a/module/testcase/js/browse.js
+++ b/module/testcase/js/browse.js
@@ -17,6 +17,18 @@ $(function()
if(flow == 'onlyTest')
{
- $('#subNavbar > .nav > li[data-id=' + browseType + ']').addClass('active');
+ $('#subNavbar > .nav li[data-id=' + browseType + ']').addClass('active');
+
+ if(browseType == 'bysuite')
+ {
+ var $moreSuite = $('#subNavbar > .nav > li[data-id=bysuite]');
+ if($moreSuite.find('.dropdown-menu').children().length)
+ {
+ $moreSuite.find('.dropdown-menu').children().each(function()
+ {
+ if($(this).data('id') == suiteID) $(this).addClass('active');
+ });
+ }
+ }
}
});
diff --git a/module/testcase/js/common.js b/module/testcase/js/common.js
index 6c46c42037..f27cd7cbc4 100644
--- a/module/testcase/js/common.js
+++ b/module/testcase/js/common.js
@@ -85,7 +85,7 @@ function loadProductModules(productID, branch)
link = createLink('tree', 'ajaxGetOptionMenu', 'productID=' + productID + '&viewtype=case&branch=' + branch + '&rootModuleID=0&returnType=html&fieldID=&needManage=true');
$('#moduleIdBox').load(link, function()
{
- $(this).find('select').chosen(defaultChosenOptions)
+ $(this).find('select').chosen()
if(typeof(caseModule) == 'string') $('#moduleIdBox').prepend("" + caseModule + "")
});
setStories();
@@ -105,7 +105,7 @@ function loadLibModules(libID, branch)
link = createLink('tree', 'ajaxGetOptionMenu', 'rootID=' + libID + '&viewtype=caselib&branch=' + branch + '&rootModuleID=0&returnType=html&fieldID=&needManage=true');
$('#moduleIdBox').load(link, function()
{
- $(this).find('select').chosen(defaultChosenOptions)
+ $(this).find('select').chosen()
if(typeof(caseModule) == 'string') $('#moduleIdBox').prepend("" + caseModule + "")
});
}
@@ -130,7 +130,7 @@ function setStories()
$('#story').replaceWith(stories);
$('#story').val(value);
$('#story_chosen').remove();
- $("#story").chosen(defaultChosenOptions);
+ $("#story").chosen();
});
}
diff --git a/module/testcase/js/edit.js b/module/testcase/js/edit.js
index 29011ee17b..9768a4ee9a 100644
--- a/module/testcase/js/edit.js
+++ b/module/testcase/js/edit.js
@@ -15,7 +15,7 @@ function getList()
$(document).ready(function()
{
- $("#story").chosen(defaultChosenOptions);
+ $("#story").chosen();
initSteps();
});
@@ -32,7 +32,7 @@ function loadLibModules(libID)
link = createLink('tree', 'ajaxGetOptionMenu', 'libID=' + libID + '&viewtype=caselib&branch=0&rootModuleID=0&returnType=html&fieldID=&needManage=true');
$('#moduleIdBox').load(link, function()
{
- $(this).find('select').chosen(defaultChosenOptions)
+ $(this).find('select').chosen()
if(typeof(caseModule) == 'string') $('#moduleIdBox').prepend("" + caseModule + "")
});
}
diff --git a/module/testcase/model.php b/module/testcase/model.php
index b8a0fdef6a..7490e3578e 100644
--- a/module/testcase/model.php
+++ b/module/testcase/model.php
@@ -118,38 +118,50 @@ class testcaseModel extends model
}
else
{
- if($key == 'suite' and common::hasPriv('testcase', 'browse'))
+ if($key == 'bysuite')
{
- $suiteList = $this->loadModel('testsuite')->getSuites($productID);
- $currentSuiteID = isset($suiteID) ? (int)$suiteID : 0;
- $currentSuite = zget($suiteList, $currentSuiteID, '');
- $currentLable = empty($currentSuite) ? $this->lang->testsuite->common : $currentSuite->name;
+ $subMenu = array();
+ if(common::hasPriv('testcase', 'browse'))
+ {
+ $suiteList = $this->loadModel('testsuite')->getSuites($productID);
+ $currentSuiteID = isset($suiteID) ? (int)$suiteID : 0;
- $replace = "- ";
- $replace .= html::a('javascript:;', $currentLable . " ", '', "data-toggle='dropdown'");
- $replace .="
';
+ /* Replace for dropdown submenu. */
+ if(isset($this->lang->testcase->subMenu->$key))
+ {
+ $subMenu += common::createSubMenu($this->lang->testcase->subMenu->$key, $productID);
+ }
+ if(!empty($subMenu)) $this->lang->testcase->menu->{$key}['subMenu'] = $subMenu;
+
+ if($this->app->getMethodName() != 'view') $this->lang->testcase->menu->bysearch = " {$this->lang->testcase->bySearch}";
}
else
{
@@ -160,7 +172,6 @@ class testcaseModel extends model
}
common::setMenuVars($this->lang->testcase->menu, $key, $replace);
}
- if($this->config->global->flow != 'full' && $this->app->getMethodName() != 'view') $this->lang->testcase->menu->bysearch = " {$this->lang->testcase->bySearch}";
}
/**
diff --git a/module/testcase/view/browse.html.php b/module/testcase/view/browse.html.php
index 091436979d..fa64a5be98 100644
--- a/module/testcase/view/browse.html.php
+++ b/module/testcase/view/browse.html.php
@@ -22,6 +22,7 @@ js::set('confirmDelete', $lang->testcase->confirmDelete);
js::set('batchDelete', $lang->testcase->confirmBatchDelete);
js::set('productID', $productID);
js::set('branch', $branch);
+js::set('suiteID', $suiteID);
?>
|