summaryrefslogtreecommitdiffstats
path: root/client/components/boards
diff options
context:
space:
mode:
author蔡仲明 (Romulus Urakagi Tsai) <urakagi@gmail.com>2019-11-21 11:25:56 +0800
committerGitHub <noreply@github.com>2019-11-21 11:25:56 +0800
commit3e0bedd8c7a6dec97352212adb1cbde1ade44190 (patch)
tree651ff30d25ddb0416444370368d699e597c142d7 /client/components/boards
parent9bbeb73db1cd0ce1caaaca8dfb14ea92131bbf9d (diff)
parent4f5de87cc4c2281bd576548693de7c94e6a988c6 (diff)
downloadwekan-3e0bedd8c7a6dec97352212adb1cbde1ade44190.tar.gz
wekan-3e0bedd8c7a6dec97352212adb1cbde1ade44190.tar.bz2
wekan-3e0bedd8c7a6dec97352212adb1cbde1ade44190.zip
Merge pull request #1 from wekan/master
Update master
Diffstat (limited to 'client/components/boards')
-rw-r--r--client/components/boards/boardBody.js141
-rw-r--r--client/components/boards/boardBody.styl78
-rw-r--r--client/components/boards/boardHeader.jade88
-rw-r--r--client/components/boards/boardHeader.js166
4 files changed, 405 insertions, 68 deletions
diff --git a/client/components/boards/boardBody.js b/client/components/boards/boardBody.js
index 6cff5ab1..41b6f4ef 100644
--- a/client/components/boards/boardBody.js
+++ b/client/components/boards/boardBody.js
@@ -89,7 +89,6 @@ BlazeComponent.extendComponent({
helper.append(list.clone());
return helper;
},
- handle: '.js-swimlane-header',
items: '.swimlane:not(.placeholder)',
placeholder: 'swimlane placeholder',
distance: 7,
@@ -193,11 +192,42 @@ BlazeComponent.extendComponent({
// ugly touch event hotfix
enableClickOnTouch('.js-swimlane:not(.placeholder)');
+ import { Cookies } from 'meteor/ostrio:cookies';
+ const cookies = new Cookies();
+
+ this.autorun(() => {
+ let showDesktopDragHandles = false;
+ currentUser = Meteor.user();
+ if (currentUser) {
+ showDesktopDragHandles = (currentUser.profile || {})
+ .showDesktopDragHandles;
+ } else if (cookies.has('showDesktopDragHandles')) {
+ showDesktopDragHandles = true;
+ } else {
+ showDesktopDragHandles = false;
+ }
+ if (
+ Utils.isMiniScreen()
+ || (!Utils.isMiniScreen() && showDesktopDragHandles)
+ ) {
+ $swimlanesDom.sortable({
+ handle: '.js-swimlane-header-handle',
+ });
+ } else {
+ $swimlanesDom.sortable({
+ handle: '.swimlane-header',
+ });
+ }
+
+ // Disable drag-dropping if the current user is not a board member or is comment only
+ $swimlanesDom.sortable('option', 'disabled', !userIsMember());
+ });
+
function userIsMember() {
return (
- Meteor.user() &&
- Meteor.user().isBoardMember() &&
- !Meteor.user().isCommentOnly()
+ Meteor.user()
+ && Meteor.user().isBoardMember()
+ && !Meteor.user().isCommentOnly()
);
}
@@ -210,21 +240,36 @@ BlazeComponent.extendComponent({
},
isViewSwimlanes() {
- const currentUser = Meteor.user();
- if (!currentUser) return false;
- return (currentUser.profile || {}).boardView === 'board-view-swimlanes';
+ currentUser = Meteor.user();
+ if (currentUser) {
+ return (currentUser.profile || {}).boardView === 'board-view-swimlanes';
+ } else {
+ import { Cookies } from 'meteor/ostrio:cookies';
+ const cookies = new Cookies();
+ return cookies.get('boardView') === 'board-view-swimlanes';
+ }
},
isViewLists() {
- const currentUser = Meteor.user();
- if (!currentUser) return true;
- return (currentUser.profile || {}).boardView === 'board-view-lists';
+ currentUser = Meteor.user();
+ if (currentUser) {
+ return (currentUser.profile || {}).boardView === 'board-view-lists';
+ } else {
+ import { Cookies } from 'meteor/ostrio:cookies';
+ const cookies = new Cookies();
+ return cookies.get('boardView') === 'board-view-lists';
+ }
},
isViewCalendar() {
- const currentUser = Meteor.user();
- if (!currentUser) return false;
- return (currentUser.profile || {}).boardView === 'board-view-cal';
+ currentUser = Meteor.user();
+ if (currentUser) {
+ return (currentUser.profile || {}).boardView === 'board-view-cal';
+ } else {
+ import { Cookies } from 'meteor/ostrio:cookies';
+ const cookies = new Cookies();
+ return cookies.get('boardView') === 'board-view-cal';
+ }
},
openNewListForm() {
@@ -261,16 +306,16 @@ BlazeComponent.extendComponent({
scrollLeft(position = 0) {
const swimlanes = this.$('.js-swimlanes');
- swimlanes &&
- swimlanes.animate({
+ swimlanes
+ && swimlanes.animate({
scrollLeft: position,
});
},
scrollTop(position = 0) {
const swimlanes = this.$('.js-swimlanes');
- swimlanes &&
- swimlanes.animate({
+ swimlanes
+ && swimlanes.animate({
scrollTop: position,
});
},
@@ -309,25 +354,46 @@ BlazeComponent.extendComponent({
events(start, end, timezone, callback) {
const currentBoard = Boards.findOne(Session.get('currentBoard'));
const events = [];
+ const pushEvent = function(card, title, start, end, extraCls) {
+ start = start || card.startAt;
+ end = end || card.endAt;
+ title = title || card.title;
+ const className =
+ (extraCls ? `${extraCls} ` : '')
+ + (card.color ? `calendar-event-${card.color}` : '');
+ events.push({
+ id: card._id,
+ title,
+ start,
+ end: end || card.endAt,
+ allDay:
+ Math.abs(end.getTime() - start.getTime()) / 1000 === 24 * 3600,
+ url: FlowRouter.url('card', {
+ boardId: currentBoard._id,
+ slug: currentBoard.slug,
+ cardId: card._id,
+ }),
+ className,
+ });
+ };
currentBoard
.cardsInInterval(start.toDate(), end.toDate())
.forEach(function(card) {
- events.push({
- id: card._id,
- title: card.title,
- start: card.startAt,
- end: card.endAt,
- allDay:
- Math.abs(card.endAt.getTime() - card.startAt.getTime()) /
- 1000 ===
- 24 * 3600,
- url: FlowRouter.url('card', {
- boardId: currentBoard._id,
- slug: currentBoard.slug,
- cardId: card._id,
- }),
- });
+ pushEvent(card);
+ });
+ currentBoard
+ .cardsDueInBetween(start.toDate(), end.toDate())
+ .forEach(function(card) {
+ pushEvent(
+ card,
+ `${card.title} ${TAPi18n.__('card-due')}`,
+ card.dueAt,
+ new Date(card.dueAt.getTime() + 36e5),
+ );
});
+ events.sort(function(first, second) {
+ return first.id > second.id ? 1 : -1;
+ });
callback(events);
},
eventResize(event, delta, revertFunc) {
@@ -360,8 +426,13 @@ BlazeComponent.extendComponent({
};
},
isViewCalendar() {
- const currentUser = Meteor.user();
- if (!currentUser) return false;
- return (currentUser.profile || {}).boardView === 'board-view-cal';
+ currentUser = Meteor.user();
+ if (currentUser) {
+ return (currentUser.profile || {}).boardView === 'board-view-cal';
+ } else {
+ import { Cookies } from 'meteor/ostrio:cookies';
+ const cookies = new Cookies();
+ return cookies.get('boardView') === 'board-view-cal';
+ }
},
}).register('calendarView');
diff --git a/client/components/boards/boardBody.styl b/client/components/boards/boardBody.styl
index dfaaa050..32207d82 100644
--- a/client/components/boards/boardBody.styl
+++ b/client/components/boards/boardBody.styl
@@ -53,3 +53,81 @@ position()
padding: 0 0px 0px 0
overflow-x: hidden
overflow-y: auto
+
+calendar-event-color(background, borderColor, color...)
+ background: background !important
+ border-color: borderColor
+ if color
+ color: color !important //overwrite text for better visibility
+
+.calendar-event-green
+ calendar-event-color(#3cb500, #2a8000, #ffffff) //White text for better visibility
+
+.calendar-event-yellow
+ calendar-event-color(#fad900, #c7ac00, #000) //Black text for better visibility
+
+.calendar-event-orange
+ calendar-event-color(#ff9f19, #cc7c14, #000) //Black text for better visibility
+
+.calendar-event-red
+ calendar-event-color(#eb4646, #b83737, #ffffff) //White text for better visibility
+
+.calendar-event-purple
+ calendar-event-color(#a632db, #7d26a6, #ffffff) //White text for better visibility
+
+.calendar-event-blue
+ calendar-event-color(#0079bf, #005a8a, #ffffff) //White text for better visibility
+
+.calendar-event-pink
+ calendar-event-color(#ff78cb, #cc62a3, #000) //Black text for better visibility
+
+.calendar-event-sky
+ calendar-event-color(#00c2e0, #0094ab, #ffffff) //White text for better visibility
+
+.calendar-event-black
+ calendar-event-color(#4d4d4d, #1a1a1a, #ffffff) //White text for better visibility
+
+.calendar-event-lime
+ calendar-event-color(#51e898, #3eb375, #000) //Black text for better visibility
+
+.calendar-event-silver
+ calendar-event-color(#c0c0c0, #8c8c8c, #000) //Black text for better visibility
+
+.calendar-event-peachpuff
+ calendar-event-color(#ffdab9, #ccaf95, #000) //Black text for better visibility
+
+.calendar-event-crimson
+ calendar-event-color(#dc143c, #a8112f, #ffffff) //White text for better visibility
+
+.calendar-event-plum
+ calendar-event-color(#dda0dd, #a87ba8, #000) //Black text for better visibility
+
+.calendar-event-darkgreen
+ calendar-event-color(#006400, #003000, #ffffff) //White text for better visibility
+
+.calendar-event-slateblue
+ calendar-event-color(#6a5acd, #4f4399, #ffffff) //White text for better visibility
+
+.calendar-event-magenta
+ calendar-event-color(#ff00ff, #cc00cc, #ffffff) //White text for better visibility
+
+.calendar-event-gold
+ calendar-event-color(#ffd700, #ccaa00, #000) //Black text for better visibility
+
+.calendar-event-navy
+ calendar-event-color(#000080, #000033, #ffffff) //White text for better visibility
+
+.calendar-event-gray
+ calendar-event-color(#808080, #333333, #ffffff) //White text for better visibility
+
+.calendar-event-saddlebrown
+ calendar-event-color(#8b4513, #572b0c, #ffffff) //White text for better visibility
+
+.calendar-event-paleturquoise
+ calendar-event-color(#afeeee, #8ababa, #000) //Black text for better visibility
+
+.calendar-event-mistyrose
+ calendar-event-color(#ffe4e1, #ccb8b6, #000) //Black text for better visibility
+
+.calendar-event-indigo
+ calendar-event-color(#4b0082, #2b004d, #ffffff) //White text for better visibility
diff --git a/client/components/boards/boardHeader.jade b/client/components/boards/boardHeader.jade
index fe533f95..39221778 100644
--- a/client/components/boards/boardHeader.jade
+++ b/client/components/boards/boardHeader.jade
@@ -77,6 +77,11 @@ template(name="boardHeaderBar")
i.fa.fa-archive
span {{_ 'archives'}}
+ //if showSort
+ // a.board-header-btn.js-open-sort-view(title="{{_ 'sort-desc'}}")
+ // i.fa(class="{{directionClass}}")
+ // span {{_ 'sort'}}{{_ listSortShortDesc}}
+
a.board-header-btn.js-open-filter-view(
title="{{#if Filter.isActive}}{{_ 'filter-on-desc'}}{{else}}{{_ 'filter'}}{{/if}}"
class="{{#if Filter.isActive}}emphasis{{/if}}")
@@ -85,15 +90,6 @@ template(name="boardHeaderBar")
if Filter.isActive
a.board-header-btn-close.js-filter-reset(title="{{_ 'filter-clear'}}")
i.fa.fa-times-thin
-
- if currentUser.isAdmin
- a.board-header-btn.js-open-rules-view(title="{{_ 'rules'}}")
- i.fa.fa-magic
- span {{_ 'rules'}}
- else if currentUser.isBoardAdmin
- a.board-header-btn.js-open-rules-view(title="{{_ 'rules'}}")
- i.fa.fa-magic
- span {{_ 'rules'}}
a.board-header-btn.js-open-search-view(title="{{_ 'search'}}")
i.fa.fa-search
@@ -102,8 +98,19 @@ template(name="boardHeaderBar")
unless currentBoard.isTemplatesBoard
a.board-header-btn.js-toggle-board-view(
title="{{_ 'board-view'}}")
- i.fa.fa-th-large
- span {{#if currentUser.profile.boardView}}{{_ currentUser.profile.boardView}}{{else}}{{_ 'board-view-lists'}}{{/if}}
+ i.fa.fa-caret-down
+ if $eq boardView 'board-view-lists'
+ i.fa.fa-trello
+ if $eq boardView 'board-view-swimlanes'
+ i.fa.fa-th-large
+ // unless collapseSwimlane
+ // i.fa.fa-th-large
+ // if collapseSwimlane
+ // i.fa.fa-play
+ if $eq boardView 'board-view-cal'
+ i.fa.fa-calendar
+ span {{#if boardView}}{{_ boardView}}{{else}}{{_ 'board-view-lists'}}{{/if}}
+ //span {{#if collapseSwimlane}}{{_ 'board-view-collapse'}}{{else}}{{#if boardView}}{{_ boardView}}{{else}}{{_ 'board-view-lists'}}{{/if}}{{/if}}
if canModifyBoard
a.board-header-btn.js-multiselection-activate(
@@ -168,6 +175,51 @@ template(name="boardChangeWatchPopup")
i.fa.fa-check
span.sub-name {{_ 'muted-info'}}
+template(name="boardChangeViewPopup")
+ ul.pop-over-list
+ li
+ with "board-view-lists"
+ a.js-open-lists-view
+ i.fa.fa-trello.colorful
+ | {{_ 'board-view-lists'}}
+ if $eq Utils.boardView "board-view-lists"
+ i.fa.fa-check
+ li
+ with "board-view-swimlanes"
+ a.js-open-swimlanes-view
+ i.fa.fa-th-large.colorful
+ | {{_ 'board-view-swimlanes'}}
+ if $eq Utils.boardView "board-view-swimlanes"
+ i.fa.fa-check
+ //li
+ // with "board-view-collapse"
+ // a.js-open-collapse-view
+ // i.fa.fa-play.colorful
+ // | {{_ 'board-view-collapse'}}
+ // if $eq Utils.boardView "board-view-collapse"
+ // i.fa.fa-check
+ li
+ with "board-view-cal"
+ a.js-open-cal-view
+ i.fa.fa-calendar.colorful
+ | {{_ 'board-view-cal'}}
+ if $eq Utils.boardView "board-view-cal"
+ i.fa.fa-check
+ if currentUser.isAdmin
+ hr
+ li
+ with "board-view-rules"
+ a.js-open-rules-view(title="{{_ 'rules'}}")
+ i.fa.fa-magic
+ | {{_ 'rules'}}
+ else if currentUser.isBoardAdmin
+ hr
+ li
+ with "board-view-rules"
+ a.js-open-rules-view(title="{{_ 'rules'}}")
+ i.fa.fa-magic
+ | {{_ 'rules'}}
+
template(name="createBoard")
form
label
@@ -194,6 +246,20 @@ template(name="createBoard")
| /
a.js-board-template {{_ 'template'}}
+//template(name="listsortPopup")
+// h2
+// | {{_ 'list-sort-by'}}
+// hr
+// ul.pop-over-list
+// each value in allowedSortValues
+// li
+// a.js-sort-by(name="{{value.name}}")
+// if $eq sortby value.name
+// i(class="fa {{Direction}}")
+// | {{_ value.label }}{{_ value.shortLabel}}
+// if $eq sortby value.name
+// i(class="fa fa-check")
+
template(name="boardChangeTitlePopup")
form
label
diff --git a/client/components/boards/boardHeader.js b/client/components/boards/boardHeader.js
index cb84c233..ffbb9b72 100644
--- a/client/components/boards/boardHeader.js
+++ b/client/components/boards/boardHeader.js
@@ -1,3 +1,7 @@
+/*
+const DOWNCLS = 'fa-sort-down';
+const UPCLS = 'fa-sort-up';
+*/
Template.boardMenuPopup.events({
'click .js-rename-board': Popup.open('boardChangeTitle'),
'click .js-custom-fields'() {
@@ -80,7 +84,27 @@ BlazeComponent.extendComponent({
const currentBoard = Boards.findOne(Session.get('currentBoard'));
return currentBoard && currentBoard.stars >= 2;
},
-
+ /*
+ showSort() {
+ return Meteor.user().hasSortBy();
+ },
+ directionClass() {
+ return this.currentDirection() === -1 ? DOWNCLS : UPCLS;
+ },
+ changeDirection() {
+ const direction = 0 - this.currentDirection() === -1 ? '-' : '';
+ Meteor.call('setListSortBy', direction + this.currentListSortBy());
+ },
+ currentDirection() {
+ return Meteor.user().getListSortByDirection();
+ },
+ currentListSortBy() {
+ return Meteor.user().getListSortBy();
+ },
+ listSortShortDesc() {
+ return `list-label-short-${this.currentListSortBy()}`;
+ },
+ */
events() {
return [
{
@@ -94,30 +118,25 @@ BlazeComponent.extendComponent({
'click .js-open-archived-board'() {
Modal.open('archivedBoards');
},
- 'click .js-toggle-board-view'() {
- const currentUser = Meteor.user();
- if (
- (currentUser.profile || {}).boardView === 'board-view-swimlanes'
- ) {
- currentUser.setBoardView('board-view-cal');
- } else if (
- (currentUser.profile || {}).boardView === 'board-view-lists'
- ) {
- currentUser.setBoardView('board-view-swimlanes');
- } else if (
- (currentUser.profile || {}).boardView === 'board-view-cal'
- ) {
- currentUser.setBoardView('board-view-lists');
- } else {
- currentUser.setBoardView('board-view-swimlanes');
- }
- },
+ 'click .js-toggle-board-view': Popup.open('boardChangeView'),
'click .js-toggle-sidebar'() {
Sidebar.toggle();
},
'click .js-open-filter-view'() {
Sidebar.setView('filter');
},
+ /*
+ 'click .js-open-sort-view'(evt) {
+ const target = evt.target;
+ if (target.tagName === 'I') {
+ // click on the text, popup choices
+ this.changeDirection();
+ } else {
+ // change the sort order
+ Popup.open('listsort')(evt);
+ }
+ },
+ */
'click .js-filter-reset'(event) {
event.stopPropagation();
Sidebar.setView();
@@ -126,9 +145,6 @@ BlazeComponent.extendComponent({
'click .js-open-search-view'() {
Sidebar.setView('search');
},
- 'click .js-open-rules-view'() {
- Modal.openWide('rulesMain');
- },
'click .js-multiselection-activate'() {
const currentCard = Session.get('currentCard');
MultiSelection.activate();
@@ -156,6 +172,40 @@ Template.boardHeaderBar.helpers({
!Meteor.user().isCommentOnly()
);
},
+ boardView() {
+ return Utils.boardView();
+ },
+ //collapseSwimlane() {
+ // import { Cookies } from 'meteor/ostrio:cookies';
+ // const cookies = new Cookies();
+ // if (cookies.has('collapseSwimlane')) {
+ // return true;
+ // } else {
+ // return false;
+ // }
+ //},
+});
+
+Template.boardChangeViewPopup.events({
+ 'click .js-open-lists-view'() {
+ Utils.setBoardView('board-view-lists');
+ Popup.close();
+ },
+ 'click .js-open-swimlanes-view'() {
+ Utils.setBoardView('board-view-swimlanes');
+ Popup.close();
+ },
+ //'click .js-open-collapse-view'() {
+ // Utils.setBoardView('board-view-collapse');
+ //Popup.close();
+ 'click .js-open-cal-view'() {
+ Utils.setBoardView('board-view-cal');
+ Popup.close();
+ },
+ 'click .js-open-rules-view'() {
+ Modal.openWide('rulesMain');
+ Popup.close();
+ },
});
const CreateBoard = BlazeComponent.extendComponent({
@@ -277,3 +327,75 @@ BlazeComponent.extendComponent({
];
},
}).register('boardChangeWatchPopup');
+
+/*
+BlazeComponent.extendComponent({
+ onCreated() {
+ //this.sortBy = new ReactiveVar();
+ ////this.sortDirection = new ReactiveVar();
+ //this.setSortBy();
+ this.downClass = DOWNCLS;
+ this.upClass = UPCLS;
+ },
+ allowedSortValues() {
+ const types = [];
+ const pushed = {};
+ Meteor.user()
+ .getListSortTypes()
+ .forEach(type => {
+ const key = type.replace(/^-/, '');
+ if (pushed[key] === undefined) {
+ types.push({
+ name: key,
+ label: `list-label-${key}`,
+ shortLabel: `list-label-short-${key}`,
+ });
+ pushed[key] = 1;
+ }
+ });
+ return types;
+ },
+ Direction() {
+ return Meteor.user().getListSortByDirection() === -1
+ ? this.downClass
+ : this.upClass;
+ },
+ sortby() {
+ return Meteor.user().getListSortBy();
+ },
+
+ setSortBy(type = null) {
+ const user = Meteor.user();
+ if (type === null) {
+ type = user._getListSortBy();
+ } else {
+ let value = '';
+ if (type.map) {
+ // is an array
+ value = (type[1] === -1 ? '-' : '') + type[0];
+ }
+ Meteor.call('setListSortBy', value);
+ }
+ //this.sortBy.set(type[0]);
+ //this.sortDirection.set(type[1]);
+ },
+
+ events() {
+ return [
+ {
+ 'click .js-sort-by'(evt) {
+ evt.preventDefault();
+ const target = evt.target;
+ const sortby = target.getAttribute('name');
+ const down = !!target.querySelector(`.${this.upClass}`);
+ const direction = down ? -1 : 1;
+ this.setSortBy([sortby, direction]);
+ if (Utils.isMiniScreen) {
+ Popup.close();
+ }
+ },
+ },
+ ];
+ },
+}).register('listsortPopup');
+*/