From 324aa3eb61bbee5301ee733f3d5d48083eef239b Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Tue, 15 Sep 2020 09:39:12 +0200 Subject: [PATCH] REFACTOR: reworks all the search-advanced-options panel (#10661) * REFACTOR: reworks all the search-advanced-options panel This commit includes the following changes: - prevents any mutation of external (to the component) values - get rid of observers - uses @action - minor UI tweaks - dropped the unecessary debounce - drops all the legacy code for badges/groups which is not being used - replaces user-selector by user-chooser and improves multi-select to not show `search` if maximum has been reached Most importantly this refactor should fix multiple bugs due to _update() being called multiple times if searchTerm was empty and other various bugs where some changes in searchTerm was not applied to the sidebar. --- .../app/components/search-advanced-options.js | 441 ++++++++---------- .../components/search-advanced-options.hbs | 109 +++-- .../app/templates/full-page-search.hbs | 19 +- .../multi-select/multi-select-header.js | 8 + .../multi-select/multi-select-header.hbs | 12 +- .../stylesheets/common/base/search.scss | 7 +- app/assets/stylesheets/mobile/search.scss | 3 +- .../acceptance/search-full-test.js | 6 +- test/javascripts/helpers/qunit-helpers.js | 13 + 9 files changed, 307 insertions(+), 311 deletions(-) diff --git a/app/assets/javascripts/discourse/app/components/search-advanced-options.js b/app/assets/javascripts/discourse/app/components/search-advanced-options.js index 375177a080c..37bf5c291e0 100644 --- a/app/assets/javascripts/discourse/app/components/search-advanced-options.js +++ b/app/assets/javascripts/discourse/app/components/search-advanced-options.js @@ -1,19 +1,13 @@ import I18n from "I18n"; -import { debounce, scheduleOnce } from "@ember/runloop"; import Component from "@ember/component"; -import { observes } from "discourse-common/utils/decorators"; +import { action } from "@ember/object"; import { escapeExpression } from "discourse/lib/utilities"; -import Group from "discourse/models/group"; -import Badge from "discourse/models/badge"; import Category from "discourse/models/category"; -import { INPUT_DELAY } from "discourse-common/config/environment"; const REGEXP_BLOCKS = /(([^" \t\n\x0B\f\r]+)?(("[^"]+")?))/g; const REGEXP_USERNAME_PREFIX = /^(user:|@)/gi; const REGEXP_CATEGORY_PREFIX = /^(category:|#)/gi; -const REGEXP_GROUP_PREFIX = /^group:/gi; -const REGEXP_BADGE_PREFIX = /^badge:/gi; const REGEXP_TAGS_PREFIX = /^(tags?:|#(?=[a-z0-9\-]+::tag))/gi; const REGEXP_IN_PREFIX = /^(in|with):/gi; const REGEXP_STATUS_PREFIX = /^status:/gi; @@ -77,30 +71,17 @@ function addAdvancedSearchOptions(options) { export default Component.extend({ classNames: ["search-advanced-options"], + category: null, init() { this._super(...arguments); - this._init(); - - scheduleOnce("afterRender", this, this._update); - }, - - @observes("searchTerm") - _updateOptions() { - this._update(); - debounce(this, this._update, INPUT_DELAY); - }, - - _init() { this.setProperties({ searchedTerms: { - username: "", - category: "", - group: [], - badge: [], - tags: [], - in: "", + username: null, + category: null, + tags: null, + in: null, special: { in: { title: false, @@ -110,11 +91,11 @@ export default Component.extend({ }, all_tags: false, }, - status: "", - min_post_count: "", + status: null, + min_post_count: null, time: { when: "before", - days: "", + days: null, }, }, inOptions: this.currentUser @@ -125,16 +106,11 @@ export default Component.extend({ }); }, - _update() { - if (!this.searchTerm) { - this._init(); - return; - } + didReceiveAttrs() { + this._super(...arguments); this.setSearchedTermValue("searchedTerms.username", REGEXP_USERNAME_PREFIX); this.setSearchedTermValueForCategory(); - this.setSearchedTermValueForGroup(); - this.setSearchedTermValueForBadge(); this.setSearchedTermValueForTags(); let regExpInMatch = this.inOptions.map((option) => option.value).join("|"); @@ -216,14 +192,14 @@ export default Component.extend({ const match = this.filterBlocks(matchRegEx); let val = this.get(key); - if (match.length !== 0) { const userInput = match[0].replace(replaceRegEx, ""); - if (val !== userInput) { + + if (val !== userInput && userInput.length) { this.set(key, userInput); } } else if (val && val.length !== 0) { - this.set(key, ""); + this.set(key, null); } }, @@ -239,11 +215,6 @@ export default Component.extend({ } }, - setCategory(category) { - this.set("searchedTerms.category", category); - this.set("category", category); - }, - setSearchedTermValueForCategory() { const match = this.filterBlocks(REGEXP_CATEGORY_PREFIX); if (match.length !== 0) { @@ -259,61 +230,28 @@ export default Component.extend({ if ( (!existingInput && userInput) || (existingInput && userInput && existingInput.id !== userInput.id) - ) - this.setCategory(userInput); + ) { + this.set("searchedTerms.category", userInput); + } } else if (isNaN(subcategories)) { const userInput = Category.findSingleBySlug(subcategories[0]); if ( (!existingInput && userInput) || (existingInput && userInput && existingInput.id !== userInput.id) - ) - this.setCategory(userInput); + ) { + this.set("searchedTerms.category", userInput); + } } else { const userInput = Category.findById(subcategories[0]); if ( (!existingInput && userInput) || (existingInput && userInput && existingInput.id !== userInput.id) - ) - this.setCategory(userInput); + ) { + this.set("searchedTerms.category", userInput); + } } - } else this.set("searchedTerms.category", ""); - }, - - setSearchedTermValueForGroup() { - const match = this.filterBlocks(REGEXP_GROUP_PREFIX); - const group = this.get("searchedTerms.group"); - - if (match.length !== 0) { - const existingInput = Array.isArray(group) ? group[0] : group; - const userInput = match[0].replace(REGEXP_GROUP_PREFIX, ""); - - if (existingInput !== userInput) { - this.set( - "searchedTerms.group", - userInput.length !== 0 ? [userInput] : [] - ); - } - } else if (group.length !== 0) { - this.set("searchedTerms.group", []); - } - }, - - setSearchedTermValueForBadge() { - const match = this.filterBlocks(REGEXP_BADGE_PREFIX); - const badge = this.get("searchedTerms.badge"); - - if (match.length !== 0) { - const existingInput = Array.isArray(badge) ? badge[0] : badge; - const userInput = match[0].replace(REGEXP_BADGE_PREFIX, ""); - - if (existingInput !== userInput) { - this.set( - "searchedTerms.badge", - userInput.length !== 0 ? [userInput] : [] - ); - } - } else if (badge.length !== 0) { - this.set("searchedTerms.badge", []); + } else { + this.set("searchedTerms.category", null); } }, @@ -322,21 +260,24 @@ export default Component.extend({ const match = this.filterBlocks(REGEXP_TAGS_PREFIX); const tags = this.get("searchedTerms.tags"); - const contain_all_tags = this.get("searchedTerms.special.all_tags"); + if (match.length) { + this.set("searchedTerms.special.all_tags", match[0].includes("+")); + } + const containAllTags = this.get("searchedTerms.special.all_tags"); if (match.length !== 0) { - const join_char = contain_all_tags ? "+" : ","; - const existingInput = Array.isArray(tags) ? tags.join(join_char) : tags; + const joinChar = containAllTags ? "+" : ","; + const existingInput = Array.isArray(tags) ? tags.join(joinChar) : tags; const userInput = match[0].replace(REGEXP_TAGS_REPLACE, ""); if (existingInput !== userInput) { this.set( "searchedTerms.tags", - userInput.length !== 0 ? userInput.split(join_char) : [] + userInput.length !== 0 ? userInput.split(joinChar) : null ); } - } else if (tags.length !== 0) { - this.set("searchedTerms.tags", []); + } else if (!tags) { + this.set("searchedTerms.tags", null); } }, @@ -360,32 +301,141 @@ export default Component.extend({ this.setProperties(properties); } else { - this.set("searchedTerms.time.days", ""); + this.set("searchedTerms.time.when", "before"); + this.set("searchedTerms.time.days", null); } }, - @observes("searchedTerms.username") - updateSearchTermForUsername() { - const match = this.filterBlocks(REGEXP_USERNAME_PREFIX); - const userFilter = this.get("searchedTerms.username"); + updateInRegex(regex, filter) { + const match = this.filterBlocks(regex); + const inFilter = this.get("searchedTerms.special.in." + filter); let searchTerm = this.searchTerm || ""; - if (userFilter && userFilter.length !== 0) { - if (match.length !== 0) { - searchTerm = searchTerm.replace(match[0], `@${userFilter}`); - } else { - searchTerm += ` @${userFilter}`; + if (inFilter) { + if (match.length === 0) { + searchTerm += ` in:${filter}`; + this._updateSearchTerm(searchTerm); } - - this.set("searchTerm", searchTerm.trim()); } else if (match.length !== 0) { - searchTerm = searchTerm.replace(match[0], ""); - this.set("searchTerm", searchTerm.trim()); + searchTerm = searchTerm.replace(match, ""); + this._updateSearchTerm(searchTerm); } }, - @observes("searchedTerms.category") - updateSearchTermForCategory() { + @action + onChangeSearchTermMinPostCount(value) { + this.set("searchedTerms.min_post_count", value.length ? value : null); + this._updateSearchTermForMinPostCount(); + }, + + @action + onChangeSearchTermForIn(value) { + this.set("searchedTerms.in", value); + this._updateSearchTermForIn(); + }, + + @action + onChangeSearchTermForStatus(value) { + this.set("searchedTerms.status", value); + this._updateSearchTermForStatus(); + }, + + @action + onChangeWhenTime(time) { + if (time) { + this.set("searchedTerms.time.when", time); + this._updateSearchTermForPostTime(); + } + }, + + @action + onChangeWhenDate(date) { + if (date) { + this.set("searchedTerms.time.days", date.format("YYYY-MM-DD")); + this._updateSearchTermForPostTime(); + } + }, + + @action + onChangeSearchTermForCategory(categoryId) { + if (categoryId) { + const category = Category.findById(categoryId); + this.onChangeCategory && this.onChangeCategory(category); + this.set("searchedTerms.category", category); + } else { + this.onChangeCategory && this.onChangeCategory(null); + this.set("searchedTerms.category", null); + } + + this._updateSearchTermForCategory(); + }, + + @action + onChangeSearchTermForUsername(username) { + this.set("searchedTerms.username", username.length ? username : null); + this._updateSearchTermForUsername(); + }, + + @action + onChangeSearchTermForTags(tags) { + this.set("searchedTerms.tags", tags.length ? tags : null); + this._updateSearchTermForTags(); + }, + + @action + onChangeSearchTermForAllTags(checked) { + this.set("searchedTerms.special.all_tags", checked); + this._updateSearchTermForTags(); + }, + + @action + onChangeSearchTermForSpecialInLikes(checked) { + this.set("searchedTerms.special.in.likes", checked); + this.updateInRegex(REGEXP_SPECIAL_IN_LIKES_MATCH, "likes"); + }, + + @action + onChangeSearchTermForSpecialInPersonal(checked) { + this.set("searchedTerms.special.in.personal", checked); + this.updateInRegex(REGEXP_SPECIAL_IN_PERSONAL_MATCH, "personal"); + }, + + @action + onChangeSearchTermForSpecialInSeen(checked) { + this.set("searchedTerms.special.in.seen", checked); + this.updateInRegex(REGEXP_SPECIAL_IN_SEEN_MATCH, "seen"); + }, + + @action + onChangeSearchTermForSpecialInTitle(checked) { + this.set("searchedTerms.special.in.title", checked); + this.updateInRegex(REGEXP_SPECIAL_IN_TITLE_MATCH, "title"); + }, + + _updateSearchTermForTags() { + const match = this.filterBlocks(REGEXP_TAGS_PREFIX); + const tagFilter = this.get("searchedTerms.tags"); + let searchTerm = this.searchTerm || ""; + const containAllTags = this.get("searchedTerms.special.all_tags"); + + if (tagFilter && tagFilter.length !== 0) { + const joinChar = containAllTags ? "+" : ","; + const tags = tagFilter.join(joinChar); + + if (match.length !== 0) { + searchTerm = searchTerm.replace(match[0], `tags:${tags}`); + } else { + searchTerm += ` tags:${tags}`; + } + + this._updateSearchTerm(searchTerm); + } else if (match.length !== 0) { + searchTerm = searchTerm.replace(match[0], ""); + this._updateSearchTerm(searchTerm); + } + }, + + _updateSearchTermForCategory() { const match = this.filterBlocks(REGEXP_CATEGORY_PREFIX); const categoryFilter = this.get("searchedTerms.category"); let searchTerm = this.searchTerm || ""; @@ -411,7 +461,7 @@ export default Component.extend({ ); else searchTerm += ` #${parentSlug}:${slug}`; - this.set("searchTerm", searchTerm.trim()); + this._updateSearchTerm(searchTerm); } else { if (slugCategoryMatches) searchTerm = searchTerm.replace(slugCategoryMatches[0], `#${slug}`); @@ -422,7 +472,7 @@ export default Component.extend({ ); else searchTerm += ` #${slug}`; - this.set("searchTerm", searchTerm.trim()); + this._updateSearchTerm(searchTerm); } } else { if (slugCategoryMatches) @@ -430,76 +480,50 @@ export default Component.extend({ if (idCategoryMatches) searchTerm = searchTerm.replace(idCategoryMatches[0], ""); - this.set("searchTerm", searchTerm.trim()); + this._updateSearchTerm(searchTerm); } }, - @observes("searchedTerms.group") - updateSearchTermForGroup() { - const match = this.filterBlocks(REGEXP_GROUP_PREFIX); - const groupFilter = this.get("searchedTerms.group"); + _updateSearchTermForUsername() { + const match = this.filterBlocks(REGEXP_USERNAME_PREFIX); + const userFilter = this.get("searchedTerms.username"); let searchTerm = this.searchTerm || ""; - if (groupFilter && groupFilter.length !== 0) { + if (userFilter && userFilter.length !== 0) { if (match.length !== 0) { - searchTerm = searchTerm.replace(match[0], ` group:${groupFilter}`); + searchTerm = searchTerm.replace(match[0], `@${userFilter}`); } else { - searchTerm += ` group:${groupFilter}`; + searchTerm += ` @${userFilter}`; } - this.set("searchTerm", searchTerm); + this._updateSearchTerm(searchTerm); } else if (match.length !== 0) { searchTerm = searchTerm.replace(match[0], ""); - this.set("searchTerm", searchTerm.trim()); + this._updateSearchTerm(searchTerm); } }, - @observes("searchedTerms.badge") - updateSearchTermForBadge() { - const match = this.filterBlocks(REGEXP_BADGE_PREFIX); - const badgeFilter = this.get("searchedTerms.badge"); + _updateSearchTermForPostTime() { + const match = this.filterBlocks(REGEXP_POST_TIME_PREFIX); + const timeDaysFilter = this.get("searchedTerms.time.days"); let searchTerm = this.searchTerm || ""; - if (badgeFilter && badgeFilter.length !== 0) { + if (timeDaysFilter) { + const when = this.get("searchedTerms.time.when"); if (match.length !== 0) { - searchTerm = searchTerm.replace(match[0], ` badge:${badgeFilter}`); + searchTerm = searchTerm.replace(match[0], `${when}:${timeDaysFilter}`); } else { - searchTerm += ` badge:${badgeFilter}`; + searchTerm += ` ${when}:${timeDaysFilter}`; } - this.set("searchTerm", searchTerm); + this._updateSearchTerm(searchTerm); } else if (match.length !== 0) { searchTerm = searchTerm.replace(match[0], ""); - this.set("searchTerm", searchTerm.trim()); + this._updateSearchTerm(searchTerm); } }, - @observes("searchedTerms.tags", "searchedTerms.special.all_tags") - updateSearchTermForTags() { - const match = this.filterBlocks(REGEXP_TAGS_PREFIX); - const tagFilter = this.get("searchedTerms.tags"); - let searchTerm = this.searchTerm || ""; - const contain_all_tags = this.get("searchedTerms.special.all_tags"); - - if (tagFilter && tagFilter.length !== 0) { - const join_char = contain_all_tags ? "+" : ","; - const tags = tagFilter.join(join_char); - - if (match.length !== 0) { - searchTerm = searchTerm.replace(match[0], `tags:${tags}`); - } else { - searchTerm += ` tags:${tags}`; - } - - this.set("searchTerm", searchTerm.trim()); - } else if (match.length !== 0) { - searchTerm = searchTerm.replace(match[0], ""); - this.set("searchTerm", searchTerm.trim()); - } - }, - - @observes("searchedTerms.in") - updateSearchTermForIn() { + _updateSearchTermForIn() { let regExpInMatch = this.inOptions.map((option) => option.value).join("|"); const REGEXP_IN_MATCH = new RegExp(`(in|with):(${regExpInMatch})`); @@ -518,51 +542,14 @@ export default Component.extend({ searchTerm += ` ${keyword}:${inFilter}`; } - this.set("searchTerm", searchTerm.trim()); + this._updateSearchTerm(searchTerm); } else if (match.length !== 0) { searchTerm = searchTerm.replace(match, ""); - this.set("searchTerm", searchTerm.trim()); + this._updateSearchTerm(searchTerm); } }, - updateInRegex(regex, filter) { - const match = this.filterBlocks(regex); - const inFilter = this.get("searchedTerms.special.in." + filter); - let searchTerm = this.searchTerm || ""; - - if (inFilter) { - if (match.length === 0) { - searchTerm += ` in:${filter}`; - this.set("searchTerm", searchTerm.trim()); - } - } else if (match.length !== 0) { - searchTerm = searchTerm.replace(match, ""); - this.set("searchTerm", searchTerm.trim()); - } - }, - - @observes("searchedTerms.special.in.likes") - updateSearchTermForSpecialInLikes() { - this.updateInRegex(REGEXP_SPECIAL_IN_LIKES_MATCH, "likes"); - }, - - @observes("searchedTerms.special.in.personal") - updateSearchTermForSpecialInPersonal() { - this.updateInRegex(REGEXP_SPECIAL_IN_PERSONAL_MATCH, "personal"); - }, - - @observes("searchedTerms.special.in.seen") - updateSearchTermForSpecialInSeen() { - this.updateInRegex(REGEXP_SPECIAL_IN_SEEN_MATCH, "seen"); - }, - - @observes("searchedTerms.special.in.title") - updateSearchTermForSpecialInTitle() { - this.updateInRegex(REGEXP_SPECIAL_IN_TITLE_MATCH, "title"); - }, - - @observes("searchedTerms.status") - updateSearchTermForStatus() { + _updateSearchTermForStatus() { let regExpStatusMatch = this.statusOptions .map((status) => status.value) .join("|"); @@ -579,35 +566,14 @@ export default Component.extend({ searchTerm += ` status:${statusFilter}`; } - this.set("searchTerm", searchTerm.trim()); + this._updateSearchTerm(searchTerm); } else if (match.length !== 0) { searchTerm = searchTerm.replace(match[0], ""); - this.set("searchTerm", searchTerm.trim()); + this._updateSearchTerm(searchTerm); } }, - updateSearchTermForPostTime() { - const match = this.filterBlocks(REGEXP_POST_TIME_PREFIX); - const timeDaysFilter = this.get("searchedTerms.time.days"); - let searchTerm = this.searchTerm || ""; - - if (timeDaysFilter) { - const when = this.get("searchedTerms.time.when"); - if (match.length !== 0) { - searchTerm = searchTerm.replace(match[0], `${when}:${timeDaysFilter}`); - } else { - searchTerm += ` ${when}:${timeDaysFilter}`; - } - - this.set("searchTerm", searchTerm.trim()); - } else if (match.length !== 0) { - searchTerm = searchTerm.replace(match[0], ""); - this.set("searchTerm", searchTerm.trim()); - } - }, - - @observes("searchedTerms.min_post_count") - updateSearchTermForMinPostCount() { + _updateSearchTermForMinPostCount() { const match = this.filterBlocks(REGEXP_MIN_POST_COUNT_PREFIX); const postsCountFilter = this.get("searchedTerms.min_post_count"); let searchTerm = this.searchTerm || ""; @@ -622,42 +588,15 @@ export default Component.extend({ searchTerm += ` min_post_count:${postsCountFilter}`; } - this.set("searchTerm", searchTerm.trim()); + this._updateSearchTerm(searchTerm); } else if (match.length !== 0) { searchTerm = searchTerm.replace(match[0], ""); - this.set("searchTerm", searchTerm.trim()); + this._updateSearchTerm(searchTerm); } }, - groupFinder(term) { - return Group.findAll({ term: term, ignore_automatic: false }); - }, - - badgeFinder(term) { - return Badge.findAll({ search: term }); - }, - - actions: { - onChangeWhenTime(time) { - if (time) { - this.set("searchedTerms.time.when", time); - this.updateSearchTermForPostTime(); - } - }, - onChangeWhenDate(date) { - if (date) { - this.set("searchedTerms.time.days", moment(date).format("YYYY-MM-DD")); - this.updateSearchTermForPostTime(); - } - }, - - onChangeCategory(categoryId) { - if (categoryId) { - this.set("searchedTerms.category", Category.findById(categoryId)); - } else { - this.set("searchedTerms.category", null); - } - }, + _updateSearchTerm(searchTerm) { + this.onChangeSearchTerm(searchTerm.trim()); }, }); diff --git a/app/assets/javascripts/discourse/app/templates/components/search-advanced-options.hbs b/app/assets/javascripts/discourse/app/templates/components/search-advanced-options.hbs index 334df9f68cf..3994363d8b4 100644 --- a/app/assets/javascripts/discourse/app/templates/components/search-advanced-options.hbs +++ b/app/assets/javascripts/discourse/app/templates/components/search-advanced-options.hbs @@ -2,14 +2,17 @@
- +
- {{user-selector - excludeCurrentUser=false - usernames=searchedTerms.username - single=true - canReceiveUpdates=true - class="user-selector" + {{user-chooser + value=searchedTerms.username + onChange=(action "onChangeSearchTermForUsername") + options=(hash + maximum=1 + excludeCurrentUser=false + ) }}
@@ -18,28 +21,12 @@
{{search-advanced-category-chooser value=searchedTerms.category.id - onChange=(action "onChangeCategory") + onChange=(action "onChangeSearchTermForCategory") }}
-{{!-- disable these super-advanced searches for now -
-
- -
- {{group-selector groupFinder=groupFinder groupNames=searchedTerms.group single="true" canReceiveUpdates="true"}} -
-
-
- -
- {{badge-selector badgeFinder=badgeFinder badgeNames=searchedTerms.badge single="true" canReceiveUpdates="true"}} -
-
-
--}} - {{#if siteSettings.tagging_enabled}}
@@ -50,10 +37,18 @@ allowCreate=false everyTag=true unlimitedTagCount=true - onChange=(action (mut searchedTerms.tags)) + onChange=(action "onChangeSearchTermForTags") }}
- +
@@ -66,10 +61,42 @@
{{#if currentUser}}
- - - - + + + +
{{/if}} {{combo-box @@ -77,8 +104,11 @@ valueProperty="value" content=inOptions value=searchedTerms.in - none="user.locale.any" - onChange=(action (mut searchedTerms.in)) + onChange=(action "onChangeSearchTermForIn") + options=(hash + none="user.locale.any" + clearable=true + ) }}
@@ -90,8 +120,11 @@ valueProperty="value" content=statusOptions value=searchedTerms.status - none="user.locale.any" - onChange=(action (mut searchedTerms.status)) + onChange=(action "onChangeSearchTermForStatus") + options=(hash + none="user.locale.any" + clearable=true + ) }} @@ -118,7 +151,13 @@
- {{input type="number" value=searchedTerms.min_post_count class="input-small" id="search-min-post-count"}} + {{input + type="number" + value=(readonly searchedTerms.min_post_count) + class="input-small" + id="search-min-post-count" + input=(action "onChangeSearchTermMinPostCount" value="target.value") + }}
diff --git a/app/assets/javascripts/discourse/app/templates/full-page-search.hbs b/app/assets/javascripts/discourse/app/templates/full-page-search.hbs index 3f860f55256..f95bc36dc71 100644 --- a/app/assets/javascripts/discourse/app/templates/full-page-search.hbs +++ b/app/assets/javascripts/discourse/app/templates/full-page-search.hbs @@ -198,11 +198,10 @@ {{/if}} {{#if site.mobileView}} - {{d-button - class="search-advanced-title" - action=(action "toggleAdvancedSearch") - icon=(if expanded "caret-down" "caret-right") - label="search.advanced.title"}} +
+ {{d-icon (if expanded "caret-down" "caret-right")}} + {{i18n "search.advanced.title"}} +
{{else}} {{i18n "search.advanced.title"}} @@ -213,17 +212,17 @@ {{#if expanded}}
{{search-advanced-options - searchTerm=searchTerm - isExpanded=expanded + searchTerm=(readonly searchTerm) + onChangeSearchTerm=(action (mut searchTerm)) }}
{{/if}} {{else}}
{{search-advanced-options - searchTerm=searchTerm - isExpanded=true - category=category + searchTerm=(readonly searchTerm) + onChangeSearchTerm=(action (mut searchTerm)) + onChangeCategory=(action (mut category)) }} {{d-button diff --git a/app/assets/javascripts/select-kit/addon/components/multi-select/multi-select-header.js b/app/assets/javascripts/select-kit/addon/components/multi-select/multi-select-header.js index f53a608c255..e01a0f7ca80 100644 --- a/app/assets/javascripts/select-kit/addon/components/multi-select/multi-select-header.js +++ b/app/assets/javascripts/select-kit/addon/components/multi-select/multi-select-header.js @@ -11,6 +11,14 @@ export default SelectKitHeaderComponent.extend({ return makeArray(this.selectedContent).map((c) => this.getName(c)); }), + hasReachedMaximumSelection: computed("selectedValue", function () { + if (!this.selectKit.options.maximum) { + return false; + } + + return this.selectedValue.length >= this.selectKit.options.maximum; + }), + selectedValue: computed("selectedContent", function () { return makeArray(this.selectedContent) .map((c) => { diff --git a/app/assets/javascripts/select-kit/addon/templates/components/multi-select/multi-select-header.hbs b/app/assets/javascripts/select-kit/addon/templates/components/multi-select/multi-select-header.hbs index 78f0d8f6aad..67b7191840b 100644 --- a/app/assets/javascripts/select-kit/addon/templates/components/multi-select/multi-select-header.hbs +++ b/app/assets/javascripts/select-kit/addon/templates/components/multi-select/multi-select-header.hbs @@ -7,9 +7,11 @@ }} {{/each}} -
- {{component selectKit.options.filterComponent - selectKit=selectKit - }} -
+ {{#unless hasReachedMaximumSelection}} +
+ {{component selectKit.options.filterComponent + selectKit=selectKit + }} +
+ {{/unless}}
diff --git a/app/assets/stylesheets/common/base/search.scss b/app/assets/stylesheets/common/base/search.scss index 8a813bff4fe..8fdb982d36c 100644 --- a/app/assets/stylesheets/common/base/search.scss +++ b/app/assets/stylesheets/common/base/search.scss @@ -12,7 +12,6 @@ display: flex; justify-content: space-between; align-items: center; - justify-content: space-between; margin-bottom: 1em; .search-query { @@ -133,11 +132,7 @@ } font-weight: 700; text-align: left; - font-weight: bold; - - &.btn { - background: var(--primary-low); - } + cursor: pointer; .d-icon { margin: 0; diff --git a/app/assets/stylesheets/mobile/search.scss b/app/assets/stylesheets/mobile/search.scss index c4c9892bda7..a22c4ae9a9a 100644 --- a/app/assets/stylesheets/mobile/search.scss +++ b/app/assets/stylesheets/mobile/search.scss @@ -34,7 +34,8 @@ width: 100%; margin: 0; - .tag-chooser { + .tag-chooser, + .user-chooser { width: 100%; } } diff --git a/test/javascripts/acceptance/search-full-test.js b/test/javascripts/acceptance/search-full-test.js index 9d2967508f1..4388ac7106a 100644 --- a/test/javascripts/acceptance/search-full-test.js +++ b/test/javascripts/acceptance/search-full-test.js @@ -1,5 +1,5 @@ import selectKit from "helpers/select-kit-helper"; -import { acceptance, waitFor } from "helpers/qunit-helpers"; +import { selectDate, acceptance, waitFor } from "helpers/qunit-helpers"; acceptance("Search - Full Page", { settings: { tagging_enabled: true }, @@ -109,7 +109,7 @@ QUnit.test("escape search term", async (assert) => { assert.ok( exists( - '.search-advanced-options span:contains("gmail.com")' + '.search-advanced-options span:contains("<script>prompt(1337)</script>gmail.com")' ), "it escapes search term" ); @@ -355,7 +355,7 @@ QUnit.test("update post time through advanced search ui", async (assert) => { await visit("/search"); await fillIn(".search-query", "none"); - await fillIn("#search-post-date .date-picker", "2016-10-05"); + await selectDate("#search-post-date .date-picker", "2016-10-05"); const postTimeSelector = selectKit( ".search-advanced-options .select-kit#postTime" diff --git a/test/javascripts/helpers/qunit-helpers.js b/test/javascripts/helpers/qunit-helpers.js index 84b3e1d4ab1..95500cf7665 100644 --- a/test/javascripts/helpers/qunit-helpers.js +++ b/test/javascripts/helpers/qunit-helpers.js @@ -1,3 +1,4 @@ +import { Promise } from "rsvp"; import { isEmpty } from "@ember/utils"; import { later } from "@ember/runloop"; /* global QUnit, resetSite */ @@ -283,3 +284,15 @@ export function waitFor(assert, callback, timeout) { done(); }, timeout); } + +export async function selectDate(selector, date) { + return new Promise((resolve) => { + const elem = document.querySelector(selector); + elem.value = date; + const evt = new Event("input", { bubbles: true, cancelable: false }); + elem.dispatchEvent(evt); + elem.blur(); + + resolve(); + }); +}