mirror of
https://github.com/wekan/wekan.git
synced 2026-01-06 01:28:49 +01:00
Enforce a consistent ES6 coding style
Replace the old (and broken) jshint + jscsrc by eslint and configure it to support some of the ES6 features. The command `eslint` currently has one error which is a bug that was discovered by its static analysis and should be fixed (usage of a dead object).
This commit is contained in:
parent
039cfe7edf
commit
b3851817ec
60 changed files with 1604 additions and 1692 deletions
|
|
@ -1,99 +1,98 @@
|
|||
var activitiesPerPage = 20;
|
||||
const activitiesPerPage = 20;
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
template: function() {
|
||||
template() {
|
||||
return 'activities';
|
||||
},
|
||||
|
||||
onCreated: function() {
|
||||
var self = this;
|
||||
onCreated() {
|
||||
// XXX Should we use ReactiveNumber?
|
||||
self.page = new ReactiveVar(1);
|
||||
self.loadNextPageLocked = false;
|
||||
var sidebar = self.componentParent(); // XXX for some reason not working
|
||||
this.page = new ReactiveVar(1);
|
||||
this.loadNextPageLocked = false;
|
||||
const sidebar = this.componentParent(); // XXX for some reason not working
|
||||
sidebar.callFirstWith(null, 'resetNextPeak');
|
||||
self.autorun(function() {
|
||||
var mode = self.data().mode;
|
||||
var capitalizedMode = Utils.capitalize(mode);
|
||||
var id = Session.get('current' + capitalizedMode);
|
||||
var limit = self.page.get() * activitiesPerPage;
|
||||
this.autorun(() => {
|
||||
const mode = this.data().mode;
|
||||
const capitalizedMode = Utils.capitalize(mode);
|
||||
const id = Session.get(`current${capitalizedMode}`);
|
||||
const limit = this.page.get() * activitiesPerPage;
|
||||
if (id === null)
|
||||
return;
|
||||
|
||||
self.subscribe('activities', mode, id, limit, function() {
|
||||
self.loadNextPageLocked = false;
|
||||
this.subscribe('activities', mode, id, limit, () => {
|
||||
this.loadNextPageLocked = false;
|
||||
|
||||
// If the sibear peak hasn't increased, that mean that there are no more
|
||||
// activities, and we can stop calling new subscriptions.
|
||||
// XXX This is hacky! We need to know excatly and reactively how many
|
||||
// activities there are, we probably want to denormalize this number
|
||||
// dirrectly into card and board documents.
|
||||
var a = sidebar.callFirstWith(null, 'getNextPeak');
|
||||
const nextPeakBefore = sidebar.callFirstWith(null, 'getNextPeak');
|
||||
sidebar.calculateNextPeak();
|
||||
var b = sidebar.callFirstWith(null, 'getNextPeak');
|
||||
if (a === b) {
|
||||
const nextPeakAfter = sidebar.callFirstWith(null, 'getNextPeak');
|
||||
if (nextPeakBefore === nextPeakAfter) {
|
||||
sidebar.callFirstWith(null, 'resetNextPeak');
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
loadNextPage: function() {
|
||||
loadNextPage() {
|
||||
if (this.loadNextPageLocked === false) {
|
||||
this.page.set(this.page.get() + 1);
|
||||
this.loadNextPageLocked = true;
|
||||
}
|
||||
},
|
||||
|
||||
boardLabel: function() {
|
||||
boardLabel() {
|
||||
return TAPi18n.__('this-board');
|
||||
},
|
||||
|
||||
cardLabel: function() {
|
||||
cardLabel() {
|
||||
return TAPi18n.__('this-card');
|
||||
},
|
||||
|
||||
cardLink: function() {
|
||||
var card = this.currentData().card();
|
||||
cardLink() {
|
||||
const card = this.currentData().card();
|
||||
return card && Blaze.toHTML(HTML.A({
|
||||
href: card.absoluteUrl(),
|
||||
'class': 'action-card'
|
||||
'class': 'action-card',
|
||||
}, card.title));
|
||||
},
|
||||
|
||||
memberLink: function() {
|
||||
memberLink() {
|
||||
return Blaze.toHTMLWithData(Template.memberName, {
|
||||
user: this.currentData().member()
|
||||
user: this.currentData().member(),
|
||||
});
|
||||
},
|
||||
|
||||
attachmentLink: function() {
|
||||
var attachment = this.currentData().attachment();
|
||||
attachmentLink() {
|
||||
const attachment = this.currentData().attachment();
|
||||
return attachment && Blaze.toHTML(HTML.A({
|
||||
href: attachment.url(),
|
||||
'class': 'js-open-attachment-viewer'
|
||||
'class': 'js-open-attachment-viewer',
|
||||
}, attachment.name()));
|
||||
},
|
||||
|
||||
events: function() {
|
||||
events() {
|
||||
return [{
|
||||
// XXX We should use Popup.afterConfirmation here
|
||||
'click .js-delete-comment': function() {
|
||||
var commentId = this.currentData().commentId;
|
||||
'click .js-delete-comment'() {
|
||||
const commentId = this.currentData().commentId;
|
||||
CardComments.remove(commentId);
|
||||
},
|
||||
'submit .js-edit-comment': function(evt) {
|
||||
'submit .js-edit-comment'(evt) {
|
||||
evt.preventDefault();
|
||||
var commentText = this.currentComponent().getValue();
|
||||
var commentId = Template.parentData().commentId;
|
||||
const commentText = this.currentComponent().getValue();
|
||||
const commentId = Template.parentData().commentId;
|
||||
if ($.trim(commentText)) {
|
||||
CardComments.update(commentId, {
|
||||
$set: {
|
||||
text: commentText
|
||||
}
|
||||
text: commentText,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
}];
|
||||
}
|
||||
},
|
||||
}).register('activities');
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
let commentFormIsOpen = new ReactiveVar(false);
|
||||
const commentFormIsOpen = new ReactiveVar(false);
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
template() {
|
||||
|
|
@ -19,16 +19,16 @@ BlazeComponent.extendComponent({
|
|||
|
||||
events() {
|
||||
return [{
|
||||
'click .js-new-comment:not(.focus)': function() {
|
||||
'click .js-new-comment:not(.focus)'() {
|
||||
commentFormIsOpen.set(true);
|
||||
},
|
||||
'submit .js-new-comment-form': function(evt) {
|
||||
let input = this.getInput();
|
||||
'submit .js-new-comment-form'(evt) {
|
||||
const input = this.getInput();
|
||||
if ($.trim(input.val())) {
|
||||
CardComments.insert({
|
||||
boardId: this.currentData().boardId,
|
||||
cardId: this.currentData()._id,
|
||||
text: input.val()
|
||||
text: input.val(),
|
||||
});
|
||||
resetCommentInput(input);
|
||||
Tracker.flush();
|
||||
|
|
@ -37,13 +37,13 @@ BlazeComponent.extendComponent({
|
|||
evt.preventDefault();
|
||||
},
|
||||
// Pressing Ctrl+Enter should submit the form
|
||||
'keydown form textarea': function(evt) {
|
||||
'keydown form textarea'(evt) {
|
||||
if (evt.keyCode === 13 && (evt.metaKey || evt.ctrlKey)) {
|
||||
this.find('button[type=submit]').click();
|
||||
}
|
||||
}
|
||||
},
|
||||
}];
|
||||
}
|
||||
},
|
||||
}).register('commentForm');
|
||||
|
||||
// XXX This should be a static method of the `commentForm` component
|
||||
|
|
@ -63,15 +63,15 @@ Tracker.autorun(() => {
|
|||
Tracker.afterFlush(() => {
|
||||
autosize.update($('.js-new-comment-input'));
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
EscapeActions.register('inlinedForm',
|
||||
function() {
|
||||
() => {
|
||||
const draftKey = {
|
||||
fieldName: 'cardComment',
|
||||
docId: Session.get('currentCard')
|
||||
docId: Session.get('currentCard'),
|
||||
};
|
||||
let commentInput = $('.js-new-comment-input');
|
||||
const commentInput = $('.js-new-comment-input');
|
||||
if ($.trim(commentInput.val())) {
|
||||
UnsavedEdits.set(draftKey, commentInput.val());
|
||||
} else {
|
||||
|
|
@ -79,7 +79,7 @@ EscapeActions.register('inlinedForm',
|
|||
}
|
||||
resetCommentInput(commentInput);
|
||||
},
|
||||
function() { return commentFormIsOpen.get(); }, {
|
||||
noClickEscapeOn: '.js-new-comment'
|
||||
() => { return commentFormIsOpen.get(); }, {
|
||||
noClickEscapeOn: '.js-new-comment',
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
Template.headerTitle.events({
|
||||
'click .js-open-archived-board': function() {
|
||||
Modal.open('archivedBoards')
|
||||
}
|
||||
})
|
||||
'click .js-open-archived-board'() {
|
||||
Modal.open('archivedBoards');
|
||||
},
|
||||
});
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
template() {
|
||||
|
|
@ -10,26 +10,26 @@ BlazeComponent.extendComponent({
|
|||
},
|
||||
|
||||
onCreated() {
|
||||
this.subscribe('archivedBoards')
|
||||
this.subscribe('archivedBoards');
|
||||
},
|
||||
|
||||
archivedBoards() {
|
||||
return Boards.find({ archived: true }, {
|
||||
sort: ['title']
|
||||
})
|
||||
sort: ['title'],
|
||||
});
|
||||
},
|
||||
|
||||
events() {
|
||||
return [{
|
||||
'click .js-restore-board': function() {
|
||||
let boardId = this.currentData()._id
|
||||
'click .js-restore-board'() {
|
||||
const boardId = this.currentData()._id;
|
||||
Boards.update(boardId, {
|
||||
$set: {
|
||||
archived: false
|
||||
}
|
||||
})
|
||||
Utils.goBoardId(boardId)
|
||||
}
|
||||
}]
|
||||
archived: false,
|
||||
},
|
||||
});
|
||||
Utils.goBoardId(boardId);
|
||||
},
|
||||
}];
|
||||
},
|
||||
}).register('archivedBoards')
|
||||
}).register('archivedBoards');
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
var subManager = new SubsManager();
|
||||
const subManager = new SubsManager();
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
template: function() {
|
||||
template() {
|
||||
return 'board';
|
||||
},
|
||||
|
||||
onCreated: function() {
|
||||
onCreated() {
|
||||
this.draggingActive = new ReactiveVar(false);
|
||||
this.showOverlay = new ReactiveVar(false);
|
||||
this.isBoardReady = new ReactiveVar(false);
|
||||
|
|
@ -15,15 +15,15 @@ BlazeComponent.extendComponent({
|
|||
// XXX The boardId should be readed from some sort the component "props",
|
||||
// unfortunatly, Blaze doesn't have this notion.
|
||||
this.autorun(() => {
|
||||
let currentBoardId = Session.get('currentBoard');
|
||||
if (! currentBoardId)
|
||||
const currentBoardId = Session.get('currentBoard');
|
||||
if (!currentBoardId)
|
||||
return;
|
||||
var handle = subManager.subscribe('board', currentBoardId);
|
||||
const handle = subManager.subscribe('board', currentBoardId);
|
||||
Tracker.nonreactive(() => {
|
||||
Tracker.autorun(() => {
|
||||
this.isBoardReady.set(handle.ready());
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
this._isDragging = false;
|
||||
|
|
@ -33,52 +33,52 @@ BlazeComponent.extendComponent({
|
|||
this.mouseHasEnterCardDetails = false;
|
||||
},
|
||||
|
||||
openNewListForm: function() {
|
||||
openNewListForm() {
|
||||
this.componentChildren('addListForm')[0].open();
|
||||
},
|
||||
|
||||
// XXX Flow components allow us to avoid creating these two setter methods by
|
||||
// exposing a public API to modify the component state. We need to investigate
|
||||
// best practices here.
|
||||
setIsDragging: function(bool) {
|
||||
setIsDragging(bool) {
|
||||
this.draggingActive.set(bool);
|
||||
},
|
||||
|
||||
scrollLeft: function(position = 0) {
|
||||
scrollLeft(position = 0) {
|
||||
this.$('.js-lists').animate({
|
||||
scrollLeft: position
|
||||
scrollLeft: position,
|
||||
});
|
||||
},
|
||||
|
||||
currentCardIsInThisList: function() {
|
||||
var currentCard = Cards.findOne(Session.get('currentCard'));
|
||||
var listId = this.currentData()._id;
|
||||
currentCardIsInThisList() {
|
||||
const currentCard = Cards.findOne(Session.get('currentCard'));
|
||||
const listId = this.currentData()._id;
|
||||
return currentCard && currentCard.listId === listId;
|
||||
},
|
||||
|
||||
events: function() {
|
||||
events() {
|
||||
return [{
|
||||
// XXX The board-overlay div should probably be moved to the parent
|
||||
// component.
|
||||
'mouseenter .board-overlay': function() {
|
||||
'mouseenter .board-overlay'() {
|
||||
if (this.mouseHasEnterCardDetails) {
|
||||
this.showOverlay.set(false);
|
||||
}
|
||||
},
|
||||
|
||||
// Click-and-drag action
|
||||
'mousedown .board-canvas': function(evt) {
|
||||
'mousedown .board-canvas'(evt) {
|
||||
if ($(evt.target).closest('a,.js-list-header').length === 0) {
|
||||
this._isDragging = true;
|
||||
this._lastDragPositionX = evt.clientX;
|
||||
}
|
||||
},
|
||||
'mouseup': function(evt) {
|
||||
'mouseup'() {
|
||||
if (this._isDragging) {
|
||||
this._isDragging = false;
|
||||
}
|
||||
},
|
||||
'mousemove': function(evt) {
|
||||
'mousemove'(evt) {
|
||||
if (this._isDragging) {
|
||||
// Update the canvas position
|
||||
this.listsDom.scrollLeft -= evt.clientX - this._lastDragPositionX;
|
||||
|
|
@ -91,40 +91,40 @@ BlazeComponent.extendComponent({
|
|||
EscapeActions.executeUpTo('popup-close');
|
||||
EscapeActions.preventNextClick();
|
||||
}
|
||||
}
|
||||
},
|
||||
}];
|
||||
}
|
||||
},
|
||||
}).register('board');
|
||||
|
||||
Template.boardBody.onRendered(function() {
|
||||
var self = BlazeComponent.getComponentForElement(this.firstNode);
|
||||
const self = BlazeComponent.getComponentForElement(this.firstNode);
|
||||
|
||||
self.listsDom = this.find('.js-lists');
|
||||
|
||||
if (! Session.get('currentCard')) {
|
||||
if (!Session.get('currentCard')) {
|
||||
self.scrollLeft();
|
||||
}
|
||||
|
||||
// We want to animate the card details window closing. We rely on CSS
|
||||
// transition for the actual animation.
|
||||
self.listsDom._uihooks = {
|
||||
removeElement: function(node) {
|
||||
var removeNode = _.once(function() {
|
||||
removeElement(node) {
|
||||
const removeNode = _.once(() => {
|
||||
node.parentNode.removeChild(node);
|
||||
});
|
||||
if ($(node).hasClass('js-card-details')) {
|
||||
$(node).css({
|
||||
flexBasis: 0,
|
||||
padding: 0
|
||||
padding: 0,
|
||||
});
|
||||
$(self.listsDom).one(CSSEvents.transitionend, removeNode);
|
||||
} else {
|
||||
removeNode();
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
if (! Meteor.user() || ! Meteor.user().isBoardMember())
|
||||
if (!Meteor.user() || !Meteor.user().isBoardMember())
|
||||
return;
|
||||
|
||||
self.$(self.listsDom).sortable({
|
||||
|
|
@ -134,63 +134,63 @@ Template.boardBody.onRendered(function() {
|
|||
items: '.js-list:not(.js-list-composer)',
|
||||
placeholder: 'list placeholder',
|
||||
distance: 7,
|
||||
start: function(evt, ui) {
|
||||
start(evt, ui) {
|
||||
ui.placeholder.height(ui.helper.height());
|
||||
Popup.close();
|
||||
},
|
||||
stop: function() {
|
||||
stop() {
|
||||
self.$('.js-lists').find('.js-list:not(.js-list-composer)').each(
|
||||
function(i, list) {
|
||||
var data = Blaze.getData(list);
|
||||
(i, list) => {
|
||||
const data = Blaze.getData(list);
|
||||
Lists.update(data._id, {
|
||||
$set: {
|
||||
sort: i
|
||||
}
|
||||
sort: i,
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// Disable drag-dropping while in multi-selection mode
|
||||
self.autorun(function() {
|
||||
self.autorun(() => {
|
||||
self.$(self.listsDom).sortable('option', 'disabled',
|
||||
MultiSelection.isActive());
|
||||
});
|
||||
|
||||
// If there is no data in the board (ie, no lists) we autofocus the list
|
||||
// creation form by clicking on the corresponding element.
|
||||
var currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
if (currentBoard.lists().count() === 0) {
|
||||
self.openNewListForm();
|
||||
}
|
||||
});
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
template: function() {
|
||||
template() {
|
||||
return 'addListForm';
|
||||
},
|
||||
|
||||
// Proxy
|
||||
open: function() {
|
||||
open() {
|
||||
this.componentChildren('inlinedForm')[0].open();
|
||||
},
|
||||
|
||||
events: function() {
|
||||
events() {
|
||||
return [{
|
||||
submit: function(evt) {
|
||||
submit(evt) {
|
||||
evt.preventDefault();
|
||||
var title = this.find('.list-name-input');
|
||||
const title = this.find('.list-name-input');
|
||||
if ($.trim(title.value)) {
|
||||
Lists.insert({
|
||||
title: title.value,
|
||||
boardId: Session.get('currentBoard'),
|
||||
sort: $('.list').length
|
||||
sort: $('.list').length,
|
||||
});
|
||||
|
||||
title.value = '';
|
||||
}
|
||||
}
|
||||
},
|
||||
}];
|
||||
}
|
||||
},
|
||||
}).register('addListForm');
|
||||
|
|
|
|||
|
|
@ -1,143 +1,143 @@
|
|||
Template.boardMenuPopup.events({
|
||||
'click .js-rename-board': Popup.open('boardChangeTitle'),
|
||||
'click .js-open-archives': function() {
|
||||
'click .js-open-archives'() {
|
||||
Sidebar.setView('archives');
|
||||
Popup.close();
|
||||
},
|
||||
'click .js-change-board-color': Popup.open('boardChangeColor'),
|
||||
'click .js-change-language': Popup.open('changeLanguage'),
|
||||
'click .js-archive-board ': Popup.afterConfirm('archiveBoard', function() {
|
||||
var boardId = Session.get('currentBoard');
|
||||
'click .js-archive-board ': Popup.afterConfirm('archiveBoard', () => {
|
||||
const boardId = Session.get('currentBoard');
|
||||
Boards.update(boardId, { $set: { archived: true }});
|
||||
// XXX We should have some kind of notification on top of the page to
|
||||
// confirm that the board was successfully archived.
|
||||
FlowRouter.go('home');
|
||||
})
|
||||
}),
|
||||
});
|
||||
|
||||
Template.boardChangeTitlePopup.events({
|
||||
submit: function(evt, t) {
|
||||
var title = t.$('.js-board-name').val().trim();
|
||||
submit(evt, tpl) {
|
||||
const title = tpl.$('.js-board-name').val().trim();
|
||||
if (title) {
|
||||
Boards.update(this._id, {
|
||||
$set: {
|
||||
title: title
|
||||
}
|
||||
title,
|
||||
},
|
||||
});
|
||||
Popup.close();
|
||||
}
|
||||
evt.preventDefault();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
template: function() {
|
||||
template() {
|
||||
return 'headerBoard';
|
||||
},
|
||||
|
||||
isStarred: function() {
|
||||
var boardId = Session.get('currentBoard');
|
||||
var user = Meteor.user();
|
||||
isStarred() {
|
||||
const boardId = Session.get('currentBoard');
|
||||
const user = Meteor.user();
|
||||
return user && user.hasStarred(boardId);
|
||||
},
|
||||
|
||||
// Only show the star counter if the number of star is greater than 2
|
||||
showStarCounter: function() {
|
||||
var currentBoard = this.currentData();
|
||||
showStarCounter() {
|
||||
const currentBoard = this.currentData();
|
||||
return currentBoard && currentBoard.stars >= 2;
|
||||
},
|
||||
|
||||
events: function() {
|
||||
events() {
|
||||
return [{
|
||||
'click .js-edit-board-title': Popup.open('boardChangeTitle'),
|
||||
'click .js-star-board': function() {
|
||||
'click .js-star-board'() {
|
||||
Meteor.user().toggleBoardStar(Session.get('currentBoard'));
|
||||
},
|
||||
'click .js-open-board-menu': Popup.open('boardMenu'),
|
||||
'click .js-change-visibility': Popup.open('boardChangeVisibility'),
|
||||
'click .js-open-filter-view': function() {
|
||||
'click .js-open-filter-view'() {
|
||||
Sidebar.setView('filter');
|
||||
},
|
||||
'click .js-filter-reset': function(evt) {
|
||||
'click .js-filter-reset'(evt) {
|
||||
evt.stopPropagation();
|
||||
Sidebar.setView();
|
||||
Filter.reset();
|
||||
},
|
||||
'click .js-multiselection-activate': function() {
|
||||
var currentCard = Session.get('currentCard');
|
||||
'click .js-multiselection-activate'() {
|
||||
const currentCard = Session.get('currentCard');
|
||||
MultiSelection.activate();
|
||||
if (currentCard) {
|
||||
MultiSelection.add(currentCard);
|
||||
}
|
||||
},
|
||||
'click .js-multiselection-reset': function(evt) {
|
||||
'click .js-multiselection-reset'(evt) {
|
||||
evt.stopPropagation();
|
||||
MultiSelection.disable();
|
||||
}
|
||||
},
|
||||
}];
|
||||
}
|
||||
},
|
||||
}).register('headerBoard');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
template: function() {
|
||||
template() {
|
||||
return 'boardChangeColorPopup';
|
||||
},
|
||||
|
||||
backgroundColors: function() {
|
||||
backgroundColors() {
|
||||
return Boards.simpleSchema()._schema.color.allowedValues;
|
||||
},
|
||||
|
||||
isSelected: function() {
|
||||
var currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
isSelected() {
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
return currentBoard.color === this.currentData().toString();
|
||||
},
|
||||
|
||||
events: function() {
|
||||
events() {
|
||||
return [{
|
||||
'click .js-select-background': function(evt) {
|
||||
var currentBoardId = Session.get('currentBoard');
|
||||
'click .js-select-background'(evt) {
|
||||
const currentBoardId = Session.get('currentBoard');
|
||||
Boards.update(currentBoardId, {
|
||||
$set: {
|
||||
color: this.currentData().toString()
|
||||
}
|
||||
color: this.currentData().toString(),
|
||||
},
|
||||
});
|
||||
evt.preventDefault();
|
||||
}
|
||||
},
|
||||
}];
|
||||
}
|
||||
},
|
||||
}).register('boardChangeColorPopup');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
template: function() {
|
||||
template() {
|
||||
return 'createBoardPopup';
|
||||
},
|
||||
|
||||
onCreated: function() {
|
||||
onCreated() {
|
||||
this.visibilityMenuIsOpen = new ReactiveVar(false);
|
||||
this.visibility = new ReactiveVar('private');
|
||||
},
|
||||
|
||||
visibilityCheck: function() {
|
||||
visibilityCheck() {
|
||||
return this.currentData() === this.visibility.get();
|
||||
},
|
||||
|
||||
setVisibility: function(visibility) {
|
||||
setVisibility(visibility) {
|
||||
this.visibility.set(visibility);
|
||||
this.visibilityMenuIsOpen.set(false);
|
||||
},
|
||||
|
||||
toogleVisibilityMenu: function() {
|
||||
this.visibilityMenuIsOpen.set(! this.visibilityMenuIsOpen.get());
|
||||
toogleVisibilityMenu() {
|
||||
this.visibilityMenuIsOpen.set(!this.visibilityMenuIsOpen.get());
|
||||
},
|
||||
|
||||
onSubmit: function(evt) {
|
||||
onSubmit(evt) {
|
||||
evt.preventDefault();
|
||||
var title = this.find('.js-new-board-title').value;
|
||||
var visibility = this.visibility.get();
|
||||
const title = this.find('.js-new-board-title').value;
|
||||
const visibility = this.visibility.get();
|
||||
|
||||
var boardId = Boards.insert({
|
||||
title: title,
|
||||
permission: visibility
|
||||
const boardId = Boards.insert({
|
||||
title,
|
||||
permission: visibility,
|
||||
});
|
||||
|
||||
Utils.goBoardId(boardId);
|
||||
|
|
@ -146,39 +146,39 @@ BlazeComponent.extendComponent({
|
|||
Meteor.user().toggleBoardStar(boardId);
|
||||
},
|
||||
|
||||
events: function() {
|
||||
events() {
|
||||
return [{
|
||||
'click .js-select-visibility': function() {
|
||||
'click .js-select-visibility'() {
|
||||
this.setVisibility(this.currentData());
|
||||
},
|
||||
'click .js-change-visibility': this.toogleVisibilityMenu,
|
||||
submit: this.onSubmit
|
||||
submit: this.onSubmit,
|
||||
}];
|
||||
}
|
||||
},
|
||||
}).register('createBoardPopup');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
template: function() {
|
||||
template() {
|
||||
return 'boardChangeVisibilityPopup';
|
||||
},
|
||||
|
||||
visibilityCheck: function() {
|
||||
var currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
visibilityCheck() {
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
return this.currentData() === currentBoard.permission;
|
||||
},
|
||||
|
||||
selectBoardVisibility: function() {
|
||||
selectBoardVisibility() {
|
||||
Boards.update(Session.get('currentBoard'), {
|
||||
$set: {
|
||||
permission: this.currentData()
|
||||
}
|
||||
permission: this.currentData(),
|
||||
},
|
||||
});
|
||||
Popup.close();
|
||||
},
|
||||
|
||||
events: function() {
|
||||
events() {
|
||||
return [{
|
||||
'click .js-select-visibility': this.selectBoardVisibility
|
||||
'click .js-select-visibility': this.selectBoardVisibility,
|
||||
}];
|
||||
}
|
||||
},
|
||||
}).register('boardChangeVisibilityPopup');
|
||||
|
|
|
|||
|
|
@ -1,30 +1,30 @@
|
|||
BlazeComponent.extendComponent({
|
||||
template: function() {
|
||||
template() {
|
||||
return 'boardList';
|
||||
},
|
||||
|
||||
boards: function() {
|
||||
boards() {
|
||||
return Boards.find({
|
||||
archived: false,
|
||||
'members.userId': Meteor.userId()
|
||||
'members.userId': Meteor.userId(),
|
||||
}, {
|
||||
sort: ['title']
|
||||
sort: ['title'],
|
||||
});
|
||||
},
|
||||
|
||||
isStarred: function() {
|
||||
var user = Meteor.user();
|
||||
isStarred() {
|
||||
const user = Meteor.user();
|
||||
return user && user.hasStarred(this.currentData()._id);
|
||||
},
|
||||
|
||||
events: function() {
|
||||
events() {
|
||||
return [{
|
||||
'click .js-add-board': Popup.open('createBoard'),
|
||||
'click .js-star-board': function(evt) {
|
||||
var boardId = this.currentData()._id;
|
||||
'click .js-star-board'(evt) {
|
||||
const boardId = this.currentData()._id;
|
||||
Meteor.user().toggleBoardStar(boardId);
|
||||
evt.preventDefault();
|
||||
}
|
||||
},
|
||||
}];
|
||||
}
|
||||
},
|
||||
}).register('boardList');
|
||||
|
|
|
|||
|
|
@ -1,32 +1,32 @@
|
|||
Template.attachmentsGalery.events({
|
||||
'click .js-add-attachment': Popup.open('cardAttachments'),
|
||||
'click .js-confirm-delete': Popup.afterConfirm('attachmentDelete',
|
||||
function() {
|
||||
() => {
|
||||
Attachments.remove(this._id);
|
||||
Popup.close();
|
||||
}
|
||||
),
|
||||
// If we let this event bubble, FlowRouter will handle it and empty the page
|
||||
// content, see #101.
|
||||
'click .js-download': function(event) {
|
||||
'click .js-download'(event) {
|
||||
event.stopPropagation();
|
||||
},
|
||||
'click .js-open-viewer': function() {
|
||||
'click .js-open-viewer'() {
|
||||
// XXX Not implemented!
|
||||
},
|
||||
'click .js-add-cover': function() {
|
||||
'click .js-add-cover'() {
|
||||
Cards.update(this.cardId, { $set: { coverId: this._id } });
|
||||
},
|
||||
'click .js-remove-cover': function() {
|
||||
'click .js-remove-cover'() {
|
||||
Cards.update(this.cardId, { $unset: { coverId: '' } });
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Template.cardAttachmentsPopup.events({
|
||||
'change .js-attach-file': function(evt) {
|
||||
var card = this;
|
||||
FS.Utility.eachFile(evt, function(f) {
|
||||
var file = new FS.File(f);
|
||||
'change .js-attach-file'(evt) {
|
||||
const card = this;
|
||||
FS.Utility.eachFile(evt, (f) => {
|
||||
const file = new FS.File(f);
|
||||
file.boardId = card.boardId;
|
||||
file.cardId = card._id;
|
||||
|
||||
|
|
@ -34,8 +34,8 @@ Template.cardAttachmentsPopup.events({
|
|||
Popup.close();
|
||||
});
|
||||
},
|
||||
'click .js-computer-upload': function(evt, tpl) {
|
||||
'click .js-computer-upload'(evt, tpl) {
|
||||
tpl.find('.js-attach-file').click();
|
||||
evt.preventDefault();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,39 +1,39 @@
|
|||
BlazeComponent.extendComponent({
|
||||
template: function() {
|
||||
template() {
|
||||
return 'cardDetails';
|
||||
},
|
||||
|
||||
mixins: function() {
|
||||
mixins() {
|
||||
return [Mixins.InfiniteScrolling, Mixins.PerfectScrollbar];
|
||||
},
|
||||
|
||||
calculateNextPeak: function() {
|
||||
var altitude = this.find('.js-card-details').scrollHeight;
|
||||
calculateNextPeak() {
|
||||
const altitude = this.find('.js-card-details').scrollHeight;
|
||||
this.callFirstWith(this, 'setNextPeak', altitude);
|
||||
},
|
||||
|
||||
reachNextPeak: function() {
|
||||
var activitiesComponent = this.componentChildren('activities')[0];
|
||||
reachNextPeak() {
|
||||
const activitiesComponent = this.componentChildren('activities')[0];
|
||||
activitiesComponent.loadNextPage();
|
||||
},
|
||||
|
||||
onCreated: function() {
|
||||
onCreated() {
|
||||
this.isLoaded = new ReactiveVar(false);
|
||||
this.componentParent().showOverlay.set(true);
|
||||
this.componentParent().mouseHasEnterCardDetails = false;
|
||||
},
|
||||
|
||||
scrollParentContainer: function() {
|
||||
scrollParentContainer() {
|
||||
const cardPanelWidth = 510;
|
||||
let bodyBoardComponent = this.componentParent();
|
||||
const bodyBoardComponent = this.componentParent();
|
||||
|
||||
let $cardContainer = bodyBoardComponent.$('.js-lists');
|
||||
let $cardView = this.$(this.firstNode());
|
||||
let cardContainerScroll = $cardContainer.scrollLeft();
|
||||
let cardContainerWidth = $cardContainer.width();
|
||||
const $cardContainer = bodyBoardComponent.$('.js-lists');
|
||||
const $cardView = this.$(this.firstNode());
|
||||
const cardContainerScroll = $cardContainer.scrollLeft();
|
||||
const cardContainerWidth = $cardContainer.width();
|
||||
|
||||
let cardViewStart = $cardView.offset().left;
|
||||
let cardViewEnd = cardViewStart + cardPanelWidth;
|
||||
const cardViewStart = $cardView.offset().left;
|
||||
const cardViewEnd = cardViewStart + cardPanelWidth;
|
||||
|
||||
let offset = false;
|
||||
if (cardViewStart < 0) {
|
||||
|
|
@ -47,53 +47,53 @@ BlazeComponent.extendComponent({
|
|||
}
|
||||
},
|
||||
|
||||
onRendered: function() {
|
||||
onRendered() {
|
||||
this.scrollParentContainer();
|
||||
},
|
||||
|
||||
onDestroyed: function() {
|
||||
onDestroyed() {
|
||||
this.componentParent().showOverlay.set(false);
|
||||
},
|
||||
|
||||
updateCard: function(modifier) {
|
||||
updateCard(modifier) {
|
||||
Cards.update(this.data()._id, {
|
||||
$set: modifier
|
||||
$set: modifier,
|
||||
});
|
||||
},
|
||||
|
||||
events: function() {
|
||||
var events = {
|
||||
[CSSEvents.animationend + ' .js-card-details']: function() {
|
||||
events() {
|
||||
const events = {
|
||||
[`${CSSEvents.animationend} .js-card-details`]() {
|
||||
this.isLoaded.set(true);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
return [_.extend(events, {
|
||||
'click .js-close-card-details': function() {
|
||||
'click .js-close-card-details'() {
|
||||
Utils.goBoardId(this.data().boardId);
|
||||
},
|
||||
'click .js-open-card-details-menu': Popup.open('cardDetailsActions'),
|
||||
'submit .js-card-description': function(evt) {
|
||||
'submit .js-card-description'(evt) {
|
||||
evt.preventDefault();
|
||||
var description = this.currentComponent().getValue();
|
||||
this.updateCard({ description: description });
|
||||
const description = this.currentComponent().getValue();
|
||||
this.updateCard({ description });
|
||||
},
|
||||
'submit .js-card-details-title': function(evt) {
|
||||
'submit .js-card-details-title'(evt) {
|
||||
evt.preventDefault();
|
||||
var title = this.currentComponent().getValue();
|
||||
const title = this.currentComponent().getValue();
|
||||
if ($.trim(title)) {
|
||||
this.updateCard({ title: title });
|
||||
this.updateCard({ title });
|
||||
}
|
||||
},
|
||||
'click .js-member': Popup.open('cardMember'),
|
||||
'click .js-add-members': Popup.open('cardMembers'),
|
||||
'click .js-add-labels': Popup.open('cardLabels'),
|
||||
'mouseenter .js-card-details': function() {
|
||||
'mouseenter .js-card-details'() {
|
||||
this.componentParent().showOverlay.set(true);
|
||||
this.componentParent().mouseHasEnterCardDetails = true;
|
||||
}
|
||||
},
|
||||
})];
|
||||
}
|
||||
},
|
||||
}).register('cardDetails');
|
||||
|
||||
// We extends the normal InlinedForm component to support UnsavedEdits draft
|
||||
|
|
@ -103,12 +103,12 @@ BlazeComponent.extendComponent({
|
|||
return {
|
||||
fieldName: 'cardDescription',
|
||||
docId: Session.get('currentCard'),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
close(isReset = false) {
|
||||
if (this.isOpen.get() && ! isReset) {
|
||||
let draft = $.trim(this.getValue());
|
||||
if (this.isOpen.get() && !isReset) {
|
||||
const draft = $.trim(this.getValue());
|
||||
if (draft !== Cards.findOne(Session.get('currentCard')).description) {
|
||||
UnsavedEdits.set(this._getUnsavedEditKey(), this.getValue());
|
||||
}
|
||||
|
|
@ -136,45 +136,45 @@ Template.cardDetailsActionsPopup.events({
|
|||
'click .js-attachments': Popup.open('cardAttachments'),
|
||||
'click .js-move-card': Popup.open('moveCard'),
|
||||
// 'click .js-copy': Popup.open(),
|
||||
'click .js-archive': function(evt) {
|
||||
'click .js-archive'(evt) {
|
||||
evt.preventDefault();
|
||||
Cards.update(this._id, {
|
||||
$set: {
|
||||
archived: true
|
||||
}
|
||||
archived: true,
|
||||
},
|
||||
});
|
||||
Popup.close();
|
||||
},
|
||||
'click .js-more': Popup.open('cardMore')
|
||||
'click .js-more': Popup.open('cardMore'),
|
||||
});
|
||||
|
||||
Template.moveCardPopup.events({
|
||||
'click .js-select-list': function() {
|
||||
'click .js-select-list'() {
|
||||
// XXX We should *not* get the currentCard from the global state, but
|
||||
// instead from a “component” state.
|
||||
var cardId = Session.get('currentCard');
|
||||
var newListId = this._id;
|
||||
const cardId = Session.get('currentCard');
|
||||
const newListId = this._id;
|
||||
Cards.update(cardId, {
|
||||
$set: {
|
||||
listId: newListId
|
||||
}
|
||||
listId: newListId,
|
||||
},
|
||||
});
|
||||
Popup.close();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Template.cardMorePopup.events({
|
||||
'click .js-delete': Popup.afterConfirm('cardDelete', function() {
|
||||
'click .js-delete': Popup.afterConfirm('cardDelete', () => {
|
||||
Popup.close();
|
||||
Cards.remove(this._id);
|
||||
Utils.goBoardId(this.board()._id);
|
||||
})
|
||||
}),
|
||||
});
|
||||
|
||||
// Close the card details pane by pressing escape
|
||||
EscapeActions.register('detailsPane',
|
||||
function() { Utils.goBoardId(Session.get('currentBoard')); },
|
||||
function() { return ! Session.equals('currentCard', null); }, {
|
||||
noClickEscapeOn: '.js-card-details,.board-sidebar,#header'
|
||||
() => { Utils.goBoardId(Session.get('currentBoard')); },
|
||||
() => { return !Session.equals('currentCard', null); }, {
|
||||
noClickEscapeOn: '.js-card-details,.board-sidebar,#header',
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,136 +1,136 @@
|
|||
|
||||
var labelColors;
|
||||
Meteor.startup(function() {
|
||||
let labelColors;
|
||||
Meteor.startup(() => {
|
||||
labelColors = Boards.simpleSchema()._schema['labels.$.color'].allowedValues;
|
||||
});
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
template: function() {
|
||||
template() {
|
||||
return 'formLabel';
|
||||
},
|
||||
|
||||
onCreated: function() {
|
||||
onCreated() {
|
||||
this.currentColor = new ReactiveVar(this.data().color);
|
||||
},
|
||||
|
||||
labels: function() {
|
||||
return _.map(labelColors, function(color) {
|
||||
return { color: color, name: '' };
|
||||
labels() {
|
||||
return _.map(labelColors, (color) => {
|
||||
return { color, name: '' };
|
||||
});
|
||||
},
|
||||
|
||||
isSelected: function(color) {
|
||||
isSelected(color) {
|
||||
return this.currentColor.get() === color;
|
||||
},
|
||||
|
||||
events: function() {
|
||||
events() {
|
||||
return [{
|
||||
'click .js-palette-color': function() {
|
||||
'click .js-palette-color'() {
|
||||
this.currentColor.set(this.currentData().color);
|
||||
}
|
||||
},
|
||||
}];
|
||||
}
|
||||
},
|
||||
}).register('formLabel');
|
||||
|
||||
Template.createLabelPopup.helpers({
|
||||
// This is the default color for a new label. We search the first color that
|
||||
// is not already used in the board (although it's not a problem if two
|
||||
// labels have the same color).
|
||||
defaultColor: function() {
|
||||
var labels = Boards.findOne(Session.get('currentBoard')).labels;
|
||||
var usedColors = _.pluck(labels, 'color');
|
||||
var availableColors = _.difference(labelColors, usedColors);
|
||||
defaultColor() {
|
||||
const labels = Boards.findOne(Session.get('currentBoard')).labels;
|
||||
const usedColors = _.pluck(labels, 'color');
|
||||
const availableColors = _.difference(labelColors, usedColors);
|
||||
return availableColors.length > 1 ? availableColors[0] : labelColors[0];
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Template.cardLabelsPopup.events({
|
||||
'click .js-select-label': function(evt) {
|
||||
var cardId = Template.parentData(2).data._id;
|
||||
var labelId = this._id;
|
||||
var operation;
|
||||
'click .js-select-label'(evt) {
|
||||
const cardId = Template.parentData(2).data._id;
|
||||
const labelId = this._id;
|
||||
let operation;
|
||||
if (Cards.find({ _id: cardId, labelIds: labelId}).count() === 0)
|
||||
operation = '$addToSet';
|
||||
else
|
||||
operation = '$pull';
|
||||
|
||||
var query = {};
|
||||
query[operation] = {
|
||||
labelIds: labelId
|
||||
};
|
||||
Cards.update(cardId, query);
|
||||
Cards.update(cardId, {
|
||||
[operation]: {
|
||||
labelIds: labelId,
|
||||
},
|
||||
});
|
||||
evt.preventDefault();
|
||||
},
|
||||
'click .js-edit-label': Popup.open('editLabel'),
|
||||
'click .js-add-label': Popup.open('createLabel')
|
||||
'click .js-add-label': Popup.open('createLabel'),
|
||||
});
|
||||
|
||||
Template.formLabel.events({
|
||||
'click .js-palette-color': function(evt) {
|
||||
var $this = $(evt.currentTarget);
|
||||
'click .js-palette-color'(evt) {
|
||||
const $this = $(evt.currentTarget);
|
||||
|
||||
// hide selected ll colors
|
||||
$('.js-palette-select').addClass('hide');
|
||||
|
||||
// show select color
|
||||
$this.find('.js-palette-select').removeClass('hide');
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Template.createLabelPopup.events({
|
||||
// Create the new label
|
||||
'submit .create-label': function(evt, tpl) {
|
||||
var name = tpl.$('#labelName').val().trim();
|
||||
var boardId = Session.get('currentBoard');
|
||||
var color = Blaze.getData(tpl.find('.fa-check')).color;
|
||||
'submit .create-label'(evt, tpl) {
|
||||
const name = tpl.$('#labelName').val().trim();
|
||||
const boardId = Session.get('currentBoard');
|
||||
const color = Blaze.getData(tpl.find('.fa-check')).color;
|
||||
|
||||
Boards.update(boardId, {
|
||||
$push: {
|
||||
labels: {
|
||||
name,
|
||||
color,
|
||||
_id: Random.id(6),
|
||||
name: name,
|
||||
color: color
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Popup.back();
|
||||
evt.preventDefault();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Template.editLabelPopup.events({
|
||||
'click .js-delete-label': Popup.afterConfirm('deleteLabel', function() {
|
||||
var boardId = Session.get('currentBoard');
|
||||
const boardId = Session.get('currentBoard');
|
||||
Boards.update(boardId, {
|
||||
$pull: {
|
||||
labels: {
|
||||
_id: this._id
|
||||
}
|
||||
}
|
||||
_id: this._id,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Popup.back(2);
|
||||
}),
|
||||
'submit .edit-label': function(evt, tpl) {
|
||||
'submit .edit-label'(evt, tpl) {
|
||||
evt.preventDefault();
|
||||
var name = tpl.$('#labelName').val().trim();
|
||||
var boardId = Session.get('currentBoard');
|
||||
var getLabel = Utils.getLabelIndex(boardId, this._id);
|
||||
var color = Blaze.getData(tpl.find('.fa-check')).color;
|
||||
const name = tpl.$('#labelName').val().trim();
|
||||
const boardId = Session.get('currentBoard');
|
||||
const getLabel = Utils.getLabelIndex(boardId, this._id);
|
||||
const color = Blaze.getData(tpl.find('.fa-check')).color;
|
||||
|
||||
var $set = {};
|
||||
$set[getLabel.key('name')] = name;
|
||||
$set[getLabel.key('color')] = color;
|
||||
|
||||
Boards.update(boardId, { $set: $set });
|
||||
Boards.update(boardId, {
|
||||
$set: {
|
||||
[getLabel.key('name')]: name,
|
||||
[getLabel.key('color')]: color,
|
||||
},
|
||||
});
|
||||
|
||||
Popup.back();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Template.cardLabelsPopup.helpers({
|
||||
isLabelSelected: function(cardId) {
|
||||
isLabelSelected(cardId) {
|
||||
return _.contains(Cards.findOne(cardId).labelIds, this._id);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
// });
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
template: function() {
|
||||
template() {
|
||||
return 'minicard';
|
||||
}
|
||||
},
|
||||
}).register('minicard');
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
const { calculateIndex } = Utils;
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
template: function() {
|
||||
template() {
|
||||
return 'list';
|
||||
},
|
||||
|
||||
// Proxies
|
||||
openForm: function(options) {
|
||||
// Proxy
|
||||
openForm(options) {
|
||||
this.componentChildren('listBody')[0].openForm(options);
|
||||
},
|
||||
|
||||
onCreated: function() {
|
||||
onCreated() {
|
||||
this.newCardFormIsVisible = new ReactiveVar(true);
|
||||
},
|
||||
|
||||
|
|
@ -19,28 +21,27 @@ BlazeComponent.extendComponent({
|
|||
// By calling asking the sortable library to cancel its move on the `stop`
|
||||
// callback, we basically solve all issues related to reactive updates. A
|
||||
// comment below provides further details.
|
||||
onRendered: function() {
|
||||
var self = this;
|
||||
if (! Meteor.user() || ! Meteor.user().isBoardMember())
|
||||
onRendered() {
|
||||
if (!Meteor.user() || !Meteor.user().isBoardMember())
|
||||
return;
|
||||
|
||||
var boardComponent = self.componentParent();
|
||||
var itemsSelector = '.js-minicard:not(.placeholder, .js-card-composer)';
|
||||
var $cards = self.$('.js-minicards');
|
||||
const boardComponent = this.componentParent();
|
||||
const itemsSelector = '.js-minicard:not(.placeholder, .js-card-composer)';
|
||||
const $cards = this.$('.js-minicards');
|
||||
$cards.sortable({
|
||||
connectWith: '.js-minicards',
|
||||
tolerance: 'pointer',
|
||||
appendTo: 'body',
|
||||
helper: function(evt, item) {
|
||||
var helper = item.clone();
|
||||
helper(evt, item) {
|
||||
const helper = item.clone();
|
||||
if (MultiSelection.isActive()) {
|
||||
var andNOthers = $cards.find('.js-minicard.is-checked').length - 1;
|
||||
const andNOthers = $cards.find('.js-minicard.is-checked').length - 1;
|
||||
if (andNOthers > 0) {
|
||||
helper.append($(Blaze.toHTML(HTML.DIV(
|
||||
// XXX Super bad class name
|
||||
{'class': 'and-n-other'},
|
||||
// XXX Need to translate
|
||||
'and ' + andNOthers + ' other cards.'
|
||||
`and ${andNOthers} other cards.`
|
||||
))));
|
||||
}
|
||||
}
|
||||
|
|
@ -50,19 +51,19 @@ BlazeComponent.extendComponent({
|
|||
items: itemsSelector,
|
||||
scroll: false,
|
||||
placeholder: 'minicard-wrapper placeholder',
|
||||
start: function(evt, ui) {
|
||||
start(evt, ui) {
|
||||
ui.placeholder.height(ui.helper.height());
|
||||
EscapeActions.executeUpTo('popup');
|
||||
boardComponent.setIsDragging(true);
|
||||
},
|
||||
stop: function(evt, ui) {
|
||||
stop(evt, ui) {
|
||||
// To attribute the new index number, we need to get the DOM element
|
||||
// of the previous and the following card -- if any.
|
||||
var prevCardDom = ui.item.prev('.js-minicard').get(0);
|
||||
var nextCardDom = ui.item.next('.js-minicard').get(0);
|
||||
var nCards = MultiSelection.isActive() ? MultiSelection.count() : 1;
|
||||
var sortIndex = Utils.calculateIndex(prevCardDom, nextCardDom, nCards);
|
||||
var listId = Blaze.getData(ui.item.parents('.list').get(0))._id;
|
||||
const prevCardDom = ui.item.prev('.js-minicard').get(0);
|
||||
const nextCardDom = ui.item.next('.js-minicard').get(0);
|
||||
const nCards = MultiSelection.isActive() ? MultiSelection.count() : 1;
|
||||
const sortIndex = calculateIndex(prevCardDom, nextCardDom, nCards);
|
||||
const listId = Blaze.getData(ui.item.parents('.list').get(0))._id;
|
||||
|
||||
// Normally the jquery-ui sortable library moves the dragged DOM element
|
||||
// to its new position, which disrupts Blaze reactive updates mechanism
|
||||
|
|
@ -74,53 +75,53 @@ BlazeComponent.extendComponent({
|
|||
$cards.sortable('cancel');
|
||||
|
||||
if (MultiSelection.isActive()) {
|
||||
Cards.find(MultiSelection.getMongoSelector()).forEach(function(c, i) {
|
||||
Cards.find(MultiSelection.getMongoSelector()).forEach((c, i) => {
|
||||
Cards.update(c._id, {
|
||||
$set: {
|
||||
listId: listId,
|
||||
sort: sortIndex.base + i * sortIndex.increment
|
||||
}
|
||||
listId,
|
||||
sort: sortIndex.base + i * sortIndex.increment,
|
||||
},
|
||||
});
|
||||
});
|
||||
} else {
|
||||
var cardDomElement = ui.item.get(0);
|
||||
var cardId = Blaze.getData(cardDomElement)._id;
|
||||
const cardDomElement = ui.item.get(0);
|
||||
const cardId = Blaze.getData(cardDomElement)._id;
|
||||
Cards.update(cardId, {
|
||||
$set: {
|
||||
listId: listId,
|
||||
sort: sortIndex.base
|
||||
}
|
||||
listId,
|
||||
sort: sortIndex.base,
|
||||
},
|
||||
});
|
||||
}
|
||||
boardComponent.setIsDragging(false);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// We want to re-run this function any time a card is added.
|
||||
self.autorun(function() {
|
||||
var currentBoardId = Tracker.nonreactive(function() {
|
||||
this.autorun(() => {
|
||||
const currentBoardId = Tracker.nonreactive(() => {
|
||||
return Session.get('currentBoard');
|
||||
});
|
||||
Cards.find({ boardId: currentBoardId }).fetch();
|
||||
Tracker.afterFlush(function() {
|
||||
Tracker.afterFlush(() => {
|
||||
$cards.find(itemsSelector).droppable({
|
||||
hoverClass: 'draggable-hover-card',
|
||||
accept: '.js-member,.js-label',
|
||||
drop: function(event, ui) {
|
||||
var cardId = Blaze.getData(this)._id;
|
||||
var addToSet;
|
||||
drop(event, ui) {
|
||||
const cardId = Blaze.getData(this)._id;
|
||||
let addToSet;
|
||||
|
||||
if (ui.draggable.hasClass('js-member')) {
|
||||
var memberId = Blaze.getData(ui.draggable.get(0)).userId;
|
||||
const memberId = Blaze.getData(ui.draggable.get(0)).userId;
|
||||
addToSet = { members: memberId };
|
||||
} else {
|
||||
var labelId = Blaze.getData(ui.draggable.get(0))._id;
|
||||
const labelId = Blaze.getData(ui.draggable.get(0))._id;
|
||||
addToSet = { labelIds: labelId };
|
||||
}
|
||||
Cards.update(cardId, { $addToSet: addToSet });
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
}).register('list');
|
||||
|
|
|
|||
|
|
@ -1,46 +1,46 @@
|
|||
BlazeComponent.extendComponent({
|
||||
template: function() {
|
||||
template() {
|
||||
return 'listBody';
|
||||
},
|
||||
|
||||
mixins: function() {
|
||||
mixins() {
|
||||
return [Mixins.PerfectScrollbar];
|
||||
},
|
||||
|
||||
openForm: function(options) {
|
||||
openForm(options) {
|
||||
options = options || {};
|
||||
options.position = options.position || 'top';
|
||||
|
||||
var forms = this.componentChildren('inlinedForm');
|
||||
var form = _.find(forms, function(component) {
|
||||
const forms = this.componentChildren('inlinedForm');
|
||||
let form = _.find(forms, (component) => {
|
||||
return component.data().position === options.position;
|
||||
});
|
||||
if (! form && forms.length > 0) {
|
||||
if (!form && forms.length > 0) {
|
||||
form = forms[0];
|
||||
}
|
||||
form.open();
|
||||
},
|
||||
|
||||
addCard: function(evt) {
|
||||
addCard(evt) {
|
||||
evt.preventDefault();
|
||||
var textarea = $(evt.currentTarget).find('textarea');
|
||||
var title = textarea.val();
|
||||
var position = Blaze.getData(evt.currentTarget).position;
|
||||
var sortIndex;
|
||||
var firstCard = this.find('.js-minicard:first');
|
||||
var lastCard = this.find('.js-minicard:last');
|
||||
const firstCardDom = this.find('.js-minicard:first');
|
||||
const lastCardDom = this.find('.js-minicard:last');
|
||||
const textarea = $(evt.currentTarget).find('textarea');
|
||||
const title = textarea.val();
|
||||
const position = Blaze.getData(evt.currentTarget).position;
|
||||
let sortIndex;
|
||||
if (position === 'top') {
|
||||
sortIndex = Utils.calculateIndex(null, firstCard).base;
|
||||
sortIndex = Utils.calculateIndex(null, firstCardDom).base;
|
||||
} else if (position === 'bottom') {
|
||||
sortIndex = Utils.calculateIndex(lastCard, null).base;
|
||||
sortIndex = Utils.calculateIndex(lastCardDom, null).base;
|
||||
}
|
||||
|
||||
if ($.trim(title)) {
|
||||
var _id = Cards.insert({
|
||||
title: title,
|
||||
const _id = Cards.insert({
|
||||
title,
|
||||
listId: this.data()._id,
|
||||
boardId: this.data().board()._id,
|
||||
sort: sortIndex
|
||||
sort: sortIndex,
|
||||
});
|
||||
// In case the filter is active we need to add the newly inserted card in
|
||||
// the list of exceptions -- cards that are not filtered. Otherwise the
|
||||
|
|
@ -56,18 +56,18 @@ BlazeComponent.extendComponent({
|
|||
}
|
||||
},
|
||||
|
||||
scrollToBottom: function() {
|
||||
var container = this.firstNode();
|
||||
scrollToBottom() {
|
||||
const container = this.firstNode();
|
||||
$(container).animate({
|
||||
scrollTop: container.scrollHeight
|
||||
scrollTop: container.scrollHeight,
|
||||
});
|
||||
},
|
||||
|
||||
clickOnMiniCard: function(evt) {
|
||||
clickOnMiniCard(evt) {
|
||||
if (MultiSelection.isActive() || evt.shiftKey) {
|
||||
evt.stopImmediatePropagation();
|
||||
evt.preventDefault();
|
||||
var methodName = evt.shiftKey ? 'toogleRange' : 'toogle';
|
||||
const methodName = evt.shiftKey ? 'toogleRange' : 'toogle';
|
||||
MultiSelection[methodName](this.currentData()._id);
|
||||
|
||||
// If the card is already selected, we want to de-select it.
|
||||
|
|
@ -80,36 +80,36 @@ BlazeComponent.extendComponent({
|
|||
}
|
||||
},
|
||||
|
||||
cardIsSelected: function() {
|
||||
cardIsSelected() {
|
||||
return Session.equals('currentCard', this.currentData()._id);
|
||||
},
|
||||
|
||||
toggleMultiSelection: function(evt) {
|
||||
toggleMultiSelection(evt) {
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
MultiSelection.toogle(this.currentData()._id);
|
||||
},
|
||||
|
||||
events: function() {
|
||||
events() {
|
||||
return [{
|
||||
'click .js-minicard': this.clickOnMiniCard,
|
||||
'click .js-toggle-multi-selection': this.toggleMultiSelection,
|
||||
'click .open-minicard-composer': this.scrollToBottom,
|
||||
submit: this.addCard
|
||||
submit: this.addCard,
|
||||
}];
|
||||
}
|
||||
},
|
||||
}).register('listBody');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
template: function() {
|
||||
template() {
|
||||
return 'addCardForm';
|
||||
},
|
||||
|
||||
pressKey: function(evt) {
|
||||
pressKey(evt) {
|
||||
// Pressing Enter should submit the card
|
||||
if (evt.keyCode === 13) {
|
||||
evt.preventDefault();
|
||||
var $form = $(evt.currentTarget).closest('form');
|
||||
const $form = $(evt.currentTarget).closest('form');
|
||||
// XXX For some reason $form.submit() does not work (it's probably a bug
|
||||
// of blaze-component related to the fact that the submit event is non-
|
||||
// bubbling). This is why we click on the submit button instead -- which
|
||||
|
|
@ -120,24 +120,24 @@ BlazeComponent.extendComponent({
|
|||
// in the reverse order
|
||||
} else if (evt.keyCode === 9) {
|
||||
evt.preventDefault();
|
||||
var isReverse = evt.shiftKey;
|
||||
var list = $('#js-list-' + this.data().listId);
|
||||
var listSelector = '.js-list:not(.js-list-composer)';
|
||||
var nextList = list[isReverse ? 'prev' : 'next'](listSelector).get(0);
|
||||
const isReverse = evt.shiftKey;
|
||||
const list = $(`#js-list-${this.data().listId}`);
|
||||
const listSelector = '.js-list:not(.js-list-composer)';
|
||||
let nextList = list[isReverse ? 'prev' : 'next'](listSelector).get(0);
|
||||
// If there is no next list, loop back to the beginning.
|
||||
if (! nextList) {
|
||||
if (!nextList) {
|
||||
nextList = $(listSelector + (isReverse ? ':last' : ':first')).get(0);
|
||||
}
|
||||
|
||||
BlazeComponent.getComponentForElement(nextList).openForm({
|
||||
position:this.data().position
|
||||
position:this.data().position,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
events: function() {
|
||||
events() {
|
||||
return [{
|
||||
keydown: this.pressKey
|
||||
keydown: this.pressKey,
|
||||
}];
|
||||
}
|
||||
},
|
||||
}).register('addCardForm');
|
||||
|
|
|
|||
|
|
@ -1,78 +1,78 @@
|
|||
BlazeComponent.extendComponent({
|
||||
template: function() {
|
||||
template() {
|
||||
return 'listHeader';
|
||||
},
|
||||
|
||||
editTitle: function(evt) {
|
||||
editTitle(evt) {
|
||||
evt.preventDefault();
|
||||
var form = this.componentChildren('inlinedForm')[0];
|
||||
var newTitle = form.getValue();
|
||||
const form = this.componentChildren('inlinedForm')[0];
|
||||
const newTitle = form.getValue();
|
||||
if ($.trim(newTitle)) {
|
||||
Lists.update(this.currentData()._id, {
|
||||
$set: {
|
||||
title: newTitle
|
||||
}
|
||||
title: newTitle,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
events: function() {
|
||||
events() {
|
||||
return [{
|
||||
'click .js-open-list-menu': Popup.open('listAction'),
|
||||
submit: this.editTitle
|
||||
submit: this.editTitle,
|
||||
}];
|
||||
}
|
||||
},
|
||||
}).register('listHeader');
|
||||
|
||||
Template.listActionPopup.events({
|
||||
'click .js-add-card': function() {
|
||||
var listDom = document.getElementById('js-list-' + this._id);
|
||||
var listComponent = BlazeComponent.getComponentForElement(listDom);
|
||||
'click .js-add-card'() {
|
||||
const listDom = document.getElementById(`js-list-${this._id}`);
|
||||
const listComponent = BlazeComponent.getComponentForElement(listDom);
|
||||
listComponent.openForm({ position: 'top' });
|
||||
Popup.close();
|
||||
},
|
||||
'click .js-list-subscribe': function() {},
|
||||
'click .js-select-cards': function() {
|
||||
var cardIds = Cards.find(
|
||||
'click .js-list-subscribe'() {},
|
||||
'click .js-select-cards'() {
|
||||
const cardIds = Cards.find(
|
||||
{listId: this._id},
|
||||
{fields: { _id: 1 }}
|
||||
).map(function(card) { return card._id; });
|
||||
).map((card) => card._id);
|
||||
MultiSelection.add(cardIds);
|
||||
Popup.close();
|
||||
},
|
||||
'click .js-move-cards': Popup.open('listMoveCards'),
|
||||
'click .js-archive-cards': Popup.afterConfirm('listArchiveCards', function() {
|
||||
Cards.find({listId: this._id}).forEach(function(card) {
|
||||
'click .js-archive-cards': Popup.afterConfirm('listArchiveCards', () => {
|
||||
Cards.find({listId: this._id}).forEach((card) => {
|
||||
Cards.update(card._id, {
|
||||
$set: {
|
||||
archived: true
|
||||
}
|
||||
archived: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
Popup.close();
|
||||
}),
|
||||
'click .js-close-list': function(evt) {
|
||||
'click .js-close-list'(evt) {
|
||||
evt.preventDefault();
|
||||
Lists.update(this._id, {
|
||||
$set: {
|
||||
archived: true
|
||||
}
|
||||
archived: true,
|
||||
},
|
||||
});
|
||||
Popup.close();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Template.listMoveCardsPopup.events({
|
||||
'click .js-select-list': function() {
|
||||
var fromList = Template.parentData(2).data._id;
|
||||
var toList = this._id;
|
||||
Cards.find({listId: fromList}).forEach(function(card) {
|
||||
'click .js-select-list'() {
|
||||
const fromList = Template.parentData(2).data._id;
|
||||
const toList = this._id;
|
||||
Cards.find({ listId: fromList }).forEach((card) => {
|
||||
Cards.update(card._id, {
|
||||
$set: {
|
||||
listId: toList
|
||||
}
|
||||
listId: toList,
|
||||
},
|
||||
});
|
||||
});
|
||||
Popup.close();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
var dropdownMenuIsOpened = false;
|
||||
let dropdownMenuIsOpened = false;
|
||||
|
||||
Template.editor.onRendered(function() {
|
||||
var $textarea = this.$('textarea');
|
||||
Template.editor.onRendered(() => {
|
||||
const $textarea = this.$('textarea');
|
||||
|
||||
autosize($textarea);
|
||||
|
||||
|
|
@ -9,39 +9,40 @@ Template.editor.onRendered(function() {
|
|||
// Emojies
|
||||
{
|
||||
match: /\B:([\-+\w]*)$/,
|
||||
search: function(term, callback) {
|
||||
callback($.map(Emoji.values, function(emoji) {
|
||||
search(term, callback) {
|
||||
callback($.map(Emoji.values, (emoji) => {
|
||||
return emoji.indexOf(term) === 0 ? emoji : null;
|
||||
}));
|
||||
},
|
||||
template: function(value) {
|
||||
var image = '<img src="' + Emoji.baseImagePath + value + '.png"></img>';
|
||||
template(value) {
|
||||
const imgSrc = Emoji.baseImagePath + value;
|
||||
const image = `<img src="${imgSrc}.png" />`;
|
||||
return image + value;
|
||||
},
|
||||
replace: function(value) {
|
||||
return ':' + value + ':';
|
||||
replace(value) {
|
||||
return `:${value}:`;
|
||||
},
|
||||
index: 1
|
||||
index: 1,
|
||||
},
|
||||
|
||||
// User mentions
|
||||
{
|
||||
match: /\B@(\w*)$/,
|
||||
search: function(term, callback) {
|
||||
var currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
callback($.map(currentBoard.members, function(member) {
|
||||
var username = Users.findOne(member.userId).username;
|
||||
search(term, callback) {
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
callback($.map(currentBoard.members, (member) => {
|
||||
const username = Users.findOne(member.userId).username;
|
||||
return username.indexOf(term) === 0 ? username : null;
|
||||
}));
|
||||
},
|
||||
template: function(value) {
|
||||
template(value) {
|
||||
return value;
|
||||
},
|
||||
replace: function(username) {
|
||||
return '@' + username + ' ';
|
||||
replace(username) {
|
||||
return `@${username} `;
|
||||
},
|
||||
index: 1
|
||||
}
|
||||
index: 1,
|
||||
},
|
||||
]);
|
||||
|
||||
// Since commit d474017 jquery-textComplete automatically closes a potential
|
||||
|
|
@ -51,27 +52,27 @@ Template.editor.onRendered(function() {
|
|||
// 'open' and 'hide' events, and create a ghost escapeAction when the dropdown
|
||||
// is opened (and rely on textComplete to execute the actual action).
|
||||
$textarea.on({
|
||||
'textComplete:show': function() {
|
||||
'textComplete:show'() {
|
||||
dropdownMenuIsOpened = true;
|
||||
},
|
||||
'textComplete:hide': function() {
|
||||
Tracker.afterFlush(function() {
|
||||
'textComplete:hide'() {
|
||||
Tracker.afterFlush(() => {
|
||||
dropdownMenuIsOpened = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
EscapeActions.register('textcomplete',
|
||||
function() {},
|
||||
function() { return dropdownMenuIsOpened; }
|
||||
() => {},
|
||||
() => dropdownMenuIsOpened
|
||||
);
|
||||
|
||||
Template.viewer.events({
|
||||
// Viewer sometimes have click-able wrapper around them (for instance to edit
|
||||
// the corresponding text). Clicking a link shouldn't fire these actions, stop
|
||||
// we stop these event at the viewer component level.
|
||||
'click a': function(evt) {
|
||||
'click a'(evt) {
|
||||
evt.stopPropagation();
|
||||
|
||||
// XXX We hijack the build-in browser action because we currently don't have
|
||||
|
|
@ -79,7 +80,7 @@ Template.viewer.events({
|
|||
// handled by a third party package that we can't configure easily. Fix that
|
||||
// by using directly `_blank` attribute in the rendered HTML.
|
||||
evt.preventDefault();
|
||||
let href = evt.currentTarget.href;
|
||||
const href = evt.currentTarget.href;
|
||||
window.open(href, '_blank');
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
Template.header.helpers({
|
||||
// Reactively set the color of the page from the color of the current board.
|
||||
headerTemplate: function() {
|
||||
headerTemplate() {
|
||||
return 'headerBoard';
|
||||
},
|
||||
|
||||
wrappedHeader: function() {
|
||||
return ! Session.get('currentBoard');
|
||||
}
|
||||
wrappedHeader() {
|
||||
return !Session.get('currentBoard');
|
||||
},
|
||||
});
|
||||
|
||||
Template.header.events({
|
||||
'click .js-create-board': Popup.open('createBoard')
|
||||
'click .js-create-board': Popup.open('createBoard'),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,65 +0,0 @@
|
|||
var Helpers = {
|
||||
error: function() {
|
||||
return Session.get('error');
|
||||
},
|
||||
|
||||
toLowerCase: function(text) {
|
||||
return text && text.toLowerCase();
|
||||
},
|
||||
|
||||
toUpperCase: function(text) {
|
||||
return text && text.toUpperCase();
|
||||
},
|
||||
|
||||
firstChar: function(text) {
|
||||
return text && text[0].toUpperCase();
|
||||
},
|
||||
|
||||
session: function(prop) {
|
||||
return Session.get(prop);
|
||||
},
|
||||
|
||||
getUser: function(userId) {
|
||||
return Users.findOne(userId);
|
||||
}
|
||||
};
|
||||
|
||||
// Register all Helpers
|
||||
_.each(Helpers, function(fn, name) { Blaze.registerHelper(name, fn); });
|
||||
|
||||
// XXX I believe we should compute a HTML rendered field on the server that
|
||||
// would handle markdown, emojies and user mentions. We can simply have two
|
||||
// fields, one source, and one compiled version (in HTML) and send only the
|
||||
// compiled version to most users -- who don't need to edit.
|
||||
// In the meantime, all the transformation are done on the client using the
|
||||
// Blaze API.
|
||||
var at = HTML.CharRef({html: '@', str: '@'});
|
||||
Blaze.Template.registerHelper('mentions', new Template('mentions', function() {
|
||||
var view = this;
|
||||
var content = Blaze.toHTML(view.templateContentBlock);
|
||||
var currentBoard = Session.get('currentBoard');
|
||||
var knowedUsers = _.map(currentBoard.members, function(member) {
|
||||
member.username = Users.findOne(member.userId).username;
|
||||
return member;
|
||||
});
|
||||
|
||||
var mentionRegex = /\B@(\w*)/gi;
|
||||
var currentMention, knowedUser, href, linkClass, linkValue, link;
|
||||
while (!! (currentMention = mentionRegex.exec(content))) {
|
||||
|
||||
knowedUser = _.findWhere(knowedUsers, { username: currentMention[1] });
|
||||
if (! knowedUser)
|
||||
continue;
|
||||
|
||||
linkValue = [' ', at, knowedUser.username];
|
||||
href = Router.url('Profile', { username: knowedUser.username });
|
||||
linkClass = 'atMention';
|
||||
if (knowedUser.userId === Meteor.userId())
|
||||
linkClass += ' me';
|
||||
link = HTML.A({ href: href, 'class': linkClass }, linkValue);
|
||||
|
||||
content = content.replace(currentMention[0], Blaze.toHTML(link));
|
||||
}
|
||||
|
||||
return HTML.Raw(content);
|
||||
}));
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
Meteor.subscribe('boards')
|
||||
Meteor.subscribe('boards');
|
||||
|
||||
BlazeLayout.setRoot('body')
|
||||
BlazeLayout.setRoot('body');
|
||||
|
||||
Template.userFormsLayout.onRendered(function() {
|
||||
EscapeActions.executeAll()
|
||||
})
|
||||
Template.userFormsLayout.onRendered(() => {
|
||||
EscapeActions.executeAll();
|
||||
});
|
||||
|
||||
Template.defaultLayout.events({
|
||||
'click .js-close-modal': () => {
|
||||
Modal.close()
|
||||
}
|
||||
})
|
||||
Modal.close();
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
Popup.template.events({
|
||||
'click .js-back-view': function() {
|
||||
'click .js-back-view'() {
|
||||
Popup.back();
|
||||
},
|
||||
'click .js-close-pop-over': function() {
|
||||
'click .js-close-pop-over'() {
|
||||
Popup.close();
|
||||
},
|
||||
'click .js-confirm': function() {
|
||||
'click .js-confirm'() {
|
||||
this.__afterConfirmAction.call(this);
|
||||
},
|
||||
// This handler intends to solve a pretty tricky bug with our popup
|
||||
|
|
@ -18,22 +18,22 @@ Popup.template.events({
|
|||
// in moving the whole popup container outside of the popup wrapper. To
|
||||
// disable this behavior we have to manually reset the scrollLeft position
|
||||
// whenever it is modified.
|
||||
'scroll .content-wrapper': function(evt) {
|
||||
'scroll .content-wrapper'(evt) {
|
||||
evt.currentTarget.scrollLeft = 0;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// When a popup content is removed (ie, when the user press the "back" button),
|
||||
// we need to wait for the container translation to end before removing the
|
||||
// actual DOM element. For that purpose we use the undocumented `_uihooks` API.
|
||||
Popup.template.onRendered(function() {
|
||||
var container = this.find('.content-container');
|
||||
Popup.template.onRendered(() => {
|
||||
const container = this.find('.content-container');
|
||||
container._uihooks = {
|
||||
removeElement: function(node) {
|
||||
removeElement(node) {
|
||||
$(node).addClass('no-height');
|
||||
$(container).one(CSSEvents.transitionend, function() {
|
||||
$(container).one(CSSEvents.transitionend, () => {
|
||||
node.parentNode.removeChild(node);
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,37 +1,37 @@
|
|||
var peakAnticipation = 200;
|
||||
const peakAnticipation = 200;
|
||||
|
||||
Mixins.InfiniteScrolling = BlazeComponent.extendComponent({
|
||||
onCreated: function() {
|
||||
onCreated() {
|
||||
this._nextPeak = Infinity;
|
||||
},
|
||||
|
||||
setNextPeak: function(v) {
|
||||
setNextPeak(v) {
|
||||
this._nextPeak = v;
|
||||
},
|
||||
|
||||
getNextPeak: function() {
|
||||
getNextPeak() {
|
||||
return this._nextPeak;
|
||||
},
|
||||
|
||||
resetNextPeak: function() {
|
||||
resetNextPeak() {
|
||||
this._nextPeak = Infinity;
|
||||
},
|
||||
|
||||
// To be overwritten by consumers of this mixin
|
||||
reachNextPeak: function() {
|
||||
reachNextPeak() {
|
||||
|
||||
},
|
||||
|
||||
events: function() {
|
||||
events() {
|
||||
return [{
|
||||
scroll: function(evt) {
|
||||
var domElement = evt.currentTarget;
|
||||
var altitude = domElement.scrollTop + domElement.offsetHeight;
|
||||
scroll(evt) {
|
||||
const domElement = evt.currentTarget;
|
||||
let altitude = domElement.scrollTop + domElement.offsetHeight;
|
||||
altitude += peakAnticipation;
|
||||
if (altitude >= this.callFirstWith(null, 'getNextPeak')) {
|
||||
this.callFirstWith(null, 'reachNextPeak');
|
||||
}
|
||||
}
|
||||
},
|
||||
}];
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
Mixins.PerfectScrollbar = BlazeComponent.extendComponent({
|
||||
onRendered: function() {
|
||||
var component = this.mixinParent();
|
||||
var domElement = component.find('.js-perfect-scrollbar');
|
||||
onRendered() {
|
||||
const component = this.mixinParent();
|
||||
const domElement = component.find('.js-perfect-scrollbar');
|
||||
Ps.initialize(domElement);
|
||||
|
||||
// XXX We should create an event map to be consistent with other components
|
||||
// but since BlazeComponent doesn't merge Mixins events transparently I
|
||||
// prefered to use a jQuery event (which is what an event map ends up doing)
|
||||
component.$(domElement).on('mouseenter', function() {
|
||||
Ps.update(domElement);
|
||||
});
|
||||
}
|
||||
component.$(domElement).on('mouseenter', () => Ps.update(domElement));
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,76 +1,76 @@
|
|||
Sidebar = null;
|
||||
|
||||
var defaultView = 'home';
|
||||
const defaultView = 'home';
|
||||
|
||||
var viewTitles = {
|
||||
const viewTitles = {
|
||||
filter: 'filter-cards',
|
||||
multiselection: 'multi-selection',
|
||||
archives: 'archives'
|
||||
archives: 'archives',
|
||||
};
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
template: function() {
|
||||
template() {
|
||||
return 'sidebar';
|
||||
},
|
||||
|
||||
mixins: function() {
|
||||
mixins() {
|
||||
return [Mixins.InfiniteScrolling, Mixins.PerfectScrollbar];
|
||||
},
|
||||
|
||||
onCreated: function() {
|
||||
this._isOpen = new ReactiveVar(! Session.get('currentCard'));
|
||||
onCreated() {
|
||||
this._isOpen = new ReactiveVar(!Session.get('currentCard'));
|
||||
this._view = new ReactiveVar(defaultView);
|
||||
Sidebar = this;
|
||||
},
|
||||
|
||||
onDestroyed: function() {
|
||||
onDestroyed() {
|
||||
Sidebar = null;
|
||||
},
|
||||
|
||||
isOpen: function() {
|
||||
isOpen() {
|
||||
return this._isOpen.get();
|
||||
},
|
||||
|
||||
open: function() {
|
||||
if (! this._isOpen.get()) {
|
||||
open() {
|
||||
if (!this._isOpen.get()) {
|
||||
this._isOpen.set(true);
|
||||
EscapeActions.executeUpTo('detailsPane');
|
||||
}
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
hide() {
|
||||
if (this._isOpen.get()) {
|
||||
this._isOpen.set(false);
|
||||
}
|
||||
},
|
||||
|
||||
toogle: function() {
|
||||
this._isOpen.set(! this._isOpen.get());
|
||||
toogle() {
|
||||
this._isOpen.set(!this._isOpen.get());
|
||||
},
|
||||
|
||||
calculateNextPeak: function() {
|
||||
var altitude = this.find('.js-board-sidebar-content').scrollHeight;
|
||||
calculateNextPeak() {
|
||||
const altitude = this.find('.js-board-sidebar-content').scrollHeight;
|
||||
this.callFirstWith(this, 'setNextPeak', altitude);
|
||||
},
|
||||
|
||||
reachNextPeak: function() {
|
||||
var activitiesComponent = this.componentChildren('activities')[0];
|
||||
reachNextPeak() {
|
||||
const activitiesComponent = this.componentChildren('activities')[0];
|
||||
activitiesComponent.loadNextPage();
|
||||
},
|
||||
|
||||
isTongueHidden: function() {
|
||||
isTongueHidden() {
|
||||
return this.isOpen() && this.getView() !== defaultView;
|
||||
},
|
||||
|
||||
scrollTop: function() {
|
||||
scrollTop() {
|
||||
this.$('.js-board-sidebar-content').scrollTop(0);
|
||||
},
|
||||
|
||||
getView: function() {
|
||||
getView() {
|
||||
return this._view.get();
|
||||
},
|
||||
|
||||
setView: function(view) {
|
||||
setView(view) {
|
||||
view = _.isString(view) ? view : defaultView;
|
||||
if (this._view.get() !== view) {
|
||||
this._view.set(view);
|
||||
|
|
@ -80,83 +80,84 @@ BlazeComponent.extendComponent({
|
|||
this.open();
|
||||
},
|
||||
|
||||
isDefaultView: function() {
|
||||
isDefaultView() {
|
||||
return this.getView() === defaultView;
|
||||
},
|
||||
|
||||
getViewTemplate: function() {
|
||||
return this.getView() + 'Sidebar';
|
||||
getViewTemplate() {
|
||||
return `${this.getView()}Sidebar`;
|
||||
},
|
||||
|
||||
getViewTitle: function() {
|
||||
getViewTitle() {
|
||||
return TAPi18n.__(viewTitles[this.getView()]);
|
||||
},
|
||||
|
||||
events: function() {
|
||||
events() {
|
||||
// XXX Hacky, we need some kind of `super`
|
||||
var mixinEvents = this.getMixin(Mixins.InfiniteScrolling).events();
|
||||
const mixinEvents = this.getMixin(Mixins.InfiniteScrolling).events();
|
||||
return mixinEvents.concat([{
|
||||
'click .js-toogle-sidebar': this.toogle,
|
||||
'click .js-back-home': this.setView
|
||||
'click .js-back-home': this.setView,
|
||||
}]);
|
||||
}
|
||||
},
|
||||
}).register('sidebar');
|
||||
|
||||
Blaze.registerHelper('Sidebar', function() {
|
||||
return Sidebar;
|
||||
});
|
||||
Blaze.registerHelper('Sidebar', () => Sidebar);
|
||||
|
||||
EscapeActions.register('sidebarView',
|
||||
function() { Sidebar.setView(defaultView); },
|
||||
function() { return Sidebar && Sidebar.getView() !== defaultView; }
|
||||
() => { Sidebar.setView(defaultView); },
|
||||
() => { return Sidebar && Sidebar.getView() !== defaultView; }
|
||||
);
|
||||
|
||||
var getMemberIndex = function(board, searchId) {
|
||||
for (var i = 0; i < board.members.length; i++) {
|
||||
function getMemberIndex(board, searchId) {
|
||||
for (let i = 0; i < board.members.length; i++) {
|
||||
if (board.members[i].userId === searchId)
|
||||
return i;
|
||||
}
|
||||
throw new Meteor.Error('Member not found');
|
||||
};
|
||||
}
|
||||
|
||||
Template.memberPopup.helpers({
|
||||
user: function() {
|
||||
user() {
|
||||
return Users.findOne(this.userId);
|
||||
},
|
||||
memberType: function() {
|
||||
var type = Users.findOne(this.userId).isBoardAdmin() ? 'admin' : 'normal';
|
||||
memberType() {
|
||||
const type = Users.findOne(this.userId).isBoardAdmin() ? 'admin' : 'normal';
|
||||
return TAPi18n.__(type).toLowerCase();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Template.memberPopup.events({
|
||||
'click .js-filter-member': function() {
|
||||
'click .js-filter-member'() {
|
||||
Filter.members.toogle(this.userId);
|
||||
Popup.close();
|
||||
},
|
||||
'click .js-change-role': Popup.open('changePermissions'),
|
||||
'click .js-remove-member': Popup.afterConfirm('removeMember', function() {
|
||||
var currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
var memberIndex = getMemberIndex(currentBoard, this.userId);
|
||||
var setQuery = {};
|
||||
setQuery[['members', memberIndex, 'isActive'].join('.')] = false;
|
||||
Boards.update(currentBoard._id, { $set: setQuery });
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
const memberIndex = getMemberIndex(currentBoard, this.userId);
|
||||
|
||||
Boards.update(currentBoard._id, {
|
||||
$set: {
|
||||
[`members.${memberIndex}.isActive`]: false,
|
||||
},
|
||||
});
|
||||
Popup.close();
|
||||
}),
|
||||
'click .js-leave-member': function() {
|
||||
'click .js-leave-member'() {
|
||||
// XXX Not implemented
|
||||
Popup.close();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Template.membersWidget.events({
|
||||
'click .js-member': Popup.open('member'),
|
||||
'click .js-manage-board-members': Popup.open('addMember')
|
||||
'click .js-manage-board-members': Popup.open('addMember'),
|
||||
});
|
||||
|
||||
Template.labelsWidget.events({
|
||||
'click .js-label': Popup.open('editLabel'),
|
||||
'click .js-add-label': Popup.open('createLabel')
|
||||
'click .js-add-label': Popup.open('createLabel'),
|
||||
});
|
||||
|
||||
// Board members can assign people or labels by drag-dropping elements from the
|
||||
|
|
@ -164,99 +165,102 @@ Template.labelsWidget.events({
|
|||
// plugin any time a draggable member or label is modified or removed we use a
|
||||
// autorun function and register a dependency on the both members and labels
|
||||
// fields of the current board document.
|
||||
var draggableMembersLabelsWidgets = function() {
|
||||
var self = this;
|
||||
if (! Meteor.user() || ! Meteor.user().isBoardMember())
|
||||
function draggableMembersLabelsWidgets() {
|
||||
if (!Meteor.user() || !Meteor.user().isBoardMember())
|
||||
return;
|
||||
|
||||
self.autorun(function() {
|
||||
var currentBoardId = Tracker.nonreactive(function() {
|
||||
this.autorun(() => {
|
||||
const currentBoardId = Tracker.nonreactive(() => {
|
||||
return Session.get('currentBoard');
|
||||
});
|
||||
Boards.findOne(currentBoardId, {
|
||||
fields: {
|
||||
members: 1,
|
||||
labels: 1
|
||||
}
|
||||
labels: 1,
|
||||
},
|
||||
});
|
||||
Tracker.afterFlush(function() {
|
||||
self.$('.js-member,.js-label').draggable({
|
||||
Tracker.afterFlush(() => {
|
||||
this.$('.js-member,.js-label').draggable({
|
||||
appendTo: 'body',
|
||||
helper: 'clone',
|
||||
revert: 'invalid',
|
||||
revertDuration: 150,
|
||||
snap: false,
|
||||
snapMode: 'both',
|
||||
start: function() {
|
||||
start() {
|
||||
EscapeActions.executeUpTo('popup-back');
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
Template.membersWidget.onRendered(draggableMembersLabelsWidgets);
|
||||
Template.labelsWidget.onRendered(draggableMembersLabelsWidgets);
|
||||
|
||||
Template.addMemberPopup.helpers({
|
||||
isBoardMember: function() {
|
||||
var user = Users.findOne(this._id);
|
||||
isBoardMember() {
|
||||
const user = Users.findOne(this._id);
|
||||
return user && user.isBoardMember();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Template.addMemberPopup.events({
|
||||
'click .pop-over-member-list li:not(.disabled)': function() {
|
||||
var userId = this._id;
|
||||
var currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
var currentMembersIds = _.pluck(currentBoard.members, 'userId');
|
||||
'click .pop-over-member-list li:not(.disabled)'() {
|
||||
const userId = this._id;
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
const currentMembersIds = _.pluck(currentBoard.members, 'userId');
|
||||
if (currentMembersIds.indexOf(userId) === -1) {
|
||||
Boards.update(currentBoard._id, {
|
||||
$push: {
|
||||
members: {
|
||||
userId: userId,
|
||||
userId,
|
||||
isAdmin: false,
|
||||
isActive: true
|
||||
}
|
||||
}
|
||||
isActive: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
} else {
|
||||
var memberIndex = getMemberIndex(currentBoard, userId);
|
||||
var setQuery = {};
|
||||
setQuery[['members', memberIndex, 'isActive'].join('.')] = true;
|
||||
Boards.update(currentBoard._id, { $set: setQuery });
|
||||
const memberIndex = getMemberIndex(currentBoard, userId);
|
||||
|
||||
Boards.update(currentBoard._id, {
|
||||
$set: {
|
||||
[`members.${memberIndex}.isActive`]: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
Popup.close();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Template.addMemberPopup.onRendered(function() {
|
||||
Template.addMemberPopup.onRendered(() => {
|
||||
this.find('.js-search-member input').focus();
|
||||
});
|
||||
|
||||
Template.changePermissionsPopup.events({
|
||||
'click .js-set-admin, click .js-set-normal': function(event) {
|
||||
var currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
var memberIndex = getMemberIndex(currentBoard, this.user._id);
|
||||
var isAdmin = $(event.currentTarget).hasClass('js-set-admin');
|
||||
var setQuery = {};
|
||||
setQuery[['members', memberIndex, 'isAdmin'].join('.')] = isAdmin;
|
||||
'click .js-set-admin, click .js-set-normal'(event) {
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
const memberIndex = getMemberIndex(currentBoard, this.user._id);
|
||||
const isAdmin = $(event.currentTarget).hasClass('js-set-admin');
|
||||
|
||||
Boards.update(currentBoard._id, {
|
||||
$set: setQuery
|
||||
$set: {
|
||||
[`members.${memberIndex}.isAdmin`]: isAdmin,
|
||||
},
|
||||
});
|
||||
Popup.back(1);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Template.changePermissionsPopup.helpers({
|
||||
isAdmin: function() {
|
||||
isAdmin() {
|
||||
return this.user.isBoardAdmin();
|
||||
},
|
||||
isLastAdmin: function() {
|
||||
if (! this.user.isBoardAdmin())
|
||||
isLastAdmin() {
|
||||
if (!this.user.isBoardAdmin())
|
||||
return false;
|
||||
var currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
var nbAdmins = _.where(currentBoard.members, { isAdmin: true }).length;
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
const nbAdmins = _.where(currentBoard.members, { isAdmin: true }).length;
|
||||
return nbAdmins === 1;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,46 +1,46 @@
|
|||
BlazeComponent.extendComponent({
|
||||
template: function() {
|
||||
template() {
|
||||
return 'archivesSidebar';
|
||||
},
|
||||
|
||||
tabs: function() {
|
||||
tabs() {
|
||||
return [
|
||||
{ name: TAPi18n.__('cards'), slug: 'cards' },
|
||||
{ name: TAPi18n.__('lists'), slug: 'lists' }
|
||||
]
|
||||
{ name: TAPi18n.__('lists'), slug: 'lists' },
|
||||
];
|
||||
},
|
||||
|
||||
archivedCards: function() {
|
||||
archivedCards() {
|
||||
return Cards.find({ archived: true });
|
||||
},
|
||||
|
||||
archivedLists: function() {
|
||||
archivedLists() {
|
||||
return Lists.find({ archived: true });
|
||||
},
|
||||
|
||||
cardIsInArchivedList: function() {
|
||||
cardIsInArchivedList() {
|
||||
return this.currentData().list().archived;
|
||||
},
|
||||
|
||||
onRendered: function() {
|
||||
//XXX We should support dragging a card from the sidebar to the board
|
||||
onRendered() {
|
||||
// XXX We should support dragging a card from the sidebar to the board
|
||||
},
|
||||
|
||||
events: function() {
|
||||
events() {
|
||||
return [{
|
||||
'click .js-restore-card': function() {
|
||||
var cardId = this.currentData()._id;
|
||||
'click .js-restore-card'() {
|
||||
const cardId = this.currentData()._id;
|
||||
Cards.update(cardId, {$set: {archived: false}});
|
||||
},
|
||||
'click .js-delete-card': Popup.afterConfirm('cardDelete', function() {
|
||||
var cardId = this._id;
|
||||
const cardId = this._id;
|
||||
Cards.remove(cardId);
|
||||
Popup.close();
|
||||
}),
|
||||
'click .js-restore-list': function() {
|
||||
var listId = this.currentData()._id;
|
||||
'click .js-restore-list'() {
|
||||
const listId = this.currentData()._id;
|
||||
Lists.update(listId, {$set: {archived: false}});
|
||||
}
|
||||
},
|
||||
}];
|
||||
}
|
||||
},
|
||||
}).register('archivesSidebar');
|
||||
|
|
|
|||
|
|
@ -1,136 +1,136 @@
|
|||
BlazeComponent.extendComponent({
|
||||
template: function() {
|
||||
template() {
|
||||
return 'filterSidebar';
|
||||
},
|
||||
|
||||
events: function() {
|
||||
events() {
|
||||
return [{
|
||||
'click .js-toggle-label-filter': function(evt) {
|
||||
'click .js-toggle-label-filter'(evt) {
|
||||
evt.preventDefault();
|
||||
Filter.labelIds.toogle(this.currentData()._id);
|
||||
Filter.resetExceptions();
|
||||
},
|
||||
'click .js-toogle-member-filter': function(evt) {
|
||||
'click .js-toogle-member-filter'(evt) {
|
||||
evt.preventDefault();
|
||||
Filter.members.toogle(this.currentData()._id);
|
||||
Filter.resetExceptions();
|
||||
},
|
||||
'click .js-clear-all': function(evt) {
|
||||
'click .js-clear-all'(evt) {
|
||||
evt.preventDefault();
|
||||
Filter.reset();
|
||||
},
|
||||
'click .js-filter-to-selection': function(evt) {
|
||||
'click .js-filter-to-selection'(evt) {
|
||||
evt.preventDefault();
|
||||
var selectedCards = Cards.find(Filter.mongoSelector()).map(function(c) {
|
||||
const selectedCards = Cards.find(Filter.mongoSelector()).map((c) => {
|
||||
return c._id;
|
||||
});
|
||||
MultiSelection.add(selectedCards);
|
||||
}
|
||||
},
|
||||
}];
|
||||
}
|
||||
},
|
||||
}).register('filterSidebar');
|
||||
|
||||
var updateSelectedCards = function(query) {
|
||||
Cards.find(MultiSelection.getMongoSelector()).forEach(function(card) {
|
||||
function updateSelectedCards(query) {
|
||||
Cards.find(MultiSelection.getMongoSelector()).forEach((card) => {
|
||||
Cards.update(card._id, query);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
template: function() {
|
||||
template() {
|
||||
return 'multiselectionSidebar';
|
||||
},
|
||||
|
||||
mapSelection: function(kind, _id) {
|
||||
return Cards.find(MultiSelection.getMongoSelector()).map(function(card) {
|
||||
var methodName = kind === 'label' ? 'hasLabel' : 'isAssigned';
|
||||
mapSelection(kind, _id) {
|
||||
return Cards.find(MultiSelection.getMongoSelector()).map((card) => {
|
||||
const methodName = kind === 'label' ? 'hasLabel' : 'isAssigned';
|
||||
return card[methodName](_id);
|
||||
});
|
||||
},
|
||||
|
||||
allSelectedElementHave: function(kind, _id) {
|
||||
allSelectedElementHave(kind, _id) {
|
||||
if (MultiSelection.isEmpty())
|
||||
return false;
|
||||
else
|
||||
return _.every(this.mapSelection(kind, _id));
|
||||
},
|
||||
|
||||
someSelectedElementHave: function(kind, _id) {
|
||||
someSelectedElementHave(kind, _id) {
|
||||
if (MultiSelection.isEmpty())
|
||||
return false;
|
||||
else
|
||||
return _.some(this.mapSelection(kind, _id));
|
||||
},
|
||||
|
||||
events: function() {
|
||||
events() {
|
||||
return [{
|
||||
'click .js-toggle-label-multiselection': function(evt) {
|
||||
var labelId = this.currentData()._id;
|
||||
var mappedSelection = this.mapSelection('label', labelId);
|
||||
var operation;
|
||||
'click .js-toggle-label-multiselection'(evt) {
|
||||
const labelId = this.currentData()._id;
|
||||
const mappedSelection = this.mapSelection('label', labelId);
|
||||
let operation;
|
||||
if (_.every(mappedSelection))
|
||||
operation = '$pull';
|
||||
else if (_.every(mappedSelection, function(bool) { return ! bool; }))
|
||||
else if (_.every(mappedSelection, (bool) => !bool))
|
||||
operation = '$addToSet';
|
||||
else {
|
||||
var popup = Popup.open('disambiguateMultiLabel');
|
||||
const popup = Popup.open('disambiguateMultiLabel');
|
||||
// XXX We need to have a better integration between the popup and the
|
||||
// UI components systems.
|
||||
return popup.call(this.currentData(), evt);
|
||||
}
|
||||
|
||||
var query = {};
|
||||
query[operation] = {
|
||||
labelIds: labelId
|
||||
};
|
||||
updateSelectedCards(query);
|
||||
updateSelectedCards({
|
||||
[operation]: {
|
||||
labelIds: labelId,
|
||||
},
|
||||
});
|
||||
},
|
||||
'click .js-toogle-member-multiselection': function(evt) {
|
||||
var memberId = this.currentData()._id;
|
||||
var mappedSelection = this.mapSelection('member', memberId);
|
||||
var operation;
|
||||
'click .js-toogle-member-multiselection'(evt) {
|
||||
const memberId = this.currentData()._id;
|
||||
const mappedSelection = this.mapSelection('member', memberId);
|
||||
let operation;
|
||||
if (_.every(mappedSelection))
|
||||
operation = '$pull';
|
||||
else if (_.every(mappedSelection, function(bool) { return ! bool; }))
|
||||
else if (_.every(mappedSelection, (bool) => !bool))
|
||||
operation = '$addToSet';
|
||||
else {
|
||||
var popup = Popup.open('disambiguateMultiMember');
|
||||
const popup = Popup.open('disambiguateMultiMember');
|
||||
// XXX We need to have a better integration between the popup and the
|
||||
// UI components systems.
|
||||
return popup.call(this.currentData(), evt);
|
||||
}
|
||||
|
||||
var query = {};
|
||||
query[operation] = {
|
||||
members: memberId
|
||||
};
|
||||
updateSelectedCards(query);
|
||||
updateSelectedCards({
|
||||
[operation]: {
|
||||
members: memberId,
|
||||
},
|
||||
});
|
||||
},
|
||||
'click .js-archive-selection': function() {
|
||||
'click .js-archive-selection'() {
|
||||
updateSelectedCards({$set: {archived: true}});
|
||||
}
|
||||
},
|
||||
}];
|
||||
}
|
||||
},
|
||||
}).register('multiselectionSidebar');
|
||||
|
||||
Template.disambiguateMultiLabelPopup.events({
|
||||
'click .js-remove-label': function() {
|
||||
'click .js-remove-label'() {
|
||||
updateSelectedCards({$pull: {labelIds: this._id}});
|
||||
Popup.close();
|
||||
},
|
||||
'click .js-add-label': function() {
|
||||
'click .js-add-label'() {
|
||||
updateSelectedCards({$addToSet: {labelIds: this._id}});
|
||||
Popup.close();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Template.disambiguateMultiMemberPopup.events({
|
||||
'click .js-unassign-member': function() {
|
||||
'click .js-unassign-member'() {
|
||||
updateSelectedCards({$pull: {members: this._id}});
|
||||
Popup.close();
|
||||
},
|
||||
'click .js-assign-member': function() {
|
||||
'click .js-assign-member'() {
|
||||
updateSelectedCards({$addToSet: {members: this._id}});
|
||||
Popup.close();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,98 +1,98 @@
|
|||
Meteor.subscribe('my-avatars');
|
||||
|
||||
Template.userAvatar.helpers({
|
||||
userData: function() {
|
||||
userData() {
|
||||
return Users.findOne(this.userId, {
|
||||
fields: {
|
||||
profile: 1,
|
||||
username: 1
|
||||
}
|
||||
username: 1,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
memberType: function() {
|
||||
var user = Users.findOne(this.userId);
|
||||
memberType() {
|
||||
const user = Users.findOne(this.userId);
|
||||
return user && user.isBoardAdmin() ? 'admin' : 'normal';
|
||||
},
|
||||
|
||||
presenceStatusClassName: function() {
|
||||
var userPresence = Presences.findOne({ userId: this.userId });
|
||||
if (! userPresence)
|
||||
presenceStatusClassName() {
|
||||
const userPresence = Presences.findOne({ userId: this.userId });
|
||||
if (!userPresence)
|
||||
return 'disconnected';
|
||||
else if (Session.equals('currentBoard', userPresence.state.currentBoardId))
|
||||
return 'active';
|
||||
else
|
||||
return 'idle';
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Template.userAvatar.events({
|
||||
'click .js-change-avatar': Popup.open('changeAvatar')
|
||||
'click .js-change-avatar': Popup.open('changeAvatar'),
|
||||
});
|
||||
|
||||
Template.userAvatarInitials.helpers({
|
||||
initials: function() {
|
||||
var user = Users.findOne(this.userId);
|
||||
initials() {
|
||||
const user = Users.findOne(this.userId);
|
||||
return user && user.getInitials();
|
||||
},
|
||||
|
||||
viewPortWidth: function() {
|
||||
var user = Users.findOne(this.userId);
|
||||
viewPortWidth() {
|
||||
const user = Users.findOne(this.userId);
|
||||
return (user && user.getInitials().length || 1) * 12;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
template: function() {
|
||||
template() {
|
||||
return 'changeAvatarPopup';
|
||||
},
|
||||
|
||||
onCreated: function() {
|
||||
onCreated() {
|
||||
this.error = new ReactiveVar('');
|
||||
},
|
||||
|
||||
avatarUrlOptions: function() {
|
||||
avatarUrlOptions() {
|
||||
return {
|
||||
auth: false,
|
||||
brokenIsFine: true
|
||||
brokenIsFine: true,
|
||||
};
|
||||
},
|
||||
|
||||
uploadedAvatars: function() {
|
||||
uploadedAvatars() {
|
||||
return Avatars.find({userId: Meteor.userId()});
|
||||
},
|
||||
|
||||
isSelected: function() {
|
||||
var userProfile = Meteor.user().profile;
|
||||
var avatarUrl = userProfile && userProfile.avatarUrl;
|
||||
var currentAvatarUrl = this.currentData().url(this.avatarUrlOptions());
|
||||
isSelected() {
|
||||
const userProfile = Meteor.user().profile;
|
||||
const avatarUrl = userProfile && userProfile.avatarUrl;
|
||||
const currentAvatarUrl = this.currentData().url(this.avatarUrlOptions());
|
||||
return avatarUrl === currentAvatarUrl;
|
||||
},
|
||||
|
||||
noAvatarUrl: function() {
|
||||
var userProfile = Meteor.user().profile;
|
||||
var avatarUrl = userProfile && userProfile.avatarUrl;
|
||||
return ! avatarUrl;
|
||||
noAvatarUrl() {
|
||||
const userProfile = Meteor.user().profile;
|
||||
const avatarUrl = userProfile && userProfile.avatarUrl;
|
||||
return !avatarUrl;
|
||||
},
|
||||
|
||||
setAvatar: function(avatarUrl) {
|
||||
setAvatar(avatarUrl) {
|
||||
Meteor.users.update(Meteor.userId(), {
|
||||
$set: {
|
||||
'profile.avatarUrl': avatarUrl
|
||||
}
|
||||
'profile.avatarUrl': avatarUrl,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
setError: function(error) {
|
||||
setError(error) {
|
||||
this.error.set(error);
|
||||
},
|
||||
|
||||
events: function() {
|
||||
events() {
|
||||
return [{
|
||||
'click .js-upload-avatar': function() {
|
||||
'click .js-upload-avatar'() {
|
||||
this.$('.js-upload-avatar-input').click();
|
||||
},
|
||||
'change .js-upload-avatar-input': function(evt) {
|
||||
'change .js-upload-avatar-input'(evt) {
|
||||
let file, fileUrl;
|
||||
|
||||
FS.Utility.eachFile(evt, (f) => {
|
||||
|
|
@ -106,71 +106,71 @@ BlazeComponent.extendComponent({
|
|||
|
||||
if (fileUrl) {
|
||||
this.setError('');
|
||||
let fetchAvatarInterval = window.setInterval(() => {
|
||||
const fetchAvatarInterval = window.setInterval(() => {
|
||||
$.ajax({
|
||||
url: fileUrl,
|
||||
success: () => {
|
||||
this.setAvatar(file.url(this.avatarUrlOptions()));
|
||||
window.clearInterval(fetchAvatarInterval);
|
||||
}
|
||||
},
|
||||
});
|
||||
}, 100);
|
||||
}
|
||||
},
|
||||
'click .js-select-avatar': function() {
|
||||
var avatarUrl = this.currentData().url(this.avatarUrlOptions());
|
||||
'click .js-select-avatar'() {
|
||||
const avatarUrl = this.currentData().url(this.avatarUrlOptions());
|
||||
this.setAvatar(avatarUrl);
|
||||
},
|
||||
'click .js-select-initials': function() {
|
||||
'click .js-select-initials'() {
|
||||
this.setAvatar('');
|
||||
},
|
||||
'click .js-delete-avatar': function() {
|
||||
'click .js-delete-avatar'() {
|
||||
Avatars.remove(this.currentData()._id);
|
||||
}
|
||||
},
|
||||
}];
|
||||
}
|
||||
},
|
||||
}).register('changeAvatarPopup');
|
||||
|
||||
Template.cardMembersPopup.helpers({
|
||||
isCardMember: function() {
|
||||
var cardId = Template.parentData()._id;
|
||||
var cardMembers = Cards.findOne(cardId).members || [];
|
||||
isCardMember() {
|
||||
const cardId = Template.parentData()._id;
|
||||
const cardMembers = Cards.findOne(cardId).members || [];
|
||||
return _.contains(cardMembers, this.userId);
|
||||
},
|
||||
user: function() {
|
||||
user() {
|
||||
return Users.findOne(this.userId);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Template.cardMembersPopup.events({
|
||||
'click .js-select-member': function(evt) {
|
||||
var cardId = Template.parentData(2).data._id;
|
||||
var memberId = this.userId;
|
||||
var operation;
|
||||
'click .js-select-member'(evt) {
|
||||
const cardId = Template.parentData(2).data._id;
|
||||
const memberId = this.userId;
|
||||
let operation;
|
||||
if (Cards.find({ _id: cardId, members: memberId}).count() === 0)
|
||||
operation = '$addToSet';
|
||||
else
|
||||
operation = '$pull';
|
||||
|
||||
var query = {};
|
||||
query[operation] = {
|
||||
members: memberId
|
||||
};
|
||||
Cards.update(cardId, query);
|
||||
Cards.update(cardId, {
|
||||
[operation]: {
|
||||
members: memberId,
|
||||
},
|
||||
});
|
||||
evt.preventDefault();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Template.cardMemberPopup.helpers({
|
||||
user: function() {
|
||||
user() {
|
||||
return Users.findOne(this.userId);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Template.cardMemberPopup.events({
|
||||
'click .js-remove-member': function() {
|
||||
'click .js-remove-member'() {
|
||||
Cards.update(this.cardId, {$pull: {members: this.userId}});
|
||||
Popup.close();
|
||||
},
|
||||
'click .js-edit-profile': Popup.open('editProfile')
|
||||
'click .js-edit-profile': Popup.open('editProfile'),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Template.headerUserBar.events({
|
||||
'click .js-open-header-member-menu': Popup.open('memberMenu'),
|
||||
'click .js-change-avatar': Popup.open('changeAvatar')
|
||||
'click .js-change-avatar': Popup.open('changeAvatar'),
|
||||
});
|
||||
|
||||
Template.memberMenuPopup.events({
|
||||
|
|
@ -8,58 +8,57 @@ Template.memberMenuPopup.events({
|
|||
'click .js-change-avatar': Popup.open('changeAvatar'),
|
||||
'click .js-change-password': Popup.open('changePassword'),
|
||||
'click .js-change-language': Popup.open('changeLanguage'),
|
||||
'click .js-logout': function(evt) {
|
||||
'click .js-logout'(evt) {
|
||||
evt.preventDefault();
|
||||
|
||||
AccountsTemplates.logout();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Template.editProfilePopup.events({
|
||||
submit: function(evt, tpl) {
|
||||
submit(evt, tpl) {
|
||||
evt.preventDefault();
|
||||
var fullname = $.trim(tpl.find('.js-profile-fullname').value);
|
||||
var username = $.trim(tpl.find('.js-profile-username').value);
|
||||
var initials = $.trim(tpl.find('.js-profile-initials').value);
|
||||
const fullname = $.trim(tpl.find('.js-profile-fullname').value);
|
||||
const username = $.trim(tpl.find('.js-profile-username').value);
|
||||
const initials = $.trim(tpl.find('.js-profile-initials').value);
|
||||
Users.update(Meteor.userId(), {$set: {
|
||||
'profile.fullname': fullname,
|
||||
'profile.initials': initials
|
||||
'profile.initials': initials,
|
||||
}});
|
||||
// XXX We should report the error to the user.
|
||||
if (username !== Meteor.user().username) {
|
||||
Meteor.call('setUsername', username);
|
||||
}
|
||||
Popup.back();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// XXX For some reason the useraccounts autofocus isnt working in this case.
|
||||
// See https://github.com/meteor-useraccounts/core/issues/384
|
||||
Template.changePasswordPopup.onRendered(function() {
|
||||
Template.changePasswordPopup.onRendered(() => {
|
||||
this.find('#at-field-current_password').focus();
|
||||
});
|
||||
|
||||
Template.changeLanguagePopup.helpers({
|
||||
languages: function() {
|
||||
return _.map(TAPi18n.getLanguages(), function(lang, tag) {
|
||||
return {
|
||||
tag: tag,
|
||||
name: lang.name
|
||||
};
|
||||
languages() {
|
||||
return _.map(TAPi18n.getLanguages(), (lang, tag) => {
|
||||
const name = lang.name;
|
||||
return { tag, name };
|
||||
});
|
||||
},
|
||||
isCurrentLanguage: function() {
|
||||
|
||||
isCurrentLanguage() {
|
||||
return this.tag === TAPi18n.getLanguage();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Template.changeLanguagePopup.events({
|
||||
'click .js-set-language': function(evt) {
|
||||
'click .js-set-language'(evt) {
|
||||
Users.update(Meteor.userId(), {
|
||||
$set: {
|
||||
'profile.language': this.tag
|
||||
}
|
||||
'profile.language': this.tag,
|
||||
},
|
||||
});
|
||||
evt.preventDefault();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue