diff --git a/module/project/config.php b/module/project/config.php
index 58187fd0f9..7a98d84f11 100644
--- a/module/project/config.php
+++ b/module/project/config.php
@@ -10,6 +10,7 @@ $config->project->list->exportFields = 'id,name,code,PM,end,status,totalEstimate
global $lang, $app;
$app->loadLang('task');
+$config->project->task = new stdclass();
$config->project->create = new stdclass();
$config->project->edit = new stdclass();
$config->project->create->requiredFields = 'name,code,begin,end';
diff --git a/module/project/control.php b/module/project/control.php
index 1a142a16c5..104c61e16d 100644
--- a/module/project/control.php
+++ b/module/project/control.php
@@ -2461,6 +2461,40 @@ class project extends control
die(js::reload('parent.parent'));
}
+ /**
+ * Ajax set unfoldID.
+ *
+ * @param int $projectID
+ * @param string $action
+ * @access public
+ * @return void
+ */
+ public function ajaxSetUnfoldID($projectID, $action = 'add')
+ {
+ $this->loadModel('setting');
+ $setting = $this->setting->createDAO($this->setting->parseItemParam("owner={$this->app->user->account}&module=project§ion=task&key=unfoldID"), 'select')->fetch();
+ $newUnfoldID = $this->post->newUnfoldID;
+ if(empty($newUnfoldID)) die();
+
+ $newUnfoldID = json_decode($newUnfoldID);
+ $unfoldIdList = $setting ? json_decode($setting->value, true) : array();
+ foreach($newUnfoldID as $unfoldID)
+ {
+ unset($unfoldIdList[$projectID][$unfoldID]);
+ if($action == 'add') $unfoldIdList[$projectID][$unfoldID] = $unfoldID;
+ }
+
+ if(empty($setting))
+ {
+ $this->setting->setItem($this->app->user->account . ".project.task.unfoldID", json_encode($unfoldIdList));
+ }
+ else
+ {
+ $this->dao->update(TABLE_CONFIG)->set('value')->eq(json_encode($unfoldIdList))->where('id')->eq($setting->id)->exec();
+ }
+ die('success');
+ }
+
/**
* Import stories by plan.
*
diff --git a/module/project/js/task.js b/module/project/js/task.js
index ac43b0609f..9e01c85a1c 100644
--- a/module/project/js/task.js
+++ b/module/project/js/task.js
@@ -8,6 +8,97 @@ $(function()
if($td.find('.label').length > 0) labelWidth = $td.find('.label').width();
$td.find('a').eq(0).css('max-width', $td.width() - labelWidth - 60);
});
+
+ if($('#projectTaskForm td.has-child').length > 0)
+ {
+ $('#projectTaskForm th.c-name').append("");
+ var allUnfold = true;
+ $('#projectTaskForm td.has-child').each(function()
+ {
+ var taskID = $(this).closest('tr').attr('data-id');
+ if(typeof(unfoldID[taskID]) == 'undefined')
+ {
+ allUnfold = false;
+ $('#projectTaskForm tr.parent-' + taskID).hide();
+ $(this).find('a.task-toggle').addClass('collapsed')
+ }
+
+ })
+
+ if(allUnfold)
+ {
+ $('#projectTaskForm th.c-name #toggleFold').html(foldAll).removeClass('collapsed');
+ }
+ else
+ {
+ $('#projectTaskForm th.c-name #toggleFold').html(unfoldAll).addClass('collapsed');
+ }
+
+ $(document).on('click', '#toggleFold', function()
+ {
+ var newUnfoldID = [];
+ var url = '';
+ if($(this).hasClass('collapsed'))
+ {
+ $('#projectTaskForm td.has-child').each(function()
+ {
+ var taskID = $(this).closest('tr').attr('data-id');
+ $('#projectTaskForm tr.parent-' + taskID).show();
+ $(this).find('a.task-toggle').removeClass('collapsed')
+ newUnfoldID.push(taskID);
+ })
+ $(this).html(foldAll).removeClass('collapsed');
+ url = createLink('project', 'ajaxSetUnfoldID', 'projectID=' + projectID);
+ }
+ else
+ {
+ $('#projectTaskForm td.has-child').each(function()
+ {
+ var taskID = $(this).closest('tr').attr('data-id');
+ $('#projectTaskForm tr.parent-' + taskID).hide();
+ $(this).find('a.task-toggle').addClass('collapsed');
+ newUnfoldID.push(taskID);
+ })
+ $(this).html(unfoldAll).addClass('collapsed');
+ url = createLink('project', 'ajaxSetUnfoldID', 'projectID=' + projectID + '&action=delete');
+ }
+ $.post(url, {'newUnfoldID': JSON.stringify(newUnfoldID)});
+ });
+
+ $('#projectTaskForm td.has-child a.task-toggle').click(function()
+ {
+ var newUnfoldID = [];
+ var url = '';
+ if($(this).hasClass('collapsed'))
+ {
+ var taskID = $(this).closest('tr').attr('data-id');
+ $('#projectTaskForm tr.parent-' + taskID).show();
+ newUnfoldID.push(taskID);
+ url = createLink('project', 'ajaxSetUnfoldID', 'projectID=' + projectID);
+ }
+ else
+ {
+ var taskID = $(this).closest('tr').attr('data-id');
+ $('#projectTaskForm tr.parent-' + taskID).hide();
+ newUnfoldID.push(taskID);
+ url = createLink('project', 'ajaxSetUnfoldID', 'projectID=' + projectID + '&action=delete');
+ }
+
+ setTimeout(function()
+ {
+ if($('#projectTaskForm td.has-child a.task-toggle.collapsed').length == 0)
+ {
+ $('#toggleFold').html(foldAll).removeClass('collapsed');
+ }
+ else
+ {
+ $('#toggleFold').html(unfoldAll).addClass('collapsed');
+ }
+ }, 100);
+
+ $.post(url, {'newUnfoldID': JSON.stringify(newUnfoldID)});
+ });
+ }
});
$('#module' + moduleID).closest('li').addClass('active');
diff --git a/module/project/view/task.html.php b/module/project/view/task.html.php
index 6fd0f61b35..46fa98318f 100644
--- a/module/project/view/task.html.php
+++ b/module/project/view/task.html.php
@@ -19,6 +19,13 @@ js::set('moduleID', $moduleID);
js::set('productID', $productID);
js::set('projectID', $projectID);
js::set('browseType', $browseType);
+
+/* Set unfold parent taskID. */
+$config->project->task->unfoldID = isset($config->project->task->unfoldID) ? json_decode($config->project->task->unfoldID, true) : array();
+$config->project->task->unfoldID = zget($config->project->task->unfoldID, $projectID, array());
+js::set('unfoldID', $config->project->task->unfoldID);
+js::set('unfoldAll', $lang->project->treeLevel['all']);
+js::set('foldAll', $lang->project->treeLevel['root']);
?>
diff --git a/module/task/model.php b/module/task/model.php
index 0a655419fe..2657453710 100644
--- a/module/task/model.php
+++ b/module/task/model.php
@@ -1089,11 +1089,13 @@ class taskModel extends model
if(!empty($oldTask->team))
{
- $this->dao->update(TABLE_TEAM)->set('left')->eq(0)
- ->where('root')->eq($taskID)
- ->andWhere('type')->eq('task')
- ->andWhere('account')->eq($oldTask->assignedTo)
- ->exec();
+ $beginTag = false;
+ foreach($oldTask->team as $account => $team)
+ {
+ if($account == $task->assignedTo) break;
+ if($account == $oldTask->assignedTo) $beginTag = true;
+ if($beginTag) $this->dao->update(TABLE_TEAM)->set('left')->eq(0)->where('root')->eq($taskID)->andWhere('type')->eq('task')->andWhere('account')->eq($account)->exec();
+ }
$this->dao->update(TABLE_TEAM)->set('left')->eq($task->left)
->where('root')->eq($taskID)
@@ -1417,13 +1419,24 @@ class taskModel extends model
if(!empty($oldTask->team))
{
- $this->dao->update(TABLE_TEAM)
- ->set('left')->eq(0)
- ->set('consumed')->eq($task->consumed)
+ $this->dao->update(TABLE_TEAM)->set('left')->eq(0)->set('consumed')->eq($task->consumed)
->where('root')->eq((int)$taskID)
->andWhere('type')->eq('task')
->andWhere('account')->eq($oldTask->assignedTo)->exec();
+ $beginTag = false;
+ foreach($oldTask->team as $account => $team)
+ {
+ if($account == $task->assignedTo) break;
+ if($account == $oldTask->assignedTo)
+ {
+ $beginTag = true;
+ continue;
+ }
+
+ if($beginTag) $this->dao->update(TABLE_TEAM)->set('left')->eq(0)->where('root')->eq($taskID)->andWhere('type')->eq('task')->andWhere('account')->eq($account)->exec();
+ }
+
$task = $this->computeHours4Multiple($oldTask, $task);
}