diff --git a/module/bug/view/activate.html.php b/module/bug/view/activate.html.php index adc4c9935e..e5a61b6856 100644 --- a/module/bug/view/activate.html.php +++ b/module/bug/view/activate.html.php @@ -12,7 +12,6 @@ ?> -
icons['bug']);?> id;?> diff --git a/module/bug/view/assignto.html.php b/module/bug/view/assignto.html.php index 8e0330e8f4..bd3e559fb1 100644 --- a/module/bug/view/assignto.html.php +++ b/module/bug/view/assignto.html.php @@ -13,7 +13,6 @@ bug->placeholder); js::set('page', 'assignedto'); ?> diff --git a/module/bug/view/batchcreate.html.php b/module/bug/view/batchcreate.html.php index bc9b010747..bc81a58909 100644 --- a/module/bug/view/batchcreate.html.php +++ b/module/bug/view/batchcreate.html.php @@ -11,7 +11,6 @@ */ ?> -
icons['bug']);?> diff --git a/module/bug/view/confirmbug.html.php b/module/bug/view/confirmbug.html.php index 614a266518..91a0dee309 100755 --- a/module/bug/view/confirmbug.html.php +++ b/module/bug/view/confirmbug.html.php @@ -13,7 +13,6 @@ bug->placeholder); js::set('page', 'confirmbug'); ?> diff --git a/module/bug/view/create.html.php b/module/bug/view/create.html.php index 2a92d5dd4e..2b4b38bbf3 100644 --- a/module/bug/view/create.html.php +++ b/module/bug/view/create.html.php @@ -13,7 +13,6 @@ bug->placeholder); js::set('page', 'create'); diff --git a/module/bug/view/edit.html.php b/module/bug/view/edit.html.php index 98e9be7f0b..74dc7f598b 100644 --- a/module/bug/view/edit.html.php +++ b/module/bug/view/edit.html.php @@ -12,7 +12,6 @@ ?> dot = '.'; $lang->at = ' at '; $lang->downArrow = '↓'; $lang->null = '空'; +$lang->ellipsis = '...'; $lang->zentaoPMS = 'zentao'; $lang->welcome = "%s PMS"; diff --git a/module/common/lang/zh-cn.php b/module/common/lang/zh-cn.php index b695ee2ff3..270d5773b1 100644 --- a/module/common/lang/zh-cn.php +++ b/module/common/lang/zh-cn.php @@ -16,6 +16,7 @@ $lang->dot = '。'; $lang->at = ' 于 '; $lang->downArrow = '↓'; $lang->null = '空'; +$lang->ellipsis = '…'; $lang->zentaoPMS = '禅道'; $lang->welcome = "%s项目管理系统"; diff --git a/module/common/lang/zh-tw.php b/module/common/lang/zh-tw.php index f481194df5..6bc4555a82 100644 --- a/module/common/lang/zh-tw.php +++ b/module/common/lang/zh-tw.php @@ -16,6 +16,7 @@ $lang->dot = '。'; $lang->at = ' 于 '; $lang->downArrow = '↓'; $lang->null = '空'; +$lang->ellipsis = '…'; $lang->zentaoPMS = '禪道'; $lang->welcome = "%s項目管理系統"; diff --git a/module/story/control.php b/module/story/control.php index b37686b049..fae0ee5848 100644 --- a/module/story/control.php +++ b/module/story/control.php @@ -898,10 +898,48 @@ class story extends control * @param int $moduleID * @param int $storyID * @param string $onlyOption + * @param string $status + * @param int $limit * @access public * @return void */ - public function ajaxGetProductStories($productID, $moduleID = 0, $storyID = 0, $onlyOption = 'false', $status = '') + public function ajaxGetProductStories($productID, $moduleID = 0, $storyID = 0, $onlyOption = 'false', $status = '', $limit = 0) + { + if($moduleID) + { + $moduleID = $this->loadModel('tree')->getStoryModule($moduleID); + $moduleID = $this->tree->getAllChildID($moduleID); + } + + $storyStatus = ''; + if($status == 'noclosed') + { + $storyStatus = $this->lang->story->statusList; + unset($storyStatus['closed']); + $storyStatus = array_keys($storyStatus); + } + + $stories = $this->story->getProductStoryPairs($productID, $moduleID, $storyStatus, 'id_desc', $limit); + $select = html::select('story', $stories, $storyID, "class='form-control'"); + + /* If only need options, remove select wrap. */ + if($onlyOption == 'true') die(substr($select, strpos($select, '>') + 1, -10)); + die($select); + } + + /** + * AJAX: search stories of a product as json + * + * @param string $key + * @param int $productID + * @param int $moduleID + * @param int $storyID + * @param string $status + * @param int $limit + * @access public + * @return void + */ + public function ajaxSearchProductStories($key, $productID, $moduleID = 0, $storyID = 0, $status = 'noclosed', $limit = 50) { if($moduleID) { @@ -918,11 +956,23 @@ class story extends control } $stories = $this->story->getProductStoryPairs($productID, $moduleID, $storyStatus); - $select = html::select('story', $stories, $storyID, "class='form-control'"); + $result = array(); + $i = 0; + foreach ($stories as $id => $story) + { + if($limit > 0 && $i > $limit) break; + if(('#' . $id) === $key || stripos($story, $key) !== false) + { + $result[$id] = $story; + $i++; + } + } + if($i < 1) + { + $result['info'] = $this->lang->noResultsMatch; + } - /* If only need options, remove select wrap. */ - if($onlyOption == 'true') die(substr($select, strpos($select, '>') + 1, -10)); - die($select); + die(json_encode($result)); } /** diff --git a/module/story/model.php b/module/story/model.php index 0b4ae99010..f50eb0fc57 100644 --- a/module/story/model.php +++ b/module/story/model.php @@ -945,10 +945,11 @@ class storyModel extends model * @param array|string $moduleIds * @param string $status * @param string $order + * @param int $limit * @access public * @return array */ - public function getProductStoryPairs($productID = 0, $moduleIds = 0, $status = 'all', $order = 'id_desc') + public function getProductStoryPairs($productID = 0, $moduleIds = 0, $status = 'all', $order = 'id_desc', $limit = 0) { $stories = $this->dao->select('t1.id, t1.title, t1.module, t1.pri, t1.estimate, t2.name AS product') ->from(TABLE_STORY)->alias('t1')->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product = t2.id') @@ -960,7 +961,7 @@ class storyModel extends model ->orderBy($order) ->fetchAll(); if(!$stories) return array(); - return $this->formatStories($stories); + return $this->formatStories($stories, 'full', $limit); } /** @@ -1379,10 +1380,11 @@ class storyModel extends model * * @param array $stories * @param string $type + * @param int $limit * @access public * @return void */ - public function formatStories($stories, $type = 'full') + public function formatStories($stories, $type = 'full', $limit = 0) { /* Get module names of stories. */ /*$modules = array(); @@ -1391,6 +1393,7 @@ class storyModel extends model /* Format these stories. */ $storyPairs = array('' => ''); + $i = 0; foreach($stories as $story) { if($type == 'short') @@ -1402,6 +1405,12 @@ class storyModel extends model $property = '(' . $this->lang->story->pri . ':' . $story->pri . ',' . $this->lang->story->estimate . ':' . $story->estimate . ')'; } $storyPairs[$story->id] = $story->id . ':' . $story->title . $property; + + if($limit > 0 && ++$i > $limit) + { + $storyPairs['showmore'] = $this->lang->more . $this->lang->ellipsis; + break; + } } return $storyPairs; } diff --git a/module/task/view/batchcreate.html.php b/module/task/view/batchcreate.html.php index 960d66fb11..3007f38eea 100644 --- a/module/task/view/batchcreate.html.php +++ b/module/task/view/batchcreate.html.php @@ -11,7 +11,6 @@ */ ?> - task->batchCreate);?>
diff --git a/module/task/view/edit.html.php b/module/task/view/edit.html.php index 92b0d351fb..8ae7a7eafc 100644 --- a/module/task/view/edit.html.php +++ b/module/task/view/edit.html.php @@ -12,7 +12,6 @@ ?> - story); ?> task->confirmChangeProject); ?> diff --git a/module/testcase/control.php b/module/testcase/control.php index 2bbcbb5eb9..6276af08dc 100644 --- a/module/testcase/control.php +++ b/module/testcase/control.php @@ -317,7 +317,7 @@ class testcase extends control $modules = $this->loadModel('tree')->getStoryModule($currentModuleID); $modules = $this->tree->getAllChildID($modules); } - $stories = $this->story->getProductStoryPairs($productID, $modules, array_keys($storyStatus)); + $stories = $this->story->getProductStoryPairs($productID, $modules, array_keys($storyStatus), 'id_desc', 20); $this->view->title = $title; $this->view->caseTitle = $caseTitle; diff --git a/module/testcase/css/create.css b/module/testcase/css/create.css new file mode 100644 index 0000000000..5f081cdc55 --- /dev/null +++ b/module/testcase/css/create.css @@ -0,0 +1,12 @@ +#searchStories .searchInput {position: relative;} +#searchStories .searchInput .icon {position: absolute; display: block; left: 9px; top: 9px; z-index: 5; color: #808080;} +#storySearchInput {padding-left: 30px;} + +#searchStories .modal-body {height: 300px; overflow-y: auto; padding: 0;} +#searchResult {padding-left: 0; list-style: none; width: 100%} +#searchResult > li {display: block} +#searchResult > li.tip {padding: 6px 15px; color: #808080} +#searchResult > li.loading {text-align: center; padding: 50px} +#searchResult > li.loading > .icon-spinner:before {font-size: 28px;} +#searchResult > li > a {display: block; padding: 6px 15px; color: #333; border-bottom: 1px solid #e5e5e5} +#searchResult > li > a:hover, #searchResult > li > a.selected {color: #1a4f85; background-color: #ddd;} diff --git a/module/testcase/js/common.js b/module/testcase/js/common.js index ee76c11f10..83371b56e7 100644 --- a/module/testcase/js/common.js +++ b/module/testcase/js/common.js @@ -47,7 +47,7 @@ function setStories() { moduleID = $('#module').val(); productID = $('#product').val(); - link = createLink('story', 'ajaxGetProductStories', 'productID=' + productID + '&moduleID=' + moduleID + '&storyID=0&onlyOption=false&status=noclosed'); + link = createLink('story', 'ajaxGetProductStories', 'productID=' + productID + '&moduleID=' + moduleID + '&storyID=0&onlyOption=false&status=noclosed&limit=20'); $.get(link, function(stories) { var value = $('#story').val(); @@ -113,7 +113,7 @@ function createRow() newRow += ""; newRow += ""; newRow += ""; - newRow += "
"; + newRow += "
"; newRow += ""; newRow += ""; newRow += ""; diff --git a/module/testcase/js/create.js b/module/testcase/js/create.js index 46f32ecd55..89a4f4f301 100644 --- a/module/testcase/js/create.js +++ b/module/testcase/js/create.js @@ -17,6 +17,109 @@ function setPreview() $(function() { - $("#story").chosen(defaultChosenOptions); - $("#preview").modalTrigger({width:960, type:'iframe'}); + var $searchStories = $('#searchStories'); + var lastSearchFn = false; + var $searchInput = $('#storySearchInput'); + var $searchResult = $('#searchResult'); + var $selectedItem; + var $story = $('#story'); + $(document).on('change', '#story', function() + { + if($(this).val() === 'showmore') + { + $searchStories.modal('show').on('shown.zui.modal', function(){$searchInput.focus();}); + } + }); + + $searchStories.on('hide.zui.modal', function() + { + var key = ''; + if($selectedItem && $selectedItem.length) + { + key = $selectedItem.data('key'); + if(!$story.children('option[value="' + key + '"]').length) + { + $story.prepend(''); + } + } + $story.val(key).trigger("chosen:updated"); + $selectedItem = null; + }); + + var selectItem = function(item) + { + $selectedItem = $(item).first(); + $searchStories.modal('hide'); + }; + + $searchResult.on('click', 'a', function(){selectItem(this);}).on('mouseenter', 'a', function() + { + $searchResult.find('a.selected').removeClass('selected'); + $(this).addClass('selected'); + }).on('mouseleave', 'a', function() + { + $(this).removeClass('selected'); + }); + + $searchInput.on('paste change keyup', function() + { + if(lastSearchFn) clearTimeout(lastSearchFn); + lastSearchFn = setTimeout(function() + { + var key = $searchInput.val() || ''; + if(key && key != $searchInput.data('lastkey')) + { + $searchResult.empty().append('
  • '); + var link = createLink('story', 'ajaxSearchProductStories', 'key=' + key + '&productID=' + $('#product').val() + '&moduleID=' + $('#module').val() + '&storyID=0&status=noclosed&limit=20'); + $.getJSON(link, function(result) + { + $searchResult.empty(); + if(result) + { + for(var key in result) + { + if(key === 'info') + { + $searchResult.append('
  • ' + result[key] + '
  • '); + } + else + { + $searchResult.append("
  • " + result[key] + "
  • "); + } + } + $searchResult.find('li:first > a').addClass('selected'); + } + }); + $searchInput.data('lastkey', key); + } + else if(!key.length) + { + $searchResult.empty(); + } + }, 500); + }).on('keyup', function(e) + { + var $selected = $searchResult.find('a.selected').first(); + if(e.keyCode == 38) // keyup + { + var $prev = $selected.closest('li').prev().children('a'); + if($prev.length) + { + $selected.removeClass('selected'); + $prev.addClass('selected'); + } + } + else if(e.keyCode == 40) // keydown + { + var $next = $selected.closest('li').next().children('a'); + if($next.length) + { + $selected.removeClass('selected'); + $next.addClass('selected'); + } + } + else if(e.keyCode == 13) selectItem($selected); + }); + + $("#preview").modalTrigger({width:960, type:'iframe'}); }) diff --git a/module/testcase/lang/en.php b/module/testcase/lang/en.php index 7d5ce36a45..086fd21f8f 100644 --- a/module/testcase/lang/en.php +++ b/module/testcase/lang/en.php @@ -156,3 +156,5 @@ $lang->testcase->buttonToList = 'Back'; $lang->testcase->errorEncode = 'No data, please select right encode and upload again!'; $lang->testcase->noFunction = 'Iconv and mb_convert_encoding does not exist, you can not turn the data into the desired coding!'; $lang->testcase->noRequire = "In the row of %s, the %s is a required field"; + +$lang->testcase->searchStories = 'Type to search stories'; diff --git a/module/testcase/lang/zh-cn.php b/module/testcase/lang/zh-cn.php index f6d5b94a72..b51346c553 100644 --- a/module/testcase/lang/zh-cn.php +++ b/module/testcase/lang/zh-cn.php @@ -156,3 +156,5 @@ $lang->testcase->buttonToList = '返回'; $lang->testcase->errorEncode = '无数据,请选择正确的编码重新上传!'; $lang->testcase->noFunction = '不存在iconv和mb_convert_encoding转码方法,不能将数据转成想要的编码!'; $lang->testcase->noRequire = "%s行的“%s”是必填字段,不能为空"; + +$lang->testcase->searchStories = '键入来搜索需求'; diff --git a/module/testcase/view/create.html.php b/module/testcase/view/create.html.php index 1ca6f3ab0e..0d3e679322 100644 --- a/module/testcase/view/create.html.php +++ b/module/testcase/view/create.html.php @@ -12,7 +12,6 @@ ?> - testcase->deleteStep);?> testcase->insertBefore);?> testcase->insertAfter);?> @@ -126,4 +125,20 @@
    + diff --git a/module/testcase/view/edit.html.php b/module/testcase/view/edit.html.php index 8873497191..e27e8e7062 100644 --- a/module/testcase/view/edit.html.php +++ b/module/testcase/view/edit.html.php @@ -11,7 +11,6 @@ */ ?> - testcase->deleteStep);?> testcase->insertBefore);?> diff --git a/module/tree/view/edit.html.php b/module/tree/view/edit.html.php index 862351aad8..929f4ce890 100644 --- a/module/tree/view/edit.html.php +++ b/module/tree/view/edit.html.php @@ -14,7 +14,6 @@ $webRoot = $this->app->getWebRoot(); $jsRoot = $webRoot . "js/"; ?> -