diff --git a/module/execution/view/edit.html.php b/module/execution/view/edit.html.php
index aba139060f..56ead0a3f4 100644
--- a/module/execution/view/edit.html.php
+++ b/module/execution/view/edit.html.php
@@ -141,7 +141,7 @@
type != 'normal' and isset($branchGroups[$product->id]);?>
id] as $branchID => $branch):?>
-
">
+
id, "class='form-control chosen' $class onchange='loadBranches(this)' data-last='" . $product->id . "' data-type='". $product->type ."'");?>
id], $branchID, "class='form-control chosen' $class onchange=\"loadPlans('#products{$i}', this.value)\" data-last='" . $branchID . "'");?>
@@ -159,7 +159,7 @@
diff --git a/module/kanban/js/view.js b/module/kanban/js/view.js
index d7def024ed..89800ac5d2 100644
--- a/module/kanban/js/view.js
+++ b/module/kanban/js/view.js
@@ -1388,6 +1388,7 @@ function initSortable()
{
selector: '.region, .kanban-board, .kanban-lane, .kanban-col',
trigger: '.region.sort > .region-header, .kanban-board.sort > .kanban-header > .kanban-group-header, .kanban-lane.sort > .kanban-lane-name, .kanban-header-col.sort',
+ dropOnMouseleave: true,
container: function($ele)
{
return $ele.parent();
diff --git a/module/program/model.php b/module/program/model.php
index 49c9e07f15..9def3df994 100644
--- a/module/program/model.php
+++ b/module/program/model.php
@@ -1259,7 +1259,7 @@ class programModel extends model
*/
public function getProjectStats($programID = 0, $browseType = 'undone', $queryID = 0, $orderBy = 'id_desc', $pager = null, $programTitle = 0, $involved = 0, $queryAll = false)
{
- if(defined('TUTORIAL')) return $this->loadModel('tutorial')->getProjectStats();
+ if(defined('TUTORIAL')) return $this->loadModel('tutorial')->getProjectStats($browseType);
/* Init vars. */
$projects = $this->getProjectList($programID, $browseType, $queryID, $orderBy, $pager, $programTitle, $involved, $queryAll);
diff --git a/module/task/control.php b/module/task/control.php
index 2c360a27e5..88d0f6b940 100644
--- a/module/task/control.php
+++ b/module/task/control.php
@@ -562,7 +562,7 @@ class task extends control
if($this->post->names)
{
$allChanges = $this->task->batchUpdate();
- if(dao::isError()) return print(js::error(dao::getError()));
+ if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
if(!empty($allChanges))
{
diff --git a/module/task/lang/en.php b/module/task/lang/en.php
index c0cf60ed5b..b6eacee3be 100644
--- a/module/task/lang/en.php
+++ b/module/task/lang/en.php
@@ -246,6 +246,8 @@ $lang->task->error->finishedDateEmpty = '"Finished Date" should not be empty.';
$lang->task->error->finishedDateSmall = '"Finished Date" should be > "Real Started"';
$lang->task->error->alreadyConsumed = 'The currently selected parent task has been consumed.';
$lang->task->error->date = 'The date should be >= today.';
+$lang->task->error->leftEmptyAB = 'When the task status is %s, "Hours Left" cannot be 0';
+$lang->task->error->leftEmpty = 'Task#%sWhen the task status is %s, "Left" cannot be 0';
/* Report. */
$lang->task->report = new stdclass();
diff --git a/module/task/lang/zh-cn.php b/module/task/lang/zh-cn.php
index 8f7f05cecd..f1a9a910b1 100644
--- a/module/task/lang/zh-cn.php
+++ b/module/task/lang/zh-cn.php
@@ -246,6 +246,8 @@ $lang->task->error->finishedDateEmpty = '实际完成不能为空';
$lang->task->error->finishedDateSmall = '实际完成不能小于实际开始';
$lang->task->error->alreadyConsumed = '当前选中的父任务已有消耗。';
$lang->task->error->date = '日期不能大于今天';
+$lang->task->error->leftEmptyAB = '任务状态为%s时,预计剩余不能为0';
+$lang->task->error->leftEmpty = 'Task#%s任务状态为%s时,剩余不能为0';
/* Report. */
$lang->task->report = new stdclass();
diff --git a/module/task/model.php b/module/task/model.php
index f524c69262..f959536a27 100644
--- a/module/task/model.php
+++ b/module/task/model.php
@@ -35,6 +35,30 @@ class taskModel extends model
if($this->post->selectTestStory)
{
+ /* Check required fields when create test task. */
+ foreach($this->post->testStory as $i => $storyID)
+ {
+ if(empty($storyID)) continue;
+
+ $task = new stdclass();
+ $task->pri = $this->post->testPri[$i];
+ $task->estStarted = $this->post->testEstStarted[$i];
+ $task->deadline = $this->post->testDeadline[$i];
+ $task->assignedTo = $this->post->testAssignedTo[$i];
+ $task->estimate = $this->post->testEstimate[$i];
+ $task->left = $this->post->testEstimate[$i];
+
+ $this->dao->insert(TABLE_TASK)->data($task)->batchCheck($requiredFields, 'notempty');
+ if(dao::isError())
+ {
+ foreach(dao::getError() as $field => $error)
+ {
+ dao::$errors[] = $error;
+ return false;
+ }
+ }
+ }
+
$requiredFields = str_replace(",estimate,", ',', "$requiredFields");
$requiredFields = str_replace(",story,", ',', "$requiredFields");
$requiredFields = str_replace(",estStarted,", ',', "$requiredFields");
@@ -998,6 +1022,12 @@ class taskModel extends model
$requiredFields = str_replace(',estimate,', ',', $requiredFields);
}
+ if(strpos(',doing,pause,', $task->status) && empty($teams) && empty($task->left))
+ {
+ dao::$errors[] = sprintf($this->lang->task->error->leftEmptyAB, $this->lang->task->statusList[$task->status]);
+ return false;
+ }
+
$requiredFields = trim($requiredFields, ',');
$this->dao->update(TABLE_TASK)->data($task)
@@ -1008,7 +1038,6 @@ class taskModel extends model
->checkIF($task->estimate != false, 'estimate', 'float')
->checkIF($task->left != false, 'left', 'float')
->checkIF($task->consumed != false, 'consumed', 'float')
- ->checkIF($task->status != 'wait' and empty($teams) and $task->left == 0 and $task->status != 'cancel' and $task->status != 'closed', 'status', 'equal', 'done')
->batchCheckIF($task->status == 'wait' or $task->status == 'doing', 'finishedBy, finishedDate,canceledBy, canceledDate, closedBy, closedDate, closedReason', 'empty')
@@ -1113,7 +1142,6 @@ class taskModel extends model
{
if(isset($data->modules[$taskID]) and ($data->modules[$taskID] == 'ditto')) $data->modules[$taskID] = isset($prev['module']) ? $prev['module'] : 0;
if($data->types[$taskID] == 'ditto') $data->types[$taskID] = isset($prev['type']) ? $prev['type'] : '';
- if($data->statuses[$taskID] == 'ditto') $data->statuses[$taskID] = isset($prev['status']) ? $prev['status'] : '';
if($data->assignedTos[$taskID] == 'ditto') $data->assignedTos[$taskID] = isset($prev['assignedTo']) ? $prev['assignedTo'] : '';
if($data->pris[$taskID] == 'ditto') $data->pris[$taskID] = isset($prev['pri']) ? $prev['pri'] : 0;
if($data->finishedBys[$taskID] == 'ditto') $data->finishedBys[$taskID] = isset($prev['finishedBy']) ? $prev['finishedBy'] : '';
@@ -1124,7 +1152,6 @@ class taskModel extends model
$prev['module'] = $data->modules[$taskID];
$prev['type'] = $data->types[$taskID];
- $prev['status'] = $data->statuses[$taskID];
$prev['assignedTo'] = $data->assignedTos[$taskID];
$prev['pri'] = $data->pris[$taskID];
$prev['finishedBy'] = $data->finishedBys[$taskID];
@@ -1145,7 +1172,7 @@ class taskModel extends model
$task->name = $data->names[$taskID];
$task->module = isset($data->modules[$taskID]) ? $data->modules[$taskID] : 0;
$task->type = $data->types[$taskID];
- $task->status = $data->statuses[$taskID];
+ $task->status = isset($data->statuses[$taskID]) ? $data->statuses[$taskID] : $oldTask->status;
$task->assignedTo = $task->status == 'closed' ? 'closed' : $data->assignedTos[$taskID];
$task->pri = $data->pris[$taskID];
$task->estimate = isset($data->estimates[$taskID]) ? $data->estimates[$taskID] : $oldTask->estimate;
@@ -1180,11 +1207,12 @@ class taskModel extends model
if($message) return print(js::alert($message));
}
- if($data->consumeds[$taskID])
+ if(isset($data->consumeds[$taskID]))
{
if($data->consumeds[$taskID] < 0)
{
- echo js::alert(sprintf($this->lang->task->error->consumed, $taskID));
+ dao::$errors[] = sprintf($this->lang->task->error->consumed, $taskID);
+ return false;
}
else
{
@@ -1256,9 +1284,19 @@ class taskModel extends model
/* Check field not empty. */
foreach($tasks as $taskID => $task)
{
- if($task->status == 'done' and $task->consumed == false) return print(js::error('task#' . $taskID . sprintf($this->lang->error->notempty, $this->lang->task->consumedThisTime)));
if($task->status == 'cancel') continue;
- if(!empty($task->deadline) and $task->estStarted > $task->deadline) return print(js::error('task#' . $taskID . $this->lang->task->error->deadlineSmall));
+ if($task->status == 'done' and $task->consumed == false)
+ {
+ dao::$errors[] = 'Task#' . $taskID . sprintf($this->lang->error->notempty, $this->lang->task->consumedThisTime);
+ return false;
+ }
+
+ if(!empty($task->deadline) and $task->estStarted > $task->deadline)
+ {
+ dao::$errors[] = 'Task#' . $taskID . $this->lang->task->error->deadlineSmall;
+ return false;
+ }
+
foreach(explode(',', $this->config->task->edit->requiredFields) as $field)
{
$field = trim($field);
@@ -1275,6 +1313,12 @@ class taskModel extends model
foreach($tasks as $taskID => $task)
{
+ if(strpos(',doing,pause,', $task->status) && empty($teams) && $task->parent >= 0 && empty($task->left))
+ {
+ dao::$errors[] = sprintf($this->lang->task->error->leftEmpty, $taskID, $this->lang->task->statusList[$task->status]);
+ return false;
+ }
+
$oldTask = $oldTasks[$taskID];
$this->dao->update(TABLE_TASK)->data($task)
->autoCheck()
@@ -1282,7 +1326,6 @@ class taskModel extends model
->checkIF($task->estimate != false, 'estimate', 'float')
->checkIF($task->consumed != false, 'consumed', 'float')
->checkIF($task->left != false, 'left', 'float')
- ->checkIF($task->parent > 0 and $task->left == 0 and $task->status != 'cancel' and $task->status != 'closed' and $task->status != 'wait' and $task->consumed != 0, 'status', 'equal', 'done')
->batchCheckIF($task->status == 'wait' or $task->status == 'doing', 'finishedBy, finishedDate,canceledBy, canceledDate, closedBy, closedDate, closedReason', 'empty')
@@ -1294,6 +1337,11 @@ class taskModel extends model
->batchCheckIF($task->closedReason == 'cancel', 'finishedBy, finishedDate', 'empty')
->where('id')->eq((int)$taskID)
->exec();
+ if(dao::isError())
+ {
+ dao::$errors[] = 'Task#' . $taskID . dao::getError(true);
+ return false;
+ }
if($task->status == 'done' and $task->closedReason) $this->dao->update(TABLE_TASK)->set('status')->eq('closed')->where('id')->eq($taskID)->exec();
@@ -1324,10 +1372,6 @@ class taskModel extends model
if($task->status != $oldTask->status) $this->loadModel('kanban')->updateLane($oldTask->execution, 'task', $oldTask->id);
$allChanges[$taskID] = common::createChanges($oldTask, $task);
}
- else
- {
- return print(js::error('task#' . $taskID . dao::getError(true)));
- }
}
if(!dao::isError()) $this->loadModel('score')->create('ajax', 'batchEdit');
return $allChanges;
diff --git a/module/task/view/batchedit.html.php b/module/task/view/batchedit.html.php
index 2c1de060e9..ecfdc202fa 100755
--- a/module/task/view/batchedit.html.php
+++ b/module/task/view/batchedit.html.php
@@ -127,7 +127,7 @@ js::set('dittoNotice', $dittoNotice);
' style='overflow:visible'>module, "class='form-control chosen'")?> |
' style='overflow:visible'>assignedTo, "class='form-control chosen' {$disableAssignedTo}");?> |
type, "class='form-control'");?> |
-
>status, "class='form-control'");?> |
+
>status, "class='form-control' {$disableHour}");?> |
>estStarted) ? '' : $tasks[$taskID]->estStarted, "class='form-control text-center form-date'");?> |
>deadline) ? '' : $tasks[$taskID]->deadline, "class='form-control text-center form-date'");?> |
>pri, "class='form-control'");?> |
diff --git a/module/tutorial/lang/en.php b/module/tutorial/lang/en.php
index 7f7124b580..18742840c3 100644
--- a/module/tutorial/lang/en.php
+++ b/module/tutorial/lang/en.php
@@ -59,12 +59,12 @@ $lang->tutorial->tasks['createProject']['desc'] = "
Create a project:
$lang->tutorial->tasks['manageTeam'] = array('title' => "Manage Project Team");
$lang->tutorial->tasks['manageTeam']['mode'] = 'new';
-$lang->tutorial->tasks['manageTeam']['nav'] = array('app' => 'project', 'module' => 'project', 'method' => 'managemembers', 'menuModule' => '', 'menu' => '#navbar>.nav>li[data-id="browse"],#cards>.col>.panel:first .project-name,#projectTableList>tr:first>.c-name a,#navbar>.nav>li[data-id="settings"],#subNavbar>.nav>li[data-id="members"],.manage-team-btn', 'target' => '.manage-team-btn', 'vars' => 'projectID=0', 'form' => '#teamForm', 'requiredFields' => 'accounts1,accounts', 'submit' => '#submit', 'targetPageName' => 'Manage team members');
+$lang->tutorial->tasks['manageTeam']['nav'] = array('app' => 'project', 'module' => 'project', 'method' => 'managemembers', 'menuModule' => '', 'menu' => '#navbar>.nav>li[data-id="browse"],#cards>.col>.panel:first .project-name,#projectForm td.c-name:first a,#navbar>.nav>li[data-id="settings"],#subNavbar>.nav>li[data-id="members"],.manage-team-btn', 'target' => '.manage-team-btn', 'vars' => 'projectID=0', 'form' => '#teamForm', 'requiredFields' => 'accounts1,accounts', 'submit' => '#submit', 'targetPageName' => 'Manage team members');
$lang->tutorial->tasks['manageTeam']['desc'] = "Manage project team members:
- Open project Team Manage Team Members Page;
- Choose users for the team.
- Save
";
$lang->tutorial->tasks['createProjectExecution'] = array('title' => 'Create a ' . $lang->executionCommon);
$lang->tutorial->tasks['createProjectExecution']['mode'] = 'new';
-$lang->tutorial->tasks['createProjectExecution']['nav'] = array('app' => 'project', 'module' => 'execution', 'method' => 'create', 'menuModule' => 'browse', 'menu' => '#navbar>.nav>li[data-id="browse"],#cards>.col>.panel:first .project-name,#projectTableList>tr:first>.c-name a,#navbar>.nav>li[data-id="execution"],.create-execution-btn', 'form' => '#dataform', 'submit' => '#submit', 'target' => '.create-execution-btn', 'targetPageName' => 'Create' . $lang->executionCommon);
+$lang->tutorial->tasks['createProjectExecution']['nav'] = array('app' => 'project', 'module' => 'execution', 'method' => 'create', 'menuModule' => 'browse', 'menu' => '#navbar>.nav>li[data-id="browse"],#cards>.col>.panel:first .project-name,#projectForm td.c-name:first a,#navbar>.nav>li[data-id="execution"],.create-execution-btn', 'form' => '#dataform', 'submit' => '#submit', 'target' => '.create-execution-btn', 'targetPageName' => 'Create' . $lang->executionCommon);
$lang->tutorial->tasks['createProjectExecution']['desc'] = "Create a new {$lang->executionCommon}:
- Open Project {$lang->executionCommon} list Create {$lang->executionCommon};
- Fill the form with {$lang->executionCommon} information;
- Save {$lang->executionCommon}
";
$lang->tutorial->tasks['createExecution'] = array('title' => 'Create a ' . $lang->executionCommon);
diff --git a/module/tutorial/lang/zh-cn.php b/module/tutorial/lang/zh-cn.php
index b6510d7eea..a698817db8 100644
--- a/module/tutorial/lang/zh-cn.php
+++ b/module/tutorial/lang/zh-cn.php
@@ -59,12 +59,12 @@ $lang->tutorial->tasks['createProject']['desc'] = "在系统创建一个新
$lang->tutorial->tasks['manageTeam'] = array('title' => "管理项目团队");
$lang->tutorial->tasks['manageTeam']['mode'] = 'new';
-$lang->tutorial->tasks['manageTeam']['nav'] = array('app' => 'project', 'module' => 'project', 'method' => 'managemembers', 'menuModule' => '', 'menu' => '#navbar>.nav>li[data-id="browse"],#cards>.col>.panel:first .project-name,#projectTableList>tr:first>.c-name a,#navbar>.nav>li[data-id="settings"],#subNavbar>.nav>li[data-id="members"],.manage-team-btn', 'target' => '.manage-team-btn', 'vars' => 'projectID=0', 'form' => '#teamForm', 'requiredFields' => 'accounts1', 'submit' => '#submit', 'targetPageName' => '团队管理');
+$lang->tutorial->tasks['manageTeam']['nav'] = array('app' => 'project', 'module' => 'project', 'method' => 'managemembers', 'menuModule' => '', 'menu' => '#navbar>.nav>li[data-id="browse"],#cards>.col>.panel:first .project-name,#projectForm td.c-name:first a,#navbar>.nav>li[data-id="settings"],#subNavbar>.nav>li[data-id="members"],.manage-team-btn', 'target' => '.manage-team-btn', 'vars' => 'projectID=0', 'form' => '#teamForm', 'requiredFields' => 'accounts1', 'submit' => '#submit', 'targetPageName' => '团队管理');
$lang->tutorial->tasks['manageTeam']['desc'] = "
管理项目团队成员:
- 打开 项目 设置 团队 团队管理 页面;
- 选择要加入项目团队的成员;
- 保存团队成员信息。
";
$lang->tutorial->tasks['createProjectExecution'] = array('title' => '添加' . $lang->executionCommon);
$lang->tutorial->tasks['createProjectExecution']['mode'] = 'new';
-$lang->tutorial->tasks['createProjectExecution']['nav'] = array('app' => 'project', 'module' => 'execution', 'method' => 'create', 'menuModule' => 'browse', 'menu' => '#navbar>.nav>li[data-id="browse"],#cards>.col>.panel:first .project-name,#projectTableList>tr:first>.c-name a,#navbar>.nav>li[data-id="execution"],.create-execution-btn', 'form' => '#dataform', 'submit' => '#submit', 'target' => '.create-execution-btn', 'targetPageName' => '添加' . $lang->executionCommon);
+$lang->tutorial->tasks['createProjectExecution']['nav'] = array('app' => 'project', 'module' => 'execution', 'method' => 'create', 'menuModule' => 'browse', 'menu' => '#navbar>.nav>li[data-id="browse"],#cards>.col>.panel:first .project-name,#projectForm td.c-name:first a,#navbar>.nav>li[data-id="execution"],.create-execution-btn', 'form' => '#dataform', 'submit' => '#submit', 'target' => '.create-execution-btn', 'targetPageName' => '添加' . $lang->executionCommon);
$lang->tutorial->tasks['createProjectExecution']['desc'] = "在系统创建一个新的{$lang->executionCommon}:
- 打开 项目 {$lang->executionCommon} 添加{$lang->executionCommon} 页面;
- 在{$lang->executionCommon}表单中填写要创建的{$lang->executionCommon}信息;
- 保存{$lang->executionCommon}信息。
";
$lang->tutorial->tasks['createExecution'] = array('title' => '创建' . $lang->executionCommon);
diff --git a/module/tutorial/model.php b/module/tutorial/model.php
index 3353025775..ad45c76f6d 100644
--- a/module/tutorial/model.php
+++ b/module/tutorial/model.php
@@ -178,10 +178,11 @@ class tutorialModel extends model
/**
* Get project stats for tutorial
*
+ * @param string $browseType
* @access public
* @return array
*/
- public function getProjectStats()
+ public function getProjectStats($browseType = '')
{
$project = $this->getProject();
$emptyHour = array('totalEstimate' => 0, 'totalConsumed' => 0, 'totalLeft' => 0, 'progress' => 0);
@@ -191,6 +192,8 @@ class tutorialModel extends model
$project->teamMembers = array_keys($this->getTeamMembers());
$project->teamCount = count($project->teamMembers);
+ if($browseType and $browseType != 'all') $project->name .= '-' . $browseType; // Fix bug #21096
+
$projectStat[$project->id] = $project;
return $projectStat;
}
@@ -268,6 +271,14 @@ class tutorialModel extends model
*/
public function getExecution()
{
+ /* Fix bug #21097. */
+ $hours = new stdclass();
+ $hours->totalEstimate = 52;
+ $hours->totalConsumed = 43;
+ $hours->totalLeft = 7;
+ $hours->progress = 86;
+ $hours->totalReal = 50;
+
$execution = new stdclass();
$execution->id = 3;
$execution->project = 2;
@@ -300,6 +311,8 @@ class tutorialModel extends model
$execution->totalEstimate = 0;
$execution->displayCards = 0;
$execution->fluidBoard = 0;
+ $execution->hours = $hours;
+ $execution->burns = array(35, 35);
return $execution;
}
diff --git a/test/class/kanban.class.php b/test/class/kanban.class.php
index 6e22e60c08..ef7afa2043 100644
--- a/test/class/kanban.class.php
+++ b/test/class/kanban.class.php
@@ -249,31 +249,86 @@ class kanbanTest
return $object;
}
+ /**
+ * Test get kanban data.
+ *
+ * @param int $kanbanID
+ * @access public
+ * @return string
+ */
public function getKanbanDataTest($kanbanID)
{
$objects = $this->objectModel->getKanbanData($kanbanID);
if(dao::isError()) return dao::getError();
- return $objects;
+ $columnCount = 0;
+ $laneCount = 0;
+ $cardCount = 0;
+ foreach($objects as $regions)
+ {
+ foreach($regions->groups as $group)
+ {
+ foreach($group->lanes as $lane) $cardCount += count($lane->items);
+
+ $columnCount += count($group->columns);
+ $laneCount += count($group->lanes);
+ }
+ }
+ return 'columns:' . $columnCount . ', lanes:' . $laneCount . ', cards:' . $cardCount;
}
- public function getPlanKanbanTest($product, $branchID = 0, $planGroup = '')
+ /**
+ * Test get plan kanban.
+ *
+ * @param int $productID
+ * @param int $branchID
+ * @access public
+ * @return string
+ */
+ public function getPlanKanbanTest($productID, $branchID = 0)
{
- $objects = $this->objectModel->getPlanKanban($product, $branchID = 0, $planGroup = '');
+ global $tester;
+ $product = $tester->loadModel('product')->getByID($productID);
+
+ $tester->loadModel('productplan');
+ $planGroup = $product->type == 'normal' ? $tester->productplan->getList($product->id, 0, 'all', '', 'begin_desc', 'skipparent') : $tester->productplan->getGroupByProduct($product->id, 'skipParent', '', 'begin_desc');
+
+ $objects = $this->objectModel->getPlanKanban($product, $branchID, $planGroup);
if(dao::isError()) return dao::getError();
- return $objects;
+ $laneCount = 0;
+ $cardCount = 0;
+ foreach($objects->lanes as $lane)
+ {
+ foreach($lane->items as $item) $cardCount += count($item);
+ }
+ return 'lanes:' . count($objects->lanes) . ', cards:' . $cardCount;
}
- public function getRDKanbanTest($executionID, $browseType = 'all', $orderBy = 'id_desc', $regionID = 0, $groupBy = 'default')
+ public function getRDKanbanTest($executionID, $browseType = 'all', $regionID = 0)
{
- $objects = $this->objectModel->getRDKanban($executionID, $browseType = 'all', $orderBy = 'id_desc', $regionID = 0, $groupBy = 'default');
+ $objects = $this->objectModel->getRDKanban($executionID, $browseType, 'id_desc', $regionID);
if(dao::isError()) return dao::getError();
- return $objects;
+ $columnCount = 0;
+ $laneCount = 0;
+ $cardCount = 0;
+ foreach($objects as $regions)
+ {
+ foreach($regions->groups as $group)
+ {
+ $columnCount += count($group->columns);
+ $laneCount += count($group->lanes);
+ foreach($group->lanes as $lane)
+ {
+ foreach($lane->items as $item) $cardCount += count($item);
+ }
+ }
+ }
+ return 'columns:' . $columnCount . ', lanes:' . $laneCount . ', cards:' . $cardCount;
}
public function getRegionByIDTest($regionID)
@@ -294,13 +349,20 @@ class kanbanTest
return $objects;
}
+ /**
+ * Test get kanban id by region id.
+ *
+ * @param int $regionID
+ * @access public
+ * @return int
+ */
public function getKanbanIDByRegionTest($regionID)
{
- $objects = $this->objectModel->getKanbanIDByRegion($regionID);
+ $object = $this->objectModel->getKanbanIDByRegion($regionID);
if(dao::isError()) return dao::getError();
- return $objects;
+ return $object;
}
/**
@@ -324,20 +386,31 @@ class kanbanTest
public function getLaneGroupByRegionsTest($regions, $browseType = 'all')
{
- $objects = $this->objectModel->getLaneGroupByRegions($regions, $browseType = 'all');
+ $objects = $this->objectModel->getLaneGroupByRegions($regions, $browseType);
if(dao::isError()) return dao::getError();
- return $objects;
+ $count = 0;
+ foreach($objects as $object) $count += count($object);
+ return $count;
}
+ /**
+ * Test get lane pairs by group id.
+ *
+ * @param int $groupID
+ * @param string $orderBy
+ * @access public
+ * @return string
+ */
public function getLanePairsByGroupTest($groupID, $orderBy = '`order`_asc')
{
$objects = $this->objectModel->getLanePairsByGroup($groupID, $orderBy = '`order`_asc');
if(dao::isError()) return dao::getError();
- return $objects;
+ $names = implode(',', $objects);
+ return $names;
}
public function getColumnGroupByRegionsTest($regions, $order = 'order')
@@ -376,13 +449,23 @@ class kanbanTest
return $objects;
}
+ /**
+ * Test get RD column group by regions.
+ *
+ * @param int $regions
+ * @param array $groupIDList
+ * @access public
+ * @return int
+ */
public function getRDColumnGroupByRegionsTest($regions, $groupIDList = array())
{
- $objects = $this->objectModel->getRDColumnGroupByRegions($regions, $groupIDList = array());
+ $objects = $this->objectModel->getRDColumnGroupByRegions($regions, $groupIDList);
if(dao::isError()) return dao::getError();
- return $objects;
+ $count = 0;
+ foreach($objects as $object) $count += count($object);
+ return $count;
}
/**
@@ -431,10 +514,7 @@ class kanbanTest
{
foreach($types['lanes'] as $lane)
{
- foreach($lane['cards'] as $card)
- {
- $cardCount += count($card);
- }
+ foreach($lane['cards'] as $card) $cardCount += count($card);
}
$columnCount += count($types['columns']);
$laneCount += count($types['lanes']);
@@ -458,26 +538,46 @@ class kanbanTest
if(empty($objects))
{
$this->objectModel->createExecutionLane($executionID, $browseType, $groupBy);
- $objects = $this->objectModel->getExecutionKanban($executionID, $browseType, $groupBy);
+ $objects = $this->objectModel->getKanban4Group($executionID, $browseType, $groupBy);
}
if(dao::isError()) return dao::getError();
$laneCount = 0;
- foreach($objects as $types)
- {
- $laneCount += count($types['lanes']);
- }
+ foreach($objects as $types) $laneCount += count($types['lanes']);
+
return 'lanes:' . $laneCount;
}
- public function getLanes4GroupTest($executionID, $browseType, $groupBy, $cardList)
+ /**
+ * Test get kanban for group view.
+ *
+ * @param int $executionID
+ * @param string $browseType
+ * @param string $groupBy
+ * @access public
+ * @return void
+ */
+ public function getLanes4GroupTest($executionID, $browseType, $groupBy)
{
+ global $tester;
+ /* Get group objects. */
+ if($browseType == 'story') $cardList = $tester->loadModel('story')->getExecutionStories($executionID, 0, 0, 't1.`order`_desc', 'allStory');
+ if($browseType == 'bug') $cardList = $tester->loadModel('bug')->getExecutionBugs($executionID);
+ if($browseType == 'task') $cardList = $tester->loadModel('execution')->getKanbanTasks($executionID, "id");
$objects = $this->objectModel->getLanes4Group($executionID, $browseType, $groupBy, $cardList);
+ if(empty($objects))
+ {
+ $this->objectModel->createExecutionLane($executionID, $browseType, $groupBy);
+ $objects = $this->objectModel->getLanes4Group($executionID, $browseType, $groupBy);
+ }
+
if(dao::isError()) return dao::getError();
- return $objects;
+ $names = '';
+ foreach($objects as $object) $names .= ',' . $object->name;
+ return $names;
}
public function getSpaceListTest($browseType, $pager = null)
@@ -498,13 +598,21 @@ class kanbanTest
return $objects;
}
- public function getKanbanPairsTest()
+ /**
+ * Test get Kanban pairs.
+ *
+ * @param string $user
+ * @access public
+ * @return int
+ */
+ public function getKanbanPairsTest($user)
{
+ su($user);
$objects = $this->objectModel->getKanbanPairs();
if(dao::isError()) return dao::getError();
- return $objects;
+ return count($objects);
}
/**
@@ -556,22 +664,39 @@ class kanbanTest
return $objects;
}
+ /**
+ * Test get lane pairs by region id.
+ *
+ * @param int $regionID
+ * @param string $type
+ * @access public
+ * @return string
+ */
public function getLanePairsByRegionTest($regionID, $type = 'all')
{
- $objects = $this->objectModel->getLanePairsByRegion($regionID, $type = 'all');
+ $objects = $this->objectModel->getLanePairsByRegion($regionID, $type);
if(dao::isError()) return dao::getError();
- return $objects;
+ $names = implode(',', $objects);
+ return $names;
}
+ /**
+ * Test get lane group by regionid.
+ *
+ * @param int $regionID
+ * @param string $type
+ * @access public
+ * @return int
+ */
public function getLaneGroupByRegionTest($regionID, $type = 'all')
{
- $objects = $this->objectModel->getLaneGroupByRegion($regionID, $type = 'all');
+ $objects = $this->objectModel->getLaneGroupByRegion($regionID, $type);
if(dao::isError()) return dao::getError();
- return $objects;
+ return count($objects[$regionID]);
}
/**
@@ -1116,13 +1241,20 @@ class kanbanTest
return $object;
}
+ /**
+ * Test get lane by id.
+ *
+ * @param int $laneID
+ * @access public
+ * @return object
+ */
public function getLaneByIdTest($laneID)
{
- $objects = $this->objectModel->getLaneById($laneID);
+ $object = $this->objectModel->getLaneById($laneID);
if(dao::isError()) return dao::getError();
- return $objects;
+ return $object;
}
public function getObjectGroupTest($executionID, $type, $groupBy)
@@ -1131,6 +1263,7 @@ class kanbanTest
if(dao::isError()) return dao::getError();
+ $objects = implode(',', $objects);
return $objects;
}
diff --git a/test/data/kanban.yaml b/test/data/kanban.yaml
index 54f26af451..0df05382ee 100644
--- a/test/data/kanban.yaml
+++ b/test/data/kanban.yaml
@@ -61,6 +61,7 @@ fields:
range: "0"
- field: object
range: ""
+ prefix: "plans,releases,builds,executions,cards"
- field: createdBy
range: "admin"
- field: createdDate
diff --git a/test/data/kanbancard.yaml b/test/data/kanbancard.yaml
index 7422226af8..8b41cb3652 100644
--- a/test/data/kanbancard.yaml
+++ b/test/data/kanbancard.yaml
@@ -10,18 +10,21 @@ fields:
- field: group
range: 1-100{8}
- field: fromID
- range: "0"
+ range: 0{800},1-70,1-10,101-200,1-20
- field: fromType
- range: ""
+ range: []{800},productplan{70},release{10},execution{100},build{20}
- field: name
- range: 1-1000000
- prefix: "卡片"
+ fields:
+ - field: name1
+ range: 卡片{800},[]{200}
+ - field: name2
+ range: 1-800,[]{200}
- field: status
range: doing,doing,done
- field: pri
- range: "3"
+ range: 3{800},0{200}
- field: assignedTo
- range: "admin"
+ range: admin{800},[]{200}
- field: desc
range: ""
- field: begin
diff --git a/test/data/kanbancell.yaml b/test/data/kanbancell.yaml
index fb53137baa..901509dee9 100644
--- a/test/data/kanbancell.yaml
+++ b/test/data/kanbancell.yaml
@@ -16,7 +16,10 @@ fields:
- field: card1
prefix: ","
postfix: ","
- range: 1-800:2
+ range: 1-1000:2
- field: card2
postfix: ","
- range: 2-800:2
+ range: 2-1000:2
+ - field: card3
+ postfix: ","
+ range: 801-1000:2
diff --git a/test/data/zentao/config.php b/test/data/zentao/config.php
index e639a4127e..35b4a398a4 100644
--- a/test/data/zentao/config.php
+++ b/test/data/zentao/config.php
@@ -60,7 +60,7 @@ $builder->kanbanregion = array('rows' => 100, 'extends' => array('kanbanregion',
$builder->kanbangroup = array('rows' => 100, 'extends' => array('kanbangroup','kanbangroup'));
$builder->kanbanlane = array('rows' => 100, 'extends' => array('kanbanlane','kanbanlane'));
$builder->kanbancolumn = array('rows' => 400, 'extends' => array('kanbancolumn','kanbancolumn'));
-$builder->kanbancard = array('rows' => 800, 'extends' => array('kanbancard','kanbancard'));
+$builder->kanbancard = array('rows' => 1000, 'extends' => array('kanbancard','kanbancard'));
$builder->kanbancell = array('rows' => 400, 'extends' => array('kanbancell','kanbancell'));
$builder->kanbanregionproject = array('rows' => 180, 'extends' => array('kanbanregion','kanbanregionproject'));
diff --git a/test/model/kanban/getcanviewobjects.php b/test/model/kanban/getcanviewobjects.php
index 874fbee425..cf2e4db4d8 100755
--- a/test/model/kanban/getcanviewobjects.php
+++ b/test/model/kanban/getcanviewobjects.php
@@ -13,7 +13,7 @@ pid=1
$kanban = new kanbanTest();
-$userList = array('admin', 'po1', 'po2', 'user1', 'user2', 'pm1', 'pm2');
+$userList = array('admin', 'po1', 'po2', 'user1', 'user2', 'pm1', 'pm2');
$objectType = array('kanban', 'kanbanspace');
$paramList = array('noclosed', 'private', 'cooperation', 'public', 'involved');
diff --git a/test/model/kanban/getkanbandata.php b/test/model/kanban/getkanbandata.php
new file mode 100755
index 0000000000..723cd52b84
--- /dev/null
+++ b/test/model/kanban/getkanbandata.php
@@ -0,0 +1,24 @@
+#!/usr/bin/env php
+getKanbanData();
+cid=1
+pid=1
+
+*/
+
+$kanbanIDList = array('1', '2', '3', '4', '5', '1000001');
+
+$kanban = new kanbanTest();
+
+r($kanban->getKanbanDataTest($kanbanIDList[0])) && p() && e('columns:4, lanes:1, cards:4'); // 测试获取kanban1的视图
+r($kanban->getKanbanDataTest($kanbanIDList[1])) && p() && e('columns:4, lanes:1, cards:4'); // 测试获取kanban2的视图
+r($kanban->getKanbanDataTest($kanbanIDList[2])) && p() && e('columns:4, lanes:1, cards:4'); // 测试获取kanban3的视图
+r($kanban->getKanbanDataTest($kanbanIDList[3])) && p() && e('columns:4, lanes:1, cards:4'); // 测试获取kanban4的视图
+r($kanban->getKanbanDataTest($kanbanIDList[4])) && p() && e('columns:4, lanes:1, cards:4'); // 测试获取kanban5的视图
+r($kanban->getKanbanDataTest($kanbanIDList[5])) && p() && e('columns:0, lanes:0, cards:0'); // 测试获取不存在的kanban的视图
diff --git a/test/model/kanban/getkanbanidbyregion.php b/test/model/kanban/getkanbanidbyregion.php
new file mode 100755
index 0000000000..c486008c37
--- /dev/null
+++ b/test/model/kanban/getkanbanidbyregion.php
@@ -0,0 +1,23 @@
+#!/usr/bin/env php
+getKanbanIDByRegion();
+cid=1
+pid=1
+
+*/
+$regionIDList = array('1', '2', '3', '4', '5', '1000001');
+
+$kanban = new kanbanTest();
+
+r($kanban->getKanbanIDByRegionTest($regionIDList[0])) && p() && e('1'); // 测试通过区域1获取看板id
+r($kanban->getKanbanIDByRegionTest($regionIDList[1])) && p() && e('2'); // 测试通过区域2获取看板id
+r($kanban->getKanbanIDByRegionTest($regionIDList[2])) && p() && e('3'); // 测试通过区域3获取看板id
+r($kanban->getKanbanIDByRegionTest($regionIDList[3])) && p() && e('4'); // 测试通过区域4获取看板id
+r($kanban->getKanbanIDByRegionTest($regionIDList[4])) && p() && e('5'); // 测试通过区域5获取看板id
+r($kanban->getKanbanIDByRegionTest($regionIDList[5])) && p() && e('0'); // 测试通过不存在的区域获取看板id
diff --git a/test/model/kanban/getkanbanpairs.php b/test/model/kanban/getkanbanpairs.php
new file mode 100755
index 0000000000..99562a08af
--- /dev/null
+++ b/test/model/kanban/getkanbanpairs.php
@@ -0,0 +1,24 @@
+#!/usr/bin/env php
+getKanbanPairs();
+cid=1
+pid=1
+
+*/
+
+$userList = array('admin', 'po1', 'po2', 'user1', 'user2', 'pm1', 'pm2');
+
+$kanban = new kanbanTest();
+
+r($kanban->getKanbanPairsTest($userList[0])) && p() && e('100'); //获取用户admin可以看到的看板pairs
+r($kanban->getKanbanPairsTest($userList[1])) && p() && e('32'); //获取用户po1可以看到的看板pairs
+r($kanban->getKanbanPairsTest($userList[2])) && p() && e('32'); //获取用户po2可以看到的看板pairs
+r($kanban->getKanbanPairsTest($userList[3])) && p() && e('32'); //获取用户user1可以看到的看板pairs
+r($kanban->getKanbanPairsTest($userList[4])) && p() && e('32'); //获取用户user2可以看到的看板pairs
+r($kanban->getKanbanPairsTest($userList[5])) && p() && e('32'); //获取用户pm1可以看到的看板pairs
+r($kanban->getKanbanPairsTest($userList[6])) && p() && e('32'); //获取用户pm2可以看到的看板pairs
diff --git a/test/model/kanban/getlanebyid.php b/test/model/kanban/getlanebyid.php
new file mode 100755
index 0000000000..2b14b2d76a
--- /dev/null
+++ b/test/model/kanban/getlanebyid.php
@@ -0,0 +1,24 @@
+#!/usr/bin/env php
+getLaneById();
+cid=1
+pid=1
+
+*/
+
+$laneIDList = array('1', '2', '3', '4', '5', '1000001');
+
+$kanban = new kanbanTest();
+
+r($kanban->getLaneByIdTest($laneIDList[0])) && p('name,type,region,group') && e('默认泳道,common,1,1'); // 测试通过id1获取泳道信息
+r($kanban->getLaneByIdTest($laneIDList[1])) && p('name,type,region,group') && e('默认泳道,common,2,2'); // 测试通过id2获取泳道信息
+r($kanban->getLaneByIdTest($laneIDList[2])) && p('name,type,region,group') && e('默认泳道,common,3,3'); // 测试通过id3获取泳道信息
+r($kanban->getLaneByIdTest($laneIDList[3])) && p('name,type,region,group') && e('默认泳道,common,4,4'); // 测试通过id4获取泳道信息
+r($kanban->getLaneByIdTest($laneIDList[4])) && p('name,type,region,group') && e('默认泳道,common,5,5'); // 测试通过id5获取泳道信息
+r($kanban->getLaneByIdTest($laneIDList[5])) && p('name,type,region,group') && e('0'); // 测试通过不存在的id获取泳道信息
diff --git a/test/model/kanban/getlanegroupbyregion.php b/test/model/kanban/getlanegroupbyregion.php
new file mode 100755
index 0000000000..030c057ed1
--- /dev/null
+++ b/test/model/kanban/getlanegroupbyregion.php
@@ -0,0 +1,42 @@
+#!/usr/bin/env php
+getLaneGroupByRegion();
+cid=1
+pid=1
+
+*/
+
+$regionIDList = array('101', '102', '103', '104', '105', '1000001');
+$type = array('bug', 'task', 'story');
+
+$kanban = new kanbanTest();
+r($kanban->getLaneGroupByRegionTest($regionIDList[0])) && p() && e('3'); // 测试获取区域101的泳道
+r($kanban->getLaneGroupByRegionTest($regionIDList[0], $type[0])) && p() && e('1'); // 测试获取区域101的bug泳道
+r($kanban->getLaneGroupByRegionTest($regionIDList[0], $type[1])) && p() && e('1'); // 测试获取区域101的task泳道
+r($kanban->getLaneGroupByRegionTest($regionIDList[0], $type[2])) && p() && e('1'); // 测试获取区域101的story泳道
+r($kanban->getLaneGroupByRegionTest($regionIDList[1])) && p() && e('3'); // 测试获取区域102的泳道
+r($kanban->getLaneGroupByRegionTest($regionIDList[1], $type[0])) && p() && e('1'); // 测试获取区域102的bug泳道
+r($kanban->getLaneGroupByRegionTest($regionIDList[1], $type[1])) && p() && e('1'); // 测试获取区域102的task泳道
+r($kanban->getLaneGroupByRegionTest($regionIDList[1], $type[2])) && p() && e('1'); // 测试获取区域102的story泳道
+r($kanban->getLaneGroupByRegionTest($regionIDList[2])) && p() && e('3'); // 测试获取区域103的泳道
+r($kanban->getLaneGroupByRegionTest($regionIDList[2], $type[0])) && p() && e('1'); // 测试获取区域103的bug泳道
+r($kanban->getLaneGroupByRegionTest($regionIDList[2], $type[1])) && p() && e('1'); // 测试获取区域103的task泳道
+r($kanban->getLaneGroupByRegionTest($regionIDList[2], $type[2])) && p() && e('1'); // 测试获取区域103的story泳道
+r($kanban->getLaneGroupByRegionTest($regionIDList[3])) && p() && e('3'); // 测试获取区域104的泳道
+r($kanban->getLaneGroupByRegionTest($regionIDList[3], $type[0])) && p() && e('1'); // 测试获取区域104的bug泳道
+r($kanban->getLaneGroupByRegionTest($regionIDList[3], $type[1])) && p() && e('1'); // 测试获取区域104的task泳道
+r($kanban->getLaneGroupByRegionTest($regionIDList[3], $type[2])) && p() && e('1'); // 测试获取区域104的story泳道
+r($kanban->getLaneGroupByRegionTest($regionIDList[4])) && p() && e('3'); // 测试获取区域105的泳道
+r($kanban->getLaneGroupByRegionTest($regionIDList[4], $type[0])) && p() && e('1'); // 测试获取区域105的bug泳道
+r($kanban->getLaneGroupByRegionTest($regionIDList[4], $type[1])) && p() && e('1'); // 测试获取区域105的task泳道
+r($kanban->getLaneGroupByRegionTest($regionIDList[4], $type[2])) && p() && e('1'); // 测试获取区域105的story泳道
+r($kanban->getLaneGroupByRegionTest($regionIDList[5])) && p() && e('0'); // 测试获取不存在的区域的泳道
+r($kanban->getLaneGroupByRegionTest($regionIDList[5], $type[0])) && p() && e('0'); // 测试获取不存在的区域的bug泳道
+r($kanban->getLaneGroupByRegionTest($regionIDList[5], $type[1])) && p() && e('0'); // 测试获取不存在的区域的task泳道
+r($kanban->getLaneGroupByRegionTest($regionIDList[5], $type[2])) && p() && e('0'); // 测试获取不存在的区域的story泳道
diff --git a/test/model/kanban/getlanegroupbyregions.php b/test/model/kanban/getlanegroupbyregions.php
new file mode 100755
index 0000000000..2f9e094b16
--- /dev/null
+++ b/test/model/kanban/getlanegroupbyregions.php
@@ -0,0 +1,42 @@
+#!/usr/bin/env php
+getLaneGroupByRegions();
+cid=1
+pid=1
+
+*/
+$regionsList = array('101,102,103', '104,105,106', '107,108,109', '110,111,112', '113,114,115', '1000001');
+$type = array('bug', 'task', 'story');
+
+$kanban = new kanbanTest();
+
+r($kanban->getLaneGroupByRegionsTest($regionsList[0])) && p() && e('9'); // 测试获取区域101,102,103的泳道
+r($kanban->getLaneGroupByRegionsTest($regionsList[0], $type[0])) && p() && e('3'); // 测试获取区域101,102,103的bug泳道
+r($kanban->getLaneGroupByRegionsTest($regionsList[0], $type[1])) && p() && e('3'); // 测试获取区域101,102,103的task泳道
+r($kanban->getLaneGroupByRegionsTest($regionsList[0], $type[2])) && p() && e('3'); // 测试获取区域101,102,103的story泳道
+r($kanban->getLaneGroupByRegionsTest($regionsList[1])) && p() && e('9'); // 测试获取区域104,105,106的泳道
+r($kanban->getLaneGroupByRegionsTest($regionsList[1], $type[0])) && p() && e('3'); // 测试获取区域104,105,106的bug泳道
+r($kanban->getLaneGroupByRegionsTest($regionsList[1], $type[1])) && p() && e('3'); // 测试获取区域104,105,106的task泳道
+r($kanban->getLaneGroupByRegionsTest($regionsList[1], $type[2])) && p() && e('3'); // 测试获取区域104,105,106的story泳道
+r($kanban->getLaneGroupByRegionsTest($regionsList[2])) && p() && e('9'); // 测试获取区域107,108,109的泳道
+r($kanban->getLaneGroupByRegionsTest($regionsList[2], $type[0])) && p() && e('3'); // 测试获取区域107,108,109的bug泳道
+r($kanban->getLaneGroupByRegionsTest($regionsList[2], $type[1])) && p() && e('3'); // 测试获取区域107,108,109的task泳道
+r($kanban->getLaneGroupByRegionsTest($regionsList[2], $type[2])) && p() && e('3'); // 测试获取区域107,108,109的story泳道
+r($kanban->getLaneGroupByRegionsTest($regionsList[3])) && p() && e('9'); // 测试获取区域110,111,112的泳道
+r($kanban->getLaneGroupByRegionsTest($regionsList[3], $type[0])) && p() && e('3'); // 测试获取区域110,111,112的bug泳道
+r($kanban->getLaneGroupByRegionsTest($regionsList[3], $type[1])) && p() && e('3'); // 测试获取区域110,111,112的task泳道
+r($kanban->getLaneGroupByRegionsTest($regionsList[3], $type[2])) && p() && e('3'); // 测试获取区域110,111,112的story泳道
+r($kanban->getLaneGroupByRegionsTest($regionsList[4])) && p() && e('9'); // 测试获取区域113,114,115的泳道
+r($kanban->getLaneGroupByRegionsTest($regionsList[4], $type[0])) && p() && e('3'); // 测试获取区域113,114,115的bug泳道
+r($kanban->getLaneGroupByRegionsTest($regionsList[4], $type[1])) && p() && e('3'); // 测试获取区域113,114,115的task泳道
+r($kanban->getLaneGroupByRegionsTest($regionsList[4], $type[2])) && p() && e('3'); // 测试获取区域113,114,115的story泳道
+r($kanban->getLaneGroupByRegionsTest($regionsList[5])) && p() && e('0'); // 测试获取不存在的区域的泳道
+r($kanban->getLaneGroupByRegionsTest($regionsList[5], $type[0])) && p() && e('0'); // 测试获取不存在的区域的bug泳道
+r($kanban->getLaneGroupByRegionsTest($regionsList[5], $type[1])) && p() && e('0'); // 测试获取不存在的区域的task泳道
+r($kanban->getLaneGroupByRegionsTest($regionsList[5], $type[2])) && p() && e('0'); // 测试获取不存在的区域的story泳道
diff --git a/test/model/kanban/getlanepairsbygroup.php b/test/model/kanban/getlanepairsbygroup.php
new file mode 100755
index 0000000000..51ba429f89
--- /dev/null
+++ b/test/model/kanban/getlanepairsbygroup.php
@@ -0,0 +1,24 @@
+#!/usr/bin/env php
+getLanePairsByGroup();
+cid=1
+pid=1
+
+*/
+
+$groupIDList = array('101', '102', '103', '104', '105', '1000001');
+
+$kanban = new kanbanTest();
+
+r($kanban->getLanePairsByGroupTest($groupIDList[0])) && p() && e('研发需求'); // 获取泳道组101的泳道
+r($kanban->getLanePairsByGroupTest($groupIDList[1])) && p() && e('Bug'); // 获取泳道组102的泳道
+r($kanban->getLanePairsByGroupTest($groupIDList[2])) && p() && e('任务'); // 获取泳道组103的泳道
+r($kanban->getLanePairsByGroupTest($groupIDList[3])) && p() && e('研发需求'); // 获取泳道组104的泳道
+r($kanban->getLanePairsByGroupTest($groupIDList[4])) && p() && e('Bug'); // 获取泳道组105的泳道
+r($kanban->getLanePairsByGroupTest($groupIDList[5])) && p() && e('0'); // 获取不存在泳道组的泳道
diff --git a/test/model/kanban/getlanepairsbyregion.php b/test/model/kanban/getlanepairsbyregion.php
new file mode 100755
index 0000000000..39bdb8d1c9
--- /dev/null
+++ b/test/model/kanban/getlanepairsbyregion.php
@@ -0,0 +1,43 @@
+#!/usr/bin/env php
+getLanePairsByRegion();
+cid=1
+pid=1
+
+*/
+
+$regionIDList = array('101', '102', '103', '104', '105', '1000001');
+$type = array('bug', 'task', 'story');
+
+$kanban = new kanbanTest();
+
+r($kanban->getLanePairsByRegionTest($regionIDList[0])) && p() && e('研发需求,Bug,任务'); // 测试获取区域101的泳道
+r($kanban->getLanePairsByRegionTest($regionIDList[0], $type[0])) && p() && e('Bug'); // 测试获取区域101的bug泳道
+r($kanban->getLanePairsByRegionTest($regionIDList[0], $type[1])) && p() && e('任务'); // 测试获取区域101的task泳道
+r($kanban->getLanePairsByRegionTest($regionIDList[0], $type[2])) && p() && e('研发需求'); // 测试获取区域101的story泳道
+r($kanban->getLanePairsByRegionTest($regionIDList[1])) && p() && e('研发需求,Bug,任务'); // 测试获取区域102的泳道
+r($kanban->getLanePairsByRegionTest($regionIDList[1], $type[0])) && p() && e('Bug'); // 测试获取区域102的bug泳道
+r($kanban->getLanePairsByRegionTest($regionIDList[1], $type[1])) && p() && e('任务'); // 测试获取区域102的task泳道
+r($kanban->getLanePairsByRegionTest($regionIDList[1], $type[2])) && p() && e('研发需求'); // 测试获取区域102的story泳道
+r($kanban->getLanePairsByRegionTest($regionIDList[2])) && p() && e('研发需求,Bug,任务'); // 测试获取区域103的泳道
+r($kanban->getLanePairsByRegionTest($regionIDList[2], $type[0])) && p() && e('Bug'); // 测试获取区域103的bug泳道
+r($kanban->getLanePairsByRegionTest($regionIDList[2], $type[1])) && p() && e('任务'); // 测试获取区域103的task泳道
+r($kanban->getLanePairsByRegionTest($regionIDList[2], $type[2])) && p() && e('研发需求'); // 测试获取区域103的story泳道
+r($kanban->getLanePairsByRegionTest($regionIDList[3])) && p() && e('研发需求,Bug,任务'); // 测试获取区域104的泳道
+r($kanban->getLanePairsByRegionTest($regionIDList[3], $type[0])) && p() && e('Bug'); // 测试获取区域104的bug泳道
+r($kanban->getLanePairsByRegionTest($regionIDList[3], $type[1])) && p() && e('任务'); // 测试获取区域104的task泳道
+r($kanban->getLanePairsByRegionTest($regionIDList[3], $type[2])) && p() && e('研发需求'); // 测试获取区域104的story泳道
+r($kanban->getLanePairsByRegionTest($regionIDList[4])) && p() && e('研发需求,Bug,任务'); // 测试获取区域105的泳道
+r($kanban->getLanePairsByRegionTest($regionIDList[4], $type[0])) && p() && e('Bug'); // 测试获取区域105的bug泳道
+r($kanban->getLanePairsByRegionTest($regionIDList[4], $type[1])) && p() && e('任务'); // 测试获取区域105的task泳道
+r($kanban->getLanePairsByRegionTest($regionIDList[4], $type[2])) && p() && e('研发需求'); // 测试获取区域105的story泳道
+r($kanban->getLanePairsByRegionTest($regionIDList[5])) && p() && e('0'); // 测试获取不存在的区域的泳道
+r($kanban->getLanePairsByRegionTest($regionIDList[5], $type[0])) && p() && e('0'); // 测试获取不存在的区域的bug泳道
+r($kanban->getLanePairsByRegionTest($regionIDList[5], $type[1])) && p() && e('0'); // 测试获取不存在的区域的task泳道
+r($kanban->getLanePairsByRegionTest($regionIDList[5], $type[2])) && p() && e('0'); // 测试获取不存在的区域的story泳道
diff --git a/test/model/kanban/getlanes4group.php b/test/model/kanban/getlanes4group.php
new file mode 100755
index 0000000000..2c69fc4c58
--- /dev/null
+++ b/test/model/kanban/getlanes4group.php
@@ -0,0 +1,40 @@
+#!/usr/bin/env php
+getLanes4Group();
+cid=1
+pid=1
+
+*/
+$executionIDList = array('101', '102', '103', '104', '105');
+$browseTypeList = array('story', 'task', 'bug');
+$groupByList = array('pri', 'category', 'module', 'source', 'assignedTo', 'story', 'severity');
+
+$kanban = new kanbanTest();
+
+r($kanban->getLanes4GroupTest($executionIDList[0], $browseTypeList[0], $groupByList[0])) && p() && e(',优先级: 无,2,4'); // 获取执行101 story pri的泳道
+r($kanban->getLanes4GroupTest($executionIDList[0], $browseTypeList[0], $groupByList[1])) && p() && e(',类型: 无,功能'); // 获取执行101 story category的泳道
+r($kanban->getLanes4GroupTest($executionIDList[0], $browseTypeList[0], $groupByList[2])) && p() && e(',所属模块: 无,产品模块2,产品模块4'); // 获取执行101 story module的泳道
+r($kanban->getLanes4GroupTest($executionIDList[0], $browseTypeList[0], $groupByList[3])) && p() && e(',来源: 无,用户,市场'); // 获取执行101 story source的泳道
+r($kanban->getLanes4GroupTest($executionIDList[1], $browseTypeList[1], $groupByList[0])) && p() && e(',优先级: 无,1,2,4'); // 获取执行102 task pri的泳道
+r($kanban->getLanes4GroupTest($executionIDList[1], $browseTypeList[1], $groupByList[2])) && p() && e(',所属模块: 无,模块4,模块10,模块13,模块16'); // 获取执行102 task module的泳道
+r($kanban->getLanes4GroupTest($executionIDList[1], $browseTypeList[1], $groupByList[4])) && p() && e(',指派给: 无'); // 获取执行102 task assignedTo的泳道
+r($kanban->getLanes4GroupTest($executionIDList[1], $browseTypeList[1], $groupByList[5])) && p() && e(',相关研发需求: 无,用户需求5'); // 获取执行102 task story的泳道
+r($kanban->getLanes4GroupTest($executionIDList[2], $browseTypeList[2], $groupByList[0])) && p() && e(',优先级: 无,1,3,4'); // 获取执行101 bug pri的泳道
+r($kanban->getLanes4GroupTest($executionIDList[2], $browseTypeList[2], $groupByList[2])) && p() && e(',所属模块: 无,产品模块11,产品模块12,产品模块13'); // 获取执行101 bug module的泳道
+r($kanban->getLanes4GroupTest($executionIDList[2], $browseTypeList[2], $groupByList[4])) && p() && e(',指派给: 无,admin,测试1'); // 获取执行101 bug assignedTo的泳道
+r($kanban->getLanes4GroupTest($executionIDList[2], $browseTypeList[2], $groupByList[6])) && p() && e(',严重程度: 无,1,3,4'); // 获取执行101 bug severity的泳道
+r($kanban->getLanes4GroupTest($executionIDList[3], $browseTypeList[0], $groupByList[0])) && p() && e(',优先级: 无,2,4'); // 获取执行101 story pri的泳道
+r($kanban->getLanes4GroupTest($executionIDList[3], $browseTypeList[0], $groupByList[1])) && p() && e(',类型: 无,功能'); // 获取执行101 story category的泳道
+r($kanban->getLanes4GroupTest($executionIDList[3], $browseTypeList[0], $groupByList[2])) && p() && e(',所属模块: 无,产品模块14,产品模块16'); // 获取执行101 story module的泳道
+r($kanban->getLanes4GroupTest($executionIDList[3], $browseTypeList[0], $groupByList[3])) && p() && e(',来源: 无,用户,其他'); // 获取执行101 story source的泳道
+r($kanban->getLanes4GroupTest($executionIDList[4], $browseTypeList[1], $groupByList[0])) && p() && e(',优先级: 无,1,2,3'); // 获取执行102 task pri的泳道
+r($kanban->getLanes4GroupTest($executionIDList[4], $browseTypeList[1], $groupByList[2])) && p() && e(',所属模块: 无,模块13,模块37,模块40,模块43'); // 获取执行102 task module的泳道
+r($kanban->getLanes4GroupTest($executionIDList[4], $browseTypeList[1], $groupByList[4])) && p() && e(',指派给: 无'); // 获取执行102 task assignedTo的泳道
+r($kanban->getLanes4GroupTest($executionIDList[4], $browseTypeList[1], $groupByList[5])) && p() && e(',相关研发需求: 无,用户需求17'); // 获取执行102 task story的泳道
+system("./ztest init");
diff --git a/test/model/kanban/getobjectgroup.php b/test/model/kanban/getobjectgroup.php
new file mode 100755
index 0000000000..fff58fe98c
--- /dev/null
+++ b/test/model/kanban/getobjectgroup.php
@@ -0,0 +1,39 @@
+#!/usr/bin/env php
+getObjectGroup();
+cid=1
+pid=1
+
+*/
+$executionIDList = array('101', '102', '103', '104', '105');
+$browseTypeList = array('story', 'task', 'bug');
+$groupByList = array('pri', 'category', 'module', 'source', 'assignedTo', 'story', 'severity');
+
+$kanban = new kanbanTest();
+
+r($kanban->getObjectGroupTest($executionIDList[0], $browseTypeList[0], $groupByList[0])) && p() && e('4,2'); // 获取执行101 story pri的分组
+r($kanban->getObjectGroupTest($executionIDList[0], $browseTypeList[0], $groupByList[1])) && p() && e('feature'); // 获取执行101 story category的分组
+r($kanban->getObjectGroupTest($executionIDList[0], $browseTypeList[0], $groupByList[2])) && p() && e('1824,1822'); // 获取执行101 story module的分组
+r($kanban->getObjectGroupTest($executionIDList[0], $browseTypeList[0], $groupByList[3])) && p() && e('user,market'); // 获取执行101 story source的分组
+r($kanban->getObjectGroupTest($executionIDList[1], $browseTypeList[1], $groupByList[0])) && p() && e('4,2,1'); // 获取执行102 task pri的分组
+r($kanban->getObjectGroupTest($executionIDList[1], $browseTypeList[1], $groupByList[2])) && p() && e('36,33,30,24'); // 获取执行102 task module的分组
+r($kanban->getObjectGroupTest($executionIDList[1], $browseTypeList[1], $groupByList[4])) && p() && e('0'); // 获取执行102 task assignedTo的分组
+r($kanban->getObjectGroupTest($executionIDList[1], $browseTypeList[1], $groupByList[5])) && p() && e('8,6,0'); // 获取执行102 task story的分组
+r($kanban->getObjectGroupTest($executionIDList[2], $browseTypeList[2], $groupByList[0])) && p() && e('4,3,1'); // 获取执行101 bug pri的分组
+r($kanban->getObjectGroupTest($executionIDList[2], $browseTypeList[2], $groupByList[2])) && p() && e('1833,1832,1831,0'); // 获取执行101 bug module的分组
+r($kanban->getObjectGroupTest($executionIDList[2], $browseTypeList[2], $groupByList[4])) && p() && e('test1,admin'); // 获取执行101 bug assignedTo的分组
+r($kanban->getObjectGroupTest($executionIDList[2], $browseTypeList[2], $groupByList[6])) && p() && e('4,3,1'); // 获取执行101 bug severity的分组
+r($kanban->getObjectGroupTest($executionIDList[3], $browseTypeList[0], $groupByList[0])) && p() && e('4,2'); // 获取执行101 story pri的分组
+r($kanban->getObjectGroupTest($executionIDList[3], $browseTypeList[0], $groupByList[1])) && p() && e('feature'); // 获取执行101 story category的分组
+r($kanban->getObjectGroupTest($executionIDList[3], $browseTypeList[0], $groupByList[2])) && p() && e('1836,1834'); // 获取执行101 story module的分组
+r($kanban->getObjectGroupTest($executionIDList[3], $browseTypeList[0], $groupByList[3])) && p() && e('user,other'); // 获取执行101 story source的分组
+r($kanban->getObjectGroupTest($executionIDList[4], $browseTypeList[1], $groupByList[0])) && p() && e('3,2,1'); // 获取执行102 task pri的分组
+r($kanban->getObjectGroupTest($executionIDList[4], $browseTypeList[1], $groupByList[2])) && p() && e('63,60,57,33'); // 获取执行102 task module的分组
+r($kanban->getObjectGroupTest($executionIDList[4], $browseTypeList[1], $groupByList[4])) && p() && e('0'); // 获取执行102 task assignedTo的分组
+r($kanban->getObjectGroupTest($executionIDList[4], $browseTypeList[1], $groupByList[5])) && p() && e('20,18,0'); // 获取执行102 task story的分组
diff --git a/test/model/kanban/getplankanban.php b/test/model/kanban/getplankanban.php
new file mode 100755
index 0000000000..b1a25f814b
--- /dev/null
+++ b/test/model/kanban/getplankanban.php
@@ -0,0 +1,26 @@
+#!/usr/bin/env php
+getPlanKanban();
+cid=1
+pid=1
+
+*/
+
+$productIDList = array('1', '2', '3', '41', '42');
+$branchIDList = array('0', '1', '3');
+
+$kanban = new kanbanTest();
+
+r($kanban->getPlanKanbanTest($productIDList[0])) && p() && e('lanes:1, cards:3'); // 测试获取产品1的计划看板
+r($kanban->getPlanKanbanTest($productIDList[1])) && p() && e('lanes:1, cards:3'); // 测试获取产品2的计划看板
+r($kanban->getPlanKanbanTest($productIDList[2])) && p() && e('lanes:1, cards:3'); // 测试获取产品3的计划看板
+r($kanban->getPlanKanbanTest($productIDList[3])) && p() && e('lanes:3, cards:2'); // 测试获取产品4的计划看板
+r($kanban->getPlanKanbanTest($productIDList[3], $branchIDList[1])) && p() && e('lanes:1, cards:1'); // 测试获取产品4 分支1的计划看板
+r($kanban->getPlanKanbanTest($productIDList[4])) && p() && e('lanes:3, cards:2'); // 测试获取产品5的计划看板
+r($kanban->getPlanKanbanTest($productIDList[4], $branchIDList[2])) && p() && e('lanes:1, cards:1'); // 测试获取产品5 分支3的计划看板
diff --git a/test/model/kanban/getrdcolumngroupbyregions.php b/test/model/kanban/getrdcolumngroupbyregions.php
new file mode 100755
index 0000000000..89242d2468
--- /dev/null
+++ b/test/model/kanban/getrdcolumngroupbyregions.php
@@ -0,0 +1,32 @@
+#!/usr/bin/env php
+getRDColumnGroupByRegions();
+cid=1
+pid=1
+
+*/
+
+$regions = array('1', '2', '3,4', '5,6,7', '8,9,10,11');
+$groupIDList = array('1', '2', '3', '5,6', '8,10');
+
+$kanban = new kanbanTest();
+
+r($kanban->getRDColumnGroupByRegionsTest($regions[0])) && p() && e('4'); // 测试获取region 1 执行看板泳道列组
+r($kanban->getRDColumnGroupByRegionsTest($regions[0], $groupIDList[0])) && p() && e('4'); // 测试获取region 1 group 1执行看板泳道列组
+r($kanban->getRDColumnGroupByRegionsTest($regions[0], $groupIDList[1])) && p() && e('0'); // 测试获取region 1 group 2执行看板泳道列组
+r($kanban->getRDColumnGroupByRegionsTest($regions[1])) && p() && e('4'); // 测试获取region 2 执行看板泳道列组
+r($kanban->getRDColumnGroupByRegionsTest($regions[1], $groupIDList[1])) && p() && e('4'); // 测试获取region 2 group 2执行看板泳道列组
+r($kanban->getRDColumnGroupByRegionsTest($regions[1], $groupIDList[0])) && p() && e('0'); // 测试获取region 2 group 1执行看板泳道列组
+r($kanban->getRDColumnGroupByRegionsTest($regions[2])) && p() && e('8'); // 测试获取region 3 执行看板泳道列组
+r($kanban->getRDColumnGroupByRegionsTest($regions[2], $groupIDList[2])) && p() && e('4'); // 测试获取region 3 group 3执行看板泳道列组
+r($kanban->getRDColumnGroupByRegionsTest($regions[2], $groupIDList[0])) && p() && e('0'); // 测试获取region 3 group 1执行看板泳道列组
+r($kanban->getRDColumnGroupByRegionsTest($regions[3])) && p() && e('12'); // 测试获取region 4 执行看板泳道列组
+r($kanban->getRDColumnGroupByRegionsTest($regions[3], $groupIDList[3])) && p() && e('8'); // 测试获取region 4 group 5,6执行看板泳道列组
+r($kanban->getRDColumnGroupByRegionsTest($regions[4])) && p() && e('16'); // 测试获取region 5 执行看板泳道列组
+r($kanban->getRDColumnGroupByRegionsTest($regions[4], $groupIDList[4])) && p() && e('8'); // 测试获取region 5 group 8,10执行看板泳道列组
diff --git a/test/model/kanban/getrdkanban.php b/test/model/kanban/getrdkanban.php
new file mode 100755
index 0000000000..feffb0a8ae
--- /dev/null
+++ b/test/model/kanban/getrdkanban.php
@@ -0,0 +1,31 @@
+#!/usr/bin/env php
+getRDKanban();
+cid=1
+pid=1
+
+*/
+$executionIDList = array('161', '162', '163', '164', '165');
+$browseTypeList = array('all', 'story', 'task', 'bug');
+$regionIDList = array('0', '101', '102', '103', '104', '105');
+$groupBy = 'pri';
+
+$kanban = new kanbanTest();
+
+r($kanban->getRDKanbanTest($executionIDList[0])) && p() && e('columns:27, lanes:3, cards:5'); // 获取执行161的执行看板
+r($kanban->getRDKanbanTest($executionIDList[0], $browseTypeList[0], $regionIDList[1])) && p() && e('columns:27, lanes:3, cards:8'); // 获取执行161 all region 101的执行看板
+r($kanban->getRDKanbanTest($executionIDList[0], $browseTypeList[0], $regionIDList[2])) && p() && e('columns:0, lanes:0, cards:0'); // 获取执行161 all region 102的执行看板
+r($kanban->getRDKanbanTest($executionIDList[1])) && p() && e('columns:27, lanes:3, cards:5'); // 获取执行162的执行看板
+r($kanban->getRDKanbanTest($executionIDList[1], $browseTypeList[1], $regionIDList[2])) && p() && e('columns:11, lanes:1, cards:2'); // 获取执行162 story region 102的执行看板
+r($kanban->getRDKanbanTest($executionIDList[2])) && p() && e('columns:27, lanes:3, cards:0'); // 获取执行163的执行看板
+r($kanban->getRDKanbanTest($executionIDList[2], $browseTypeList[2], $regionIDList[3])) && p() && e('columns:7, lanes:1, cards:4'); // 获取执行163 task region 103的执行看板
+r($kanban->getRDKanbanTest($executionIDList[3])) && p() && e('columns:27, lanes:3, cards:0'); // 获取执行164的执行看板
+r($kanban->getRDKanbanTest($executionIDList[3], $browseTypeList[3], $regionIDList[4])) && p() && e('columns:9, lanes:1, cards:3'); // 获取执行164 bug region 104的执行看板
+r($kanban->getRDKanbanTest($executionIDList[4])) && p() && e('columns:27, lanes:3, cards:0'); // 获取执行165的执行看板
+r($kanban->getRDKanbanTest($executionIDList[4], $browseTypeList[1], $regionIDList[5])) && p() && e('columns:11, lanes:1, cards:2'); // 获取执行165 story region 105的执行看板
diff --git a/www/js/zui/min.js b/www/js/zui/min.js
index beb9092f34..49def157ce 100644
--- a/www/js/zui/min.js
+++ b/www/js/zui/min.js
@@ -1,5 +1,5 @@
/*!
- * ZUI: ZUI for Zentao - v1.10.0 - 2022-03-28
+ * ZUI: ZUI for Zentao - v1.10.0 - 2022-03-30
* http://openzui.com
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2022 cnezsoft.com; Licensed MIT
@@ -42,7 +42,7 @@ Copyright (c) 2011 Harvest http://getharvest.com
MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md
*/
function(){var t,e,i,n,o,a={}.hasOwnProperty,s=function(t,e){function i(){this.constructor=t}for(var n in e)a.call(e,n)&&(t[n]=e[n]);return i.prototype=e.prototype,t.prototype=new i,t.__super__=e.prototype,t},r={zh_cn:{no_results_text:"没有找到"},zh_tw:{no_results_text:"沒有找到"},en:{no_results_text:"No results match"}},l={};n=function(){function e(){this.options_index=0,this.parsed=[]}return e.prototype.add_node=function(t){return"OPTGROUP"===t.nodeName.toUpperCase()?this.add_group(t):this.add_option(t)},e.prototype.add_group=function(e){var i,n,o,a,s,r;for(i=this.parsed.length,this.parsed.push({array_index:i,group:!0,label:this.escapeExpression(e.label),children:0,disabled:e.disabled,title:e.title,search_keys:t.trim(e.getAttribute("data-keys")||"").replace(/,/g," ")}),s=e.childNodes,r=[],o=0,a=s.length;o\"\'\`]/.test(t)?(e={"<":"<",">":">",'"':""","'":"'","`":"`"},i=/&(?!\w+;)|[\<\>\"\'\`]/g,t.replace(i,function(t){return e[t]||"&"})):t},e}(),n.select_to_array=function(t){var e,i,o,a,s;for(i=new n,s=t.childNodes,o=0,a=s.length;o0?(e=document.createElement("li"),e.className="group-result",e.title=t.title,e.innerHTML=t.search_text,this.outerHTML(e)):""},e.prototype.results_update_field=function(){this.set_default_text(),this.is_multiple||this.results_reset_cleanup(),this.result_clear_highlight(),this.results_build(),this.results_showing&&(this.winnow_results(),this.autoResizeDrop())},e.prototype.reset_single_select_options=function(){var t,e,i,n,o;for(n=this.results_data,o=[],e=0,i=n.length;e"+i.search_text.substr(l+r.length),i.search_text=c.substr(0,l)+""+c.substr(l)):i.search_keys_match&&i.search_keys.length&&(l=i.search_keys.search(h),c=i.search_keys.substr(0,l+r.length)+""+i.search_keys.substr(l+r.length),i.search_text+=' '+c.substr(0,l)+""+c.substr(l)+""),null!=s&&(s.group_match=!0)):null!=i.group_array_index&&this.results_data[i.group_array_index].search_match&&(i.search_match=!0)));return this.result_clear_highlight(),a<1&&r.length?(this.update_results_content(""),this.no_results(r)):(this.update_results_content(this.results_option_build()),this.winnow_results_set_highlight(t))},e.prototype.search_string_match=function(t,e){var i,n,o,a;if(e.test(t))return!0;if(this.enable_split_word_search&&(t.indexOf(" ")>=0||0===t.indexOf("["))&&(n=t.replace(/\[|\]/g,"").split(" "),n.length))for(o=0,a=n.length;o0)return this.keydown_backstroke();if(!this.pending_backstroke)return this.result_clear_highlight(),this.results_search();break;case 13:if(t.preventDefault(),this.results_showing)return this.result_select(t);break;case 27:return this.results_showing&&this.results_hide(),!0;case 9:case 38:case 40:case 16:case 91:case 17:break;default:return this.results_search()}},e.prototype.clipboard_event_checker=function(t){var e=this;return setTimeout(function(){return e.results_search()},50)},e.prototype.container_width=function(){return null!=this.options.width?this.options.width:this.form_field&&this.form_field.classList&&this.form_field.classList.contains("form-control")?"100%":""+this.form_field.offsetWidth+"px"},e.prototype.include_option_in_results=function(t){return!(this.is_multiple&&!this.display_selected_options&&t.selected)&&(!(!this.display_disabled_options&&t.disabled)&&!t.empty)},e.prototype.search_results_touchstart=function(t){return this.touch_started=!0,this.search_results_mouseover(t)},e.prototype.search_results_touchmove=function(t){return this.touch_started=!1,this.search_results_mouseout(t)},e.prototype.search_results_touchend=function(t){if(this.touch_started)return this.search_results_mouseup(t)},e.prototype.outerHTML=function(t){var e;return t.outerHTML?t.outerHTML:(e=document.createElement("div"),e.appendChild(t),e.innerHTML)},e.browser_is_supported=function(){return"Microsoft Internet Explorer"===window.navigator.appName?document.documentMode>=8:!/iP(od|hone)/i.test(window.navigator.userAgent)&&(!/Android/i.test(window.navigator.userAgent)||!/Mobile/i.test(window.navigator.userAgent))},e.default_multiple_text="",e.default_single_text="",e.default_no_result_text="No results match",e}(),t=jQuery,t.fn.extend({chosen:function(n){return e.browser_is_supported()?this.each(function(e){var o=t(this),a=o.data("chosen");"destroy"===n&&a?a.destroy():a||o.data("chosen",new i(this,t.extend({},o.data(),n)))}):this}}),i=function(e){function i(){return o=i.__super__.constructor.apply(this,arguments)}return s(i,e),i.prototype.setup=function(){return this.form_field_jq=t(this.form_field),this.current_selectedIndex=this.form_field.selectedIndex,this.is_rtl=this.form_field_jq.hasClass("chosen-rtl")},i.prototype.set_up_html=function(){var e,i;e=["chosen-container"],e.push("chosen-container-"+(this.is_multiple?"multi":"single")),this.inherit_select_classes&&this.form_field.className&&e.push(this.form_field.className),this.is_rtl&&e.push("chosen-rtl");var n=this.form_field.getAttribute("data-css-class");return n&&e.push(n),i={"class":e.join(" "),style:"width: "+this.container_width()+";",title:this.form_field.title},this.form_field.id.length&&(i.id=this.form_field.id.replace(/[^\w]/g,"_")+"_chosen"),this.container=t("",i),this.is_multiple?this.container.html(''):(this.container.html(''+this.default_text+'
'),this.compact_search?this.container.addClass("chosen-compact").find(".chosen-search").appendTo(this.container.find(".chosen-single")):this.container.find(".chosen-search").prependTo(this.container.find(".chosen-drop")),this.options.highlight_selected!==!1&&this.container.addClass("chosen-highlight-selected")),this.form_field_jq.hide().after(this.container),this.dropdown=this.container.find("div.chosen-drop").first(),this.search_field=this.container.find("input").first(),this.search_results=this.container.find("ul.chosen-results").first(),this.search_field_scale(),this.search_no_results=this.container.find("li.no-results").first(),this.is_multiple?(this.search_choices=this.container.find("ul.chosen-choices").first(),this.search_container=this.container.find("li.search-field").first()):(this.search_container=this.container.find("div.chosen-search").first(),this.selected_item=this.container.find(".chosen-single").first()),this.options.drop_width&&this.dropdown.css("width",this.options.drop_width).addClass("chosen-drop-size-limited"),this.max_drop_width&&this.dropdown.addClass("chosen-auto-max-width"),this.options.no_wrap&&this.dropdown.addClass("chosen-no-wrap"),this.results_build(),this.set_tab_index(),this.set_label_behavior(),this.form_field_jq.trigger("chosen:ready",{chosen:this})},i.prototype.register_observers=function(){var t=this;return this.container.bind("mousedown.chosen",function(e){t.container_mousedown(e)}),this.container.bind("mouseup.chosen",function(e){t.container_mouseup(e)}),this.container.bind("mouseenter.chosen",function(e){t.mouse_enter(e)}),this.container.bind("mouseleave.chosen",function(e){t.mouse_leave(e)}),this.search_results.bind("mouseup.chosen",function(e){t.search_results_mouseup(e)}),this.search_results.bind("mouseover.chosen",function(e){t.search_results_mouseover(e)}),this.search_results.bind("mouseout.chosen",function(e){t.search_results_mouseout(e)}),this.search_results.bind("mousewheel.chosen DOMMouseScroll.chosen",function(e){t.search_results_mousewheel(e)}),this.search_results.bind("touchstart.chosen",function(e){t.search_results_touchstart(e)}),this.search_results.bind("touchmove.chosen",function(e){t.search_results_touchmove(e)}),this.search_results.bind("touchend.chosen",function(e){t.search_results_touchend(e)}),this.form_field_jq.bind("chosen:updated.chosen",function(e){t.results_update_field(e)}),this.form_field_jq.bind("chosen:activate.chosen",function(e){t.activate_field(e)}),this.form_field_jq.bind("chosen:open.chosen",function(e){t.container_mousedown(e)}),this.form_field_jq.bind("chosen:close.chosen",function(e){t.input_blur(e)}),this.search_field.bind("blur.chosen",function(e){t.input_blur(e)}),this.search_field.bind("keyup.chosen",function(e){t.keyup_checker(e)}),this.search_field.bind("keydown.chosen",function(e){t.keydown_checker(e)}),this.search_field.bind("focus.chosen",function(e){t.input_focus(e)}),this.search_field.bind("cut.chosen",function(e){t.clipboard_event_checker(e)}),this.search_field.bind("paste.chosen",function(e){t.clipboard_event_checker(e)}),this.is_multiple?this.search_choices.bind("click.chosen",function(e){t.choices_click(e)}):this.container.bind("click.chosen",function(t){t.preventDefault()})},i.prototype.destroy=function(){return t(this.container[0].ownerDocument).unbind("click.chosen",this.click_test_action),this.search_field[0].tabIndex&&(this.form_field_jq[0].tabIndex=this.search_field[0].tabIndex),this.container.remove(),this.form_field_jq.removeData("chosen"),this.form_field_jq.show()},i.prototype.search_field_disabled=function(){return this.is_disabled=this.form_field_jq[0].disabled,this.is_disabled?(this.container.addClass("chosen-disabled"),this.search_field[0].disabled=!0,this.is_multiple||this.selected_item.unbind("focus.chosen",this.activate_action),this.close_field()):(this.container.removeClass("chosen-disabled"),this.search_field[0].disabled=!1,this.is_multiple?void 0:this.selected_item.bind("focus.chosen",this.activate_action))},i.prototype.container_mousedown=function(e){if(!this.is_disabled&&(e&&"mousedown"===e.type&&!this.results_showing&&e.preventDefault(),null==e||!t(e.target).hasClass("search-choice-close")))return this.active_field?this.is_multiple||!e||t(e.target)[0]!==this.selected_item[0]&&!t(e.target).parents("a.chosen-single").length||(e.preventDefault(),this.results_toggle()):(this.is_multiple&&this.search_field.val(""),t(this.container[0].ownerDocument).bind("click.chosen",this.click_test_action),this.results_show()),this.activate_field()},i.prototype.container_mouseup=function(t){if("ABBR"===t.target.nodeName&&!this.is_disabled)return this.results_reset(t)},i.prototype.search_results_mousewheel=function(t){var e;if(t.originalEvent&&(e=-t.originalEvent.wheelDelta||t.originalEvent.detail),null!=e)return t.preventDefault(),"DOMMouseScroll"===t.type&&(e=40*e),this.search_results.scrollTop(e+this.search_results.scrollTop())},i.prototype.blur_test=function(t){if(!this.active_field&&this.container.hasClass("chosen-container-active"))return this.close_field()},i.prototype.close_field=function(){return t(this.container[0].ownerDocument).unbind("click.chosen",this.click_test_action),this.active_field=!1,this.results_hide(),this.container.removeClass("chosen-container-active"),this.clear_backstroke(),this.show_search_field_default(),this.search_field_scale()},i.prototype.activate_field=function(){return this.container.addClass("chosen-container-active"),this.active_field=!0,this.search_field.val(this.search_field.val()),this.search_field.focus()},i.prototype.test_active_click=function(e){var i;return i=t(e.target).closest(".chosen-container"),i.length&&this.container[0]===i[0]?this.active_field=!0:this.close_field()},i.prototype.results_build=function(){return this.parsing=!0,this.selected_option_count=null,this.results_data=n.select_to_array(this.form_field),this.is_multiple?this.search_choices.find("li.search-choice").remove():this.is_multiple||(this.single_set_selected_text(),this.disable_search||this.form_field.options.length<=this.disable_search_threshold?(this.search_field[0].readOnly=!0,this.container.addClass("chosen-container-single-nosearch"),this.container.removeClass("chosen-with-search")):(this.search_field[0].readOnly=!1,this.container.removeClass("chosen-container-single-nosearch"),this.container.addClass("chosen-with-search"))),this.update_results_content(this.results_option_build({first:!0})),this.search_field_disabled(),this.show_search_field_default(),this.search_field_scale(),this.parsing=!1},i.prototype.result_do_highlight=function(t,e){if(t.length){var i,n,o,a,s,r,l=-1;this.result_clear_highlight(),this.result_highlight=t,this.result_highlight.addClass("highlighted"),o=parseInt(this.search_results.css("maxHeight"),10),r=this.result_highlight.outerHeight(),s=this.search_results.scrollTop(),a=o+s,n=this.result_highlight.position().top+this.search_results.scrollTop(),i=n+r,this.middle_highlight&&(e||"always"===this.middle_highlight)?l=Math.min(n-r,Math.max(0,n-(o-r)/2)):i>=a?l=i-o>0?i-o:0:n-1?this.search_results.scrollTop(l):this.result_highlight.scrollIntoView&&this.result_highlight.scrollIntoView()}},i.prototype.result_clear_highlight=function(){return this.result_highlight&&this.result_highlight.removeClass("highlighted"),this.result_highlight=null},i.prototype.results_show=function(){var e=this;if(e.is_multiple&&e.max_selected_options<=e.choices_count())return e.form_field_jq.trigger("chosen:maxselected",{chosen:this}),!1;e.results_showing=!0,e.search_field.focus(),e.search_field.val(e.search_field.val()),e.container.addClass("chosen-with-drop"),e.winnow_results(1);var i=e.drop_direction;if("function"==typeof i&&(i=i.call(this)),"auto"===i)if(e.drop_directionFixed)i=e.drop_directionFixed;else{var n=e.container.find(".chosen-drop"),o=n.outerHeight();e.drop_item_height&&o.active-result").length*e.drop_item_height));var a=e.container.offset();a.top+o+30>t(window).height()+t(window).scrollTop()&&(i="up"),e.drop_directionFixed=i}return e.container.toggleClass("chosen-up","up"===i),e.autoResizeDrop(),e.form_field_jq.trigger("chosen:showing_dropdown",{chosen:e})},i.prototype.autoResizeDrop=function(){var e=this,i=e.max_drop_width;if(i){var n=e.container.find(".chosen-drop");n.removeClass("in");var o=0,a=n.find(".chosen-results"),s=a.children("li"),r=parseFloat(a.css("padding-left").replace("px","")),l=parseFloat(a.css("padding-right").replace("px","")),c=(isNaN(r)?0:r)+(isNaN(l)?0:l);s.each(function(){o=Math.max(o,t(this).outerWidth())}),n.css("width",Math.min(o+c+20,i)),e.fixDropWidthTimer=setTimeout(function(){e.fixDropWidthTimer=null,n.addClass("in"),e.winnow_results_set_highlight(1)},50)}},i.prototype.update_results_content=function(t){return this.search_results.html(t)},i.prototype.results_hide=function(){var t=this;return t.fixDropWidthTimer&&(clearTimeout(t.fixDropWidthTimer),t.fixDropWidthTimer=null),t.results_showing&&(t.result_clear_highlight(),t.container.removeClass("chosen-with-drop"),t.form_field_jq.trigger("chosen:hiding_dropdown",{chosen:t}),t.drop_directionFixed=0),t.results_showing=!1},i.prototype.set_tab_index=function(t){var e;if(this.form_field.tabIndex)return e=this.form_field.tabIndex,this.form_field.tabIndex=-1,this.search_field[0].tabIndex=e},i.prototype.set_label_behavior=function(){var e=this;if(this.form_field_label=this.form_field_jq.parents("label"),!this.form_field_label.length&&this.form_field.id.length&&(this.form_field_label=t("label[for='"+this.form_field.id+"']")),this.form_field_label.length>0)return this.form_field_label.bind("click.chosen",function(t){return e.is_multiple?e.container_mousedown(t):e.activate_field()})},i.prototype.show_search_field_default=function(){return this.is_multiple&&this.choices_count()<1&&!this.active_field?(this.search_field.val(this.default_text),this.search_field.addClass("default")):(this.search_field.val(""),this.search_field.removeClass("default"))},i.prototype.search_results_mouseup=function(e){var i;if(i=t(e.target).hasClass("active-result")?t(e.target):t(e.target).parents(".active-result").first(),i.length)return this.result_highlight=i,this.result_select(e),this.search_field.focus()},i.prototype.search_results_mouseover=function(e){var i;if(i=t(e.target).hasClass("active-result")?t(e.target):t(e.target).parents(".active-result").first())return this.result_do_highlight(i)},i.prototype.search_results_mouseout=function(e){if(t(e.target).hasClass("active-result"))return this.result_clear_highlight()},i.prototype.choice_build=function(e){var i,n,o=this;return i=t("",{"class":"search-choice"}).html(""+e.html+""),e.disabled?i.addClass("search-choice-disabled"):(n=t("",{"class":"search-choice-close","data-option-array-index":e.array_index}),n.bind("click.chosen",function(t){return o.choice_destroy_link_click(t)}),i.append(n)),this.search_container.before(i)},i.prototype.choice_destroy_link_click=function(e){if(e.preventDefault(),e.stopPropagation(),!this.is_disabled)return this.choice_destroy(t(e.target))},i.prototype.choice_destroy=function(t){if(this.result_deselect(t[0].getAttribute("data-option-array-index")))return this.show_search_field_default(),this.is_multiple&&this.choices_count()>0&&this.search_field.val().length<1&&this.results_hide(),t.parents("li").first().remove(),this.search_field_scale()},i.prototype.results_reset=function(){var t=this.form_field_jq.val();this.reset_single_select_options(),this.form_field.options[0].selected=!0,this.single_set_selected_text(),this.show_search_field_default(),this.results_reset_cleanup();var e=this.form_field_jq.val(),i={selected:e};if(t===e||e.length||(i.deselected=t),this.form_field_jq.trigger("change",i),this.sync_sort_field(),this.active_field)return this.results_hide()},i.prototype.results_reset_cleanup=function(){return this.current_selectedIndex=this.form_field.selectedIndex,this.selected_item.find("abbr").remove()},i.prototype.result_select=function(t){var e,i;if(this.result_highlight)return e=this.result_highlight,this.result_clear_highlight(),this.is_multiple&&this.max_selected_options<=this.choices_count()?(this.form_field_jq.trigger("chosen:maxselected",{chosen:this}),!1):(this.is_multiple?e.removeClass("active-result"):this.reset_single_select_options(),i=this.results_data[e[0].getAttribute("data-option-array-index")],i.selected=!0,this.form_field.options[i.options_index].selected=!0,this.selected_option_count=null,this.is_multiple?this.choice_build(i):this.single_set_selected_text(i.text),(t.metaKey||t.ctrlKey)&&this.is_multiple||this.results_hide(),this.search_field.val(""),(this.is_multiple||this.form_field.selectedIndex!==this.current_selectedIndex)&&(this.form_field_jq.trigger("change",{selected:this.form_field.options[i.options_index].value}),this.sync_sort_field()),this.current_selectedIndex=this.form_field.selectedIndex,this.search_field_scale())},i.prototype.single_set_selected_text=function(t){return null==t&&(t=this.default_text),t===this.default_text?this.selected_item.addClass("chosen-default"):(this.single_deselect_control_build(),this.selected_item.removeClass("chosen-default")),this.compact_search&&this.search_field.attr("placeholder",t),this.selected_item.find("span").attr("title",t).text(t)},i.prototype.sync_sort_field=function(){var e=this;if(e.is_multiple&&e.sort_field){var i=t(e.sort_field);if(!i.length)return;var n=[];e.search_choices.find("li.search-choice").each(function(){var i=t(this),o=i.children(".search-choice-close").first().data("optionArrayIndex"),a=e.results_data[o];a&&a.selected&&n.push(a.value)}),i.val(n.join(e.sort_value_splitter)).trigger("change")}},i.prototype.result_deselect=function(t){var e;return e=this.results_data[t],!this.form_field.options[e.options_index].disabled&&(e.selected=!1,this.form_field.options[e.options_index].selected=!1,this.selected_option_count=null,this.result_clear_highlight(),this.results_showing&&this.winnow_results(),this.form_field_jq.trigger("change",{deselected:this.form_field.options[e.options_index].value}),this.sync_sort_field(),this.search_field_scale(),!0)},i.prototype.single_deselect_control_build=function(){if(this.allow_single_deselect)return this.selected_item.find("abbr").length||this.selected_item.find("span").first().after(''),this.selected_item.addClass("chosen-single-with-deselect")},i.prototype.get_search_text=function(){return this.search_field.val()===this.default_text?"":t("").text(t.trim(this.search_field.val())).html()},i.prototype.winnow_results_set_highlight=function(t){var e,i;if(i=this.is_multiple?[]:this.search_results.find(".result-selected.active-result"),e=i.length?i.first():this.search_results.find(".active-result").first(),null!=e)return this.result_do_highlight(e,t)},i.prototype.no_results=function(e){var i;return i=t('- '+this.results_none_found+' ""
'),i.find("span").first().html(e),this.search_results.append(i),this.form_field_jq.trigger("chosen:no_results",{chosen:this})},i.prototype.no_results_clear=function(){return this.search_results.find(".no-results").remove()},i.prototype.keydown_arrow=function(){var t;return this.results_showing&&this.result_highlight?(t=this.result_highlight.nextAll("li.active-result").first())?this.result_do_highlight(t):void 0:this.results_show()},i.prototype.keyup_arrow=function(){var t;return this.results_showing||this.is_multiple?this.result_highlight?(t=this.result_highlight.prevAll("li.active-result"),t.length?this.result_do_highlight(t.first()):(this.choices_count()>0&&this.results_hide(),this.result_clear_highlight())):void 0:this.results_show()},i.prototype.keydown_backstroke=function(){var t;return this.pending_backstroke?(this.choice_destroy(this.pending_backstroke.find("a").first()),this.clear_backstroke()):(t=this.search_container.siblings("li.search-choice").last(),t.length&&!t.hasClass("search-choice-disabled")?(this.pending_backstroke=t,this.single_backstroke_delete?this.keydown_backstroke():this.pending_backstroke.addClass("search-choice-focus")):void 0)},i.prototype.clear_backstroke=function(){return this.pending_backstroke&&this.pending_backstroke.removeClass("search-choice-focus"),this.pending_backstroke=null},i.prototype.keydown_checker=function(t){var e,i;switch(e=null!=(i=t.which)?i:t.keyCode,this.search_field_scale(),8!==e&&this.pending_backstroke&&this.clear_backstroke(),e){case 8:this.backstroke_length=this.search_field.val().length;break;case 9:this.results_showing&&!this.is_multiple&&this.result_select(t),this.mouse_on_container=!1;break;case 13:t.preventDefault();break;case 38:t.preventDefault(),this.keyup_arrow();break;case 40:t.preventDefault(),this.keydown_arrow()}},i.prototype.search_field_scale=function(){var e,i,n,o,a,s,r,l,c;if(this.is_multiple){for(n=0,r=0,a="position:absolute; left: -1000px; top: -1000px; display:none;",s=["font-size","font-style","font-weight","font-family","line-height","text-transform","letter-spacing"],l=0,c=s.length;l",{style:a}),e.text(this.search_field.val()),t("body").append(e),r=e.width()+25,e.remove(),i=this.container.outerWidth(),r>i-10&&(r=i-10),this.search_field.css({width:r+"px"})}},i}(e),i.DEFAULTS=l,i.LANGUAGES=r,t.fn.chosen.Constructor=i}.call(this),function(t){"use strict";var e="zui.selectable",i=function(i,n){this.name=e,this.$=t(i),this.id=t.zui.uuid(),this.selectOrder=1,this.selections={},this.getOptions(n),this._init()},n=function(t,e,i){return t>=i.left&&t<=i.left+i.width&&e>=i.top&&e<=i.top+i.height},o=function(t,e){var i=Math.max(t.left,e.left),o=Math.max(t.top,e.top),a=Math.min(t.left+t.width,e.left+e.width),s=Math.min(t.top+t.height,e.top+e.height);return n(i,o,t)&&n(a,s,t)&&n(i,o,e)&&n(a,s,e)};i.DEFAULTS={selector:"li,tr,div",trigger:"",selectClass:"active",rangeStyle:{border:"1px solid "+(t.zui.colorset?t.zui.colorset.primary:"#3280fc"),backgroundColor:t.zui.colorset?new t.zui.Color(t.zui.colorset.primary).fade(20).toCssStr():"rgba(50, 128, 252, 0.2)"},clickBehavior:"toggle",ignoreVal:3,listenClick:!0},i.prototype.getOptions=function(e){this.options=t.extend({},i.DEFAULTS,this.$.data(),e)},i.prototype.select=function(t){this.toggle(t,!0)},i.prototype.unselect=function(t){this.toggle(t,!1)},i.prototype.toggle=function(e,i,n){var o,a,s=this.options.selector,r=this;if(void 0===e)return void this.$.find(s).each(function(){r.toggle(this,i)});if("object"==typeof e?(o=t(e).closest(s),a=o.data("id")):(a=e,o=r.$.find('.selectable-item[data-id="'+a+'"]')),o&&o.length){if(a||(a=t.zui.uuid(),o.attr("data-id",a)),void 0!==i&&null!==i||(i=!r.selections[a]),!!i!=!!r.selections[a]){var l;"function"==typeof n&&(l=n(i)),l!==!0&&(r.selections[a]=!!i&&r.selectOrder++,r.callEvent(i?"select":"unselect",{id:a,selections:r.selections,target:o,
-selected:r.getSelectedArray()},r))}r.options.selectClass&&o.toggleClass(r.options.selectClass,i)}},i.prototype.getSelectedArray=function(){var e=[];return t.each(this.selections,function(t,i){i&&e.push(t)}),e},i.prototype.syncSelectionsFromClass=function(){var e=this,i=e.$children=e.$.find(e.options.selector);e.selections={},i.each(function(){var i=t(this);e.selections[i.data("id")]=i.hasClass(e.options.selectClass)})},i.prototype._init=function(){var e,i,n,a,s,r,l,c=this.options,h=this,d=c.ignoreVal,u=!0,p="."+this.name+"."+this.id,f="function"==typeof c.checkFunc?c.checkFunc:null,g="function"==typeof c.rangeFunc?c.rangeFunc:null,m=!1,v=null,y="mousedown"+p,b=function(){a&&h.$children.each(function(){var e=t(this),i=e.offset();i.width=e.outerWidth(),i.height=e.outerHeight();var n=g?g.call(this,a,i):o(a,i);if(f){var s=f.call(h,{intersect:n,target:e,range:a,targetRange:i});s===!0?h.select(e):s===!1&&h.unselect(e)}else n?h.select(e):h.multiKey||h.unselect(e)})},w=function(o){m&&(s=o.pageX,r=o.pageY,a={width:Math.abs(s-e),height:Math.abs(r-i),left:s>e?e:s,top:r>i?i:r},u&&a.width
').css(t.extend({zIndex:1060,position:"absolute",top:e,left:i,pointerEvents:"none"},h.options.rangeStyle)).appendTo(t("body")))),n.css(a),clearTimeout(l),l=setTimeout(b,10),u=!1))},x=function(e){t(document).off(p),clearTimeout(v),m&&(m=!1,n&&n.remove(),u||a&&(clearTimeout(l),b(),a=null),h.callEvent("finish",{selections:h.selections,selected:h.getSelectedArray()}),e.preventDefault())},C=function(o){if(m)return x(o);var a=t.zui.getMouseButtonCode(c.mouseButton);if(!(a>-1&&o.button!==a||t(o.target).closest("input,select,textarea,label").length||h.altKey||3===o.which||h.callEvent("start",o)===!1)){var s=h.$children=h.$.find(c.selector);s.addClass("selectable-item");var r=h.multiKey?"multi":c.clickBehavior;if("single"===r&&h.unselect(),c.listenClick&&("multi"===r?h.toggle(o.target):"single"===r?h.select(o.target):"toggle"===r&&h.toggle(o.target,null,function(t){h.unselect()})),h.callEvent("startDrag",o)===!1)return void h.callEvent("finish",{selections:h.selections,selected:h.getSelectedArray()});e=o.pageX,i=o.pageY,n=null,u=!0,m=!0,t(document).on("mousemove"+p,w).on("mouseup"+p,x),v=setTimeout(function(){t(document).on(y,x)},10),o.preventDefault()}},_=c.container&&"default"!==c.container?t(c.container):this.$;c.trigger?_.on(y,c.trigger,C):_.on(y,C),t(document).on("keydown",function(t){var e=t.keyCode;17===e||91==e?h.multiKey=e:18===e&&(h.altKey=!0)}).on("keyup",function(t){h.multiKey=!1,h.altKey=!1})},i.prototype.callEvent=function(e,i){var n=t.Event(e+"."+this.name);this.$.trigger(n,i);var o=n.result,a=this.options[e];return"function"==typeof a&&(o=a.apply(this,Array.isArray(i)?i:[i])),o},t.fn.selectable=function(n){return this.each(function(){var o=t(this),a=o.data(e),s="object"==typeof n&&n;a||o.data(e,a=new i(this,s)),"string"==typeof n&&a[n]()})},t.fn.selectable.Constructor=i,t(function(){t('[data-ride="selectable"]').selectable()})}(jQuery),+function(t,e,i){"use strict";if(!t.fn.droppable)return void console.error("Sortable requires droppable.js");var n="zui.sortable",o={selector:"li,div",dragCssClass:"invisible",sortingClass:"sortable-sorting"},a="order",s=function(e,i){var n=this;n.$=t(e),n.options=t.extend({},o,n.$.data(),i),n.init()};s.DEFAULTS=o,s.NAME=n,s.prototype.init=function(){var e,i=this,n=i.$,o=i.options,s=o.selector,r=o.containerSelector,l=o.sortingClass,c=o.dragCssClass,h=o.targetSelector,d=o.reverse,u=o.moveDirection,p=function(e){e=e||i.getItems(1);var n=e.length;n&&e.each(function(e){var i=d?n-e:e;t(this).attr("data-"+a,i).data(a,i)})};h||p(),n.droppable({handle:o.trigger,target:h?h:r?s+","+r:s,selector:s,container:o.container||n,always:o.always,flex:!0,lazy:o.lazy,canMoveHere:o.canMoveHere,dropToClass:o.dropToClass,before:o.before,nested:!!r,mouseButton:o.mouseButton,noShadow:o.noShadow,stopPropagation:o.stopPropagation,start:function(t){if(c&&t.element.addClass(c),e=!1,i.$element=t.element,!u&&t.targets.length>1){var n=t.targets.eq(0).offset(),o=t.targets.eq(1).offset();u=Math.abs(n.left-o.left)>Math.abs(n.top-o.top)?"h":"v"}p(),i.trigger("start",t)},drag:function(t){if(n.addClass(l),t.isIn){var o=t.element,c=t.target,h=r&&c.is(r);if(h)return void(c.children(s).filter(".dragging").length||(c.append(o),p(b),i.trigger(a,{list:b,element:o})));var f=o.data(a),g=c.data(a);if(f===g)return;var m="h"===u?"left":"top",v=t.mouseOffset[m]-t.lastMouseOffset[m];if(0===v)return;var y=f>g?d:!d;if(v<0&&y||v>0&&!y)return;c[y?"after":"before"](o),e=!0;var b=i.getItems(1);p(b),i.trigger(a,{list:b,element:o})}},finish:function(t){c&&t.element&&t.element.removeClass(c),n.removeClass(l),i.trigger("finish",{list:i.getItems(),element:t.element,changed:e}),i.$element=null}})},s.prototype.destroy=function(){this.$.droppable("destroy"),this.$.data(n,null)},s.prototype.reset=function(){this.destroy(),this.init()},s.prototype.getItems=function(e){var i,n=this,o=n.options.targetSelector;return i=o?"function"==typeof o?o(n.$element,n.$):n.$.find(o):n.$.find(n.options.selector),i=i.not(".drag-shadow"),e?i:i.map(function(){var e=t(this);return{item:e,order:e.data("order")}})},s.prototype.trigger=function(e,i){return t.zui.callEvent(this.options[e],i,this)},t.fn.sortable=function(e){return this.each(function(){var i=t(this),o=i.data(n),a="object"==typeof e&&e;o?"object"==typeof e&&o.reset():i.data(n,o=new s(this,a)),"string"==typeof e&&o[e]()})},t.fn.sortable.Constructor=s}(jQuery,window,document),function(t,e){"use strict";function i(e,i){if("string"==typeof e&&(e="seperator"===e||"divider"===e||"-"===e||"|"===e?{type:"seperator"}:{label:e,id:i}),"seperator"===e.type||"divider"===e.type)return t('
');var n=t("
").attr(t.extend({href:e.url||"###","class":e.className,style:e.style},e.attrs)).data("item",e);e.html?e.html===!0?n.html(e.label||e.text):n=t(e.html):n.text(e.label||e.text),e.icon&&n.prepend('
'),e.onClick&&n.on("click",e.onClick);var o=t("
").toggleClass("disabled",e.disabled===!0).append(n);return e.items&&o.data("item",e).addClass("dropdown-submenu"),o}function n(e,n,o){var a=o.itemCreator||i,s=typeof e;return"string"===s?e=e.split(","):"function"===s&&(e=e(o)),!!e&&(t.each(e,function(t,e){n.append(a(e,t,o))}),!0)}var o="zui.contextmenu",a={animation:"fade",menuTemplate:'',toggleTrigger:!1,duration:200},s=!1,r={},l="zui-contextmenu-"+t.zui.uuid(),c=0,h=0,d=function(){return t(document).off("mousemove."+o).on("mousemove."+o,function(t){c=t.clientX,h=t.clientY}),r},u=function(e){var i=t("#"+l);return i.length&&i.hasClass("contextmenu-show")&&(!e||(i.data("options")||{}).id===e)},p=null,f=function(e,i){"function"==typeof e&&(i=e,e=null),p&&(clearTimeout(p),p=null);var n=t("#"+l);if(n.length){var o=n.removeClass("contextmenu-show").data("options");if(!e||o.id===e){var a=function(){n.find(".contextmenu-menu").removeClass("open"),o.onHidden&&o.onHidden(),i&&i()};o.onHide&&o.onHide();var s=o.animation;n.find(".contextmenu-menu").removeClass("in"),s?p=setTimeout(a,o.duration):a()}}return r},g=function(i,d,u){t.isPlainObject(i)&&(u=d,d=i,i=d.items),s=!0,d=t.extend({},a,d);var g=t("#"+l);g.length||(g=t('').appendTo("body"));var m=g.find(".contextmenu-menu").empty();m.off("click."+o).on("click."+o,"a,.contextmenu-item",function(e){var i=t(this),n=d.onClickItem&&d.onClickItem(i.data("item"),i,e,d);n!==!1&&f()}).off("mouseenter."+o).on("mouseenter."+o,".dropdown-submenu",function(e){var i=t(this),o=i.data("item"),a=i.children(".dropdown-menu");if(o&&(o.items&&(a.length||(a=t(d.menuTemplate).appendTo(i)),n(o.items,a,d)),i.removeData("item")),a.length){a.removeClass("pull-left").css("top",0);var s=(i[0].getBoundingClientRect(),a[0].getBoundingClientRect()),r=window.innerWidth,l=window.innerHeight;if(s.bottom>l){var c=Math.max(-s.top,l-s.bottom);a.css("top",c)}s.right>r&&a.addClass("pull-left")}}),m.attr("class","contextmenu-menu"+(d.className?" "+d.className:"")),g.attr("class","contextmenu contextmenu-show");var v=d.menuCreator;if(v)m.append(v(i,d));else{m.append(d.menuTemplate);var y=m.children().first(),b=n(i,y,d);if(b===!1)return b}var w=d.animation,x=d.duration;w===!0&&(d.animation=w="fade"),p&&(clearTimeout(p),p=null);var C=function(){m.addClass("in"),d.onShown&&d.onShown(),u&&u()};d.onShow&&d.onShow(),g.data("options",{animation:w,onHide:d.onHide,onHidden:d.onHidden,id:d.id,duration:x});var _=d.x,k=d.y;_===e&&(_=(d.event||d).clientX),_===e&&(_=c),k===e&&(k=(d.event||d).clientY),k===e&&(k=h);var T=window.innerHeight,S=window.innerWidth,y=m.children().first(),D=y.outerWidth(),M=y.outerHeight();if(d.position){var L=d.position({x:_,y:k,width:D,height:M,winHeight:T,winWidth:S},d,m);L&&(_=L.x,k=L.y)}return _=Math.max(0,Math.min(_,S-D)),k=Math.max(0,Math.min(k,T-M)),g.css({left:_,top:k}).show(),m.addClass("open"),w?(m.addClass(w),p=setTimeout(function(){C(),s=!1},10)):(C(),s=!1),r};t.extend(r,{NAME:o,DEFAULTS:a,show:g,hide:f,listenMouse:d,isShow:u}),t.zui({ContextMenu:r});var m=function(e,i){var n=this;n.name=o,n.$=t(e),n.id=t.zui.uuid(),i=n.options=t.extend({trigger:"contextmenu"},r.DEFAULTS,this.$.data(),i);var a=function(t){if("mousedown"!==t.type||2===t.button){if(i.toggleTrigger&&n.isShow())n.hide();else{var e={x:t.clientX,y:t.clientY,event:t};if(n.show(e)===!1)return}return t.preventDefault(),t.returnValue=!1,!1}},s=i.trigger,l=s+"."+o;i.selector?n.$.on(l,i.selector,a):n.$.on(l,a),i.show&&n.show("object"==typeof i.show?i.show:null)};m.prototype.destory=function(){that.$.off("."+o)},m.prototype.hide=function(t){return r.hide(this.id,t)},m.prototype.show=function(e,i){return e=t.extend({id:this.id,$toggle:this.$},this.options,e),r.show(e,i)},m.prototype.isShow=function(){return u(this.id)},t.fn.contextmenu=function(e){return this.each(function(){var i=t(this),n=i.data(o),a="object"==typeof e&&e;n||i.data(o,n=new m(this,a)),"string"==typeof e&&n[e]()})},t.fn.contextmenu.Constructor=m,t.fn.contextDropdown=function(e){t(this).contextmenu(t.extend({trigger:"click",animation:"fade",toggleTrigger:!0,menuCreator:function(e,i){var n=i.$toggle,o=n.attr("data-target");o||(o=n.attr("href"),o=o&&/#/.test(o)&&o.replace(/.*(?=#[^\s]*$)/,""));var a=o?t(o):n.next(".dropdown-menu"),s=i.transferEvent;if(s!==!1){var r="data-contextmenu-index";a.find("a,.contextmenu-item").each(function(e){t(this).attr(r,e)});var l=a.clone();return l.on("string"==typeof s?s:"click","a,.contextmenu-item",function(e){var i=a.find("["+r+'="'+t(this).attr(r)+'"]'),n=i[0];if(n)return n[e.type]?n[e.type]():i.trigger(e.type),e.preventDefault(),e.stopPropagation(),!1}),l}return a.clone()},position:function(t,e,i){var n=e.placement,o=e.$toggle;if(!n){var a=i.find(".dropdown-menu"),s=a.hasClass("pull-right"),r=o.parent().hasClass("dropup");n=s?r?"top-right":"bottom-right":r?"top-left":"bottom-left",s&&a.removeClass("pull-right")}var l=o[0].getBoundingClientRect();switch(n){case"top-left":return{x:l.left,y:Math.floor(l.top-t.height)};case"top-right":return{x:Math.floor(l.right-t.width),y:Math.floor(l.top-t.height)};case"bottom-left":return{x:l.left,y:l.bottom};case"bottom-right":return{x:Math.floor(l.right-t.width),y:l.bottom}}return t}},e))},t(document).on("click",function(e){var i=t(e.target),n=i.closest('[data-toggle="context-dropdown"]');if(n.length){var a=n.data(o);a||n.contextDropdown({show:!0})}else s||i.closest(".contextmenu").length||f()})}(jQuery,void 0),/*!
+selected:r.getSelectedArray()},r))}r.options.selectClass&&o.toggleClass(r.options.selectClass,i)}},i.prototype.getSelectedArray=function(){var e=[];return t.each(this.selections,function(t,i){i&&e.push(t)}),e},i.prototype.syncSelectionsFromClass=function(){var e=this,i=e.$children=e.$.find(e.options.selector);e.selections={},i.each(function(){var i=t(this);e.selections[i.data("id")]=i.hasClass(e.options.selectClass)})},i.prototype._init=function(){var e,i,n,a,s,r,l,c=this.options,h=this,d=c.ignoreVal,u=!0,p="."+this.name+"."+this.id,f="function"==typeof c.checkFunc?c.checkFunc:null,g="function"==typeof c.rangeFunc?c.rangeFunc:null,m=!1,v=null,y="mousedown"+p,b=function(){a&&h.$children.each(function(){var e=t(this),i=e.offset();i.width=e.outerWidth(),i.height=e.outerHeight();var n=g?g.call(this,a,i):o(a,i);if(f){var s=f.call(h,{intersect:n,target:e,range:a,targetRange:i});s===!0?h.select(e):s===!1&&h.unselect(e)}else n?h.select(e):h.multiKey||h.unselect(e)})},w=function(o){m&&(s=o.pageX,r=o.pageY,a={width:Math.abs(s-e),height:Math.abs(r-i),left:s>e?e:s,top:r>i?i:r},u&&a.width
').css(t.extend({zIndex:1060,position:"absolute",top:e,left:i,pointerEvents:"none"},h.options.rangeStyle)).appendTo(t("body")))),n.css(a),clearTimeout(l),l=setTimeout(b,10),u=!1))},x=function(e){t(document).off(p),clearTimeout(v),m&&(m=!1,n&&n.remove(),u||a&&(clearTimeout(l),b(),a=null),h.callEvent("finish",{selections:h.selections,selected:h.getSelectedArray()}),e.preventDefault())},C=function(o){if(m)return x(o);var a=t.zui.getMouseButtonCode(c.mouseButton);if(!(a>-1&&o.button!==a||t(o.target).closest("input,select,textarea,label").length||h.altKey||3===o.which||h.callEvent("start",o)===!1)){var s=h.$children=h.$.find(c.selector);s.addClass("selectable-item");var r=h.multiKey?"multi":c.clickBehavior;if("single"===r&&h.unselect(),c.listenClick&&("multi"===r?h.toggle(o.target):"single"===r?h.select(o.target):"toggle"===r&&h.toggle(o.target,null,function(t){h.unselect()})),h.callEvent("startDrag",o)===!1)return void h.callEvent("finish",{selections:h.selections,selected:h.getSelectedArray()});e=o.pageX,i=o.pageY,n=null,u=!0,m=!0,t(document).on("mousemove"+p,w).on("mouseup"+p,x),v=setTimeout(function(){t(document).on(y,x)},10),o.preventDefault()}},_=c.container&&"default"!==c.container?t(c.container):this.$;c.trigger?_.on(y,c.trigger,C):_.on(y,C),t(document).on("keydown",function(t){var e=t.keyCode;17===e||91==e?h.multiKey=e:18===e&&(h.altKey=!0)}).on("keyup",function(t){h.multiKey=!1,h.altKey=!1})},i.prototype.callEvent=function(e,i){var n=t.Event(e+"."+this.name);this.$.trigger(n,i);var o=n.result,a=this.options[e];return"function"==typeof a&&(o=a.apply(this,Array.isArray(i)?i:[i])),o},t.fn.selectable=function(n){return this.each(function(){var o=t(this),a=o.data(e),s="object"==typeof n&&n;a||o.data(e,a=new i(this,s)),"string"==typeof n&&a[n]()})},t.fn.selectable.Constructor=i,t(function(){t('[data-ride="selectable"]').selectable()})}(jQuery),+function(t,e,i){"use strict";if(!t.fn.droppable)return void console.error("Sortable requires droppable.js");var n="zui.sortable",o={selector:"li,div",dragCssClass:"invisible",sortingClass:"sortable-sorting"},a="order",s=function(e,i){var n=this;n.$=t(e),n.options=t.extend({},o,n.$.data(),i),n.init()};s.DEFAULTS=o,s.NAME=n,s.prototype.init=function(){var e,i=this,n=i.$,o=i.options,s=o.selector,r=o.containerSelector,l=o.sortingClass,c=o.dragCssClass,h=o.targetSelector,d=o.reverse,u=o.moveDirection,p=function(e){e=e||i.getItems(1);var n=e.length;n&&e.each(function(e){var i=d?n-e:e;t(this).attr("data-"+a,i).data(a,i)})};h||p(),n.droppable({handle:o.trigger,target:h?h:r?s+","+r:s,selector:s,container:o.container||n,always:o.always,flex:!0,lazy:o.lazy,canMoveHere:o.canMoveHere,dropToClass:o.dropToClass,before:o.before,nested:!!r,mouseButton:o.mouseButton,noShadow:o.noShadow,dropOnMouseleave:o.dropOnMouseleave,stopPropagation:o.stopPropagation,start:function(t){if(c&&t.element.addClass(c),e=!1,i.$element=t.element,!u&&t.targets.length>1){var n=t.targets.eq(0).offset(),o=t.targets.eq(1).offset();u=Math.abs(n.left-o.left)>Math.abs(n.top-o.top)?"h":"v"}p(),i.trigger("start",t)},drag:function(t){if(n.addClass(l),t.isIn){var o=t.element,c=t.target,h=r&&c.is(r);if(h)return void(c.children(s).filter(".dragging").length||(c.append(o),p(b),i.trigger(a,{list:b,element:o})));var f=o.data(a),g=c.data(a);if(f===g)return;var m="h"===u?"left":"top",v=t.mouseOffset[m]-t.lastMouseOffset[m];if(0===v)return;var y=f>g?d:!d;if(v<0&&y||v>0&&!y)return;c[y?"after":"before"](o),e=!0;var b=i.getItems(1);p(b),i.trigger(a,{list:b,element:o})}},finish:function(t){c&&t.element&&t.element.removeClass(c),n.removeClass(l),i.trigger("finish",{list:i.getItems(),element:t.element,changed:e}),i.$element=null}})},s.prototype.destroy=function(){this.$.droppable("destroy"),this.$.data(n,null)},s.prototype.reset=function(){this.destroy(),this.init()},s.prototype.getItems=function(e){var i,n=this,o=n.options.targetSelector;return i=o?"function"==typeof o?o(n.$element,n.$):n.$.find(o):n.$.find(n.options.selector),i=i.not(".drag-shadow"),e?i:i.map(function(){var e=t(this);return{item:e,order:e.data("order")}})},s.prototype.trigger=function(e,i){return t.zui.callEvent(this.options[e],i,this)},t.fn.sortable=function(e){return this.each(function(){var i=t(this),o=i.data(n),a="object"==typeof e&&e;o?"object"==typeof e&&o.reset():i.data(n,o=new s(this,a)),"string"==typeof e&&o[e]()})},t.fn.sortable.Constructor=s}(jQuery,window,document),function(t,e){"use strict";function i(e,i){if("string"==typeof e&&(e="seperator"===e||"divider"===e||"-"===e||"|"===e?{type:"seperator"}:{label:e,id:i}),"seperator"===e.type||"divider"===e.type)return t('
');var n=t("
").attr(t.extend({href:e.url||"###","class":e.className,style:e.style},e.attrs)).data("item",e);e.html?e.html===!0?n.html(e.label||e.text):n=t(e.html):n.text(e.label||e.text),e.icon&&n.prepend('
'),e.onClick&&n.on("click",e.onClick);var o=t("
").toggleClass("disabled",e.disabled===!0).append(n);return e.items&&o.data("item",e).addClass("dropdown-submenu"),o}function n(e,n,o){var a=o.itemCreator||i,s=typeof e;return"string"===s?e=e.split(","):"function"===s&&(e=e(o)),!!e&&(t.each(e,function(t,e){n.append(a(e,t,o))}),!0)}var o="zui.contextmenu",a={animation:"fade",menuTemplate:'',toggleTrigger:!1,duration:200},s=!1,r={},l="zui-contextmenu-"+t.zui.uuid(),c=0,h=0,d=function(){return t(document).off("mousemove."+o).on("mousemove."+o,function(t){c=t.clientX,h=t.clientY}),r},u=function(e){var i=t("#"+l);return i.length&&i.hasClass("contextmenu-show")&&(!e||(i.data("options")||{}).id===e)},p=null,f=function(e,i){"function"==typeof e&&(i=e,e=null),p&&(clearTimeout(p),p=null);var n=t("#"+l);if(n.length){var o=n.removeClass("contextmenu-show").data("options");if(!e||o.id===e){var a=function(){n.find(".contextmenu-menu").removeClass("open"),o.onHidden&&o.onHidden(),i&&i()};o.onHide&&o.onHide();var s=o.animation;n.find(".contextmenu-menu").removeClass("in"),s?p=setTimeout(a,o.duration):a()}}return r},g=function(i,d,u){t.isPlainObject(i)&&(u=d,d=i,i=d.items),s=!0,d=t.extend({},a,d);var g=t("#"+l);g.length||(g=t('').appendTo("body"));var m=g.find(".contextmenu-menu").empty();m.off("click."+o).on("click."+o,"a,.contextmenu-item",function(e){var i=t(this),n=d.onClickItem&&d.onClickItem(i.data("item"),i,e,d);n!==!1&&f()}).off("mouseenter."+o).on("mouseenter."+o,".dropdown-submenu",function(e){var i=t(this),o=i.data("item"),a=i.children(".dropdown-menu");if(o&&(o.items&&(a.length||(a=t(d.menuTemplate).appendTo(i)),n(o.items,a,d)),i.removeData("item")),a.length){a.removeClass("pull-left").css("top",0);var s=(i[0].getBoundingClientRect(),a[0].getBoundingClientRect()),r=window.innerWidth,l=window.innerHeight;if(s.bottom>l){var c=Math.max(-s.top,l-s.bottom);a.css("top",c)}s.right>r&&a.addClass("pull-left")}}),m.attr("class","contextmenu-menu"+(d.className?" "+d.className:"")),g.attr("class","contextmenu contextmenu-show");var v=d.menuCreator;if(v)m.append(v(i,d));else{m.append(d.menuTemplate);var y=m.children().first(),b=n(i,y,d);if(b===!1)return b}var w=d.animation,x=d.duration;w===!0&&(d.animation=w="fade"),p&&(clearTimeout(p),p=null);var C=function(){m.addClass("in"),d.onShown&&d.onShown(),u&&u()};d.onShow&&d.onShow(),g.data("options",{animation:w,onHide:d.onHide,onHidden:d.onHidden,id:d.id,duration:x});var _=d.x,k=d.y;_===e&&(_=(d.event||d).clientX),_===e&&(_=c),k===e&&(k=(d.event||d).clientY),k===e&&(k=h);var T=window.innerHeight,S=window.innerWidth,y=m.children().first(),D=y.outerWidth(),M=y.outerHeight();if(d.position){var L=d.position({x:_,y:k,width:D,height:M,winHeight:T,winWidth:S},d,m);L&&(_=L.x,k=L.y)}return _=Math.max(0,Math.min(_,S-D)),k=Math.max(0,Math.min(k,T-M)),g.css({left:_,top:k}).show(),m.addClass("open"),w?(m.addClass(w),p=setTimeout(function(){C(),s=!1},10)):(C(),s=!1),r};t.extend(r,{NAME:o,DEFAULTS:a,show:g,hide:f,listenMouse:d,isShow:u}),t.zui({ContextMenu:r});var m=function(e,i){var n=this;n.name=o,n.$=t(e),n.id=t.zui.uuid(),i=n.options=t.extend({trigger:"contextmenu"},r.DEFAULTS,this.$.data(),i);var a=function(t){if("mousedown"!==t.type||2===t.button){if(i.toggleTrigger&&n.isShow())n.hide();else{var e={x:t.clientX,y:t.clientY,event:t};if(n.show(e)===!1)return}return t.preventDefault(),t.returnValue=!1,!1}},s=i.trigger,l=s+"."+o;i.selector?n.$.on(l,i.selector,a):n.$.on(l,a),i.show&&n.show("object"==typeof i.show?i.show:null)};m.prototype.destory=function(){that.$.off("."+o)},m.prototype.hide=function(t){return r.hide(this.id,t)},m.prototype.show=function(e,i){return e=t.extend({id:this.id,$toggle:this.$},this.options,e),r.show(e,i)},m.prototype.isShow=function(){return u(this.id)},t.fn.contextmenu=function(e){return this.each(function(){var i=t(this),n=i.data(o),a="object"==typeof e&&e;n||i.data(o,n=new m(this,a)),"string"==typeof e&&n[e]()})},t.fn.contextmenu.Constructor=m,t.fn.contextDropdown=function(e){t(this).contextmenu(t.extend({trigger:"click",animation:"fade",toggleTrigger:!0,menuCreator:function(e,i){var n=i.$toggle,o=n.attr("data-target");o||(o=n.attr("href"),o=o&&/#/.test(o)&&o.replace(/.*(?=#[^\s]*$)/,""));var a=o?t(o):n.next(".dropdown-menu"),s=i.transferEvent;if(s!==!1){var r="data-contextmenu-index";a.find("a,.contextmenu-item").each(function(e){t(this).attr(r,e)});var l=a.clone();return l.on("string"==typeof s?s:"click","a,.contextmenu-item",function(e){var i=a.find("["+r+'="'+t(this).attr(r)+'"]'),n=i[0];if(n)return n[e.type]?n[e.type]():i.trigger(e.type),e.preventDefault(),e.stopPropagation(),!1}),l}return a.clone()},position:function(t,e,i){var n=e.placement,o=e.$toggle;if(!n){var a=i.find(".dropdown-menu"),s=a.hasClass("pull-right"),r=o.parent().hasClass("dropup");n=s?r?"top-right":"bottom-right":r?"top-left":"bottom-left",s&&a.removeClass("pull-right")}var l=o[0].getBoundingClientRect();switch(n){case"top-left":return{x:l.left,y:Math.floor(l.top-t.height)};case"top-right":return{x:Math.floor(l.right-t.width),y:Math.floor(l.top-t.height)};case"bottom-left":return{x:l.left,y:l.bottom};case"bottom-right":return{x:Math.floor(l.right-t.width),y:l.bottom}}return t}},e))},t(document).on("click",function(e){var i=t(e.target),n=i.closest('[data-toggle="context-dropdown"]');if(n.length){var a=n.data(o);a||n.contextDropdown({show:!0})}else s||i.closest(".contextmenu").length||f()})}(jQuery,void 0),/*!
* jQuery Form Plugin
* version: 4.2.2
* Requires jQuery v1.7.2 or later