FEATURE: user/category/tag results in full page search (#14346)
See PR for details, this commit also changes the layout of the full page search.
This commit is contained in:
parent
a736ff5f69
commit
dfeca42bf8
|
@ -80,7 +80,9 @@ export function addAdvancedSearchOptions(options) {
|
|||
}
|
||||
|
||||
export default Component.extend({
|
||||
classNames: ["search-advanced-options"],
|
||||
tagName: "details",
|
||||
attributeBindings: ["expandFilters:open"],
|
||||
classNames: ["advanced-filters"],
|
||||
category: null,
|
||||
|
||||
init() {
|
||||
|
@ -116,6 +118,7 @@ export default Component.extend({
|
|||
: inOptionsForAll(),
|
||||
statusOptions: statusOptions(),
|
||||
postTimeOptions: postTimeOptions(),
|
||||
showAllTagsCheckbox: false,
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -313,10 +316,10 @@ export default Component.extend({
|
|||
const userInput = match[0].replace(REGEXP_TAGS_REPLACE, "");
|
||||
|
||||
if (existingInput !== userInput) {
|
||||
this.set(
|
||||
"searchedTerms.tags",
|
||||
userInput.length !== 0 ? userInput.split(joinChar) : null
|
||||
);
|
||||
const updatedTags = userInput?.split(joinChar);
|
||||
|
||||
this.set("searchedTerms.tags", updatedTags);
|
||||
this.set("showAllTagsCheckbox", !!(updatedTags.length > 1));
|
||||
}
|
||||
} else if (!tags) {
|
||||
this.set("searchedTerms.tags", null);
|
||||
|
@ -496,6 +499,9 @@ export default Component.extend({
|
|||
searchTerm += ` tags:${tags}`;
|
||||
}
|
||||
|
||||
if (tagFilter.length > 1) {
|
||||
this.set("showAllTagsCheckbox", true);
|
||||
}
|
||||
this._updateSearchTerm(searchTerm);
|
||||
} else if (match.length !== 0) {
|
||||
searchTerm = searchTerm.replace(match[0], "");
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import Component from "@ember/component";
|
||||
|
||||
export default Component.extend({
|
||||
tagName: "",
|
||||
tagName: "div",
|
||||
classNames: ["fps-result"],
|
||||
classNameBindings: ["bulkSelectEnabled"],
|
||||
});
|
||||
|
|
|
@ -15,6 +15,9 @@ import { isEmpty } from "@ember/utils";
|
|||
import { or } from "@ember/object/computed";
|
||||
import { scrollTop } from "discourse/mixins/scroll-top";
|
||||
import { setTransient } from "discourse/lib/page-tracker";
|
||||
import { Promise } from "rsvp";
|
||||
import { search as searchCategoryTag } from "discourse/lib/category-tag-search";
|
||||
import userSearch from "discourse/lib/user-search";
|
||||
|
||||
const SortOrders = [
|
||||
{ name: I18n.t("search.relevance"), id: 0 },
|
||||
|
@ -23,6 +26,19 @@ const SortOrders = [
|
|||
{ name: I18n.t("search.most_viewed"), id: 3, term: "order:views" },
|
||||
{ name: I18n.t("search.latest_topic"), id: 4, term: "order:latest_topic" },
|
||||
];
|
||||
|
||||
export const SEARCH_TYPE_DEFAULT = "topics_posts";
|
||||
export const SEARCH_TYPE_CATS_TAGS = "categories_tags";
|
||||
export const SEARCH_TYPE_USERS = "users";
|
||||
|
||||
const SearchTypes = [
|
||||
{ name: I18n.t("search.type.default"), id: SEARCH_TYPE_DEFAULT },
|
||||
{
|
||||
name: I18n.t("search.type.categories_and_tags"),
|
||||
id: SEARCH_TYPE_CATS_TAGS,
|
||||
},
|
||||
{ name: I18n.t("search.type.users"), id: SEARCH_TYPE_USERS },
|
||||
];
|
||||
const PAGE_LIMIT = 10;
|
||||
|
||||
export default Controller.extend({
|
||||
|
@ -31,11 +47,17 @@ export default Controller.extend({
|
|||
bulkSelectEnabled: null,
|
||||
|
||||
loading: false,
|
||||
queryParams: ["q", "expanded", "context_id", "context", "skip_context"],
|
||||
q: null,
|
||||
selected: [],
|
||||
expanded: false,
|
||||
queryParams: [
|
||||
"q",
|
||||
"expanded",
|
||||
"context_id",
|
||||
"context",
|
||||
"skip_context",
|
||||
"search_type",
|
||||
],
|
||||
q: undefined,
|
||||
context_id: null,
|
||||
search_type: SEARCH_TYPE_DEFAULT,
|
||||
context: null,
|
||||
searching: false,
|
||||
sortOrder: 0,
|
||||
|
@ -43,12 +65,24 @@ export default Controller.extend({
|
|||
invalidSearch: false,
|
||||
page: 1,
|
||||
resultCount: null,
|
||||
searchTypes: SearchTypes,
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
||||
this.selected = [];
|
||||
},
|
||||
|
||||
@discourseComputed("resultCount")
|
||||
hasResults(resultCount) {
|
||||
return (resultCount || 0) > 0;
|
||||
},
|
||||
|
||||
@discourseComputed("expanded")
|
||||
expandFilters(expanded) {
|
||||
return expanded === "true";
|
||||
},
|
||||
|
||||
@discourseComputed("q")
|
||||
hasAutofocus(q) {
|
||||
return isEmpty(q);
|
||||
|
@ -138,6 +172,14 @@ export default Controller.extend({
|
|||
}
|
||||
},
|
||||
|
||||
@observes("search_type")
|
||||
triggerSearchOnTypeChange() {
|
||||
if (this.searchActive) {
|
||||
this.set("page", 1);
|
||||
this._search();
|
||||
}
|
||||
},
|
||||
|
||||
@observes("model")
|
||||
modelChanged() {
|
||||
if (this.searchTerm !== this.q) {
|
||||
|
@ -182,9 +224,19 @@ export default Controller.extend({
|
|||
return I18n.t("search.result_count", { count, plus, term });
|
||||
},
|
||||
|
||||
@observes("model.posts.length")
|
||||
@observes("model.[posts,categories,tags,users].length")
|
||||
resultCountChanged() {
|
||||
this.set("resultCount", this.get("model.posts.length"));
|
||||
if (!this.model.posts) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
this.set(
|
||||
"resultCount",
|
||||
this.model.posts.length +
|
||||
this.model.categories.length +
|
||||
this.model.tags.length +
|
||||
this.model.users.length
|
||||
);
|
||||
},
|
||||
|
||||
@discourseComputed("hasResults")
|
||||
|
@ -202,6 +254,18 @@ export default Controller.extend({
|
|||
return page === PAGE_LIMIT;
|
||||
},
|
||||
|
||||
@discourseComputed("search_type")
|
||||
usingDefaultSearchType(searchType) {
|
||||
return searchType === SEARCH_TYPE_DEFAULT;
|
||||
},
|
||||
|
||||
@discourseComputed("bulkSelectEnabled")
|
||||
searchInfoClassNames(bulkSelectEnabled) {
|
||||
return bulkSelectEnabled
|
||||
? "search-info bulk-select-visible"
|
||||
: "search-info";
|
||||
},
|
||||
|
||||
searchButtonDisabled: or("searching", "loading"),
|
||||
|
||||
_search() {
|
||||
|
@ -244,33 +308,71 @@ export default Controller.extend({
|
|||
|
||||
const searchKey = getSearchKey(args);
|
||||
|
||||
ajax("/search", { data: args })
|
||||
.then(async (results) => {
|
||||
const model = (await translateResults(results)) || {};
|
||||
switch (this.search_type) {
|
||||
case SEARCH_TYPE_CATS_TAGS:
|
||||
const categoryTagSearch = searchCategoryTag(
|
||||
searchTerm,
|
||||
this.siteSettings
|
||||
);
|
||||
Promise.resolve(categoryTagSearch)
|
||||
.then(async (results) => {
|
||||
const categories = results.filter((c) => Boolean(c.model));
|
||||
const tags = results.filter((c) => !Boolean(c.model));
|
||||
const model = (await translateResults({ categories, tags })) || {};
|
||||
this.set("model", model);
|
||||
})
|
||||
.finally(() => {
|
||||
this.setProperties({
|
||||
searching: false,
|
||||
loading: false,
|
||||
});
|
||||
});
|
||||
break;
|
||||
case SEARCH_TYPE_USERS:
|
||||
userSearch({ term: searchTerm, limit: 20 })
|
||||
.then(async (results) => {
|
||||
const model = (await translateResults({ users: results })) || {};
|
||||
this.set("model", model);
|
||||
})
|
||||
.finally(() => {
|
||||
this.setProperties({
|
||||
searching: false,
|
||||
loading: false,
|
||||
});
|
||||
});
|
||||
break;
|
||||
default:
|
||||
ajax("/search", { data: args })
|
||||
.then(async (results) => {
|
||||
const model = (await translateResults(results)) || {};
|
||||
|
||||
if (results.grouped_search_result) {
|
||||
this.set("q", results.grouped_search_result.term);
|
||||
}
|
||||
if (results.grouped_search_result) {
|
||||
this.set("q", results.grouped_search_result.term);
|
||||
}
|
||||
|
||||
if (args.page > 1) {
|
||||
if (model) {
|
||||
this.model.posts.pushObjects(model.posts);
|
||||
this.model.topics.pushObjects(model.topics);
|
||||
this.model.set(
|
||||
"grouped_search_result",
|
||||
results.grouped_search_result
|
||||
);
|
||||
}
|
||||
} else {
|
||||
setTransient("lastSearch", { searchKey, model }, 5);
|
||||
model.grouped_search_result = results.grouped_search_result;
|
||||
this.set("model", model);
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.set("searching", false);
|
||||
this.set("loading", false);
|
||||
});
|
||||
if (args.page > 1) {
|
||||
if (model) {
|
||||
this.model.posts.pushObjects(model.posts);
|
||||
this.model.topics.pushObjects(model.topics);
|
||||
this.model.set(
|
||||
"grouped_search_result",
|
||||
results.grouped_search_result
|
||||
);
|
||||
}
|
||||
} else {
|
||||
setTransient("lastSearch", { searchKey, model }, 5);
|
||||
model.grouped_search_result = results.grouped_search_result;
|
||||
this.set("model", model);
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.setProperties({
|
||||
searching: false,
|
||||
loading: false,
|
||||
});
|
||||
});
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
|
@ -309,16 +411,14 @@ export default Controller.extend({
|
|||
this.selected.clear();
|
||||
},
|
||||
|
||||
search() {
|
||||
search(collapseFilters = false) {
|
||||
if (collapseFilters) {
|
||||
document
|
||||
.querySelector("details.advanced-filters")
|
||||
?.removeAttribute("open");
|
||||
}
|
||||
this.set("page", 1);
|
||||
this._search();
|
||||
if (this.site.mobileView) {
|
||||
this.set("expanded", false);
|
||||
}
|
||||
},
|
||||
|
||||
toggleAdvancedSearch() {
|
||||
this.toggleProperty("expanded");
|
||||
},
|
||||
|
||||
loadMore() {
|
||||
|
|
|
@ -55,7 +55,7 @@ export function translateResults(results, opts) {
|
|||
|
||||
results.categories = results.categories
|
||||
.map(function (category) {
|
||||
return Category.list().findBy("id", category.id);
|
||||
return Category.list().findBy("id", category.id || category.model.id);
|
||||
})
|
||||
.compact();
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
<div>
|
||||
<form action="//google.com/search" id="google-search">
|
||||
<input type="text" name="q" aria-label={{i18n "search.search_google"}} value={{searchTerm}}>
|
||||
<input name="as_sitesearch" value={{siteUrl}} type="hidden">
|
||||
<button class="btn btn-primary" type="submit">{{i18n "search.search_google_button"}}</button>
|
||||
</form>
|
||||
</div>
|
||||
<form action="//google.com/search" id="google-search" class="inline-form">
|
||||
<input type="text" name="q" aria-label={{i18n "search.search_google"}} value={{searchTerm}}>
|
||||
<input name="as_sitesearch" value={{siteUrl}} type="hidden">
|
||||
<button class="btn btn-primary" type="submit">{{i18n "search.search_google_button"}}</button>
|
||||
</form>
|
||||
|
|
|
@ -1,170 +1,180 @@
|
|||
{{plugin-outlet name="advanced-search-options-above" args=(hash searchedTerms=searchedTerms onChangeSearchedTermField=onChangeSearchedTermField) tagName=""}}
|
||||
<summary>
|
||||
{{i18n "search.advanced.title"}}
|
||||
</summary>
|
||||
<div class="search-advanced-filters">
|
||||
<div class="search-advanced-options">
|
||||
{{plugin-outlet name="advanced-search-options-above" args=(hash searchedTerms=searchedTerms onChangeSearchedTermField=onChangeSearchedTermField) tagName=""}}
|
||||
|
||||
<div class="container advanced-search-posted-by-group">
|
||||
<div class="control-group pull-left">
|
||||
<label class="control-label" for="search-posted-by">
|
||||
{{i18n "search.advanced.posted_by.label"}}
|
||||
</label>
|
||||
<div class="controls">
|
||||
{{user-chooser
|
||||
id="search-posted-by"
|
||||
value=searchedTerms.username
|
||||
onChange=(action "onChangeSearchTermForUsername")
|
||||
options=(hash
|
||||
maximum=1
|
||||
excludeCurrentUser=false
|
||||
)
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group pull-left">
|
||||
<label class="control-label" for="search-in-category">{{i18n "search.advanced.in_category.label"}}</label>
|
||||
<div class="controls">
|
||||
{{search-advanced-category-chooser
|
||||
id="search-in-category"
|
||||
value=searchedTerms.category.id
|
||||
onChange=(action "onChangeSearchTermForCategory")
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#if siteSettings.tagging_enabled}}
|
||||
<div class="container advanced-search-tag-group">
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="search-with-tags">{{i18n "search.advanced.with_tags.label"}}</label>
|
||||
<div class="control-group advanced-search-category">
|
||||
<label class="control-label" for="search-in-category">{{i18n "search.advanced.in_category.label"}}</label>
|
||||
<div class="controls">
|
||||
{{tag-chooser
|
||||
id="search-with-tags"
|
||||
tags=searchedTerms.tags
|
||||
allowCreate=false
|
||||
everyTag=true
|
||||
unlimitedTagCount=true
|
||||
onChange=(action "onChangeSearchTermForTags")
|
||||
{{search-advanced-category-chooser
|
||||
id="search-in-category"
|
||||
value=searchedTerms.category.id
|
||||
onChange=(action "onChangeSearchTermForCategory")
|
||||
}}
|
||||
<section class="field">
|
||||
<label>
|
||||
{{input
|
||||
type="checkbox"
|
||||
class="all-tags"
|
||||
checked=searchedTerms.special.all_tags
|
||||
click=(action "onChangeSearchTermForAllTags" value="target.checked")
|
||||
}}
|
||||
{{i18n "search.advanced.filters.all_tags"}}
|
||||
</label>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="container advanced-search-topics-posts-group">
|
||||
<div class="control-group pull-left">
|
||||
<div class="controls">
|
||||
<fieldset class="grouped-control">
|
||||
<legend class="grouped-control-label" for="search-in-options">{{i18n "search.advanced.filters.label"}}</legend>
|
||||
{{#if siteSettings.tagging_enabled}}
|
||||
<div class="control-group advanced-search-tags">
|
||||
<label class="control-label" for="search-with-tags">{{i18n "search.advanced.with_tags.label"}}</label>
|
||||
<div class="controls">
|
||||
{{tag-chooser
|
||||
id="search-with-tags"
|
||||
tags=searchedTerms.tags
|
||||
allowCreate=false
|
||||
everyTag=true
|
||||
unlimitedTagCount=true
|
||||
onChange=(action "onChangeSearchTermForTags")
|
||||
}}
|
||||
{{#if showAllTagsCheckbox}}
|
||||
<section class="field">
|
||||
<label>
|
||||
{{input
|
||||
type="checkbox"
|
||||
class="all-tags"
|
||||
checked=searchedTerms.special.all_tags
|
||||
click=(action "onChangeSearchTermForAllTags" value="target.checked")
|
||||
}}
|
||||
{{i18n "search.advanced.filters.all_tags"}}
|
||||
</label>
|
||||
</section>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if currentUser}}
|
||||
<div class="grouped-control-field">
|
||||
{{input
|
||||
id="matching-title-only"
|
||||
type="checkbox"
|
||||
class="in-title"
|
||||
checked=searchedTerms.special.in.title
|
||||
click=(action "onChangeSearchTermForSpecialInTitle" value="target.checked")
|
||||
}}
|
||||
<label for="matching-title-only">
|
||||
{{i18n "search.advanced.filters.title"}}
|
||||
</label>
|
||||
</div>
|
||||
<div class="control-group advanced-search-topics-posts">
|
||||
<div class="controls">
|
||||
<fieldset class="grouped-control">
|
||||
<legend class="grouped-control-label" for="search-in-options">{{i18n "search.advanced.filters.label"}}</legend>
|
||||
|
||||
<div class="grouped-control-field">
|
||||
{{input
|
||||
id="matching-liked"
|
||||
type="checkbox"
|
||||
class="in-likes"
|
||||
checked=searchedTerms.special.in.likes
|
||||
click=(action "onChangeSearchTermForSpecialInLikes" value="target.checked")
|
||||
}}
|
||||
<label for="matching-liked">{{i18n "search.advanced.filters.likes"}}</label>
|
||||
</div>
|
||||
{{#if currentUser}}
|
||||
<div class="grouped-control-field">
|
||||
{{input
|
||||
id="matching-title-only"
|
||||
type="checkbox"
|
||||
class="in-title"
|
||||
checked=searchedTerms.special.in.title
|
||||
click=(action "onChangeSearchTermForSpecialInTitle" value="target.checked")
|
||||
}}
|
||||
<label for="matching-title-only">
|
||||
{{i18n "search.advanced.filters.title"}}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="grouped-control-field">
|
||||
{{input
|
||||
id="matching-in-messages"
|
||||
type="checkbox"
|
||||
class="in-private"
|
||||
checked=searchedTerms.special.in.personal
|
||||
click=(action "onChangeSearchTermForSpecialInPersonal" value="target.checked")
|
||||
}}
|
||||
<label for="matching-in-messages">{{i18n "search.advanced.filters.private"}}</label>
|
||||
</div>
|
||||
<div class="grouped-control-field">
|
||||
{{input
|
||||
id="matching-liked"
|
||||
type="checkbox"
|
||||
class="in-likes"
|
||||
checked=searchedTerms.special.in.likes
|
||||
click=(action "onChangeSearchTermForSpecialInLikes" value="target.checked")
|
||||
}}
|
||||
<label for="matching-liked">{{i18n "search.advanced.filters.likes"}}</label>
|
||||
</div>
|
||||
|
||||
<div class="grouped-control-field">
|
||||
{{input
|
||||
id="matching-seen"
|
||||
type="checkbox"
|
||||
class="in-seen"
|
||||
checked=searchedTerms.special.in.seen
|
||||
click=(action "onChangeSearchTermForSpecialInSeen" value="target.checked")
|
||||
}}
|
||||
<label for="matching-seen">{{i18n "search.advanced.filters.seen"}}</label>
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="grouped-control-field">
|
||||
{{input
|
||||
id="matching-in-messages"
|
||||
type="checkbox"
|
||||
class="in-private"
|
||||
checked=searchedTerms.special.in.personal
|
||||
click=(action "onChangeSearchTermForSpecialInPersonal" value="target.checked")
|
||||
}}
|
||||
<label for="matching-in-messages">{{i18n "search.advanced.filters.private"}}</label>
|
||||
</div>
|
||||
|
||||
<div class="grouped-control-field">
|
||||
{{input
|
||||
id="matching-seen"
|
||||
type="checkbox"
|
||||
class="in-seen"
|
||||
checked=searchedTerms.special.in.seen
|
||||
click=(action "onChangeSearchTermForSpecialInSeen" value="target.checked")
|
||||
}}
|
||||
<label for="matching-seen">{{i18n "search.advanced.filters.seen"}}</label>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{combo-box
|
||||
id="in"
|
||||
valueProperty="value"
|
||||
content=inOptions
|
||||
value=searchedTerms.in
|
||||
onChange=(action "onChangeSearchTermForIn")
|
||||
options=(hash
|
||||
none="user.locale.any"
|
||||
clearable=true
|
||||
)
|
||||
}}
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group advanced-search-topic-status">
|
||||
<label class="control-label" for="search-status-options">{{i18n "search.advanced.statuses.label"}}</label>
|
||||
<div class="controls">
|
||||
{{combo-box
|
||||
id="in"
|
||||
id="search-status-options"
|
||||
valueProperty="value"
|
||||
content=inOptions
|
||||
value=searchedTerms.in
|
||||
onChange=(action "onChangeSearchTermForIn")
|
||||
content=statusOptions
|
||||
value=searchedTerms.status
|
||||
onChange=(action "onChangeSearchTermForStatus")
|
||||
options=(hash
|
||||
none="user.locale.any"
|
||||
clearable=true
|
||||
)
|
||||
}}
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group pull-left">
|
||||
<label class="control-label" for="search-status-options">{{i18n "search.advanced.statuses.label"}}</label>
|
||||
<div class="controls">
|
||||
{{combo-box
|
||||
id="search-status-options"
|
||||
valueProperty="value"
|
||||
content=statusOptions
|
||||
value=searchedTerms.status
|
||||
onChange=(action "onChangeSearchTermForStatus")
|
||||
|
||||
<div class="control-group advanced-search-posted-by">
|
||||
<label class="control-label" for="search-posted-by">
|
||||
{{i18n "search.advanced.posted_by.label"}}
|
||||
</label>
|
||||
<div class="controls">
|
||||
{{user-chooser
|
||||
id="search-posted-by"
|
||||
value=searchedTerms.username
|
||||
onChange=(action "onChangeSearchTermForUsername")
|
||||
options=(hash
|
||||
none="user.locale.any"
|
||||
clearable=true
|
||||
maximum=1
|
||||
excludeCurrentUser=false
|
||||
)
|
||||
}}
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container advanced-search-date-count-group">
|
||||
<div class="control-group pull-left">
|
||||
<label class="control-label" for="search-post-date">{{i18n "search.advanced.post.time.label"}}</label>
|
||||
<div class="controls full-search-dates">
|
||||
{{combo-box
|
||||
id="postTime"
|
||||
valueProperty="value"
|
||||
content=postTimeOptions
|
||||
value=searchedTerms.time.when
|
||||
onChange=(action "onChangeWhenTime")
|
||||
}}
|
||||
{{date-input
|
||||
date=searchedTerms.time.days
|
||||
onChange=(action "onChangeWhenDate")
|
||||
id="search-post-date"
|
||||
}}
|
||||
<div class="control-group advanced-search-posted-date">
|
||||
<label class="control-label" for="search-post-date">{{i18n "search.advanced.post.time.label"}}</label>
|
||||
<div class="controls inline-form full-width">
|
||||
{{combo-box
|
||||
id="postTime"
|
||||
valueProperty="value"
|
||||
content=postTimeOptions
|
||||
value=searchedTerms.time.when
|
||||
onChange=(action "onChangeWhenTime")
|
||||
}}
|
||||
{{date-input
|
||||
date=searchedTerms.time.days
|
||||
onChange=(action "onChangeWhenDate")
|
||||
id="search-post-date"
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{plugin-outlet name="advanced-search-options-below" args=(hash searchedTerms=searchedTerms onChangeSearchedTermField=onChangeSearchedTermField) tagName=""}}
|
||||
</div>
|
||||
|
||||
<div class="count-group control-group pull-left">
|
||||
<label class="control-label" for="search-min-post-count">{{i18n "search.advanced.post.count.label"}}</label>
|
||||
<div class="count pull-left">
|
||||
<details class="search-advanced-additional-options">
|
||||
<summary>
|
||||
{{i18n "search.advanced.additional_options.label"}}
|
||||
</summary>
|
||||
<div class="count-group control-group">
|
||||
{{!-- TODO: Using a label here fails no-nested-interactive lint rule --}}
|
||||
<span class="control-label" for="search-min-post-count">{{i18n "search.advanced.post.count.label"}}</span>
|
||||
<div class="controls">
|
||||
{{input
|
||||
type="number"
|
||||
|
@ -174,11 +184,7 @@
|
|||
input=(action "onChangeSearchTermMinPostCount" value="target.value")
|
||||
placeholder=(i18n "search.advanced.post.min.placeholder")
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
<span class="count-dash">—</span>
|
||||
<div class="count pull-right">
|
||||
<div class="controls">
|
||||
{{d-icon "arrows-alt-h"}}
|
||||
{{input
|
||||
type="number"
|
||||
value=(readonly searchedTerms.max_posts)
|
||||
|
@ -189,11 +195,10 @@
|
|||
}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="count-group control-group pull-left">
|
||||
<label class="control-label" for="search-min-views">{{i18n "search.advanced.views.label"}}</label>
|
||||
<div class="count pull-left">
|
||||
<div class="count-group control-group">
|
||||
{{!-- TODO: Using a label here fails no-nested-interactive lint rule --}}
|
||||
<span class="control-label" for="search-min-views">{{i18n "search.advanced.views.label"}}</span>
|
||||
<div class="controls">
|
||||
{{input
|
||||
type="number"
|
||||
|
@ -203,11 +208,7 @@
|
|||
input=(action "onChangeSearchTermMinViews" value="target.value")
|
||||
placeholder=(i18n "search.advanced.min_views.placeholder")
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
<span class="count-dash">—</span>
|
||||
<div class="count pull-right">
|
||||
<div class="controls">
|
||||
{{d-icon "arrows-alt-h"}}
|
||||
{{input
|
||||
type="number"
|
||||
value=(readonly searchedTerms.max_views)
|
||||
|
@ -218,7 +219,5 @@
|
|||
}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
|
||||
{{plugin-outlet name="advanced-search-options-below" args=(hash searchedTerms=searchedTerms onChangeSearchedTermField=onChangeSearchedTermField) tagName=""}}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class="fps-result-entries">
|
||||
{{#each posts as |post|}}
|
||||
{{search-result-entry post=post bulkSelectEnabled=bulkSelectEnabled selected=selected}}
|
||||
{{search-result-entry post=post bulkSelectEnabled=bulkSelectEnabled selected=selected highlightQuery=highlightQuery}}
|
||||
{{/each}}
|
||||
</div>
|
||||
|
|
|
@ -1,66 +1,64 @@
|
|||
<div class="fps-result">
|
||||
<div class="author">
|
||||
<a href={{post.userPath}} data-user-card={{post.username}}>
|
||||
{{avatar post imageSize="large"}}
|
||||
</a>
|
||||
</div>
|
||||
<div class="author">
|
||||
<a href={{post.userPath}} data-user-card={{post.username}}>
|
||||
{{avatar post imageSize="large"}}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="fps-topic">
|
||||
<div class="topic">
|
||||
{{#if bulkSelectEnabled}}
|
||||
{{track-selected selectedList=selected selectedId=post.topic class="bulk-select"}}
|
||||
{{/if}}
|
||||
<div class="fps-topic">
|
||||
<div class="topic">
|
||||
{{#if bulkSelectEnabled}}
|
||||
{{track-selected selectedList=selected selectedId=post.topic class="bulk-select"}}
|
||||
{{/if}}
|
||||
|
||||
<a href={{post.url}} {{action "logClick" post.topic_id}} class="search-link">
|
||||
{{raw "topic-status" topic=post.topic showPrivateMessageIcon=true}}
|
||||
<span class="topic-title">
|
||||
{{#if post.useTopicTitleHeadline}}
|
||||
{{html-safe post.topicTitleHeadline}}
|
||||
{{else}}
|
||||
{{#highlight-search highlight=q}}
|
||||
{{html-safe post.topic.fancyTitle}}
|
||||
{{/highlight-search}}
|
||||
{{/if}}
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<div class="search-category">
|
||||
{{#if post.topic.category.parentCategory}}
|
||||
{{category-link post.topic.category.parentCategory}}
|
||||
{{/if}}
|
||||
{{category-link post.topic.category hideParent=true}}
|
||||
{{#if post.topic}}
|
||||
{{discourse-tags post.topic}}
|
||||
{{/if}}
|
||||
{{plugin-outlet name="full-page-search-category" args=(hash post=post)}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="blurb container">
|
||||
<span class="date">
|
||||
{{format-date post.created_at format="tiny"}}
|
||||
{{#if post.blurb}}
|
||||
<span class="separator">-</span>
|
||||
{{/if}}
|
||||
</span>
|
||||
|
||||
{{#if post.blurb}}
|
||||
{{#if siteSettings.use_pg_headlines_for_excerpt}}
|
||||
{{html-safe post.blurb}}
|
||||
<a href={{post.url}} {{action "logClick" post.topic_id}} class="search-link">
|
||||
{{raw "topic-status" topic=post.topic showPrivateMessageIcon=true}}
|
||||
<span class="topic-title">
|
||||
{{#if post.useTopicTitleHeadline}}
|
||||
{{html-safe post.topicTitleHeadline}}
|
||||
{{else}}
|
||||
{{#highlight-search highlight=highlightQuery}}
|
||||
{{html-safe post.blurb}}
|
||||
{{html-safe post.topic.fancyTitle}}
|
||||
{{/highlight-search}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
{{#if showLikeCount}}
|
||||
{{#if post.like_count}}
|
||||
<span class="like-count">
|
||||
<span class="value">{{post.like_count}}</span> {{d-icon "heart"}}
|
||||
</span>
|
||||
<div class="search-category">
|
||||
{{#if post.topic.category.parentCategory}}
|
||||
{{category-link post.topic.category.parentCategory}}
|
||||
{{/if}}
|
||||
{{category-link post.topic.category hideParent=true}}
|
||||
{{#if post.topic}}
|
||||
{{discourse-tags post.topic}}
|
||||
{{/if}}
|
||||
{{plugin-outlet name="full-page-search-category" args=(hash post=post)}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="blurb container">
|
||||
<span class="date">
|
||||
{{format-date post.created_at format="tiny"}}
|
||||
{{#if post.blurb}}
|
||||
<span class="separator">-</span>
|
||||
{{/if}}
|
||||
</span>
|
||||
|
||||
{{#if post.blurb}}
|
||||
{{#if siteSettings.use_pg_headlines_for_excerpt}}
|
||||
{{html-safe post.blurb}}
|
||||
{{else}}
|
||||
{{#highlight-search highlight=highlightQuery}}
|
||||
{{html-safe post.blurb}}
|
||||
{{/highlight-search}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{#if showLikeCount}}
|
||||
{{#if post.like_count}}
|
||||
<span class="like-count">
|
||||
<span class="value">{{post.like_count}}</span> {{d-icon "heart"}}
|
||||
</span>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
|
|
@ -1,20 +1,59 @@
|
|||
{{#d-section pageClass="search" class="search-container"}}
|
||||
{{scroll-tracker name="full-page-search" tag=searchTerm class="hidden"}}
|
||||
|
||||
<div class="search-advanced">
|
||||
{{#unless site.mobileView}}
|
||||
<div class="search-bar">
|
||||
{{search-text-field
|
||||
value=searchTerm
|
||||
class="full-page-search search no-blur search-query"
|
||||
aria-label=(i18n "search.full_page_title")
|
||||
enter=(action "search")
|
||||
hasAutofocus=hasAutofocus
|
||||
aria-controls="search-result-count"
|
||||
<div class="search-header">
|
||||
<h1 class="search-page-heading">
|
||||
{{#if hasResults}}
|
||||
<div class="result-count" id="search-result-count" aria-live="polite">
|
||||
{{html-safe resultCountLabel}}
|
||||
</div>
|
||||
{{else}}
|
||||
{{i18n "search.full_page_title"}}
|
||||
{{/if}}
|
||||
</h1>
|
||||
<div class="search-bar">
|
||||
{{search-text-field
|
||||
value=searchTerm
|
||||
class="full-page-search search no-blur search-query"
|
||||
aria-label=(i18n "search.search_term_label")
|
||||
enter=(action "search" true)
|
||||
hasAutofocus=hasAutofocus
|
||||
aria-controls="search-result-count"
|
||||
}}
|
||||
{{combo-box
|
||||
id="search-type"
|
||||
value=search_type
|
||||
content=searchTypes
|
||||
castInteger=true
|
||||
onChange=(action (mut search_type))
|
||||
}}
|
||||
{{d-button
|
||||
action=(action "search" true)
|
||||
icon="search"
|
||||
label="search.search_button"
|
||||
class="btn-primary search-cta"
|
||||
ariaLabel="search.search_button"
|
||||
disabled=searchButtonDisabled
|
||||
}}
|
||||
</div>
|
||||
{{#if usingDefaultSearchType}}
|
||||
{{!-- context is only provided when searching from mobile view --}}
|
||||
{{#if context}}
|
||||
<div class="search-context">
|
||||
<label>
|
||||
{{input type="checkbox" name="searchContext" checked=searchContextEnabled}} {{searchContextDescription}}
|
||||
</label>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="search-filters">
|
||||
{{search-advanced-options
|
||||
searchTerm=(readonly searchTerm)
|
||||
onChangeSearchTerm=(action (mut searchTerm))
|
||||
expandFilters=expandFilters
|
||||
}}
|
||||
{{d-button action=(action "search") icon="search" class="btn-primary search-cta" ariaLabel="search.search_button" disabled=searchButtonDisabled}}
|
||||
</div>
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
|
||||
<div class="search-notice">
|
||||
{{#if invalidSearch}}
|
||||
|
@ -24,52 +63,36 @@
|
|||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{!-- context is only provided when searching from mobile view --}}
|
||||
<div class="search-context">
|
||||
{{#if context}}
|
||||
<div class="fps-search-context">
|
||||
<label>
|
||||
{{input type="checkbox" name="searchContext" checked=searchContextEnabled}} {{searchContextDescription}}
|
||||
</label>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="search-advanced">
|
||||
{{#if hasResults}}
|
||||
<div class="search-title">
|
||||
{{#if hasResults}}
|
||||
{{create-topic-button canCreateTopic=canCreateTopic action=(action "createTopic" searchTerm)}}
|
||||
{{/if}}
|
||||
{{#if usingDefaultSearchType}}
|
||||
<div class={{searchInfoClassNames}}>
|
||||
{{#if canBulkSelect}}
|
||||
{{d-button icon="list" class="btn-default bulk-select" title="topics.bulk.toggle" action=(action "toggleBulkSelect")}}
|
||||
{{bulk-select-button selected=selected category=category action=(action "search")}}
|
||||
{{/if}}
|
||||
|
||||
{{#if canBulkSelect}}
|
||||
{{d-button icon="list" class="btn-default bulk-select" title="topics.bulk.toggle" action=(action "toggleBulkSelect")}}
|
||||
{{bulk-select-button selected=selected category=category action=(action "search")}}
|
||||
{{/if}}
|
||||
|
||||
{{#if bulkSelectEnabled}}
|
||||
<div class="fps-select">
|
||||
{{#if bulkSelectEnabled}}
|
||||
{{d-button icon="check-square" class="btn-default" action=(action "selectAll") label="search.select_all"~}}
|
||||
{{d-button icon="far-square" class="btn-default" action=(action "clearAll") label="search.clear_all"}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="search-info">
|
||||
<div class="result-count" id="search-result-count" aria-live="polite">
|
||||
{{html-safe resultCountLabel}}
|
||||
<div class="sort-by inline-form">
|
||||
<label for="search-sort-by">
|
||||
{{i18n "search.sort_by"}}
|
||||
</label>
|
||||
{{combo-box
|
||||
value=sortOrder
|
||||
content=sortOrders
|
||||
castInteger=true
|
||||
onChange=(action (mut sortOrder))
|
||||
id="search-sort-by"
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="sort-by">
|
||||
<span class="desc">
|
||||
{{i18n "search.sort_by"}}
|
||||
</span>
|
||||
{{combo-box
|
||||
value=sortOrder
|
||||
content=sortOrders
|
||||
castInteger=true
|
||||
onChange=(action (mut sortOrder))
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
{{plugin-outlet name="full-page-search-below-search-info" args=(hash search=searchTerm)}}
|
||||
|
@ -79,99 +102,113 @@
|
|||
{{else}}
|
||||
<div class="search-results">
|
||||
{{#load-more selector=".fps-result" action=(action "loadMore")}}
|
||||
{{search-result-entries posts=model.posts bulkSelectEnabled=bulkSelectEnabled selected=selected}}
|
||||
{{#if usingDefaultSearchType}}
|
||||
{{search-result-entries
|
||||
posts=model.posts
|
||||
bulkSelectEnabled=bulkSelectEnabled
|
||||
selected=selected
|
||||
highlightQuery=highlightQuery
|
||||
}}
|
||||
|
||||
{{#conditional-loading-spinner condition=loading }}
|
||||
{{#unless hasResults}}
|
||||
{{#if searchActive}}
|
||||
<h3>{{i18n "search.no_results"}}</h3>
|
||||
{{#conditional-loading-spinner condition=loading }}
|
||||
{{#unless hasResults}}
|
||||
{{#if searchActive}}
|
||||
<h3>{{i18n "search.no_results"}}</h3>
|
||||
|
||||
{{#if model.grouped_search_result.error}}
|
||||
<div class="warning">
|
||||
{{model.grouped_search_result.error}}
|
||||
{{#if model.grouped_search_result.error}}
|
||||
<div class="warning">
|
||||
{{model.grouped_search_result.error}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if showSuggestion}}
|
||||
<div class="no-results-suggestion">
|
||||
{{i18n "search.cant_find"}}
|
||||
{{#if canCreateTopic}}
|
||||
<a href {{action "createTopic" searchTerm}}>{{i18n "search.start_new_topic"}}</a>
|
||||
{{#unless siteSettings.login_required}}
|
||||
{{i18n "search.or_search_google"}}
|
||||
{{/unless}}
|
||||
{{else}}
|
||||
{{i18n "search.search_google"}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{google-search searchTerm=searchTerm}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/unless}}
|
||||
|
||||
{{#if hasResults}}
|
||||
{{#unless loading}}
|
||||
<h3 class="search-footer">
|
||||
{{#if model.grouped_search_result.more_full_page_results}}
|
||||
{{#if isLastPage }}
|
||||
{{i18n "search.more_results"}}
|
||||
{{/if}}
|
||||
{{else}}
|
||||
{{i18n "search.no_more_results"}}
|
||||
{{/if}}
|
||||
</h3>
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
{{/conditional-loading-spinner}}
|
||||
{{else}}
|
||||
{{#conditional-loading-spinner condition=loading }}
|
||||
{{#if hasResults}}
|
||||
{{#if model.categories.length}}
|
||||
<h4 class="category-heading">
|
||||
{{i18n "search.categories"}}
|
||||
</h4>
|
||||
<div class="category-items">
|
||||
{{#each model.categories as |category|}}
|
||||
{{category-link category extraClasses="fps-category-item"}}
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if showSuggestion}}
|
||||
<div class="no-results-suggestion">
|
||||
{{i18n "search.cant_find"}}
|
||||
{{#if canCreateTopic}}
|
||||
<a href {{action "createTopic" searchTerm}}>{{i18n "search.start_new_topic"}}</a>
|
||||
{{#unless siteSettings.login_required}}
|
||||
{{i18n "search.or_search_google"}}
|
||||
{{/unless}}
|
||||
{{else}}
|
||||
{{i18n "search.search_google"}}
|
||||
{{/if}}
|
||||
{{#if model.tags.length}}
|
||||
<h4 class="tag-heading">
|
||||
{{i18n "search.tags"}}
|
||||
</h4>
|
||||
<div class="tag-items">
|
||||
{{#each model.tags as |tag|}}
|
||||
<div class="fps-tag-item">
|
||||
<a href={{tag.url}}>
|
||||
{{tag.id}}
|
||||
</a>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{google-search searchTerm=searchTerm}}
|
||||
{{#if model.users}}
|
||||
{{#each model.users as |user|}}
|
||||
{{#user-link user=user class="fps-user-item"}}
|
||||
{{avatar user imageSize="large"}}
|
||||
<div class="user-titles">
|
||||
{{#if user.name}}
|
||||
<span class="name">
|
||||
{{user.name}}
|
||||
</span>
|
||||
{{/if}}
|
||||
<span class="username">
|
||||
{{user.username}}
|
||||
</span>
|
||||
</div>
|
||||
{{/user-link}}
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
{{else}}
|
||||
{{#if searchActive}}
|
||||
<h3>{{i18n "search.no_results"}}</h3>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/unless}}
|
||||
|
||||
{{#if hasResults}}
|
||||
{{#unless loading}}
|
||||
<h3 class="search-footer">
|
||||
{{#if model.grouped_search_result.more_full_page_results}}
|
||||
{{#if isLastPage }}
|
||||
{{i18n "search.more_results"}}
|
||||
{{/if}}
|
||||
{{else}}
|
||||
{{i18n "search.no_more_results"}}
|
||||
{{/if}}
|
||||
</h3>
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
{{/conditional-loading-spinner}}
|
||||
{{/conditional-loading-spinner}}
|
||||
{{/if}}
|
||||
{{/load-more}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="search-advanced-sidebar">
|
||||
{{#if site.mobileView}}
|
||||
<div class="search-bar">
|
||||
{{search-text-field value=searchTerm class="full-page-search search no-blur search-query" enter=(action "search") hasAutofocus=hasAutofocus}}
|
||||
{{d-button action=(action "search") icon="search" class="btn-primary search-cta" ariaLabel="search.search_button" disabled=searchButtonDisabled}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if site.mobileView}}
|
||||
<div role="button" class="search-advanced-title" {{on "click" (action "toggleAdvancedSearch")}}>
|
||||
{{d-icon (if expanded "caret-down" "caret-right")}}
|
||||
<span>{{i18n "search.advanced.title"}}</span>
|
||||
</div>
|
||||
{{else}}
|
||||
<h1 class="search-advanced-title">
|
||||
{{i18n "search.advanced.title"}}
|
||||
</h1>
|
||||
{{/if}}
|
||||
|
||||
{{#if site.mobileView}}
|
||||
{{#if expanded}}
|
||||
<div class="search-advanced-filters">
|
||||
{{search-advanced-options
|
||||
searchTerm=(readonly searchTerm)
|
||||
onChangeSearchTerm=(action (mut searchTerm))
|
||||
}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<div class="search-advanced-filters">
|
||||
{{search-advanced-options
|
||||
searchTerm=(readonly searchTerm)
|
||||
onChangeSearchTerm=(action (mut searchTerm))
|
||||
onChangeCategory=(action (mut category))
|
||||
}}
|
||||
|
||||
{{d-button
|
||||
label="submit"
|
||||
action=(action "search")
|
||||
icon="search"
|
||||
class="btn-primary search-cta"
|
||||
disabled=searchButtonDisabled}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/d-section}}
|
||||
|
|
|
@ -9,6 +9,11 @@ import {
|
|||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import { click, fillIn, triggerKeyEvent, visit } from "@ember/test-helpers";
|
||||
import { skip, test } from "qunit";
|
||||
import {
|
||||
SEARCH_TYPE_CATS_TAGS,
|
||||
SEARCH_TYPE_DEFAULT,
|
||||
SEARCH_TYPE_USERS,
|
||||
} from "discourse/controllers/full-page-search";
|
||||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||
|
||||
acceptance("Search - Full Page", function (needs) {
|
||||
|
@ -16,7 +21,12 @@ acceptance("Search - Full Page", function (needs) {
|
|||
needs.settings({ tagging_enabled: true });
|
||||
needs.pretender((server, helper) => {
|
||||
server.get("/tags/filter/search", () => {
|
||||
return helper.response({ results: [{ text: "monkey", count: 1 }] });
|
||||
return helper.response({
|
||||
results: [
|
||||
{ text: "monkey", count: 1 },
|
||||
{ text: "gazelle", count: 2 },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
server.get("/u/search/users", () => {
|
||||
|
@ -126,6 +136,8 @@ acceptance("Search - Full Page", function (needs) {
|
|||
1,
|
||||
"shows the right icon"
|
||||
);
|
||||
|
||||
assert.equal(count(".search-highlight"), 1, "search highlights work");
|
||||
});
|
||||
|
||||
test("escape search term", async function (assert) {
|
||||
|
@ -419,7 +431,9 @@ acceptance("Search - Full Page", function (needs) {
|
|||
await fillIn("#search-min-post-count", "5");
|
||||
|
||||
assert.equal(
|
||||
queryAll(".search-advanced-options #search-min-post-count").val(),
|
||||
queryAll(
|
||||
".search-advanced-additional-options #search-min-post-count"
|
||||
).val(),
|
||||
"5",
|
||||
'has "5" populated'
|
||||
);
|
||||
|
@ -436,7 +450,9 @@ acceptance("Search - Full Page", function (needs) {
|
|||
await fillIn("#search-max-post-count", "5");
|
||||
|
||||
assert.equal(
|
||||
queryAll(".search-advanced-options #search-max-post-count").val(),
|
||||
queryAll(
|
||||
".search-advanced-additional-options #search-max-post-count"
|
||||
).val(),
|
||||
"5",
|
||||
'has "5" populated'
|
||||
);
|
||||
|
@ -469,4 +485,100 @@ acceptance("Search - Full Page", function (needs) {
|
|||
"does not populate the likes checkbox"
|
||||
);
|
||||
});
|
||||
|
||||
test("all tags checkbox only visible for two or more tags", async function (assert) {
|
||||
await visit("/search?expanded=true");
|
||||
|
||||
const tagSelector = selectKit("#search-with-tags");
|
||||
|
||||
await tagSelector.expand();
|
||||
await tagSelector.selectRowByValue("monkey");
|
||||
|
||||
assert.ok(!visible("input.all-tags"), "all tags checkbox not visible");
|
||||
|
||||
await tagSelector.selectRowByValue("gazelle");
|
||||
assert.ok(visible("input.all-tags"), "all tags checkbox is visible");
|
||||
});
|
||||
|
||||
test("search for users", async function (assert) {
|
||||
await visit("/search");
|
||||
|
||||
const typeSelector = selectKit(".search-bar .select-kit#search-type");
|
||||
|
||||
await fillIn(".search-query", "admin");
|
||||
assert.ok(!exists(".fps-user-item"), "has no user results");
|
||||
|
||||
await typeSelector.expand();
|
||||
await typeSelector.selectRowByValue(SEARCH_TYPE_USERS);
|
||||
|
||||
assert.ok(!exists(".search-filters"), "has no filters");
|
||||
|
||||
await click(".search-cta");
|
||||
|
||||
assert.equal(count(".fps-user-item"), 1, "has one user result");
|
||||
|
||||
await typeSelector.expand();
|
||||
await typeSelector.selectRowByValue(SEARCH_TYPE_DEFAULT);
|
||||
|
||||
assert.ok(
|
||||
exists(".search-filters"),
|
||||
"returning to topic/posts shows filters"
|
||||
);
|
||||
assert.ok(!exists(".fps-user-item"), "has no user results");
|
||||
});
|
||||
|
||||
test("search for categories/tags", async function (assert) {
|
||||
await visit("/search");
|
||||
|
||||
await fillIn(".search-query", "monk");
|
||||
const typeSelector = selectKit(".search-bar .select-kit#search-type");
|
||||
|
||||
assert.ok(!exists(".fps-tag-item"), "has no category/tag results");
|
||||
|
||||
await typeSelector.expand();
|
||||
await typeSelector.selectRowByValue(SEARCH_TYPE_CATS_TAGS);
|
||||
await click(".search-cta");
|
||||
|
||||
assert.ok(!exists(".search-filters"), "has no filters");
|
||||
assert.equal(count(".fps-tag-item"), 2, "has two tag results");
|
||||
|
||||
await typeSelector.expand();
|
||||
await typeSelector.selectRowByValue(SEARCH_TYPE_DEFAULT);
|
||||
|
||||
assert.ok(
|
||||
exists(".search-filters"),
|
||||
"returning to topic/posts shows filters"
|
||||
);
|
||||
assert.ok(!exists(".user-item"), "has no user results");
|
||||
});
|
||||
|
||||
test("filters expand/collapse as expected", async function (assert) {
|
||||
await visit("/search?expanded=true");
|
||||
|
||||
assert.ok(
|
||||
visible(".search-advanced-options"),
|
||||
"advanced filters are expanded when url query param is included"
|
||||
);
|
||||
|
||||
await fillIn(".search-query", "none");
|
||||
await click(".search-cta");
|
||||
|
||||
assert.ok(
|
||||
!visible(".search-advanced-options"),
|
||||
"launching a search collapses advanced filters"
|
||||
);
|
||||
|
||||
await visit("/search");
|
||||
|
||||
assert.ok(
|
||||
!visible(".search-advanced-options"),
|
||||
"filters are collapsed when query param is not present"
|
||||
);
|
||||
|
||||
await click(".advanced-filters > summary");
|
||||
assert.ok(
|
||||
visible(".search-advanced-options"),
|
||||
"clicking on element expands filters"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,6 +3,7 @@ import {
|
|||
count,
|
||||
exists,
|
||||
queryAll,
|
||||
visible,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import { click, fillIn, visit } from "@ember/test-helpers";
|
||||
import { test } from "qunit";
|
||||
|
@ -22,11 +23,10 @@ acceptance("Search - Mobile", function (needs) {
|
|||
|
||||
assert.ok(!exists(".search-results .fps-topic"), "no results by default");
|
||||
|
||||
await click(".search-advanced-title");
|
||||
await click(".advanced-filters summary");
|
||||
|
||||
assert.equal(
|
||||
count(".search-advanced-filters"),
|
||||
1,
|
||||
assert.ok(
|
||||
visible(".search-advanced-filters"),
|
||||
"it should expand advanced search filters"
|
||||
);
|
||||
|
||||
|
@ -36,7 +36,7 @@ acceptance("Search - Mobile", function (needs) {
|
|||
assert.equal(count(".fps-topic"), 1, "has one post");
|
||||
|
||||
assert.ok(
|
||||
!exists(".search-advanced-filters"),
|
||||
!visible(".search-advanced-filters"),
|
||||
"it should collapse advanced search filters"
|
||||
);
|
||||
|
||||
|
|
|
@ -1,182 +1,179 @@
|
|||
@mixin search-page-spacing {
|
||||
padding: 1rem 10%;
|
||||
@include breakpoint(medium) {
|
||||
padding: 1rem;
|
||||
}
|
||||
}
|
||||
.search-highlight {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.search-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.search-header {
|
||||
@include search-page-spacing();
|
||||
background: var(--primary-very-low);
|
||||
}
|
||||
.warning {
|
||||
background-color: var(--danger-medium);
|
||||
padding: 5px 8px;
|
||||
color: var(--secondary);
|
||||
}
|
||||
|
||||
.search-page-heading {
|
||||
font-size: var(--font-up-3);
|
||||
|
||||
// spans can be in different orders depending of locale
|
||||
span + span {
|
||||
margin-left: 0.25em;
|
||||
}
|
||||
|
||||
span.term {
|
||||
background: var(--tertiary-low);
|
||||
}
|
||||
}
|
||||
|
||||
.search-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: stretch;
|
||||
margin-bottom: 1em;
|
||||
background: var(--primary-very-low);
|
||||
|
||||
.search-query {
|
||||
flex: 1 0 0px;
|
||||
margin: 0 0.5em 0 0;
|
||||
input.search-query {
|
||||
flex: 1 0 60%;
|
||||
margin: 0 1em 0 0;
|
||||
}
|
||||
|
||||
.search-cta {
|
||||
padding-bottom: 6.5px;
|
||||
padding-top: 6.5px;
|
||||
.select-kit {
|
||||
margin-right: 1em;
|
||||
flex: 1 0 20%;
|
||||
}
|
||||
|
||||
@include breakpoint(mobile-extra-large) {
|
||||
flex-direction: column;
|
||||
|
||||
input.search-query,
|
||||
.select-kit {
|
||||
margin-right: 0;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search-advanced {
|
||||
width: 70%;
|
||||
@include breakpoint(medium) {
|
||||
width: 65%;
|
||||
}
|
||||
|
||||
position: relative;
|
||||
.search-actions,
|
||||
.search-notice,
|
||||
.search-results,
|
||||
.search-title,
|
||||
.search-bar {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.search-results {
|
||||
@include search-page-spacing();
|
||||
padding-bottom: 3em;
|
||||
}
|
||||
|
||||
.search-info {
|
||||
display: flex;
|
||||
@include search-page-spacing();
|
||||
flex-wrap: wrap;
|
||||
border-bottom: 1px solid var(--primary-low);
|
||||
padding-bottom: 1em;
|
||||
margin-bottom: 1.5em;
|
||||
padding-top: 2em;
|
||||
margin-bottom: 2em;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
|
||||
.result-count {
|
||||
display: flex;
|
||||
|
||||
.term {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
// spans can be in different orders depending of locale
|
||||
span + span {
|
||||
margin-left: 0.25em;
|
||||
}
|
||||
&.bulk-select-visible {
|
||||
@include sticky;
|
||||
top: 60px;
|
||||
background-color: var(--secondary);
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.sort-by {
|
||||
display: flex;
|
||||
margin-left: auto;
|
||||
align-items: center;
|
||||
|
||||
.desc {
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
|
||||
.combo-box {
|
||||
min-width: 150px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search-title {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: stretch;
|
||||
flex-wrap: wrap;
|
||||
padding-right: 2.6em; // placeholder for fixed position bulk search button
|
||||
button {
|
||||
margin: 0 0.5em 0.5em 0;
|
||||
}
|
||||
|
||||
.bulk-select-container {
|
||||
order: 2; // last button
|
||||
margin-left: auto;
|
||||
z-index: z("dropdown"); // below composer
|
||||
}
|
||||
|
||||
#bulk-select {
|
||||
position: fixed;
|
||||
position: relative;
|
||||
right: unset;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: inline;
|
||||
button {
|
||||
margin: 0;
|
||||
box-shadow: 0 0 0.4em 0.45em var(--secondary); // slight fade behind the button, because it can overlay content
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search-notice {
|
||||
.fps-invalid {
|
||||
padding: 0.5em;
|
||||
background-color: var(--danger-low);
|
||||
border: 1px solid var(--danger-medium);
|
||||
color: var(--danger);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search-advanced-sidebar {
|
||||
width: 30%;
|
||||
@include breakpoint(medium) {
|
||||
width: 35%;
|
||||
}
|
||||
margin-left: 1em;
|
||||
.search-notice .fps-invalid {
|
||||
padding: 0.5em;
|
||||
background-color: var(--danger-low);
|
||||
border: 1px solid var(--danger-medium);
|
||||
color: var(--danger);
|
||||
}
|
||||
|
||||
.search-context {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.search-filters {
|
||||
background: var(--primary-very-low);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.input-small,
|
||||
.combo-box,
|
||||
.ac-wrap,
|
||||
details.advanced-filters,
|
||||
details.search-advanced-additional-options {
|
||||
margin-top: 1em;
|
||||
|
||||
> summary {
|
||||
color: var(--tertiary);
|
||||
cursor: pointer;
|
||||
}
|
||||
&[open] > summary {
|
||||
color: var(--primary);
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
details.search-advanced-additional-options {
|
||||
> summary {
|
||||
font-size: var(--font-down-1);
|
||||
}
|
||||
}
|
||||
|
||||
.combo-box:not(#postTime),
|
||||
.control-group,
|
||||
.multi-select,
|
||||
.search-advanced-category-chooser {
|
||||
box-sizing: border-box;
|
||||
.multi-select {
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
margin: 0;
|
||||
|
||||
input,
|
||||
.item {
|
||||
padding-left: 4px; // temporarily normalizing input padding for this section
|
||||
}
|
||||
}
|
||||
|
||||
.d-date-input {
|
||||
margin-top: 0.5em;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.search-advanced-title {
|
||||
font-size: $font-up-1;
|
||||
background: var(--primary-low);
|
||||
padding: 0.358em 1em;
|
||||
margin-bottom: 0;
|
||||
@include breakpoint(medium) {
|
||||
padding: 0.358em 0.5em;
|
||||
}
|
||||
font-weight: 700;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
|
||||
.d-icon {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.search-advanced-filters {
|
||||
background: var(--primary-very-low);
|
||||
padding: 1em;
|
||||
.control-group {
|
||||
margin-bottom: 15px;
|
||||
|
||||
@include breakpoint(mobile-extra-large, min-width) {
|
||||
.search-advanced-options {
|
||||
column-count: 2;
|
||||
column-gap: 2em;
|
||||
.control-group {
|
||||
break-inside: avoid;
|
||||
}
|
||||
}
|
||||
}
|
||||
section.field {
|
||||
margin-top: 5px;
|
||||
|
||||
@include breakpoint(medium, min-width) {
|
||||
.search-advanced-options {
|
||||
column-gap: 5em;
|
||||
}
|
||||
}
|
||||
|
||||
@include breakpoint(medium) {
|
||||
padding: 0.75em 0.5em;
|
||||
.ac-wrap,
|
||||
.choices,
|
||||
.select-kit.multi-select {
|
||||
// overriding inline width from JS
|
||||
|
@ -187,13 +184,18 @@
|
|||
}
|
||||
}
|
||||
|
||||
.control-group {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.count-group {
|
||||
.count {
|
||||
width: 45%;
|
||||
input[type="number"] {
|
||||
width: 8em;
|
||||
}
|
||||
.count-dash {
|
||||
padding-left: 6px;
|
||||
vertical-align: middle;
|
||||
|
||||
.d-icon {
|
||||
margin-left: 0.25em;
|
||||
margin-right: 0.25em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -201,15 +203,21 @@
|
|||
}
|
||||
|
||||
.fps-invalid {
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.fps-result {
|
||||
display: flex;
|
||||
padding: 0 0.5em;
|
||||
margin-bottom: 28px;
|
||||
max-width: 780px;
|
||||
margin-bottom: 2em;
|
||||
max-width: 100%;
|
||||
word-break: break-word;
|
||||
position: relative;
|
||||
|
||||
&.bulk-select-enabled {
|
||||
padding-left: 3em;
|
||||
}
|
||||
|
||||
.author {
|
||||
display: inline-block;
|
||||
|
@ -229,7 +237,14 @@
|
|||
grid-template-columns: auto 1fr;
|
||||
align-items: baseline;
|
||||
.bulk-select {
|
||||
grid-area: bulk-select;
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
padding: 0.5em;
|
||||
background: var(--tertiary-very-low);
|
||||
input[type="checkbox"] {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
.search-link {
|
||||
grid-area: title;
|
||||
|
@ -260,19 +275,9 @@
|
|||
}
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
margin-top: 0;
|
||||
margin-left: 0;
|
||||
// cross-browser alignment below
|
||||
position: relative;
|
||||
vertical-align: bottom;
|
||||
margin-bottom: 0.39em;
|
||||
}
|
||||
|
||||
.blurb {
|
||||
font-size: $font-0;
|
||||
line-height: $line-height-large;
|
||||
max-width: 640px;
|
||||
color: var(--primary-medium);
|
||||
.date {
|
||||
color: var(--primary-high);
|
||||
|
@ -319,18 +324,48 @@
|
|||
}
|
||||
}
|
||||
|
||||
.no-results-suggestion {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.search-footer {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.panel-body-contents .search-context label {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.no-results-suggestion,
|
||||
.google-search-form {
|
||||
margin-top: 2em;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
// temporary
|
||||
|
||||
.search-results {
|
||||
.fps-user-item {
|
||||
margin-bottom: 1.5em;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
.avatar {
|
||||
margin-right: 0.5em;
|
||||
min-width: 25px;
|
||||
}
|
||||
.user-titles {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-width: 300px;
|
||||
.name {
|
||||
color: var(--primary-high-or-secondary-low);
|
||||
font-size: var(--font-0);
|
||||
font-weight: 700;
|
||||
@include ellipsis;
|
||||
}
|
||||
.username {
|
||||
color: var(--primary-high-or-secondary-low);
|
||||
font-size: var(--font-down-1);
|
||||
@include ellipsis;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.category-items,
|
||||
.tag-items {
|
||||
margin-bottom: 1.5em;
|
||||
.fps-category-item,
|
||||
.fps-tag-item {
|
||||
margin-bottom: 1.5em;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -174,7 +174,8 @@ input[type="submit"] {
|
|||
> .select-kit,
|
||||
> input[type="text"],
|
||||
> label,
|
||||
> .btn {
|
||||
> .btn,
|
||||
> .d-date-input {
|
||||
margin-bottom: 0.5em; // for when items wrap (mobile, narrow windows)
|
||||
margin-right: 0.5em;
|
||||
&:last-child {
|
||||
|
|
|
@ -1,48 +1,6 @@
|
|||
.search-container {
|
||||
flex-direction: column;
|
||||
margin: 0;
|
||||
|
||||
.search-advanced {
|
||||
order: 1;
|
||||
width: 100%;
|
||||
|
||||
.search-info {
|
||||
flex-direction: column;
|
||||
align-items: left;
|
||||
justify-content: center;
|
||||
|
||||
.sort-by {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 0.5em;
|
||||
margin-left: 0;
|
||||
width: 100%;
|
||||
|
||||
.select-kit {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search-notice {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.search-advanced-sidebar {
|
||||
order: 0;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
|
||||
.tag-chooser,
|
||||
.user-chooser {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.fps-result {
|
||||
input[type="checkbox"] {
|
||||
vertical-align: baseline;
|
||||
.search-advanced .search-info {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2338,7 +2338,7 @@ en:
|
|||
one: "<span>%{count} result for</span><span class='term'>%{term}</span>"
|
||||
other: "<span>%{count}%{plus} results for</span><span class='term'>%{term}</span>"
|
||||
title: "search topics, posts, users, or categories"
|
||||
full_page_title: "search topics or posts"
|
||||
full_page_title: "Search"
|
||||
no_results: "No results found."
|
||||
no_more_results: "No more results found."
|
||||
post_format: "#%{post_number} by %{username}"
|
||||
|
@ -2350,6 +2350,14 @@ en:
|
|||
search_google: "Try searching with Google instead:"
|
||||
search_google_button: "Google"
|
||||
search_button: "Search"
|
||||
search_term_label: "enter search keyword"
|
||||
categories: "Categories"
|
||||
tags: "Tags"
|
||||
|
||||
type:
|
||||
default: "Topics/posts"
|
||||
users: "Users"
|
||||
categories_and_tags: "Categories/tags"
|
||||
|
||||
context:
|
||||
user: "Search posts by @%{username}"
|
||||
|
@ -2359,7 +2367,7 @@ en:
|
|||
private_messages: "Search messages"
|
||||
|
||||
advanced:
|
||||
title: Advanced Search
|
||||
title: Advanced filters
|
||||
posted_by:
|
||||
label: Posted by
|
||||
in_category:
|
||||
|
@ -2412,6 +2420,8 @@ en:
|
|||
placeholder: minimum
|
||||
max_views:
|
||||
placeholder: maximum
|
||||
additional_options:
|
||||
label: "Filter by post count and topic views"
|
||||
|
||||
hamburger_menu: "go to another topic list or category"
|
||||
new_item: "new"
|
||||
|
|
Loading…
Reference in New Issue