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.
This commit is contained in:
parent
bbddce4d3a
commit
324aa3eb61
|
@ -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());
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -2,14 +2,17 @@
|
|||
|
||||
<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>
|
||||
<label class="control-label" for="search-posted-by">
|
||||
{{i18n "search.advanced.posted_by.label"}}
|
||||
</label>
|
||||
<div class="controls">
|
||||
{{user-selector
|
||||
{{user-chooser
|
||||
value=searchedTerms.username
|
||||
onChange=(action "onChangeSearchTermForUsername")
|
||||
options=(hash
|
||||
maximum=1
|
||||
excludeCurrentUser=false
|
||||
usernames=searchedTerms.username
|
||||
single=true
|
||||
canReceiveUpdates=true
|
||||
class="user-selector"
|
||||
)
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -18,28 +21,12 @@
|
|||
<div class="controls">
|
||||
{{search-advanced-category-chooser
|
||||
value=searchedTerms.category.id
|
||||
onChange=(action "onChangeCategory")
|
||||
onChange=(action "onChangeSearchTermForCategory")
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{!-- disable these super-advanced searches for now
|
||||
<div class="container">
|
||||
<div class="control-group pull-left">
|
||||
<label class="control-label" for="search-in-group">{{i18n "search.advanced.in_group.label"}}</label>
|
||||
<div class="controls">
|
||||
{{group-selector groupFinder=groupFinder groupNames=searchedTerms.group single="true" canReceiveUpdates="true"}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group pull-left">
|
||||
<label class="control-label" for="search-with-badge">{{i18n "search.advanced.with_badge.label"}}</label>
|
||||
<div class="controls">
|
||||
{{badge-selector badgeFinder=badgeFinder badgeNames=searchedTerms.badge single="true" canReceiveUpdates="true"}}
|
||||
</div>
|
||||
</div>
|
||||
</div> --}}
|
||||
|
||||
{{#if siteSettings.tagging_enabled}}
|
||||
<div class="container advanced-search-tag-group">
|
||||
<div class="control-group">
|
||||
|
@ -50,10 +37,18 @@
|
|||
allowCreate=false
|
||||
everyTag=true
|
||||
unlimitedTagCount=true
|
||||
onChange=(action (mut searchedTerms.tags))
|
||||
onChange=(action "onChangeSearchTermForTags")
|
||||
}}
|
||||
<section class="field">
|
||||
<label>{{ input type="checkbox" class="all-tags" checked=searchedTerms.special.all_tags}} {{i18n "search.advanced.filters.all_tags"}} </label>
|
||||
<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>
|
||||
|
@ -66,10 +61,42 @@
|
|||
<div class="controls">
|
||||
{{#if currentUser}}
|
||||
<section class="field">
|
||||
<label>{{input type="checkbox" class="in-title" checked=searchedTerms.special.in.title}} {{i18n "search.advanced.filters.title"}}</label>
|
||||
<label>{{input type="checkbox" class="in-likes" checked=searchedTerms.special.in.likes}} {{i18n "search.advanced.filters.likes"}}</label>
|
||||
<label>{{input type="checkbox" class="in-private" checked=searchedTerms.special.in.personal}} {{i18n "search.advanced.filters.private"}}</label>
|
||||
<label>{{input type="checkbox" class="in-seen" checked=searchedTerms.special.in.seen}} {{i18n "search.advanced.filters.seen"}}</label>
|
||||
<label>
|
||||
{{input
|
||||
type="checkbox"
|
||||
class="in-title"
|
||||
checked=searchedTerms.special.in.title
|
||||
click=(action "onChangeSearchTermForSpecialInTitle" value="target.checked")
|
||||
}}
|
||||
{{i18n "search.advanced.filters.title"}}
|
||||
</label>
|
||||
<label>
|
||||
{{input
|
||||
type="checkbox"
|
||||
class="in-likes"
|
||||
checked=searchedTerms.special.in.likes
|
||||
click=(action "onChangeSearchTermForSpecialInLikes" value="target.checked")
|
||||
}}
|
||||
{{i18n "search.advanced.filters.likes"}}
|
||||
</label>
|
||||
<label>
|
||||
{{input
|
||||
type="checkbox"
|
||||
class="in-private"
|
||||
checked=searchedTerms.special.in.personal
|
||||
click=(action "onChangeSearchTermForSpecialInPersonal" value="target.checked")
|
||||
}}
|
||||
{{i18n "search.advanced.filters.private"}}
|
||||
</label>
|
||||
<label>
|
||||
{{input
|
||||
type="checkbox"
|
||||
class="in-seen"
|
||||
checked=searchedTerms.special.in.seen
|
||||
click=(action "onChangeSearchTermForSpecialInSeen" value="target.checked")
|
||||
}}
|
||||
{{i18n "search.advanced.filters.seen"}}
|
||||
</label>
|
||||
</section>
|
||||
{{/if}}
|
||||
{{combo-box
|
||||
|
@ -77,8 +104,11 @@
|
|||
valueProperty="value"
|
||||
content=inOptions
|
||||
value=searchedTerms.in
|
||||
onChange=(action "onChangeSearchTermForIn")
|
||||
options=(hash
|
||||
none="user.locale.any"
|
||||
onChange=(action (mut searchedTerms.in))
|
||||
clearable=true
|
||||
)
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -90,8 +120,11 @@
|
|||
valueProperty="value"
|
||||
content=statusOptions
|
||||
value=searchedTerms.status
|
||||
onChange=(action "onChangeSearchTermForStatus")
|
||||
options=(hash
|
||||
none="user.locale.any"
|
||||
onChange=(action (mut searchedTerms.status))
|
||||
clearable=true
|
||||
)
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -118,7 +151,13 @@
|
|||
<div class="control-group pull-left">
|
||||
<label class="control-label" for="search-min-post-count">{{i18n "search.advanced.post.count.label"}}</label>
|
||||
<div class="controls">
|
||||
{{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")
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -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"}}
|
||||
<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}}
|
||||
<span class="search-advanced-title">
|
||||
{{i18n "search.advanced.title"}}
|
||||
|
@ -213,17 +212,17 @@
|
|||
{{#if expanded}}
|
||||
<div class="search-advanced-filters">
|
||||
{{search-advanced-options
|
||||
searchTerm=searchTerm
|
||||
isExpanded=expanded
|
||||
searchTerm=(readonly searchTerm)
|
||||
onChangeSearchTerm=(action (mut searchTerm))
|
||||
}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<div class="search-advanced-filters">
|
||||
{{search-advanced-options
|
||||
searchTerm=searchTerm
|
||||
isExpanded=true
|
||||
category=category
|
||||
searchTerm=(readonly searchTerm)
|
||||
onChangeSearchTerm=(action (mut searchTerm))
|
||||
onChangeCategory=(action (mut category))
|
||||
}}
|
||||
|
||||
{{d-button
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -7,9 +7,11 @@
|
|||
}}
|
||||
{{/each}}
|
||||
|
||||
{{#unless hasReachedMaximumSelection}}
|
||||
<div class="choice input-wrapper">
|
||||
{{component selectKit.options.filterComponent
|
||||
selectKit=selectKit
|
||||
}}
|
||||
</div>
|
||||
{{/unless}}
|
||||
</div>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -34,7 +34,8 @@
|
|||
width: 100%;
|
||||
margin: 0;
|
||||
|
||||
.tag-chooser {
|
||||
.tag-chooser,
|
||||
.user-chooser {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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("<script>prompt(1337)</script>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"
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue