From 41842460b483d80741af873c3841579a2a13852e Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Tue, 28 Jun 2016 16:14:06 +0800 Subject: [PATCH] UX: Collapse users when composing a private message. --- .../components/composer-user-selector.js.es6 | 74 +++++++++++++++++++ .../discourse/components/user-selector.js.es6 | 15 ++-- .../discourse/lib/autocomplete.js.es6 | 7 +- .../components/composer-user-selector.hbs | 17 +++++ .../discourse/templates/composer.hbs | 8 +- .../discourse/views/composer.js.es6 | 7 ++ .../stylesheets/common/base/compose.scss | 11 +++ .../common/base/composer-user-selector.scss | 10 +++ 8 files changed, 135 insertions(+), 14 deletions(-) create mode 100644 app/assets/javascripts/discourse/components/composer-user-selector.js.es6 create mode 100644 app/assets/javascripts/discourse/templates/components/composer-user-selector.hbs create mode 100644 app/assets/stylesheets/common/base/composer-user-selector.scss diff --git a/app/assets/javascripts/discourse/components/composer-user-selector.js.es6 b/app/assets/javascripts/discourse/components/composer-user-selector.js.es6 new file mode 100644 index 000000000..d977d6e30 --- /dev/null +++ b/app/assets/javascripts/discourse/components/composer-user-selector.js.es6 @@ -0,0 +1,74 @@ +import { default as computed, observes } from 'ember-addons/ember-computed-decorators'; + +export default Ember.Component.extend({ + showSelector: true, + shouldHide: false, + defaultUsernameCount: 0, + + @observes('usernames') + _checkWidth() { + let width = 0; + const $acWrap = this.$().find('.ac-wrap'); + const limit = $acWrap.width(); + this.set('defaultUsernameCount', 0); + + $acWrap.find('.item').toArray().forEach(item => { + width += $(item).outerWidth(true); + const result = (width < limit); + + if (result) this.incrementProperty('defaultUsernameCount'); + return result; + }); + + if (width >= limit) { + this.set('shouldHide', true); + } else { + this.set('shouldHide', false); + }; + }, + + @observes('shouldHide') + _setFocus() { + const selector = '#reply-control #reply-title, #reply-control .d-editor-input'; + + if (this.get('shouldHide')) { + $(selector).on('focus.composer-user-selector', () => { + this.set('showSelector', false); + this.appEvents.trigger("composer:resize"); + }); + } else { + $(selector).off('focus.composer-user-selector'); + } + }, + + @computed('usernames') + splitUsernames(usernames) { + return usernames.split(','); + }, + + @computed('splitUsernames', 'defaultUsernameCount') + limitedUsernames(splitUsernames, count) { + return splitUsernames.slice(0, count).join(", "); + }, + + @computed('splitUsernames', 'defaultUsernameCount') + hiddenUsersCount(splitUsernames, count) { + return `${splitUsernames.length - count} ${I18n.t('more')}`; + }, + + actions: { + toggleSelector() { + this.set("showSelector", true); + + Ember.run.schedule('afterRender', () => { + this.$().find('input').focus(); + }); + }, + + triggerResize() { + this.appEvents.trigger("composer:resize"); + const $this = this.$().find('.ac-wrap'); + if ($this.height() >= 150) $this.scrollTop($this.height()); + }, + } +}); diff --git a/app/assets/javascripts/discourse/components/user-selector.js.es6 b/app/assets/javascripts/discourse/components/user-selector.js.es6 index ab695e8b2..862f0fae4 100644 --- a/app/assets/javascripts/discourse/components/user-selector.js.es6 +++ b/app/assets/javascripts/discourse/components/user-selector.js.es6 @@ -1,9 +1,11 @@ +import { observes } from 'ember-addons/ember-computed-decorators'; import TextField from 'discourse/components/text-field'; import userSearch from 'discourse/lib/user-search'; export default TextField.extend({ - _initializeAutocomplete: function() { + didInsertElement() { + this._super(); var self = this, selected = [], groups = [], @@ -63,6 +65,7 @@ export default TextField.extend({ self.set('hasGroups', hasGroups); selected = items; + if (self.get('onChangeCallback')) self.sendAction('onChangeCallback'); }, reverseTransform: function(i) { @@ -70,19 +73,21 @@ export default TextField.extend({ } }); - }.on('didInsertElement'), + }, - _removeAutocomplete: function() { + willDestroyElement() { + this._super(); this.$().autocomplete('destroy'); - }.on('willDestroyElement'), + }, // THIS IS A HUGE HACK TO SUPPORT CLEARING THE INPUT + @observes('usernames') _clearInput: function() { if (arguments.length > 1) { if (Em.isEmpty(this.get("usernames"))) { this.$().parent().find("a").click(); } } - }.observes("usernames") + } }); diff --git a/app/assets/javascripts/discourse/lib/autocomplete.js.es6 b/app/assets/javascripts/discourse/lib/autocomplete.js.es6 index a142947da..a2edb6b88 100644 --- a/app/assets/javascripts/discourse/lib/autocomplete.js.es6 +++ b/app/assets/javascripts/discourse/lib/autocomplete.js.es6 @@ -101,13 +101,16 @@ export default function(options) { transformed = _.isArray(transformedItem) ? transformedItem : [transformedItem || item]; var divs = transformed.map(function(itm) { - var d = $("
" + itm + "
"); - var prev = me.parent().find('.item:last'); + let d = $(`
${itm}
`); + const $parent = me.parent(); + const prev = $parent.find('.item:last'); + if (prev.length === 0) { me.parent().prepend(d); } else { prev.after(d); } + inputSelectedItems.push(itm); return d[0]; }); diff --git a/app/assets/javascripts/discourse/templates/components/composer-user-selector.hbs b/app/assets/javascripts/discourse/templates/components/composer-user-selector.hbs new file mode 100644 index 000000000..71b5e8176 --- /dev/null +++ b/app/assets/javascripts/discourse/templates/components/composer-user-selector.hbs @@ -0,0 +1,17 @@ +{{#if showSelector}} + {{user-selector topicId=topicId + excludeCurrentUser='true' + onChangeCallback='triggerResize' + id="private-message-users" + includeMentionableGroups='true' + class="span8" + placeholderKey="composer.users_placeholder" + tabindex="1" + usernames=usernames + hasGroups=hasGroups}} +{{else}} +
+ {{limitedUsernames}} + {{hiddenUsersCount}} +
+{{/if}} diff --git a/app/assets/javascripts/discourse/templates/composer.hbs b/app/assets/javascripts/discourse/templates/composer.hbs index 290a0815b..4471943e1 100644 --- a/app/assets/javascripts/discourse/templates/composer.hbs +++ b/app/assets/javascripts/discourse/templates/composer.hbs @@ -48,13 +48,7 @@ {{#if model.canEditTitle}}
{{#if model.creatingPrivateMessage}} - {{user-selector topicId=topicModel.id - excludeCurrentUser="true" - id="private-message-users" - includeMentionableGroups="true" - class="span8" - placeholderKey="composer.users_placeholder" - tabindex="1" + {{composer-user-selector topicId=topicModel.id usernames=model.targetUsernames hasGroups=model.hasTargetGroups }} diff --git a/app/assets/javascripts/discourse/views/composer.js.es6 b/app/assets/javascripts/discourse/views/composer.js.es6 index 5d6924718..0542b6d8d 100644 --- a/app/assets/javascripts/discourse/views/composer.js.es6 +++ b/app/assets/javascripts/discourse/views/composer.js.es6 @@ -103,6 +103,13 @@ const ComposerView = Ember.View.extend({ triggerOpen(); }); positioningWorkaround(this.$()); + + this.appEvents.on('composer:resize', this, this.resize); + }, + + willDestroyElement() { + this._super(); + this.appEvents.off('composer:resize', this, this.resize); }, click() { diff --git a/app/assets/stylesheets/common/base/compose.scss b/app/assets/stylesheets/common/base/compose.scss index 4bb02e82d..dfadbd6fb 100644 --- a/app/assets/stylesheets/common/base/compose.scss +++ b/app/assets/stylesheets/common/base/compose.scss @@ -97,6 +97,8 @@ div.ac-wrap div.item a.remove, .remove-link { } div.ac-wrap { + overflow: auto; + max-height: 150px; background-color: $secondary; border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); padding: 5px 4px 1px 4px; @@ -110,6 +112,15 @@ div.ac-wrap { line-height: 20px; } } + + .ac-collapsed-button { + float: left; + border-radius: 20px; + position: relative; + top: -2px; + margin-right: 10px; + } + input[type="text"] { float: left; margin-bottom: 4px; diff --git a/app/assets/stylesheets/common/base/composer-user-selector.scss b/app/assets/stylesheets/common/base/composer-user-selector.scss new file mode 100644 index 000000000..f3ea48c8a --- /dev/null +++ b/app/assets/stylesheets/common/base/composer-user-selector.scss @@ -0,0 +1,10 @@ +div.ac-wrap.composer-user-selector-limited { + width: 400px; + + .btn-small { + border-radius: 10px; + position: relative; + top: -2px; + float: none; + } +}