Commit 4917df5e authored by Phil Hughes's avatar Phil Hughes

Issue boards list template in JS file

This is one step closer to making the transition to .vue files for issue boards
parent 65ea732c
/* eslint-disable comma-dangle, space-before-function-paren, one-var */ /* eslint-disable comma-dangle, space-before-function-paren, one-var */
/* global Sortable */ /* global Sortable */
import boardList from './board_list';
import Vue from 'vue'; import Vue from 'vue';
import boardBlankState from './board_blank_state'; import boardBlankState from './board_blank_state';
...@@ -16,7 +17,7 @@ require('./board_list'); ...@@ -16,7 +17,7 @@ require('./board_list');
gl.issueBoards.Board = Vue.extend({ gl.issueBoards.Board = Vue.extend({
template: '#js-board-template', template: '#js-board-template',
components: { components: {
'board-list': gl.issueBoards.BoardList, boardList,
'board-delete': gl.issueBoards.BoardDelete, 'board-delete': gl.issueBoards.BoardDelete,
boardBlankState, boardBlankState,
}, },
......
/* eslint-disable comma-dangle, space-before-function-paren, max-len */
/* global Sortable */ /* global Sortable */
import Vue from 'vue'; import Vue from 'vue';
import boardNewIssue from './board_new_issue'; import boardNewIssue from './board_new_issue';
import boardCard from './board_card'; import boardCard from './board_card';
import eventHub from '../eventhub';
(() => { const Store = gl.issueBoards.BoardsStore;
const Store = gl.issueBoards.BoardsStore;
window.gl = window.gl || {}; export default {
window.gl.issueBoards = window.gl.issueBoards || {}; template: `
<div class="board-list-component">
gl.issueBoards.BoardList = Vue.extend({ <div
template: '#js-board-list-template', class="board-list-loading text-center"
components: { v-if="loading">
boardCard, <i class="fa fa-spinner fa-spin"></i>
boardNewIssue, </div>
<board-new-issue
:list="list"
v-if="list.type !== 'closed' && showIssueForm"/>
<ul
class="board-list"
v-show="!loading"
ref="list"
:data-board="list.id"
:class="{ 'is-smaller': showIssueForm }">
<board-card
v-for="(issue, index) in issues"
ref="issue"
:index="index"
:list="list"
:issue="issue"
:issue-link-base="issueLinkBase"
:root-path="rootPath"
:disabled="disabled"
:key="issue.id" />
<li
class="board-list-count text-center"
v-if="showCount"
data-id="-1">
<i
class="fa fa-spinner fa-spin"
v-show="list.loadingMore">
</i>
<span v-if="list.issues.length === list.issuesSize">
Show all issues
</span>
<span v-else>
Showing {{ list.issues.length }} of {{ list.issuesSize }} issues
</span>
</li>
</ul>
</div>
`,
components: {
boardCard,
boardNewIssue,
},
props: {
disabled: {
type: Boolean,
required: true,
}, },
props: { list: {
disabled: Boolean, type: Object,
list: Object, required: true,
issues: Array,
loading: Boolean,
issueLinkBase: String,
rootPath: String,
}, },
data () { issues: {
return { type: Array,
scrollOffset: 250, required: true,
filters: Store.state.filters,
showCount: false,
showIssueForm: false
};
}, },
watch: { loading: {
filters: { type: Boolean,
handler () { required: true,
this.list.loadingMore = false; },
this.$refs.list.scrollTop = 0; issueLinkBase: {
}, type: String,
deep: true required: true,
},
rootPath: {
type: String,
required: true,
},
},
data() {
return {
scrollOffset: 250,
filters: Store.state.filters,
showCount: false,
showIssueForm: false,
};
},
watch: {
filters: {
handler() {
this.list.loadingMore = false;
this.$refs.list.scrollTop = 0;
}, },
issues () { deep: true,
this.$nextTick(() => { },
if (this.scrollHeight() <= this.listHeight() && this.list.issuesSize > this.list.issues.length) { issues() {
this.list.page += 1; this.$nextTick(() => {
this.list.getIssues(false); if (this.scrollHeight() <= this.listHeight() &&
} this.list.issuesSize > this.list.issues.length) {
this.list.page += 1;
this.list.getIssues(false);
}
if (this.scrollHeight() > Math.ceil(this.listHeight())) {
this.showCount = true;
} else {
this.showCount = false;
}
});
},
},
methods: {
listHeight() {
return this.$refs.list.getBoundingClientRect().height;
},
scrollHeight() {
return this.$refs.list.scrollHeight;
},
scrollTop() {
return this.$refs.list.scrollTop + this.listHeight();
},
loadNextPage() {
const getIssues = this.list.nextPage();
if (this.scrollHeight() > Math.ceil(this.listHeight())) { if (getIssues) {
this.showCount = true; this.list.loadingMore = true;
} else { getIssues.then(() => {
this.showCount = false; this.list.loadingMore = false;
}
}); });
} }
}, },
methods: { toggleForm() {
listHeight () { this.showIssueForm = !this.showIssueForm;
return this.$refs.list.getBoundingClientRect().height;
},
scrollHeight () {
return this.$refs.list.scrollHeight;
},
scrollTop () {
return this.$refs.list.scrollTop + this.listHeight();
},
loadNextPage () {
const getIssues = this.list.nextPage();
if (getIssues) {
this.list.loadingMore = true;
getIssues.then(() => {
this.list.loadingMore = false;
});
}
},
toggleForm() {
this.showIssueForm = !this.showIssueForm;
},
}, },
created() { onScroll() {
gl.IssueBoardsApp.$on(`hide-issue-form-${this.list.id}`, this.toggleForm); if ((this.scrollTop() > this.scrollHeight() - this.scrollOffset) && !this.list.loadingMore) {
this.loadNextPage();
}
}, },
mounted () { },
const options = gl.issueBoards.getBoardSortableDefaultOptions({ created() {
scroll: document.querySelectorAll('.boards-list')[0], eventHub.$on(`hide-issue-form-${this.list.id}`, this.toggleForm);
group: 'issues', },
disabled: this.disabled, mounted() {
filter: '.board-list-count, .is-disabled', const options = gl.issueBoards.getBoardSortableDefaultOptions({
dataIdAttr: 'data-issue-id', scroll: document.querySelectorAll('.boards-list')[0],
onStart: (e) => { group: 'issues',
const card = this.$refs.issue[e.oldIndex]; disabled: this.disabled,
filter: '.board-list-count, .is-disabled',
dataIdAttr: 'data-issue-id',
onStart: (e) => {
const card = this.$refs.issue[e.oldIndex];
card.showDetail = false; card.showDetail = false;
Store.moving.list = card.list; Store.moving.list = card.list;
Store.moving.issue = Store.moving.list.findIssue(+e.item.dataset.issueId); Store.moving.issue = Store.moving.list.findIssue(+e.item.dataset.issueId);
gl.issueBoards.onStart(); gl.issueBoards.onStart();
}, },
onAdd: (e) => { onAdd: (e) => {
gl.issueBoards.BoardsStore.moveIssueToList(Store.moving.list, this.list, Store.moving.issue, e.newIndex); gl.issueBoards.BoardsStore
.moveIssueToList(Store.moving.list, this.list, Store.moving.issue, e.newIndex);
this.$nextTick(() => { this.$nextTick(() => {
e.item.remove(); e.item.remove();
}); });
}, },
onUpdate: (e) => { onUpdate: (e) => {
const sortedArray = this.sortable.toArray().filter(id => id !== '-1'); const sortedArray = this.sortable.toArray().filter(id => id !== '-1');
gl.issueBoards.BoardsStore.moveIssueInList(this.list, Store.moving.issue, e.oldIndex, e.newIndex, sortedArray); gl.issueBoards.BoardsStore
}, .moveIssueInList(this.list, Store.moving.issue, e.oldIndex, e.newIndex, sortedArray);
onMove(e) { },
return !e.related.classList.contains('board-list-count'); onMove(e) {
} return !e.related.classList.contains('board-list-count');
}); },
});
this.sortable = Sortable.create(this.$refs.list, options); this.sortable = Sortable.create(this.$refs.list, options);
// Scroll event on list to load more // Scroll event on list to load more
this.$refs.list.onscroll = () => { this.$refs.list.addEventListener('scroll', this.onScroll);
if ((this.scrollTop() > this.scrollHeight() - this.scrollOffset) && !this.list.loadingMore) { },
this.loadNextPage(); beforeDestroy() {
} eventHub.$off(`hide-issue-form-${this.list.id}`, this.toggleForm);
}; this.$refs.list.removeEventListener('scroll', this.onScroll);
}, },
beforeDestroy() { };
gl.IssueBoardsApp.$off(`hide-issue-form-${this.list.id}`, this.toggleForm);
},
});
})();
/* global ListIssue */ /* global ListIssue */
import eventHub from '../eventhub';
const Store = gl.issueBoards.BoardsStore; const Store = gl.issueBoards.BoardsStore;
export default { export default {
...@@ -49,7 +51,7 @@ export default { ...@@ -49,7 +51,7 @@ export default {
}, },
cancel() { cancel() {
this.title = ''; this.title = '';
gl.IssueBoardsApp.$emit(`hide-issue-form-${this.list.id}`); eventHub.$emit(`hide-issue-form-${this.list.id}`);
}, },
}, },
mounted() { mounted() {
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
= page_specific_javascript_bundle_tag('boards') = page_specific_javascript_bundle_tag('boards')
%script#js-board-template{ type: "text/x-template" }= render "projects/boards/components/board" %script#js-board-template{ type: "text/x-template" }= render "projects/boards/components/board"
%script#js-board-list-template{ type: "text/x-template" }= render "projects/boards/components/board_list"
%script#js-board-modal-filter{ type: "text/x-template" }= render "shared/issuable/search_bar", type: :boards_modal %script#js-board-modal-filter{ type: "text/x-template" }= render "shared/issuable/search_bar", type: :boards_modal
= render "projects/issues/head" = render "projects/issues/head"
......
.board-list-component
.board-list-loading.text-center{ "v-if" => "loading" }
= icon("spinner spin")
- if can? current_user, :create_issue, @project
%board-new-issue{ ":list" => "list",
"v-if" => 'list.type !== "closed" && showIssueForm' }
%ul.board-list{ "ref" => "list",
"v-show" => "!loading",
":data-board" => "list.id",
":class" => '{ "is-smaller": showIssueForm }' }
%board-card{ "v-for" => "(issue, index) in issues",
"ref" => "issue",
":index" => "index",
":list" => "list",
":issue" => "issue",
":issue-link-base" => "issueLinkBase",
":root-path" => "rootPath",
":disabled" => "disabled",
":key" => "issue.id" }
%li.board-list-count.text-center{ "v-if" => "showCount",
"data-issue-id" => "-1" }
= icon("spinner spin", "v-show" => "list.loadingMore" )
%span{ "v-if" => "list.issues.length === list.issuesSize" }
Showing all issues
%span{ "v-else" => true }
Showing {{ list.issues.length }} of {{ list.issuesSize }} issues
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment