diff options
author | Kenton Hamaluik <kenton@hamaluik.com> | 2015-10-03 15:58:36 -0600 |
---|---|---|
committer | Kenton Hamaluik <kenton@hamaluik.com> | 2015-10-03 15:58:36 -0600 |
commit | bfcfd2ebda283bed1caa973f27e1af6b81fe621b (patch) | |
tree | f5b52b56362af6734109459b700448fc4828d315 /client/components | |
parent | 57fa7af24c8d59629e1b82f6d4f2173d77710128 (diff) | |
download | wekan-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.js | 98 |
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'); |