summaryrefslogtreecommitdiffstats
path: root/client/components
diff options
context:
space:
mode:
authorMaxime Quandalle <maxime@quandalle.com>2015-06-15 17:16:56 +0200
committerMaxime Quandalle <maxime@quandalle.com>2015-06-16 14:30:21 +0200
commit5478fc93dbe3be14c4a38754881e00dc0b6a38f9 (patch)
tree8b40a29a3cbe07747112e809db3fd12b719ae3bf /client/components
parenta41e07b37ec9243191804ac2966e2d136ce79710 (diff)
downloadwekan-5478fc93dbe3be14c4a38754881e00dc0b6a38f9.tar.gz
wekan-5478fc93dbe3be14c4a38754881e00dc0b6a38f9.tar.bz2
wekan-5478fc93dbe3be14c4a38754881e00dc0b6a38f9.zip
Improve the multi-selection experience
New features: - select all filtered cards - assign or unassign a member to selected cards - archive selected cards This commit also fix the card sort indexes calculation when a multi- selection is drag-dropped.
Diffstat (limited to 'client/components')
-rw-r--r--client/components/boards/boardBody.styl3
-rw-r--r--client/components/boards/boardHeader.jade8
-rw-r--r--client/components/boards/colors.styl1
-rw-r--r--client/components/lists/body.js6
-rw-r--r--client/components/lists/main.js15
-rw-r--r--client/components/sidebar/sidebar.styl13
-rw-r--r--client/components/sidebar/sidebarFilters.jade65
-rw-r--r--client/components/sidebar/sidebarFilters.js58
8 files changed, 126 insertions, 43 deletions
diff --git a/client/components/boards/boardBody.styl b/client/components/boards/boardBody.styl
index 9db5c1c0..8ce478c3 100644
--- a/client/components/boards/boardBody.styl
+++ b/client/components/boards/boardBody.styl
@@ -32,7 +32,8 @@ position()
&.is-dragging-active
.list-composer,
- .open-minicard-composer
+ .open-minicard-composer,
+ .minicard-wrapper.is-checked
display: none
.lists
diff --git a/client/components/boards/boardHeader.jade b/client/components/boards/boardHeader.jade
index e78de3b2..a1d3ce9f 100644
--- a/client/components/boards/boardHeader.jade
+++ b/client/components/boards/boardHeader.jade
@@ -21,24 +21,20 @@ template(name="headerBoard")
title="{{#if Filter.isActive}}{{_ 'filter-on-desc'}}{{/if}}"
class="{{#if Filter.isActive}}emphasis{{/if}}")
i.fa.fa-filter
+ span {{#if Filter.isActive}}{{_ 'filter-on'}}{{else}}{{_ 'filter'}}{{/if}}
if Filter.isActive
- span {{_ 'filter-on'}}
a.board-header-btn-close.js-filter-reset(title="{{_ 'filter-clear'}}")
i.fa.fa-times-thin
- else
- span {{_ 'filter'}}
if currentUser.isBoardMember
a.board-header-btn.js-multiselection-activate(
title="{{#if MultiSelection.isActive}}{{_ 'filter-on-desc'}}{{/if}}"
class="{{#if MultiSelection.isActive}}emphasis{{/if}}")
i.fa.fa-check-square-o
+ span Multi-Selection {{#if MultiSelection.isActive}}is on{{/if}}
if MultiSelection.isActive
- span Multi-Selection is on
a.board-header-btn-close.js-multiselection-reset(title="{{_ 'filter-clear'}}")
i.fa.fa-times-thin
- else
- span Multi-Selection
.separator
a.board-header-btn.js-open-board-menu
diff --git a/client/components/boards/colors.styl b/client/components/boards/colors.styl
index ff351880..d131701c 100644
--- a/client/components/boards/colors.styl
+++ b/client/components/boards/colors.styl
@@ -19,6 +19,7 @@ setBoardColor(color)
background-color: darken(color, 20%)
&.pop-over .pop-over-list li a:hover,
+ .sidebar .sidebar-content .sidebar-btn:hover,
.sidebar-list li a:hover
background-color: lighten(color, 10%)
diff --git a/client/components/lists/body.js b/client/components/lists/body.js
index a91f0ca9..27864474 100644
--- a/client/components/lists/body.js
+++ b/client/components/lists/body.js
@@ -27,10 +27,12 @@ BlazeComponent.extendComponent({
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');
if (position === 'top') {
- sortIndex = Utils.getSortIndex(null, this.find('.js-minicard:first'));
+ sortIndex = Utils.calculateIndex(null, firstCard).base;
} else if (position === 'bottom') {
- sortIndex = Utils.getSortIndex(this.find('.js-minicard:last'), null);
+ sortIndex = Utils.calculateIndex(lastCard, null).base;
}
if ($.trim(title)) {
diff --git a/client/components/lists/main.js b/client/components/lists/main.js
index 520d0772..c7f3f5e8 100644
--- a/client/components/lists/main.js
+++ b/client/components/lists/main.js
@@ -56,22 +56,23 @@ BlazeComponent.extendComponent({
stop: function(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 cardDomElement = ui.item.get(0);
- var prevCardDomElement = ui.item.prev('.js-minicard').get(0);
- var nextCardDomElement = ui.item.next('.js-minicard').get(0);
- var sort = Utils.getSortIndex(prevCardDomElement, nextCardDomElement);
+ 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;
if (MultiSelection.isActive()) {
- Cards.find(MultiSelection.getMongoSelector()).forEach(function(c) {
+ Cards.find(MultiSelection.getMongoSelector()).forEach(function(c, i) {
Cards.update(c._id, {
$set: {
listId: listId,
- sort: sort
+ sort: sortIndex.base + i * sortIndex.increment
}
});
});
} else {
+ var cardDomElement = ui.item.get(0);
var cardId = Blaze.getData(cardDomElement)._id;
Cards.update(cardId, {
$set: {
@@ -79,7 +80,7 @@ BlazeComponent.extendComponent({
// XXX Using the same sort index for multiple cards is
// unacceptable. Keep that only until we figure out if we want to
// refactor the whole sorting mecanism or do something more basic.
- sort: sort
+ sort: sortIndex.base
}
});
}
diff --git a/client/components/sidebar/sidebar.styl b/client/components/sidebar/sidebar.styl
index 813e263a..a5b695e9 100644
--- a/client/components/sidebar/sidebar.styl
+++ b/client/components/sidebar/sidebar.styl
@@ -51,6 +51,19 @@
.fa.fa-check
margin: 0 4px
+ .sidebar-btn
+ display: block
+ margin: 5px 0
+ padding: 10px
+ border-radius: 3px
+ background: darken(white, 10%)
+
+ &:hover *
+ color: white
+
+ i.fa
+ margin-right: 10px
+
.board-sidebar
width: 248px
right: -@width
diff --git a/client/components/sidebar/sidebarFilters.jade b/client/components/sidebar/sidebarFilters.jade
index 29b65f3b..a40232d2 100644
--- a/client/components/sidebar/sidebarFilters.jade
+++ b/client/components/sidebar/sidebarFilters.jade
@@ -1,7 +1,7 @@
//-
- XXX There is a *lot* of code duplication in the above templates and in the
+ XXX There is a *lot* of code duplication in the below templates and in the
corresponding JavaScript components. We will probably need the upcoming #let
- and #each x in y constructors.
+ and #each x in y constructors to fix this.
template(name="filterSidebar")
ul.sidebar-list
@@ -16,22 +16,27 @@ template(name="filterSidebar")
span.quiet {{_ "label-default" color}}
if Filter.labelIds.isSelected _id
i.fa.fa-check
+ hr
+ ul.sidebar-list
+ each currentBoard.members
+ if isActive
+ with getUser userId
+ li(class="{{#if Filter.members.isSelected _id}}active{{/if}}")
+ a.name.js-toogle-member-filter
+ +userAvatar(userId=this._id)
+ span.sidebar-list-item-description
+ = profile.name
+ | (<span class="username">{{ username }}</span>)
+ if Filter.members.isSelected _id
+ i.fa.fa-check
+ if Filter.isActive
hr
- ul.sidebar-list
- each currentBoard.members
- if isActive
- with getUser userId
- li(class="{{#if Filter.members.isSelected _id}}active{{/if}}")
- a.name.js-toogle-member-filter
- +userAvatar(userId=this._id)
- span.sidebar-list-item-description
- = profile.name
- | (<span class="username">{{ username }}</span>)
- if Filter.members.isSelected _id
- i.fa.fa-check
- hr
- a.js-clear-all(class="{{#unless Filter.isActive}}disabled{{/unless}}")
- | {{_ 'filter-clear'}}
+ a.sidebar-btn.js-clear-all
+ i.fa.fa-filter
+ span {{_ 'filter-clear'}}
+ a.sidebar-btn.js-filter-to-selection
+ i.fa.fa-check-square-o
+ span Filter to selection
template(name="multiselectionSidebar")
ul.sidebar-list
@@ -48,10 +53,32 @@ template(name="multiselectionSidebar")
i.fa.fa-check
else if someSelectedElementHave 'label' _id
i.fa.fa-ellipsis-h
- //-
- XXX We should be able to assign a member to the list of selected cards.
+ hr
+ ul.sidebar-list
+ each currentBoard.members
+ if isActive
+ with getUser userId
+ li(class="{{#if Filter.members.isSelected _id}}active{{/if}}")
+ a.name.js-toogle-member-multiselection
+ +userAvatar(userId=this._id)
+ span.sidebar-list-item-description
+ = profile.name
+ | (<span class="username">{{ username }}</span>)
+ if allSelectedElementHave 'member' _id
+ i.fa.fa-check
+ else if someSelectedElementHave 'member' _id
+ i.fa.fa-ellipsis-h
+ hr
+ a.sidebar-btn.js-archive-selection
+ i.fa.fa-archive
+ span Archive selection
template(name="disambiguateMultiLabelPopup")
p What do you want to do?
button.wide.js-remove-label Remove the label
button.wide.js-add-label Add the label
+
+template(name="disambiguateMultiMemberPopup")
+ p What do you want to do?
+ button.wide.js-unassign-member Unassign member
+ button.wide.js-assign-member Assign member
diff --git a/client/components/sidebar/sidebarFilters.js b/client/components/sidebar/sidebarFilters.js
index 42b6e185..c7b28443 100644
--- a/client/components/sidebar/sidebarFilters.js
+++ b/client/components/sidebar/sidebarFilters.js
@@ -5,19 +5,26 @@ BlazeComponent.extendComponent({
events: function() {
return [{
- 'click .js-toggle-label-filter': function(event) {
+ 'click .js-toggle-label-filter': function(evt) {
+ evt.preventDefault();
Filter.labelIds.toogle(this.currentData()._id);
Filter.resetExceptions();
- event.preventDefault();
},
- 'click .js-toogle-member-filter': function(event) {
+ 'click .js-toogle-member-filter': function(evt) {
+ evt.preventDefault();
Filter.members.toogle(this.currentData()._id);
Filter.resetExceptions();
- event.preventDefault();
},
- 'click .js-clear-all': function(event) {
+ 'click .js-clear-all': function(evt) {
+ evt.preventDefault();
Filter.reset();
- event.preventDefault();
+ },
+ 'click .js-filter-to-selection': function(evt) {
+ evt.preventDefault();
+ var selectedCards = Cards.find(Filter.mongoSelector()).map(function(c) {
+ return c._id;
+ });
+ MultiSelection.add(selectedCards);
}
}];
}
@@ -57,7 +64,7 @@ BlazeComponent.extendComponent({
events: function() {
return [{
- 'click .js-toggle-label-multiselection': function(evt, tpl) {
+ 'click .js-toggle-label-multiselection': function(evt) {
var labelId = this.currentData()._id;
var mappedSelection = this.mapSelection('label', labelId);
var operation;
@@ -69,7 +76,7 @@ BlazeComponent.extendComponent({
var 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, tpl);
+ return popup.call(this.currentData(), evt);
}
var query = {};
@@ -77,6 +84,30 @@ BlazeComponent.extendComponent({
labelIds: labelId
};
updateSelectedCards(query);
+ },
+ 'click .js-toogle-member-multiselection': function(evt) {
+ var memberId = this.currentData()._id;
+ var mappedSelection = this.mapSelection('member', memberId);
+ var operation;
+ if (_.every(mappedSelection))
+ operation = '$pull';
+ else if (_.every(mappedSelection, function(bool) { return ! bool; }))
+ operation = '$addToSet';
+ else {
+ var 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);
+ },
+ 'click .js-archive-selection': function() {
+ updateSelectedCards({$set: {archived: true}});
}
}];
}
@@ -92,3 +123,14 @@ Template.disambiguateMultiLabelPopup.events({
Popup.close();
}
});
+
+Template.disambiguateMultiMemberPopup.events({
+ 'click .js-unassign-member': function() {
+ updateSelectedCards({$pull: {members: this._id}});
+ Popup.close();
+ },
+ 'click .js-assign-member': function() {
+ updateSelectedCards({$addToSet: {members: this._id}});
+ Popup.close();
+ }
+});