summaryrefslogtreecommitdiffstats
path: root/client/components
diff options
context:
space:
mode:
authorKenton Hamaluik <kenton@hamaluik.com>2015-10-03 15:58:36 -0600
committerKenton Hamaluik <kenton@hamaluik.com>2015-10-03 15:58:36 -0600
commitbfcfd2ebda283bed1caa973f27e1af6b81fe621b (patch)
treef5b52b56362af6734109459b700448fc4828d315 /client/components
parent57fa7af24c8d59629e1b82f6d4f2173d77710128 (diff)
downloadwekan-bfcfd2ebda283bed1caa973f27e1af6b81fe621b.tar.gz
wekan-bfcfd2ebda283bed1caa973f27e1af6b81fe621b.tar.bz2
wekan-bfcfd2ebda283bed1caa973f27e1af6b81fe621b.zip
Initial support for @user and #label use in new cards.
When creating a new [mini]card, typing `@` or `#` brings up an auto-complete box for board members and labels which will get applied to the card upon creation. These textual tags are removed from the card title before saving to maintain sanity. If a label doesn't have a name, it's colour is used (i.e. `red`, `purple`, etc). This was developed to ease the creation of new cards and allow users to rapidly create cards without having to click numerous times just to apply labels & members.
Diffstat (limited to 'client/components')
-rw-r--r--client/components/lists/listBody.js98
1 files changed, 97 insertions, 1 deletions
diff --git a/client/components/lists/listBody.js b/client/components/lists/listBody.js
index 2e00cb4f..9d6aab88 100644
--- a/client/components/lists/listBody.js
+++ b/client/components/lists/listBody.js
@@ -26,7 +26,7 @@ BlazeComponent.extendComponent({
const firstCardDom = this.find('.js-minicard:first');
const lastCardDom = this.find('.js-minicard:last');
const textarea = $(evt.currentTarget).find('textarea');
- const title = textarea.val();
+ let title = textarea.val();
const position = Blaze.getData(evt.currentTarget).position;
let sortIndex;
if (position === 'top') {
@@ -36,10 +36,41 @@ BlazeComponent.extendComponent({
}
if ($.trim(title)) {
+ // Parse for @user and #label mentions, stripping them from the title
+ // and applying the appropriate users and labels to the card instead.
+ const currentBoard = Boards.findOne(Session.get('currentBoard'));
+
+ // Find all @-mentioned usernames, collect a list of their IDs
+ // and strip their mention out of the title.
+ let foundUserIds = [];
+ currentBoard.members.forEach(member => {
+ const username = Users.findOne(member.userId).username;
+ let nameNdx = title.indexOf('@' + username);
+ if(nameNdx !== -1) {
+ foundUserIds.push(member.userId);
+ title = title.substr(0, nameNdx) + title.substr(nameNdx + username.length + 1);
+ }
+ });
+
+ // Find all #-mentioned labels (based on their colour or name),
+ // collect a list of their IDs, and strip their mention out of
+ // the title.
+ let foundLabelIds = [];
+ currentBoard.labels.forEach(label => {
+ const labelName = (!label.name || label.name === "") ? label.color : label.name;
+ let labelNdx = title.indexOf('#' + labelName);
+ if(labelNdx !== -1) {
+ foundLabelIds.push(label._id);
+ title = title.substr(0, labelNdx) + title.substr(labelNdx + labelName.length + 1);
+ }
+ });
+
const _id = Cards.insert({
title,
listId: this.data()._id,
boardId: this.data().board()._id,
+ labelIds: foundLabelIds,
+ members: foundUserIds,
sort: sortIndex,
});
// In case the filter is active we need to add the newly inserted card in
@@ -100,12 +131,18 @@ BlazeComponent.extendComponent({
},
}).register('listBody');
+let dropdownMenuIsOpened = false;
BlazeComponent.extendComponent({
template() {
return 'addCardForm';
},
pressKey(evt) {
+ // don't do anything if the drop down is showing
+ if(dropDownIsOpened) {
+ return;
+ }
+
// Pressing Enter should submit the card
if (evt.keyCode === 13) {
evt.preventDefault();
@@ -140,4 +177,63 @@ BlazeComponent.extendComponent({
keydown: this.pressKey,
}];
},
+
+ onCreated() {
+ dropDownIsOpened = false;
+ },
+
+ onRendered() {
+ const $textarea = this.$('textarea');
+ $textarea.textcomplete([
+ // User mentions
+ {
+ match: /\B@(\w*)$/,
+ 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(value) {
+ return value;
+ },
+ replace(username) {
+ return `@${username} `;
+ },
+ index: 1,
+ },
+
+ // Labels
+ {
+ match: /\B#(\w*)$/,
+ search(term, callback) {
+ const currentBoard = Boards.findOne(Session.get('currentBoard'));
+ callback($.map(currentBoard.labels, (label) => {
+ const labelName = (!label.name || label.name === "") ? label.color : label.name;
+ return labelName.indexOf(term) === 0 ? labelName : null;
+ }));
+ },
+ template(value) {
+ return value;
+ },
+ replace(label) {
+ return `#${label} `;
+ },
+ index: 1,
+ },
+ ]);
+
+ // customize hooks for dealing with the dropdowns
+ $textarea.on({
+ 'textComplete:show'() {
+ dropDownIsOpened = true;
+ },
+ 'textComplete:hide'() {
+ Tracker.afterFlush(() => {
+ dropDownIsOpened = false;
+ });
+ },
+ });
+ },
}).register('addCardForm');