This repository has been archived on 2023-03-18. You can view files and clone it, but cannot push or open issues or pull requests.
osr-discourse-src/app/assets/javascripts/discourse/components/search-advanced-options.js.es6

602 lines
18 KiB
JavaScript

import { observes } from "ember-addons/ember-computed-decorators";
import { escapeExpression } from "discourse/lib/utilities";
import Group from "discourse/models/group";
import Badge from "discourse/models/badge";
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;
const REGEXP_MIN_POST_COUNT_PREFIX = /^min_post_count:/gi;
const REGEXP_POST_TIME_PREFIX = /^(before|after):/gi;
const REGEXP_TAGS_REPLACE = /(^(tags?:|#(?=[a-z0-9\-]+::tag))|::tag\s?$)/gi;
const REGEXP_IN_MATCH = /^(in|with):(posted|watching|tracking|bookmarks|first|pinned|unpinned|wiki|unseen|image)/gi;
const REGEXP_SPECIAL_IN_LIKES_MATCH = /^in:likes/gi;
const REGEXP_SPECIAL_IN_TITLE_MATCH = /^in:title/gi;
const REGEXP_SPECIAL_IN_PRIVATE_MATCH = /^in:private/gi;
const REGEXP_SPECIAL_IN_SEEN_MATCH = /^in:seen/gi;
const REGEXP_CATEGORY_SLUG = /^(\#[a-zA-Z0-9\-:]+)/gi;
const REGEXP_CATEGORY_ID = /^(category:[0-9]+)/gi;
const REGEXP_POST_TIME_WHEN = /^(before|after)/gi;
const IN_OPTIONS_MAPPING = { images: "with" };
export default Ember.Component.extend({
classNames: ["search-advanced-options"],
init() {
this._super(...arguments);
this.inOptionsForUsers = [
{ name: I18n.t("search.advanced.filters.unseen"), value: "unseen" },
{ name: I18n.t("search.advanced.filters.posted"), value: "posted" },
{ name: I18n.t("search.advanced.filters.watching"), value: "watching" },
{ name: I18n.t("search.advanced.filters.tracking"), value: "tracking" },
{ name: I18n.t("search.advanced.filters.bookmarks"), value: "bookmarks" }
];
this.inOptionsForAll = [
{ name: I18n.t("search.advanced.filters.first"), value: "first" },
{ name: I18n.t("search.advanced.filters.pinned"), value: "pinned" },
{ name: I18n.t("search.advanced.filters.unpinned"), value: "unpinned" },
{ name: I18n.t("search.advanced.filters.wiki"), value: "wiki" },
{ name: I18n.t("search.advanced.filters.images"), value: "images" }
];
this.statusOptions = [
{ name: I18n.t("search.advanced.statuses.open"), value: "open" },
{ name: I18n.t("search.advanced.statuses.closed"), value: "closed" },
{ name: I18n.t("search.advanced.statuses.archived"), value: "archived" },
{
name: I18n.t("search.advanced.statuses.noreplies"),
value: "noreplies"
},
{
name: I18n.t("search.advanced.statuses.single_user"),
value: "single_user"
}
];
this.postTimeOptions = [
{ name: I18n.t("search.advanced.post.time.before"), value: "before" },
{ name: I18n.t("search.advanced.post.time.after"), value: "after" }
];
this._init();
Ember.run.scheduleOnce("afterRender", () => this._update());
},
@observes("searchTerm")
_updateOptions() {
this._update();
Ember.run.debounce(this, this._update, 250);
},
_init() {
this.setProperties({
searchedTerms: {
username: "",
category: "",
group: [],
badge: [],
tags: [],
in: "",
special: {
in: {
title: false,
likes: false,
private: false,
seen: false
},
all_tags: false
},
status: "",
min_post_count: "",
time: {
when: "before",
days: ""
}
},
inOptions: this.currentUser
? this.inOptionsForUsers.concat(this.inOptionsForAll)
: this.inOptionsForAll
});
},
_update() {
if (!this.searchTerm) {
this._init();
return;
}
this.setSearchedTermValue("searchedTerms.username", REGEXP_USERNAME_PREFIX);
this.setSearchedTermValueForCategory();
this.setSearchedTermValueForGroup();
this.setSearchedTermValueForBadge();
this.setSearchedTermValueForTags();
this.setSearchedTermValue(
"searchedTerms.in",
REGEXP_IN_PREFIX,
REGEXP_IN_MATCH
);
this.setSearchedTermSpecialInValue(
"searchedTerms.special.in.likes",
REGEXP_SPECIAL_IN_LIKES_MATCH
);
this.setSearchedTermSpecialInValue(
"searchedTerms.special.in.title",
REGEXP_SPECIAL_IN_TITLE_MATCH
);
this.setSearchedTermSpecialInValue(
"searchedTerms.special.in.private",
REGEXP_SPECIAL_IN_PRIVATE_MATCH
);
this.setSearchedTermSpecialInValue(
"searchedTerms.special.in.seen",
REGEXP_SPECIAL_IN_SEEN_MATCH
);
this.setSearchedTermValue("searchedTerms.status", REGEXP_STATUS_PREFIX);
this.setSearchedTermValueForPostTime();
this.setSearchedTermValue(
"searchedTerms.min_post_count",
REGEXP_MIN_POST_COUNT_PREFIX
);
},
findSearchTerms() {
const searchTerm = escapeExpression(this.searchTerm);
if (!searchTerm) return [];
const blocks = searchTerm.match(REGEXP_BLOCKS);
if (!blocks) return [];
let result = [];
blocks.forEach(block => {
if (block.length !== 0) result.push(block);
});
return result;
},
filterBlocks(regexPrefix) {
const blocks = this.findSearchTerms();
if (!blocks) return [];
let result = [];
blocks.forEach(block => {
if (block.search(regexPrefix) !== -1) result.push(block);
});
return result;
},
setSearchedTermValue(key, replaceRegEx, matchRegEx = null) {
matchRegEx = matchRegEx || replaceRegEx;
const match = this.filterBlocks(matchRegEx);
let val = this.get(key);
if (match.length !== 0) {
const userInput = match[0].replace(replaceRegEx, "");
if (val !== userInput) {
this.set(key, userInput);
}
} else if (val && val.length !== 0) {
this.set(key, "");
}
},
setSearchedTermSpecialInValue(key, replaceRegEx) {
const match = this.filterBlocks(replaceRegEx);
if (match.length !== 0) {
if (this.get(key) !== true) {
this.set(key, true);
}
} else if (this.get(key) !== false) {
this.set(key, false);
}
},
setSearchedTermValueForCategory() {
const match = this.filterBlocks(REGEXP_CATEGORY_PREFIX);
if (match.length !== 0) {
const existingInput = this.get("searchedTerms.category");
const subcategories = match[0]
.replace(REGEXP_CATEGORY_PREFIX, "")
.split(":");
if (subcategories.length > 1) {
const userInput = Discourse.Category.findBySlug(
subcategories[1],
subcategories[0]
);
if (
(!existingInput && userInput) ||
(existingInput && userInput && existingInput.id !== userInput.id)
)
this.set("searchedTerms.category", userInput);
} else if (isNaN(subcategories)) {
const userInput = Discourse.Category.findSingleBySlug(subcategories[0]);
if (
(!existingInput && userInput) ||
(existingInput && userInput && existingInput.id !== userInput.id)
)
this.set("searchedTerms.category", userInput);
} else {
const userInput = Discourse.Category.findById(subcategories[0]);
if (
(!existingInput && userInput) ||
(existingInput && userInput && existingInput.id !== userInput.id)
)
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 = _.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 = _.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", []);
}
},
setSearchedTermValueForTags() {
if (!this.siteSettings.tagging_enabled) return;
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 !== 0) {
const join_char = contain_all_tags ? "+" : ",";
const existingInput = _.isArray(tags) ? tags.join(join_char) : tags;
const userInput = match[0].replace(REGEXP_TAGS_REPLACE, "");
if (existingInput !== userInput) {
this.set(
"searchedTerms.tags",
userInput.length !== 0 ? userInput.split(join_char) : []
);
}
} else if (tags.length !== 0) {
this.set("searchedTerms.tags", []);
}
},
setSearchedTermValueForPostTime() {
const match = this.filterBlocks(REGEXP_POST_TIME_PREFIX);
if (match.length !== 0) {
const existingInputWhen = this.get("searchedTerms.time.when");
const userInputWhen = match[0].match(REGEXP_POST_TIME_WHEN)[0];
const existingInputDays = this.get("searchedTerms.time.days");
const userInputDays = match[0].replace(REGEXP_POST_TIME_PREFIX, "");
const properties = {};
if (existingInputWhen !== userInputWhen) {
properties["searchedTerms.time.when"] = userInputWhen;
}
if (existingInputDays !== userInputDays) {
properties["searchedTerms.time.days"] = userInputDays;
}
this.setProperties(properties);
} else {
this.set("searchedTerms.time.days", "");
}
},
@observes("searchedTerms.username")
updateSearchTermForUsername() {
const match = this.filterBlocks(REGEXP_USERNAME_PREFIX);
const userFilter = this.get("searchedTerms.username");
let searchTerm = this.searchTerm || "";
if (userFilter && userFilter.length !== 0) {
if (match.length !== 0) {
searchTerm = searchTerm.replace(match[0], `@${userFilter}`);
} else {
searchTerm += ` @${userFilter}`;
}
this.set("searchTerm", searchTerm.trim());
} else if (match.length !== 0) {
searchTerm = searchTerm.replace(match[0], "");
this.set("searchTerm", searchTerm.trim());
}
},
@observes("searchedTerms.category")
updateSearchTermForCategory() {
const match = this.filterBlocks(REGEXP_CATEGORY_PREFIX);
const categoryFilter = this.get("searchedTerms.category");
let searchTerm = this.searchTerm || "";
const slugCategoryMatches =
match.length !== 0 ? match[0].match(REGEXP_CATEGORY_SLUG) : null;
const idCategoryMatches =
match.length !== 0 ? match[0].match(REGEXP_CATEGORY_ID) : null;
if (categoryFilter) {
const id = categoryFilter.id;
const slug = categoryFilter.slug;
if (categoryFilter.parentCategory) {
const parentSlug = categoryFilter.parentCategory.slug;
if (slugCategoryMatches)
searchTerm = searchTerm.replace(
slugCategoryMatches[0],
`#${parentSlug}:${slug}`
);
else if (idCategoryMatches)
searchTerm = searchTerm.replace(
idCategoryMatches[0],
`category:${id}`
);
else searchTerm += ` #${parentSlug}:${slug}`;
this.set("searchTerm", searchTerm.trim());
} else {
if (slugCategoryMatches)
searchTerm = searchTerm.replace(slugCategoryMatches[0], `#${slug}`);
else if (idCategoryMatches)
searchTerm = searchTerm.replace(
idCategoryMatches[0],
`category:${id}`
);
else searchTerm += ` #${slug}`;
this.set("searchTerm", searchTerm.trim());
}
} else {
if (slugCategoryMatches)
searchTerm = searchTerm.replace(slugCategoryMatches[0], "");
if (idCategoryMatches)
searchTerm = searchTerm.replace(idCategoryMatches[0], "");
this.set("searchTerm", searchTerm.trim());
}
},
@observes("searchedTerms.group")
updateSearchTermForGroup() {
const match = this.filterBlocks(REGEXP_GROUP_PREFIX);
const groupFilter = this.get("searchedTerms.group");
let searchTerm = this.searchTerm || "";
if (groupFilter && groupFilter.length !== 0) {
if (match.length !== 0) {
searchTerm = searchTerm.replace(match[0], ` group:${groupFilter}`);
} else {
searchTerm += ` group:${groupFilter}`;
}
this.set("searchTerm", searchTerm);
} else if (match.length !== 0) {
searchTerm = searchTerm.replace(match[0], "");
this.set("searchTerm", searchTerm.trim());
}
},
@observes("searchedTerms.badge")
updateSearchTermForBadge() {
const match = this.filterBlocks(REGEXP_BADGE_PREFIX);
const badgeFilter = this.get("searchedTerms.badge");
let searchTerm = this.searchTerm || "";
if (badgeFilter && badgeFilter.length !== 0) {
if (match.length !== 0) {
searchTerm = searchTerm.replace(match[0], ` badge:${badgeFilter}`);
} else {
searchTerm += ` badge:${badgeFilter}`;
}
this.set("searchTerm", searchTerm);
} else if (match.length !== 0) {
searchTerm = searchTerm.replace(match[0], "");
this.set("searchTerm", searchTerm.trim());
}
},
@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() {
const match = this.filterBlocks(REGEXP_IN_MATCH);
const inFilter = this.get("searchedTerms.in");
let keyword = "in";
if (inFilter in IN_OPTIONS_MAPPING) {
keyword = IN_OPTIONS_MAPPING[inFilter];
}
let searchTerm = this.searchTerm || "";
if (inFilter) {
if (match.length !== 0) {
searchTerm = searchTerm.replace(match[0], `${keyword}:${inFilter}`);
} else {
searchTerm += ` ${keyword}:${inFilter}`;
}
this.set("searchTerm", searchTerm.trim());
} else if (match.length !== 0) {
searchTerm = searchTerm.replace(match, "");
this.set("searchTerm", searchTerm.trim());
}
},
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.private")
updateSearchTermForSpecialInPrivate() {
this.updateInRegex(REGEXP_SPECIAL_IN_PRIVATE_MATCH, "private");
},
@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() {
const match = this.filterBlocks(REGEXP_STATUS_PREFIX);
const statusFilter = this.get("searchedTerms.status");
let searchTerm = this.searchTerm || "";
if (statusFilter) {
if (match.length !== 0) {
searchTerm = searchTerm.replace(match[0], `status:${statusFilter}`);
} else {
searchTerm += ` status:${statusFilter}`;
}
this.set("searchTerm", searchTerm.trim());
} else if (match.length !== 0) {
searchTerm = searchTerm.replace(match[0], "");
this.set("searchTerm", searchTerm.trim());
}
},
@observes("searchedTerms.time.when", "searchedTerms.time.days")
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() {
const match = this.filterBlocks(REGEXP_MIN_POST_COUNT_PREFIX);
const postsCountFilter = this.get("searchedTerms.min_post_count");
let searchTerm = this.searchTerm || "";
if (postsCountFilter) {
if (match.length !== 0) {
searchTerm = searchTerm.replace(
match[0],
`min_post_count:${postsCountFilter}`
);
} else {
searchTerm += ` min_post_count:${postsCountFilter}`;
}
this.set("searchTerm", searchTerm.trim());
} else if (match.length !== 0) {
searchTerm = searchTerm.replace(match[0], "");
this.set("searchTerm", searchTerm.trim());
}
},
groupFinder(term) {
return Group.findAll({ term: term, ignore_automatic: false });
},
badgeFinder(term) {
return Badge.findAll({ search: term });
}
});