Removed underscoreJS uses

Removed props on main VueJS app instead uses data variables
This commit is contained in:
Phil Hughes 2016-08-11 09:51:52 +01:00
parent 4460724da7
commit 17c576c1ac
14 changed files with 160 additions and 130 deletions

View File

@ -7,7 +7,9 @@
//= require_tree ./mixins
//= require_tree ./components
$(function () {
$(() => {
const $boardApp = $('#board-app');
if (!window.gl) {
window.gl = {};
}
@ -17,38 +19,42 @@ $(function () {
}
gl.IssueBoardsApp = new Vue({
el: '#board-app',
props: {
disabled: Boolean,
endpoint: String,
issueLinkBase: String
},
el: $boardApp.get(0),
data: {
state: BoardsStore.state,
loading: true
loading: true,
endpoint: $boardApp.data('endpoint'),
disabled: $boardApp.data('disabled'),
issueLinkBase: $boardApp.data('issue-link-base')
},
init: function () {
init () {
BoardsStore.create();
},
created: function () {
created () {
this.loading = true;
gl.boardService = new BoardService(this.endpoint);
$boardApp
.removeAttr('data-endpoint')
.removeAttr('data-disabled')
.removeAttr('data-issue-link-base');
},
ready: function () {
ready () {
BoardsStore.disabled = this.disabled;
gl.boardService.all()
.then((resp) => {
const boards = resp.json();
boards.forEach((board) => {
const list = BoardsStore.addList(board);
for (let i = 0, boardsLength = boards.length; i < boardsLength; i++) {
const board = boards[i],
list = BoardsStore.addList(board);
if (list.type === 'done') {
list.position = 9999999;
list.position = Infinity;
} else if (list.type === 'backlog') {
list.position = -1;
}
});
}
BoardsStore.addBlankState();
this.loading = false;

View File

@ -1,25 +1,25 @@
(function () {
(() => {
const Board = Vue.extend({
props: {
list: Object,
disabled: Boolean,
issueLinkBase: String
},
data: function () {
data () {
return {
query: '',
filters: BoardsStore.state.filters
};
},
watch: {
'query': function () {
query () {
if (this.list.canSearch()) {
this.list.filters = this.getFilterData();
this.list.getIssues(true);
}
},
'filters': {
handler: function () {
filters: {
handler () {
this.list.page = 1;
this.list.getIssues(true);
},
@ -27,30 +27,33 @@
}
},
methods: {
clearSearch: function () {
clearSearch () {
this.query = '';
},
getFilterData: function () {
const queryData = this.list.canSearch() ? { search: this.query } : {};
getFilterData () {
const filters = this.filters;
let queryData = this.list.canSearch() ? { search: this.query } : {};
Object.keys(filters).forEach((key) => { queryData[key] = filters[key]; });
return _.extend(queryData, this.filters);
return queryData;
}
},
computed: {
isPreset: function () {
isPreset () {
return this.list.type === 'backlog' || this.list.type === 'done' || this.list.type === 'blank';
}
},
ready: function () {
let options = _.extend({
ready () {
const options = gl.getBoardSortableDefaultOptions({
disabled: this.disabled,
group: 'boards',
draggable: '.is-draggable',
handle: '.js-board-handle',
onUpdate: function (e) {
onUpdate (e) {
BoardsStore.moveList(e.oldIndex, e.newIndex);
}
}, gl.boardSortableDefaultOptions);
});
if (bp.getBreakpointSize() === 'sm' || bp.getBreakpointSize() === 'xs') {
options.handle = '.js-board-drag-handle';

View File

@ -1,6 +1,6 @@
(() => {
const BoardBlankState = Vue.extend({
data: function () {
data () {
return {
predefinedLabels: [
new ListLabel({ title: 'Development', color: '#5CB85C' }),
@ -11,11 +11,13 @@
}
},
methods: {
addDefaultLists: function (e) {
addDefaultLists (e) {
e.stopImmediatePropagation();
BoardsStore.removeBlankState();
_.each(this.predefinedLabels, (label, i) => {
for (let i = 0, labelsLength = this.predefinedLabels.length; i < labelsLength; i++) {
const label = this.predefinedLabels[i];
BoardsStore.addList({
title: label.title,
position: i,
@ -25,7 +27,7 @@
color: label.color
}
});
});
}
// Save the labels
gl.boardService
@ -33,15 +35,16 @@
.then((resp) => {
const data = resp.json();
_.each(data, (listObj) => {
const list = BoardsStore.findList('title', listObj.title);
for (let i = 0, dataLength = data.length; i < dataLength; i++) {
const listObj = data[i],
list = BoardsStore.findList('title', listObj.title);
list.id = listObj.id;
list.label.id = listObj.label.id;
list.getIssues();
});
}
});
},
clearBlankState: function () {
clearBlankState () {
BoardsStore.removeBlankState();
}
}

View File

@ -1,4 +1,4 @@
(function () {
(() => {
const BoardCard = Vue.extend({
props: {
list: Object,
@ -7,7 +7,7 @@
disabled: Boolean
},
methods: {
filterByLabel: function (label, $event) {
filterByLabel (label, $event) {
let labelToggleText = label.title;
const labelIndex = BoardsStore.state.filters['label_name'].indexOf(label.title);
$($event.target).tooltip('hide');

View File

@ -4,7 +4,7 @@
list: Object
},
methods: {
deleteBoard: function (e) {
deleteBoard (e) {
e.stopImmediatePropagation();
$(this.$el).tooltip('hide');

View File

@ -1,4 +1,4 @@
(function () {
(() => {
const BoardList = Vue.extend({
props: {
disabled: Boolean,
@ -7,7 +7,7 @@
loading: Boolean,
issueLinkBase: String
},
data: function () {
data () {
return {
scrollOffset: 250,
loadingMore: false,
@ -15,8 +15,8 @@
};
},
watch: {
'filters': {
handler: function () {
filters: {
handler () {
this.loadingMore = false;
this.$els.list.scrollTop = 0;
},
@ -24,16 +24,16 @@
}
},
methods: {
listHeight: function () {
listHeight () {
return this.$els.list.getBoundingClientRect().height;
},
scrollHeight: function () {
scrollHeight () {
return this.$els.list.scrollHeight;
},
scrollTop: function () {
scrollTop () {
return this.$els.list.scrollTop + this.listHeight();
},
loadNextPage: function () {
loadNextPage () {
this.loadingMore = true;
const getIssues = this.list.nextPage();
@ -44,24 +44,24 @@
}
},
},
ready: function () {
const list = this.list;
let options = _.extend({
group: 'issues',
sort: false,
disabled: this.disabled,
onAdd: (e) => {
const card = e.item,
fromListId = parseInt(e.from.getAttribute('data-board')),
toListId = parseInt(e.to.getAttribute('data-board')),
issueId = parseInt(card.getAttribute('data-issue'));
ready () {
const list = this.list,
options = gl.getBoardSortableDefaultOptions({
group: 'issues',
sort: false,
disabled: this.disabled,
onAdd (e) {
const card = e.item,
fromListId = parseInt(e.from.getAttribute('data-board')),
toListId = parseInt(e.to.getAttribute('data-board')),
issueId = parseInt(card.getAttribute('data-issue'));
// Remove the new dom element & let vue add the element
card.parentNode.removeChild(card);
// Remove the new dom element & let vue add the element
card.parentNode.removeChild(card);
BoardsStore.moveCardToList(fromListId, toListId, issueId);
}
}, gl.boardSortableDefaultOptions);
BoardsStore.moveCardToList(fromListId, toListId, issueId);
}
});
if (bp.getBreakpointSize() === 'sm' || bp.getBreakpointSize() === 'xs') {
options.handle = '.js-card-drag-handle';

View File

@ -1,18 +1,18 @@
$(function () {
$(() => {
$('.js-new-board-list').each(function () {
const $this = $(this);
new gl.CreateLabelDropdown($this.closest('.dropdown').find('.dropdown-new-label'), $this.data('project-id'));
$this.glDropdown({
data: function(term, callback) {
data(term, callback) {
$.ajax({
url: $this.attr('data-labels')
}).then((resp) => {
callback(resp);
});
},
renderRow: (label) => {
renderRow (label) {
const active = BoardsStore.findList('title', label.title),
$li = $('<li />',),
$a = $('<a />', {
@ -32,7 +32,7 @@ $(function () {
},
filterable: true,
selectable: true,
clicked: (label, $el, e) => {
clicked (label, $el, e) {
e.preventDefault();
if (!BoardsStore.findList('title', label.title)) {

View File

@ -3,19 +3,24 @@
window.gl = {};
}
gl.boardSortableDefaultOptions = {
forceFallback: true,
fallbackClass: 'is-dragging',
fallbackOnBody: true,
ghostClass: 'is-ghost',
filter: '.has-tooltip',
scrollSensitivity: 100,
scrollSpeed: 20,
onStart: function () {
document.body.classList.add('is-dragging');
},
onEnd: function () {
document.body.classList.remove('is-dragging');
gl.getBoardSortableDefaultOptions = (obj) => {
let defaultSortOptions = {
forceFallback: true,
fallbackClass: 'is-dragging',
fallbackOnBody: true,
ghostClass: 'is-ghost',
filter: '.has-tooltip',
scrollSensitivity: 100,
scrollSpeed: 20,
onStart () {
document.body.classList.add('is-dragging');
},
onEnd () {
document.body.classList.remove('is-dragging');
}
}
Object.keys(obj).forEach((key) => { defaultSortOptions[key] = obj[key]; });
return defaultSortOptions;
};
})(window);

View File

@ -10,11 +10,12 @@ class ListIssue {
this.labels = [];
_.each(obj.labels, (label) => {
for (let i = 0, objLabelsLength = obj.labels.length; i < objLabelsLength; i++) {
const label = obj.labels[i];
this.labels.push(new ListLabel(label));
});
}
this.priority = _.reduce(this.labels, (max, label) => {
this.priority = this.labels.reduce((max, label) => {
return (label.priority < max) ? label.priority : max;
}, Infinity);
}
@ -30,25 +31,28 @@ class ListIssue {
}
findLabel (findLabel) {
return _.find(this.labels, (label) => {
return this.labels.filter((label) => {
return label.title === findLabel.title;
});
})[0];
}
removeLabel (removeLabel) {
if (removeLabel) {
this.labels = _.reject(this.labels, (label) => {
return removeLabel.title === label.title;
this.labels = this.labels.filter((label) => {
return removeLabel.title !== label.title;
});
}
}
removeLabels (labels) {
_.each(labels, this.removeLabel.bind(this));
for (let i = 0, labelsLength = labels.length; i < labelsLength; i++) {
const label = labels[i];
this.removeLabel(label);
}
}
getLists () {
return _.filter(BoardsStore.state.lists, (list) => {
return BoardsStore.state.lists.filter((list) => {
return list.findIssue(this.id);
});
}

View File

@ -33,8 +33,8 @@ class List {
destroy () {
if (this.type !== 'blank') {
BoardsStore.state.lists = _.reject(BoardsStore.state.lists, (list) => {
return list.id === this.id;
BoardsStore.state.lists = BoardsStore.state.lists.filter((list) => {
return list.id !== this.id;
});
BoardsStore.updateNewListDropdown();
@ -59,11 +59,14 @@ class List {
}
getIssues (emptyIssues = true) {
let data = _.extend({ page: this.page }, this.filters);
const filters = this.filters;
let data = { page: this.page };
Object.keys(filters).forEach((key) => { data[key] = filters[key]; });
if (this.label) {
data.label_name = _.reject(data.label_name, (label) => {
return label === this.label.title;
data.label_name = data.label_name.filter((label) => {
return label !== this.label.title;
});
}
@ -85,9 +88,10 @@ class List {
}
createIssues (data) {
_.each(data, (issueObj) => {
for (let i = 0, dataLength = data.length; i < dataLength; i++) {
const issueObj = data[i];
this.issues.push(new ListIssue(issueObj));
});
}
}
addIssue (issue, listFrom) {
@ -99,20 +103,20 @@ class List {
}
findIssue (id) {
return _.find(this.issues, (issue) => {
return this.issues.filter((issue) => {
return issue.id === id;
});
})[0];
}
removeIssue (removeIssue) {
this.issues = _.reject(this.issues, (issue) => {
this.issues = this.issues.filter((issue) => {
const matchesRemove = removeIssue.id === issue.id;
if (matchesRemove) {
issue.removeLabel(this.label);
}
return matchesRemove;
return !matchesRemove;
});
}
}

View File

@ -55,7 +55,8 @@ class BoardService {
}
getIssuesForList (id, filter = {}) {
const data = _.extend({ id }, filter)
let data = { id };
Object.keys(filter).forEach((key) => { data[key] = filter[key]; });
this.setCSRF();
return this.issues.get(data);

View File

@ -2,7 +2,7 @@
w.BoardsStore = {
disabled: false,
state: {},
create: function () {
create () {
this.state.lists = [];
this.state.filters = {
author_id: gl.utils.getParameterValues('author_id')[0],
@ -11,26 +11,29 @@
label_name: gl.utils.getParameterValues('label_name[]')
};
},
addList: function (listObj) {
addList (listObj) {
const list = new List(listObj);
this.state.lists.push(list);
return list;
},
new: function (listObj) {
new (listObj) {
const list = this.addList(listObj),
backlogList = this.findList('type', 'backlog');
list
.save()
.then(function () {
.then(() => {
// Remove any new issues from the backlog
// as they will be visible in the new list
_.each(list.issues, backlogList.removeIssue.bind(backlogList));
for (let i = 0, issuesLength = list.issues.length; i < issuesLength; i++) {
const issue = list.issues[i];
backlogList.removeIssue(issue);
}
});
this.removeBlankState();
},
updateNewListDropdown: function () {
updateNewListDropdown () {
const glDropdown = $('.js-new-board-list').data('glDropdown');
if (glDropdown) {
@ -41,13 +44,13 @@
}
}
},
shouldAddBlankState: function () {
shouldAddBlankState () {
// Decide whether to add the blank state
return !(!!_.find(this.state.lists, function (list) {
return !(this.state.lists.filter((list) => {
return list.type !== 'backlog' && list.type !== 'done';
}));
})[0]);
},
addBlankState: function () {
addBlankState () {
if (this.welcomeIsHidden() || this.disabled) return;
if (this.shouldAddBlankState()) {
@ -59,26 +62,26 @@
});
}
},
removeBlankState: function () {
removeBlankState () {
this.removeList('blank');
$.cookie('issue_board_welcome_hidden', 'true', {
expires: 365 * 10
});
},
welcomeIsHidden: function () {
welcomeIsHidden () {
return $.cookie('issue_board_welcome_hidden') === 'true';
},
removeList: function (id) {
removeList (id) {
const list = this.findList('id', id);
if (!list) return;
this.state.lists = _.reject(this.state.lists, (list) => {
return list.id === id;
this.state.lists = this.state.lists.filter((list) => {
return list.id !== id;
});
},
moveList: function (oldIndex, newIndex) {
moveList (oldIndex, newIndex) {
if (oldIndex === newIndex) return;
const listFrom = this.findList('position', oldIndex),
@ -95,13 +98,13 @@
listFrom.update();
},
moveCardToList: function (listFromId, listToId, issueId) {
moveCardToList (listFromId, listToId, issueId) {
const listFrom = this.findList('id', listFromId),
listTo = this.findList('id', listToId),
issueTo = listTo.findIssue(issueId),
issue = listFrom.findIssue(issueId),
issueLists = issue.getLists(),
listLabels = issueLists.map(function (issue) {
listLabels = issueLists.map((issue) => {
return issue.label;
});
@ -111,20 +114,21 @@
}
if (listTo.type === 'done' && listFrom.type !== 'backlog') {
_.each(issueLists, function (list) {
for (let i = 0, listsLength = issueLists.length; i < listsLength; i++) {
const list = issueLists[i];
list.removeIssue(issue);
});
}
issue.removeLabels(listLabels);
} else {
listFrom.removeIssue(issue);
}
},
findList: function (key, val) {
return _.find(this.state.lists, (list) => {
findList (key, val) {
return this.state.lists.filter((list) => {
return list[key] === val;
});
})[0];
},
updateFiltersUrl: function () {
updateFiltersUrl () {
history.pushState(null, null, `?${$.param(this.state.filters)}`);
}
};

View File

@ -240,7 +240,7 @@
}
.is-ghost {
opacity: 0.5;
opacity: 0.3;
}
.is-dragging {

View File

@ -11,9 +11,9 @@
= render 'shared/issuable/filter', type: :boards
.boards-list#board-app{ "v-cloak" => true,
":endpoint" => "'#{namespace_project_board_path(@project.namespace, @project)}'",
":disabled" => "#{!can?(current_user, :admin_list, @project)}",
":issue-link-base" => "'#{namespace_project_issues_path(@project.namespace, @project)}'" }
"data-endpoint" => "#{namespace_project_board_path(@project.namespace, @project)}",
"data-disabled" => "#{!can?(current_user, :admin_list, @project)}",
"data-issue-link-base" => "#{namespace_project_issues_path(@project.namespace, @project)}" }
.boards-app-loading.text-center{ "v-if" => "loading" }
= icon("spinner spin")
= render "projects/boards/components/board"