From 14f06c2740338f325a2abe739ac6ce3a4135dd88 Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Fri, 25 Aug 2017 19:56:57 +0200 Subject: [PATCH] select-box minor fixes --- .../components/category-select-box.js.es6 | 14 +- .../discourse/components/select-box.js.es6 | 237 +++++++++--------- .../select-box/select-box-filter.js.es6 | 4 +- .../templates/components/select-box.hbs | 9 +- .../select-box/select-box-filter.hbs | 6 +- .../select-box/select-box-header.hbs | 20 +- .../discourse/templates/composer.hbs | 2 +- .../components/category-select-box.scss | 5 +- .../common/components/select-box.scss | 62 ++--- .../components/select-box-test.js.es6 | 2 +- 10 files changed, 188 insertions(+), 173 deletions(-) diff --git a/app/assets/javascripts/discourse/components/category-select-box.js.es6 b/app/assets/javascripts/discourse/components/category-select-box.js.es6 index e0ec28846e5..f5926a5ca77 100644 --- a/app/assets/javascripts/discourse/components/category-select-box.js.es6 +++ b/app/assets/javascripts/discourse/components/category-select-box.js.es6 @@ -1,8 +1,8 @@ import SelectBoxComponent from "discourse/components/select-box"; -import { categoryBadgeHTML } from 'discourse/helpers/category-link'; -import { observes, on } from 'ember-addons/ember-computed-decorators'; -import PermissionType from 'discourse/models/permission-type'; -import Category from 'discourse/models/category'; +import { categoryBadgeHTML } from "discourse/helpers/category-link"; +import { observes, on } from "ember-addons/ember-computed-decorators"; +import PermissionType from "discourse/models/permission-type"; +import Category from "discourse/models/category"; export default SelectBoxComponent.extend({ classNames: ["category-select-box"], @@ -13,9 +13,9 @@ export default SelectBoxComponent.extend({ castInteger: true, - width: '100%', + width: "100%", - @on("willInsertElement") + @on("init") @observes("selectedContent") _setHeaderText: function() { let headerText; @@ -30,7 +30,7 @@ export default SelectBoxComponent.extend({ headerText = this.get("selectedContent.text"); } - this.set("headerText", headerText); + this.set("headerText", Handlebars.escapeExpression(headerText)); }, // original method is kept for compatibility diff --git a/app/assets/javascripts/discourse/components/select-box.js.es6 b/app/assets/javascripts/discourse/components/select-box.js.es6 index 60a3a0bcc0c..8c2cce699b8 100644 --- a/app/assets/javascripts/discourse/components/select-box.js.es6 +++ b/app/assets/javascripts/discourse/components/select-box.js.es6 @@ -1,17 +1,17 @@ import { on, observes } from "ember-addons/ember-computed-decorators"; -import { iconHTML } from 'discourse-common/lib/icon-library'; +import { iconHTML } from "discourse-common/lib/icon-library"; export default Ember.Component.extend({ layoutName: "components/select-box", classNames: "select-box", - - width: 220, - classNameBindings: ["expanded:is-expanded"], expanded: false, focused: false, + filterFocused: false, + renderBody: false, + wrapper: true, tabindex: 0, caretUpIcon: "caret-up", @@ -39,13 +39,11 @@ export default Ember.Component.extend({ selectBoxHeaderComponent: "select-box/select-box-header", selectBoxCollectionComponent: "select-box/select-box-collection", + width: 220, maxCollectionHeight: 200, - maxWidth: 200, verticalOffset: 0, horizontalOffset: 0, - renderBody: false, - castInteger: false, filterFunction: function() { @@ -71,6 +69,30 @@ export default Ember.Component.extend({ }; }.property(), + applyDirection() { + this.$().removeClass("is-reversed"); + + const offsetTop = this.$()[0].getBoundingClientRect().top; + const windowHeight = $(window).height(); + const headerHeight = this.$(".select-box-header").outerHeight(); + const filterHeight = this.$(".select-box-filter").outerHeight(); + + if (windowHeight - (offsetTop + this.get("maxCollectionHeight") + filterHeight + headerHeight) < 0) { + this.$().addClass("is-reversed"); + this.$(".select-box-body").css({ + left: this.get("horizontalOffset"), + top: "", + bottom: headerHeight + this.get("verticalOffset") + }); + } else { + this.$(".select-box-body").css({ + left: this.get("horizontalOffset"), + top: headerHeight + this.get("verticalOffset"), + bottom: "" + }); + } + }, + init() { this._super(); @@ -82,12 +104,101 @@ export default Ember.Component.extend({ this.set("filterable", false); } + this.set("headerText", Handlebars.escapeExpression(this.get("headerText"))); + this.setProperties({ componentId: this.elementId, filteredContent: [] }); }, + @on("willDestroyElement") + _unbindEvents: function() { + $(window).off("resize.select-box"); + $(document).off("click.select-box", "keydown.select-box"); + this.$(".select-box-offscreen").off( + "focusin.select-box", + "focusout.select-box", + "keydown.select-box" + ); + this.$(".filter-query").off("focusin.select-box", "focusout.select-box"); + }, + + @on("didRender") + _configureSelectBoxDOM: function() { + this.$().css("width", this.get("width")); + this.$(".select-box-header").css("height", this.$().css("height")); + this.$(".select-box-filter").css("height", this.$().css("height")); + + if (this.get("expanded")) { + this.$(".select-box-body").css("width", this.$().css("width")); + this.$(".select-box-collection").css("max-height", this.get("maxCollectionHeight")); + + this._bindTab(); + + Ember.run.schedule("afterRender", () => { + this.applyDirection(); + + if (this.get("wrapper")) { + this._positionSelectBoxWrapper(); + } + }); + } else { + $(document).off("keydown.select-box"); + + if (this.get("wrapper")) { + this.$(".select-box-wrapper").hide(); + } + } + }, + + @on("didInsertElement") + _bindEvents: function() { + $(document).on("click.select-box", (event) => { + const clickOutside = $(event.target).parents(".select-box").attr("id") !== this.$().attr("id"); + if (this.get("expanded") && clickOutside) { + this.setProperties({ expanded: false, focused: false }); + } + }); + + this.$(".select-box-offscreen").on("focusin.select-box", () => { + this.set("focused", true); + }); + this.$(".select-box-offscreen").on("focusout.select-box", () => { + this.set("focused", false); + }); + + this.$(".filter-query").on("focusin.select-box", () => { + this.set("filterFocused", true); + }); + this.$(".filter-query").on("focusout.select-box", () => { + this.set("filterFocused", false); + }); + + this.$(".select-box-offscreen").on("keydown.select-box", (event) => { + const keyCode = event.keyCode || event.which; + + if (keyCode === 13 || keyCode === 40) { + this.setProperties({expanded: true, focused: false}); + return false; + } + + if (keyCode === 27) { + this.$(".select-box-offscreen").blur(); + return false; + } + + if (keyCode >= 65 && keyCode <= 90) { + this.setProperties({expanded: true, focused: false}); + Ember.run.schedule("afterRender", () => { + this.$(".filter-query").focus().val(String.fromCharCode(keyCode)); + }); + } + }); + + $(window).on("resize.select-box", () => this.set("expanded", false) ); + }, + @observes("value") _valueChanged: function() { if (Ember.isNone(this.get("value"))) { @@ -115,41 +226,13 @@ export default Ember.Component.extend({ if (Ember.isNone(this.get("lastHoveredId"))) { this.set("lastHoveredId", this.get("value")); } + + if (this.get("filterable")) { + Ember.run.schedule("afterRender", () => this.$(".filter-query").focus()); + } }; }, - @on("willDestroyElement") - _unbindEvents: function() { - $(document).off("click.select-box"); - $(document).off("keydown.select-box"); - this.$(".select-box-offscreen").off("focusin.select-box"); - this.$(".select-box-offscreen").off("focusout.select-box"); - this.$(".select-box-offscreen").off("keydown.select-box"); - $(window).off("resize.select-box"); - }, - - @on("didRender") - _configureSelectBoxDOM: function() { - this.$().css("width", this.get("width")); - this.$(".select-box-header").css("height", this.$().height()); - this.$(".select-box-filter").css("height", this.$().height()); - - if (this.get("expanded")) { - this.$(".select-box-body").css('width', this.$().width()); - this.$(".select-box-collection").css("max-height", this.get("maxCollectionHeight")); - - this._bindTab(); - - Ember.run.schedule('afterRender', () => { - this.applyDirection(); - this._positionSelectBoxWrapper(); - }); - } else { - $(document).off("keydown.select-box"); - this.$(".select-box-wrapper").hide(); - } - }, - @observes("content.[]", "value") @on("didReceiveAttrs") _contentChanged: function() { @@ -162,59 +245,13 @@ export default Ember.Component.extend({ this.set("filteredContent", this._remapContent(this.get("content"))); this._setSelectedContent(this.get("content")); - if (this.get("dynamicHeaderText") === true) { + if (this.get("dynamicHeaderText")) { if (!Ember.isNone(this.get("selectedContent.text"))) { this.set("headerText", this.get("selectedContent.text")); } } }, - @on("didInsertElement") - _bindEvents: function() { - $(document).on("click.select-box", (event) => { - const clickOutside = $(event.target).parents(".select-box").attr("id") !== this.$().attr("id"); - if (this.get("expanded") && clickOutside) { - this.setProperties({ - expanded: false, - focused: false - }); - } - }); - - this.$(".select-box-offscreen").on("focusin.select-box", () => { - this.set("focused", true); - }); - - this.$(".select-box-offscreen").on("keydown.select-box", (event) => { - const keyCode = event.keyCode || event.which; - - if(keyCode === 13 || keyCode === 40) { - this.setProperties({expanded: true, focused: false}); - return false; - } - - if(keyCode === 27) { - this.$(".select-box-offscreen").blur(); - return false; - } - - if (keyCode >= 65 && keyCode <= 90) { - this.setProperties({expanded: true, focused: false}); - Ember.run.schedule("afterRender", () => { - this.$(".filter-query").focus().val(String.fromCharCode(keyCode)); - }); - } - }); - - this.$(".select-box-offscreen").on("focusout.select-box", () => { - this.set("focused", false); - }); - - $(window).on("resize.select-box", () => { - this.set("expanded", false); - }); - }, - actions: { onToggle() { this.toggleProperty("expanded"); @@ -225,7 +262,7 @@ export default Ember.Component.extend({ }, onSelectRow(id) { - if(this.get("castInteger") === true) { + if (this.get("castInteger")) { id = parseInt(id, 10); } @@ -256,7 +293,7 @@ export default Ember.Component.extend({ _normalizeContent(content) { let id = content[this.get("idKey")]; - if(this.get("castInteger") === true) { + if (this.get("castInteger")) { id = parseInt(id, 10); } @@ -286,28 +323,4 @@ export default Ember.Component.extend({ height: headerHeight + this.$(".select-box-body").outerHeight() }); }, - - applyDirection() { - this.$().removeClass("is-reversed"); - - const offsetTop = this.$()[0].getBoundingClientRect().top; - const windowHeight = $(window).height(); - const headerHeight = this.$(".select-box-header").outerHeight(); - const filterHeight = this.$(".select-box-filter").outerHeight(); - - if (windowHeight - (offsetTop + this.get("maxCollectionHeight") + filterHeight + headerHeight) < 0) { - this.$().addClass("is-reversed"); - this.$(".select-box-body").css({ - left: this.get("horizontalOffset"), - top: "", - bottom: headerHeight + this.get("verticalOffset") - }); - } else { - this.$(".select-box-body").css({ - left: this.get("horizontalOffset"), - top: headerHeight + this.get("verticalOffset"), - bottom: "" - }); - } - }, }); diff --git a/app/assets/javascripts/discourse/components/select-box/select-box-filter.js.es6 b/app/assets/javascripts/discourse/components/select-box/select-box-filter.js.es6 index 8c87886c961..50c8474e5b4 100644 --- a/app/assets/javascripts/discourse/components/select-box/select-box-filter.js.es6 +++ b/app/assets/javascripts/discourse/components/select-box/select-box-filter.js.es6 @@ -1,3 +1,5 @@ export default Ember.Component.extend({ - classNames: "select-box-filter" + classNames: "select-box-filter", + + classNameBindings: ["focused:is-focused"] }); diff --git a/app/assets/javascripts/discourse/templates/components/select-box.hbs b/app/assets/javascripts/discourse/templates/components/select-box.hbs index ac6e74e2b9b..89fadee0bd2 100644 --- a/app/assets/javascripts/discourse/templates/components/select-box.hbs +++ b/app/assets/javascripts/discourse/templates/components/select-box.hbs @@ -22,8 +22,9 @@ {{#if filterable}} {{component selectBoxFilterComponent onFilterChange=(action "onFilterChange") - filterIcon=filterIcon - filterPlaceholder=filterPlaceholder + icon=filterIcon + focused=filterFocused + placeholder=filterPlaceholder }} {{/if}} @@ -40,4 +41,6 @@ {{/if}} -
+{{#if wrapper}} +
+{{/if}} diff --git a/app/assets/javascripts/discourse/templates/components/select-box/select-box-filter.hbs b/app/assets/javascripts/discourse/templates/components/select-box/select-box-filter.hbs index 3ec68be715c..3ba9d155040 100644 --- a/app/assets/javascripts/discourse/templates/components/select-box/select-box-filter.hbs +++ b/app/assets/javascripts/discourse/templates/components/select-box/select-box-filter.hbs @@ -1,7 +1,7 @@ {{input tabindex="-1" class="filter-query" - placeholder=filterPlaceholder + placeholder=placeholder key-up=onFilterChange autocomplete="off" autocorrect="off" @@ -9,6 +9,6 @@ spellcheck=false }} -{{#if filterIcon}} - {{d-icon filterIcon}} +{{#if icon}} + {{d-icon icon class="filter-icon"}} {{/if}} diff --git a/app/assets/javascripts/discourse/templates/components/select-box/select-box-header.hbs b/app/assets/javascripts/discourse/templates/components/select-box/select-box-header.hbs index c0bf0a71cef..14184521797 100644 --- a/app/assets/javascripts/discourse/templates/components/select-box/select-box-header.hbs +++ b/app/assets/javascripts/discourse/templates/components/select-box/select-box-header.hbs @@ -1,15 +1,9 @@ -
- {{#if icon}} -
- {{d-icon icon}} -
- {{/if}} +{{#if icon}} + {{d-icon icon class="icon"}} +{{/if}} - - {{text}} - + + {{{text}}} + -
- {{d-icon caretIcon}} -
-
+{{d-icon caretIcon class="caret-icon"}} diff --git a/app/assets/javascripts/discourse/templates/composer.hbs b/app/assets/javascripts/discourse/templates/composer.hbs index 7cfba0916b9..c9e32dceaf8 100644 --- a/app/assets/javascripts/discourse/templates/composer.hbs +++ b/app/assets/javascripts/discourse/templates/composer.hbs @@ -72,7 +72,7 @@ {{#if model.showCategoryChooser}}
- {{category-select-box valueAttribute="id" value=model.categoryId scopedCategoryId=scopedCategoryId tabindex="3"}} + {{category-select-box value=model.categoryId scopedCategoryId=scopedCategoryId tabindex="3"}} {{popup-input-tip validation=categoryValidation}}
{{#if model.archetype.hasOptions}} diff --git a/app/assets/stylesheets/common/components/category-select-box.scss b/app/assets/stylesheets/common/components/category-select-box.scss index 55d8ba553f7..7c3d63c9900 100644 --- a/app/assets/stylesheets/common/components/category-select-box.scss +++ b/app/assets/stylesheets/common/components/category-select-box.scss @@ -1,11 +1,8 @@ -.category-select-box.select-box { - height: 34px; - +.category-select-box { .select-box-row { display: -webkit-box; display: -ms-flexbox; display: flex; - line-height: 14px; -webkit-box-orient: vertical; -webkit-box-direction: normal; -ms-flex-direction: column; diff --git a/app/assets/stylesheets/common/components/select-box.scss b/app/assets/stylesheets/common/components/select-box.scss index 4b820bb044e..18c1dcb6a99 100644 --- a/app/assets/stylesheets/common/components/select-box.scss +++ b/app/assets/stylesheets/common/components/select-box.scss @@ -2,9 +2,7 @@ border-radius: 3px; -webkit-box-sizing: border-box; box-sizing: border-box; - display: -webkit-box; - display: -ms-flexbox; - display: flex; + display: inline-block; -webkit-box-orient: vertical; -webkit-box-direction: normal; -ms-flex-direction: column; @@ -39,6 +37,16 @@ .collection, { border-radius: 0 0 3px 3px; } + + .select-box-header { + border-radius: 3px 3px 0 0; + } + + &.is-reversed { + .select-box-header { + border-radius: 0 0 3px 3px; + } + } } &.is-highlighted { @@ -62,8 +70,7 @@ } .d-icon { - color: dark-light-choose(scale-color($header_primary, $lightness: 50%), $header_primary); - font-size: 14px; + opacity: 0.7; } .select-box-header { @@ -74,6 +81,9 @@ box-sizing: border-box; cursor: pointer; outline: none; + display: flex; + align-items: center; + justify-content: space-between; &.is-focused { border: 1px solid $tertiary; @@ -142,24 +152,22 @@ } .select-box .select-box-header { - .wrapper { - height: inherit; - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: horizontal; - -webkit-box-direction: normal; - -ms-flex-direction: row; - flex-direction: row; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - -webkit-box-pack: justify; - -ms-flex-pack: justify; - justify-content: space-between; - padding-left: 10px; - padding-right: 10px; - } + height: inherit; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + padding-left: 10px; + padding-right: 10px; .current-selection { text-align: left; @@ -169,6 +177,7 @@ text-overflow: ellipsis; white-space: nowrap; overflow: hidden; + color: inherit; } .icon { @@ -218,10 +227,6 @@ margin: 5px; min-height: 1px; - .d-icon { - margin-right: 5px; - } - .text { margin: 0; } @@ -246,7 +251,8 @@ justify-content: space-between; padding: 0 10px; - input, input:focus { + .filter-query, .filter-query:focus, .filter-query:active { + background: none; margin: 0; -webkit-box-flex: 1; -ms-flex: 1; diff --git a/test/javascripts/components/select-box-test.js.es6 b/test/javascripts/components/select-box-test.js.es6 index ccf9fd05682..47090c6e687 100644 --- a/test/javascripts/components/select-box-test.js.es6 +++ b/test/javascripts/components/select-box-test.js.es6 @@ -87,7 +87,7 @@ componentTest('customisable icon', { template: '{{select-box icon="shower"}}', test(assert) { - assert.equal(find(".select-box-header .icon").html().trim(), "", "it has a the correct icon"); + assert.equal(find(".select-box-header .icon").hasClass("d-icon-shower"), true, "it has a the correct icon"); } });