diff --git a/module/kanban/control.php b/module/kanban/control.php index 751a76400b..245182b0fb 100644 --- a/module/kanban/control.php +++ b/module/kanban/control.php @@ -14,7 +14,7 @@ class kanban extends control /** * Kanban space. * - * @param string $browseType all|my|other|closed + * @param string $browseType involved|cooperation|public|private * @param int $recTotal * @param int $recPerPage * @param int $pageID @@ -201,11 +201,16 @@ class kanban extends control * * @param int $spaceID * @param string $type + * @param int $copyKanbanID + * @param string $extra * @access public * @return void */ - public function create($spaceID = 0, $type = 'private') + public function create($spaceID = 0, $type = 'private', $copyKanbanID = 0, $extra = '') { + $extra = str_replace(array(',', ' '), array('&', ''), $extra); + parse_str($extra, $output); + if(!empty($_POST)) { $kanbanID = $this->kanban->create(); @@ -216,6 +221,15 @@ class kanban extends control return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => 'parent')); } + $enableImport = 'off'; + $importObjects = array(); + if($copyKanbanID) + { + $copyKanban = $this->kanban->getByID($copyKanbanID); + $enableImport = empty($copyKanban->object) ? 'off' : 'on'; + $importObjects = empty($copyKanban->object) ? array() : explode(',', $copyKanban->object); + } + unset($this->lang->kanbanspace->featureBar['involved']); $space = $this->kanban->getSpaceById($spaceID); @@ -223,12 +237,18 @@ class kanban extends control $users = $this->loadModel('user')->getPairs('noclosed|nodeleted', '', 0, $spaceUsers); $whitelist = (isset($space->whitelist) and !empty($space->whitelist)) ? $space->whitelist : ','; - $this->view->users = $users; - $this->view->whitelist = $this->user->getPairs('noclosed|nodeleted', '', 0, $whitelist); - $this->view->spaceID = $spaceID; - $this->view->spacePairs = array(0 => '') + $this->kanban->getSpacePairs($type); - $this->view->type = $type; - $this->view->typeList = $this->lang->kanbanspace->featureBar; + $this->view->users = $users; + $this->view->whitelist = $this->user->getPairs('noclosed|nodeleted', '', 0, $whitelist); + $this->view->spaceID = $spaceID; + $this->view->spacePairs = array(0 => '') + $this->kanban->getSpacePairs($type); + $this->view->type = $type; + $this->view->typeList = $this->lang->kanbanspace->featureBar; + $this->view->kanbans = array('' => '') + $this->kanban->getPairs(); + $this->view->copyKanbanID = $copyKanbanID; + $this->view->copyKanban = $copyKanbanID ? $copyKanban : ''; + $this->view->enableImport = $enableImport; + $this->view->importObjects = $importObjects; + $this->view->copyRegion = isset($output['copyRegion']) ? true : false; $this->display(); } @@ -386,19 +406,20 @@ class kanban extends control * * @param int $kanbanID * @param string $confirm + * @param string $browseType involved|cooperation|public|private * @access public * @return void */ - public function delete($kanbanID, $confirm = 'no') + public function delete($kanbanID, $confirm = 'no', $browseType = 'involved') { if($confirm == 'no') { - return print(js::confirm($this->lang->kanban->confirmDeleteKanban, $this->createLink('kanban', 'delete', "kanbanID=$kanbanID&confirm=yes"))); + return print(js::confirm($this->lang->kanban->confirmDeleteKanban, $this->createLink('kanban', 'delete', "kanbanID=$kanbanID&confirm=yes&browseType=$browseType"))); } else { $this->kanban->delete(TABLE_KANBAN, $kanbanID); - return print(js::locate($this->createLink('kanban', 'space'), 'parent')); + return print(js::locate($this->createLink('kanban', 'space', "browseType=$browseType"), 'parent')); } } @@ -1883,4 +1904,30 @@ class kanban extends control return print(html::select($field, $lanes, '', "class='form-control'")); } + + /** + * Ajax load space users. + * + * @param int $spaceID + * @param string $field team|whitelist|owner + * @param string $selectedUser + * @access public + * @return string + */ + public function ajaxLoadSpaceUsers($spaceID, $field = '', $selectedUser = '') + { + $space = $this->kanban->getSpaceById($spaceID); + $accounts = ''; + if(!empty($space)) + { + if($space->type == 'private' and !empty($space->whitelist)) $accounts = $space->whitelist; + if($space->type != 'private') $accounts = trim($space->owner) . ',' . trim($space->team); + } + + $users = $this->loadModel('user')->getPairs('noclosed|nodeleted', '', 0, $accounts); + $multiple = in_array($field, array('team', 'whitelist')) ? 'multiple' : ''; + $fieldName = $multiple ? $field . '[]' : $field; + + return print(html::select($fieldName, $users, $selectedUser, "class='form-control' $multiple")); + } } diff --git a/module/kanban/css/create.css b/module/kanban/css/create.css index c296d4229e..58e77c59aa 100644 --- a/module/kanban/css/create.css +++ b/module/kanban/css/create.css @@ -9,3 +9,16 @@ #mainContent .objectBox .checkbox-primary>label:after {width: 14px; height: 14px;} [lang^='en'] .columnWidth {width: 120px;} [lang^='zh-cn'] .columnWidth {width: 80px;} + +#copyKanbanModal {padding: 0;} +#copyKanbanModal {padding: 0 2px;} +#copyKanbanModal > div {position: relative;} +#copyKanbanModal a {display: block; min-height: 30px; line-height: 30px; padding: 5px 15px; border: 1px solid #e5e5e5; color: #333; margin: 5px 0; border-radius: 3px;} +#copyKanbanModal a > i {display: inline-block; margin-right: 5px;} +#copyKanbanModal a:hover {border: 1px solid #00a9fc; background-color: #E9F2FB; text-decoration: none;} +#copyKanbanModal a.active {border-color: #00da88; color: #00da88; background-color: #E5FFE6;} +#copyKanbanModal a.active:after {position: absolute; content: '\e92f'; font-family: ZentaoIcon; font-size: 20px; right: 25px;} +#copyKanbanModal a.cancel {color: #ff5d5d;} +#copyKanbanModal .copyContentBox {display: inline-block;} +#copyKanbanModal .copyContentBox > .checkbox-primary {display: inline-block; margin-left: 10px; margin-top: -1px;} +#copyKanbanModal .copyContentBox > .checkbox-primary:first-child {margin-left: 20px;} diff --git a/module/kanban/js/create.js b/module/kanban/js/create.js index 2f82c79d30..4c7fc63489 100644 --- a/module/kanban/js/create.js +++ b/module/kanban/js/create.js @@ -1,6 +1,14 @@ $(function() { if(enableImport == 'off') $("input[name^='importObjectList']").attr('disabled', 'disabled'); + $("input[id='copyContentbasicInfo']").click(function(){return false;}) + + copyRegion = $("input[id='copyContentregion']").prop('checked'); + $("input[id='copyContentregion']").click(function() + { + copyRegion = $(this).prop('checked'); + $('#copyRegion').val(copyRegion); + }); $("input[name='import']").change(function() { @@ -30,10 +38,28 @@ $(function() return false; } }) + + $(document).on('click', '#copyKanbans a', function() + { + setCopyKanban($(this).data('id')); $('#copyKanbanModal').modal('hide'); + }); }) /** - * When space type or space value change. + * Set copy kanban. + * + * @param int $kanbanID + * @access public + * @return void + */ +function setCopyKanban(kanbanID) +{ + var extra = copyRegion ? '&extra=copyRegion=' + copyRegion : ''; + location.href = createLink('kanban', 'create', 'spaceID=' + spaceID + '&type=' + spaceType + '©KanbanID=' + kanbanID + extra); +} + +/** + * When space type change. * * @oaram int spaceID * @param string type @@ -45,3 +71,44 @@ function changeValue(spaceID, type) if(typeof type === 'undefined') type = spaceType; location.href = createLink('kanban', 'create', 'spaceID=' + spaceID + '&type=' + type); } + +/** + * The team or whitelist member that loads kanban. + * + * @oaram int spaceID + * @access public + * @return void + */ +function loadUsers(spaceID) +{ + var field = spaceType == 'private' ? 'whitelist' : 'team'; + var link = createLink('kanban', 'ajaxLoadSpaceUsers', 'spaceID='+ spaceID + '&field=' + field + '&selectedUser=' + $('#' + field).val()); + $.get(link, function(data) + { + $('#' + field).replaceWith(data); + $('#' + field).next('.picker').remove(); + $('#' + field).picker(); + }); + + if(spaceType != 'private') loadOwners(spaceID); +} + +/** + * The owners that loads kanban. + * + * @oaram int spaceID + * @access public + * @return void + */ +function loadOwners(spaceID) +{ + var link = createLink('kanban', 'ajaxLoadSpaceUsers', 'spaceID='+ spaceID + '&field=owner&selectedUser=' + $('#owner').val()); + + $.get(link, function(data) + { + $('#owner').replaceWith(data); + $('#owner' + "_chosen").remove(); + $('#owner').next('.picker').remove(); + $('#owner').chosen(); + }); +} diff --git a/module/kanban/lang/de.php b/module/kanban/lang/de.php index fbad5f4970..5ed25ce96c 100644 --- a/module/kanban/lang/de.php +++ b/module/kanban/lang/de.php @@ -203,6 +203,10 @@ $lang->kanban->setting = 'Setting'; $lang->kanban->my = 'My'; $lang->kanban->other = 'Other'; $lang->kanban->showWIP = 'Show WIP'; +$lang->kanban->copyTitle = 'Please select a Kanban to copy'; +$lang->kanban->copyNoKanban = 'No Kanban available to copy'; +$lang->kanban->cancelCopy = 'Cancel Copying'; +$lang->kanban->copyContent = 'Copy Content'; $lang->kanban->error = new stdclass(); $lang->kanban->error->mustBeInt = 'The WIPs must be positive integer.'; @@ -269,6 +273,10 @@ $lang->kanban->taskColumn['pause'] = 'Pause'; $lang->kanban->taskColumn['canceled'] = 'Canceled'; $lang->kanban->taskColumn['closed'] = 'Closed'; +$lang->kanban->copyContentList = array(); +$lang->kanban->copyContentList['basicInfo'] = 'Basic Information'; +$lang->kanban->copyContentList['region'] = 'Columns and swimlanes'; + $lang->kanbanspace = new stdclass(); $lang->kanbanspace->common = 'Kanban Space'; $lang->kanbanspace->name = 'Name'; diff --git a/module/kanban/lang/en.php b/module/kanban/lang/en.php index a0428baed5..8547346371 100644 --- a/module/kanban/lang/en.php +++ b/module/kanban/lang/en.php @@ -203,6 +203,10 @@ $lang->kanban->setting = 'Setting'; $lang->kanban->my = 'My'; $lang->kanban->other = 'Other'; $lang->kanban->showWIP = 'Show WIP'; +$lang->kanban->copyTitle = 'Please select a Kanban to copy'; +$lang->kanban->copyNoKanban = 'No Kanban available to copy'; +$lang->kanban->cancelCopy = 'Cancel Copying'; +$lang->kanban->copyContent = 'Copy Content'; $lang->kanban->error = new stdclass(); $lang->kanban->error->mustBeInt = 'The WIPs must be positive integer.'; @@ -269,6 +273,10 @@ $lang->kanban->taskColumn['pause'] = 'Pause'; $lang->kanban->taskColumn['canceled'] = 'Canceled'; $lang->kanban->taskColumn['closed'] = 'Closed'; +$lang->kanban->copyContentList = array(); +$lang->kanban->copyContentList['basicInfo'] = 'Basic Information'; +$lang->kanban->copyContentList['region'] = 'Columns and swimlanes'; + $lang->kanbanspace = new stdclass(); $lang->kanbanspace->common = 'Kanban Space'; $lang->kanbanspace->name = 'Name'; diff --git a/module/kanban/lang/fr.php b/module/kanban/lang/fr.php index fbad5f4970..947b65fd2d 100644 --- a/module/kanban/lang/fr.php +++ b/module/kanban/lang/fr.php @@ -203,6 +203,10 @@ $lang->kanban->setting = 'Setting'; $lang->kanban->my = 'My'; $lang->kanban->other = 'Other'; $lang->kanban->showWIP = 'Show WIP'; +$lang->kanban->copyTitle = 'Veuillez sélectionner un Kanban àcopier'; +$lang->kanban->copyNoKanban = 'Aucun Kanban disponible àcopier'; +$lang->kanban->cancelCopy = 'Annuler Copie'; +$lang->kanban->copyContent = 'Copier Contenu'; $lang->kanban->error = new stdclass(); $lang->kanban->error->mustBeInt = 'The WIPs must be positive integer.'; @@ -269,6 +273,10 @@ $lang->kanban->taskColumn['pause'] = 'Pause'; $lang->kanban->taskColumn['canceled'] = 'Canceled'; $lang->kanban->taskColumn['closed'] = 'Closed'; +$lang->kanban->copyContentList = array(); +$lang->kanban->copyContentList['basicInfo'] = 'Informations de base'; +$lang->kanban->copyContentList['region'] = 'Colonnes et swimlanes'; + $lang->kanbanspace = new stdclass(); $lang->kanbanspace->common = 'Kanban Space'; $lang->kanbanspace->name = 'Name'; diff --git a/module/kanban/lang/zh-cn.php b/module/kanban/lang/zh-cn.php index 1b8dec9df7..91f2525eda 100644 --- a/module/kanban/lang/zh-cn.php +++ b/module/kanban/lang/zh-cn.php @@ -203,6 +203,10 @@ $lang->kanban->setting = '设置'; $lang->kanban->my = '我的看板'; $lang->kanban->other = '其他'; $lang->kanban->showWIP = '显示在制品限制'; +$lang->kanban->copyTitle = '请选择一个看板来复制'; +$lang->kanban->copyNoKanban = '没有可用的看板来复制'; +$lang->kanban->cancelCopy = '取消复制'; +$lang->kanban->copyContent = '复制内容'; $lang->kanban->error = new stdclass(); $lang->kanban->error->mustBeInt = '在制品数量必须是正整数。'; @@ -269,6 +273,10 @@ $lang->kanban->taskColumn['pause'] = '已暂停'; $lang->kanban->taskColumn['canceled'] = '已取消'; $lang->kanban->taskColumn['closed'] = '已关闭'; +$lang->kanban->copyContentList = array(); +$lang->kanban->copyContentList['basicInfo'] = '基本信息'; +$lang->kanban->copyContentList['region'] = '列和泳道'; + $lang->kanbanspace = new stdclass(); $lang->kanbanspace->common = '看板空间'; $lang->kanbanspace->name = '空间名称'; diff --git a/module/kanban/model.php b/module/kanban/model.php index 0ec764aa78..6d0b13951a 100644 --- a/module/kanban/model.php +++ b/module/kanban/model.php @@ -50,15 +50,44 @@ class kanbanModel extends model public function createDefaultRegion($kanban) { $region = new stdclass(); - $region->name = $this->lang->kanbanregion->default; - $region->kanban = $kanban->id; - $region->space = $kanban->space; - $region->createdBy = $this->app->user->account; - $region->createdDate = helper::today(); + $region->name = $this->lang->kanbanregion->default; + $region->kanban = $kanban->id; + $region->space = $kanban->space; + $region->createdBy = $this->app->user->account; + $region->createdDate = helper::now(); return $this->createRegion($kanban, $region); } + /** + * Copy kanban regions. + * + * @param object $kanban + * @param int $copyKanbanID + * @access public + * @return void + */ + public function copyRegions($kanban, $copyKanbanID) + { + if(empty($kanban) or empty($copyKanbanID)) return; + + $regions = $this->getRegionPairs($copyKanbanID); + $order = 1; + foreach($regions as $copyID => $copyName) + { + $region = new stdclass(); + $region->name = $copyName; + $region->kanban = $kanban->id; + $region->space = $kanban->space; + $region->createdBy = $this->app->user->account; + $region->createdDate = helper::now(); + $region->order = $order; + + $this->createRegion($kanban, $region, $copyID, 'kanban', 'withArchived'); + $order ++; + } + } + /** * Create a new region. * @@ -66,10 +95,11 @@ class kanbanModel extends model * @param object $region * @param int $copyRegionID * @param string $from kanban|execution + * @param string $param * @access public * @return int */ - public function createRegion($kanban, $region = null, $copyRegionID = 0, $from = 'kanban') + public function createRegion($kanban, $region = null, $copyRegionID = 0, $from = 'kanban', $param = '') { $account = $this->app->user->account; $order = 1; @@ -90,7 +120,7 @@ class kanbanModel extends model $region->space = $from == 'kanban' ? $kanban->space : 0; } - $region->order = $order; + $region->order = isset($region->order) ? $region->order : $order; $this->dao->insert(TABLE_KANBANREGION)->data($region) ->batchCheck($this->config->kanban->require->createregion, 'notempty') ->check('name', 'unique', "kanban = {$kanban->id} AND deleted = '0' AND space='$region->space'") @@ -107,7 +137,7 @@ class kanbanModel extends model /* Gets the groups, lanes and columns of the replication region. */ $copyGroups = $this->getGroupGroupByRegions($copyRegionID); $copyLaneGroup = $this->getLaneGroupByRegions($copyRegionID); - $copyColumnGroup = $this->getColumnGroupByRegions($copyRegionID, 'id_asc'); + $copyColumnGroup = $this->getColumnGroupByRegions($copyRegionID, 'id_asc', $param); /* Create groups, lanes, and columns. */ if(empty($copyGroups)) return $regionID; @@ -651,6 +681,21 @@ class kanbanModel extends model return $kanban; } + /** + * Get kanban pairs. + * + * @access public + * @return array + */ + public function getPairs() + { + $idList = $this->getCanViewObjects(); + return $this->dao->select('id,name')->from(TABLE_KANBAN) + ->where('id')->in($idList) + ->andWhere('deleted')->eq('0') + ->fetchPairs(); + } + /** * Get kanban data. * @@ -996,15 +1041,16 @@ class kanbanModel extends model * * @param array $regions * @param string $order order|id_asc + * @param string $param * @access public * @return array */ - public function getColumnGroupByRegions($regions, $order = 'order') + public function getColumnGroupByRegions($regions, $order = 'order', $param = '') { $columnGroup = $this->dao->select("*")->from(TABLE_KANBANCOLUMN) ->where('deleted')->eq('0') - ->andWhere('archived')->eq('0') ->andWhere('region')->in($regions) + ->beginIF(strpos(",$param,", ',withArchived,') === false)->andWhere('archived')->eq('0')->fi() ->orderBy($order) ->fetchGroup('group'); @@ -2104,7 +2150,7 @@ class kanbanModel extends model ->join('whitelist', ',') ->join('team', ',') ->trim('name') - ->remove('uid,contactListMenu,type,import,importObjectList') + ->remove('contactListMenu,type,import,importObjectList,copyKanbanID,copyRegion') ->get(); if($this->post->import == 'on') $kanban->object = implode(',', $this->post->importObjectList); @@ -2134,7 +2180,15 @@ class kanbanModel extends model $kanbanID = $this->dao->lastInsertID(); $kanban = $this->getByID($kanbanID); - $this->createDefaultRegion($kanban); + if($this->post->copyRegion) + { + $this->copyRegions($kanban, $this->post->copyKanbanID); + } + else + { + $this->createDefaultRegion($kanban); + } + $this->loadModel('file')->saveUpload('kanban', $kanbanID); $this->file->updateObjectID($this->post->uid, $kanbanID, 'kanban'); diff --git a/module/kanban/view/create.html.php b/module/kanban/view/create.html.php index 39d945692c..bf68bf85f9 100644 --- a/module/kanban/view/create.html.php +++ b/module/kanban/view/create.html.php @@ -12,12 +12,16 @@ ?> + - + config->vision);?>