diff --git a/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 b/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 index 9ff860f745a..9dd22b3eb2a 100644 --- a/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 +++ b/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 @@ -1,35 +1,40 @@ import { observes } from 'ember-addons/ember-computed-decorators'; -const REGEXP_FILTER_PREFIXES = /\s?(user:|@|category:|#|group:|badge:|tags?:|in:|status:|posts_count:|(before|after):)/ig; +const REGEXP_BLOCKS = /(([^" \t\n\x0B\f\r]+)?(("[^"]+")?))/g; -const REGEXP_USERNAME_PREFIX = /\s?(user:|@)/ig; -const REGEXP_CATEGORY_PREFIX = /\s?(category:|#)/ig; -const REGEXP_GROUP_PREFIX = /\s?group:/ig; -const REGEXP_BADGE_PREFIX = /\s?badge:/ig; -const REGEXP_TAGS_PREFIX = /\s?tags?:/ig; -const REGEXP_IN_PREFIX = /\s?in:/ig; -const REGEXP_STATUS_PREFIX = /\s?status:/ig; -const REGEXP_POST_COUNT_PREFIX = /\s?posts_count:/ig; -const REGEXP_POST_TIME_PREFIX = /\s?(before|after):/ig; +const REGEXP_USERNAME_PREFIX = /(user:|@)/ig; +const REGEXP_CATEGORY_PREFIX = /(category:|#)/ig; +const REGEXP_GROUP_PREFIX = /group:/ig; +const REGEXP_BADGE_PREFIX = /badge:/ig; +const REGEXP_TAGS_PREFIX = /tags?:/ig; +const REGEXP_IN_PREFIX = /in:/ig; +const REGEXP_STATUS_PREFIX = /status:/ig; +const REGEXP_POST_COUNT_PREFIX = /posts_count:/ig; +const REGEXP_POST_TIME_PREFIX = /(before|after):/ig; -const REGEXP_CATEGORY_SLUG = /\s?(\#[a-zA-Z0-9\-:]+)/ig; -const REGEXP_CATEGORY_ID = /\s?(category:[0-9]+)/ig; -const REGEXP_POST_TIME_WHEN = /(before|after)/ig; +const REGEXP_IN_MATCH = /in:(posted|watching|tracking|bookmarks|first|pinned|unpinned)/ig; +const REGEXP_SPECIAL_IN_LIKES_MATCH = /in:likes/ig; +const REGEXP_SPECIAL_IN_PRIVATE_MATCH = /in:private/ig; +const REGEXP_SPECIAL_IN_WIKI_MATCH = /in:wiki/ig; + +const REGEXP_CATEGORY_SLUG = /(\#[a-zA-Z0-9\-:]+)/ig; +const REGEXP_CATEGORY_ID = /(category:[0-9]+)/ig; +const REGEXP_POST_TIME_WHEN = /(before|after)/ig; export default Em.Component.extend({ classNames: ['search-advanced-options'], inOptions: [ - {name: I18n.t('search.advanced.filters.likes'), value: "likes"}, + //{name: I18n.t('search.advanced.filters.likes'), value: "likes"}, {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.private'), value: "private"}, + //{name: I18n.t('search.advanced.filters.private'), value: "private"}, {name: I18n.t('search.advanced.filters.bookmarks'), value: "bookmarks"}, {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.wiki'), value: "wiki"} ], statusOptions: [ {name: I18n.t('search.advanced.statuses.open'), value: "open"}, @@ -57,12 +62,19 @@ export default Em.Component.extend({ _init() { this.setProperties({ searchedTerms: { - username: null, + username: '', category: null, group: [], badge: [], tags: [], in: '', + special: { + in: { + likes: false, + private: false, + wiki: false + } + }, status: '', posts_count: '', time: { @@ -74,107 +86,207 @@ export default Em.Component.extend({ }, _update() { - let searchTerm = this.get('searchTerm'); - - if (!searchTerm) { + if (!this.get('searchTerm')) { this._init(); return; } - this.findUsername(searchTerm); - this.findCategory(searchTerm); - this.findGroup(searchTerm); - this.findBadge(searchTerm); - this.findTags(searchTerm); - this.findIn(searchTerm); - this.findStatus(searchTerm); - this.findPostsCount(searchTerm); - this.findPostTime(searchTerm); + this.findSearchTerms(); + 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.private', REGEXP_SPECIAL_IN_PRIVATE_MATCH); + this.setSearchedTermSpecialInValue('searchedTerms.special.in.wiki', REGEXP_SPECIAL_IN_WIKI_MATCH); + this.setSearchedTermValue('searchedTerms.status', REGEXP_STATUS_PREFIX); + this.setSearchedTermValueForPostTime(); + this.setSearchedTermValue('searchedTerms.posts_count', REGEXP_POST_COUNT_PREFIX); }, - findSearchTerm(EXPRESSION, searchTerm) { + findSearchTerms() { + const searchTerm = this.get('searchTerm'); if (!searchTerm) - return ""; + return []; - const expressionPosition = searchTerm.search(EXPRESSION); - if (expressionPosition === -1) - return ""; + const blocks = searchTerm.match(REGEXP_BLOCKS); + if (!blocks) return []; - const remainingPhrases = searchTerm.substring(expressionPosition + 2); - let nextExpressionPosition = remainingPhrases.search(REGEXP_FILTER_PREFIXES); - if (nextExpressionPosition === -1) - nextExpressionPosition = remainingPhrases.length; + let result = []; + blocks.forEach(block => { + if (block.length !== 0) + result.push(block); + }); - return searchTerm.substring(expressionPosition, nextExpressionPosition + expressionPosition + 2).trim().split(' ')[0]; + this.set('searchTermBlocks', result); }, - findUsername(searchTerm) { - const match = this.findSearchTerm(REGEXP_USERNAME_PREFIX, searchTerm); + filterBlocks(regexPrefix) { + const blocks = this.get('searchTermBlocks'); + 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); if (match.length !== 0) { - let userInput = match.replace(REGEXP_USERNAME_PREFIX, ''); - - if (userInput.length !== 0 && this.get('searchedTerms.username') !== userInput) { - this.set('searchedTerms.username', userInput); + const userInput = match[0].replace(replaceRegEx, ''); + if (this.get(key) !== userInput) { + this.set(key, userInput); } - } else { - this.set('searchedTerms.username', null); + } else if(this.get(key).length !== 0) { + this.set(key, ''); } }, - @observes('searchedTerms.username') - updateUsername() { - let searchTerm = this.get('searchTerm'); - const match = this.findSearchTerm(REGEXP_USERNAME_PREFIX, searchTerm); - const userFilter = this.get('searchedTerms.username'); + setSearchedTermSpecialInValue(key, replaceRegEx) { + const match = this.filterBlocks(replaceRegEx); - if (userFilter && userFilter.length !== 0) { - if (match.length !== 0) { - searchTerm = searchTerm.replace(match, `@${userFilter}`); - } else { - searchTerm += ` @${userFilter}`; + if (match.length !== 0) { + if (this.get(key) !== true) { + this.set(key, true); } - } else if (match.length !== 0) { - searchTerm = searchTerm.replace(match, ''); + } else if(this.get(key) !== false) { + this.set(key, false); } - - this.set('searchTerm', searchTerm); }, - findCategory(searchTerm) { - const match = this.findSearchTerm(REGEXP_CATEGORY_PREFIX, searchTerm); + setSearchedTermValueForCategory() { + const match = this.filterBlocks(REGEXP_CATEGORY_PREFIX); if (match.length !== 0) { - let existingInput = _.isArray(this.get('searchedTerms.category')) ? this.get('searchedTerms.category')[0] : this.get('searchedTerms.category'); - const subcategories = match.replace(REGEXP_CATEGORY_PREFIX, '').split(':'); + const existingInput = this.get('searchedTerms.category'); + const subcategories = match[0].replace(REGEXP_CATEGORY_PREFIX, '').split(':'); if (subcategories.length > 1) { - let userInput = Discourse.Category.findBySlug(subcategories[1], subcategories[0]); + const userInput = Discourse.Category.findBySlug(subcategories[1], subcategories[0]); if ((!existingInput && userInput) || (existingInput && userInput && existingInput.id !== userInput.id)) this.set('searchedTerms.category', userInput.id); } else - if (isNaN(subcategories)) { - let userInput = Discourse.Category.findSingleBySlug(subcategories[0]); - if ((!existingInput && userInput) - || (existingInput && userInput && existingInput.id !== userInput.id)) - this.set('searchedTerms.category', userInput.id); - } else { - let userInput = Discourse.Category.findById(subcategories[0]); - if ((!existingInput && userInput) - || (existingInput && userInput && existingInput.id !== userInput.id)) - this.set('searchedTerms.category', userInput.id); - } + if (isNaN(subcategories)) { + const userInput = Discourse.Category.findSingleBySlug(subcategories[0]); + if ((!existingInput && userInput) + || (existingInput && userInput && existingInput.id !== userInput.id)) + this.set('searchedTerms.category', userInput.id); + } else { + const userInput = Discourse.Category.findById(subcategories[0]); + if ((!existingInput && userInput) + || (existingInput && userInput && existingInput.id !== userInput.id)) + this.set('searchedTerms.category', userInput.id); + } } else this.set('searchedTerms.category', null); }, - @observes('searchedTerms.category') - updateCategory() { - let searchTerm = this.get('searchTerm'); - const categoryFilter = Discourse.Category.findById(this.get('searchedTerms.category')); + setSearchedTermValueForGroup() { + const match = this.filterBlocks(REGEXP_GROUP_PREFIX); + const group = this.get('searchedTerms.group'); - const match = this.findSearchTerm(REGEXP_CATEGORY_PREFIX, searchTerm); - const slugCategoryMatches = match.match(REGEXP_CATEGORY_SLUG); - const idCategoryMatches = match.match(REGEXP_CATEGORY_ID); + 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'); + + if (match.length !== 0) { + const existingInput = _.isArray(tags) ? tags.join(',') : tags; + const userInput = match[0].replace(REGEXP_TAGS_PREFIX, ''); + + if (existingInput !== userInput) { + this.set('searchedTerms.tags', (userInput.length !== 0) ? userInput.split(',') : []); + } + } 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, ''); + + if (existingInputWhen !== userInputWhen) { + this.set('searchedTerms.time.when', userInputWhen); + } + + if (existingInputDays !== userInputDays) { + this.set('searchedTerms.time.days', userInputDays); + } + } 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.get('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 = Discourse.Category.findById(this.get('searchedTerms.category')); + let searchTerm = this.get('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 && categoryFilter.length !== 0) { const id = categoryFilter.id; const slug = categoryFilter.slug; @@ -186,6 +298,8 @@ export default Em.Component.extend({ searchTerm = searchTerm.replace(idCategoryMatches[0], `category:${id}`); else searchTerm += ` #${parentSlug}:${slug}`; + + this.set('searchTerm', searchTerm.trim()); } else if (categoryFilter) { if (slugCategoryMatches) searchTerm = searchTerm.replace(slugCategoryMatches[0], `#${slug}`); @@ -193,264 +307,210 @@ export default Em.Component.extend({ 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); - }, - - findGroup(searchTerm) { - const match = this.findSearchTerm(REGEXP_GROUP_PREFIX, searchTerm); - const group = this.get('searchedTerms.group'); - - if (match.length !== 0) { - let existingInput = _.isArray(group) ? group[0] : group; - let userInput = match.replace(REGEXP_GROUP_PREFIX, ''); - - if (userInput.length !== 0 && existingInput !== userInput) { - this.set('searchedTerms.group', [userInput]); - } - } else if (group.length !== 0) { - this.set('searchedTerms.group', []); + this.set('searchTerm', searchTerm.trim()); } }, @observes('searchedTerms.group') - updateGroup() { - let searchTerm = this.get('searchTerm'); - const match = this.findSearchTerm(REGEXP_GROUP_PREFIX, searchTerm); + updateSearchTermForGroup() { + const match = this.filterBlocks(REGEXP_GROUP_PREFIX); const groupFilter = this.get('searchedTerms.group'); + let searchTerm = this.get('searchTerm') || ''; if (groupFilter && groupFilter.length !== 0) { if (match.length !== 0) { - searchTerm = searchTerm.replace(match, ` group:${groupFilter}`); + searchTerm = searchTerm.replace(match[0], ` group:${groupFilter}`); } else { searchTerm += ` group:${groupFilter}`; } this.set('searchTerm', searchTerm); } else if (match.length !== 0) { - searchTerm = searchTerm.replace(match, ''); - this.set('searchTerm', searchTerm); - } - }, - - findBadge(searchTerm) { - const match = this.findSearchTerm(REGEXP_BADGE_PREFIX, searchTerm); - const badge = this.get('searchedTerms.badge'); - - if (match.length !== 0) { - let existingInput = _.isArray(badge) ? badge[0] : badge; - let userInput = match.replace(REGEXP_BADGE_PREFIX, ''); - - if (userInput.length !== 0 && existingInput !== userInput) { - this.set('searchedTerms.badge', [match.replace(REGEXP_BADGE_PREFIX, '')]); - } - } else if (badge.length !== 0) { - this.set('searchedTerms.badge', []); + searchTerm = searchTerm.replace(match[0], ''); + this.set('searchTerm', searchTerm.trim()); } }, @observes('searchedTerms.badge') - updateBadge() { - let searchTerm = this.get('searchTerm'); - - const match = this.findSearchTerm(REGEXP_BADGE_PREFIX, searchTerm); + updateSearchTermForBadge() { + const match = this.filterBlocks(REGEXP_BADGE_PREFIX); const badgeFilter = this.get('searchedTerms.badge'); + let searchTerm = this.get('searchTerm') || ''; if (badgeFilter && badgeFilter.length !== 0) { if (match.length !== 0) { - searchTerm = searchTerm.replace(match, ` badge:${badgeFilter}`); + searchTerm = searchTerm.replace(match[0], ` badge:${badgeFilter}`); } else { searchTerm += ` badge:${badgeFilter}`; } this.set('searchTerm', searchTerm); } else if (match.length !== 0) { - searchTerm = searchTerm.replace(match, ''); - this.set('searchTerm', searchTerm); - } - }, - - findTags(searchTerm) { - if (!this.siteSettings.tagging_enabled) return; - - const match = this.findSearchTerm(REGEXP_TAGS_PREFIX, searchTerm); - const tags = this.get('searchedTerms.tags'); - - if (match.length !== 0) { - let existingInput = _.isArray(tags) ? tags.join(',') : tags; - let userInput = match.replace(REGEXP_TAGS_PREFIX, ''); - - if (userInput.length !== 0 && existingInput !== userInput) { - this.set('searchedTerms.tags', userInput.split(',')); - } - } else if (tags.length !== 0) { - this.set('searchedTerms.tags', []); + searchTerm = searchTerm.replace(match[0], ''); + this.set('searchTerm', searchTerm.trim()); } }, @observes('searchedTerms.tags') - updateTags() { - let searchTerm = this.get('searchTerm'); - const match = this.findSearchTerm(REGEXP_TAGS_PREFIX, searchTerm); + updateSearchTermForTags() { + const match = this.filterBlocks(REGEXP_TAGS_PREFIX); const tagFilter = this.get('searchedTerms.tags'); + let searchTerm = this.get('searchTerm') || ''; if (tagFilter && tagFilter.length !== 0) { const tags = tagFilter.join(','); if (match.length !== 0) { - searchTerm = searchTerm.replace(match, `tags:${tags}`); + searchTerm = searchTerm.replace(match[0], `tags:${tags}`); } else { searchTerm += ` tags:${tags}`; } - this.set('searchTerm', searchTerm); + this.set('searchTerm', searchTerm.trim()); } else if (match.length !== 0) { - searchTerm = searchTerm.replace(match, ''); - this.set('searchTerm', searchTerm); + searchTerm = searchTerm.replace(match[0], ''); + this.set('searchTerm', searchTerm.trim()); } }, - findIn(searchTerm) { - const match = this.findSearchTerm(REGEXP_IN_PREFIX, searchTerm); - if (match.length !== 0) { - let existingInput = this.get('searchedTerms.in'); - let userInput = match.replace(REGEXP_IN_PREFIX, ''); - if (userInput.length !== 0 && existingInput !== userInput) - this.set('searchedTerms.in', userInput); - } else - this.set('searchedTerms.in', ''); - }, - @observes('searchedTerms.in') - updateIn() { - let searchTerm = this.get('searchTerm'); - const match = this.findSearchTerm(REGEXP_IN_PREFIX, searchTerm); + updateSearchTermForIn() { + const match = this.filterBlocks(REGEXP_IN_MATCH); const inFilter = this.get('searchedTerms.in'); + let searchTerm = this.get('searchTerm') || ''; if (inFilter) { if (match.length !== 0) { - searchTerm = searchTerm.replace(match, `in:${inFilter}`); + searchTerm = searchTerm.replace(match[0], `in:${inFilter}`); } else { searchTerm += ` in:${inFilter}`; } - this.set('searchTerm', searchTerm); + this.set('searchTerm', searchTerm.trim()); } else if (match.length !== 0) { searchTerm = searchTerm.replace(match, ''); - this.set('searchTerm', searchTerm); + this.set('searchTerm', searchTerm.trim()); } }, - findStatus(searchTerm) { - const match = this.findSearchTerm(REGEXP_STATUS_PREFIX, searchTerm); - if (match.length !== 0) { - let existingInput = this.get('searchedTerms.status'); - let userInput = match.replace(REGEXP_STATUS_PREFIX, ''); - if (userInput.length !== 0 && existingInput !== userInput) - this.set('searchedTerms.status', userInput); - } else - this.set('searchedTerms.status', ''); + @observes('searchedTerms.special.in.likes') + updateSearchTermForSpecialInLikes() { + const match = this.filterBlocks(REGEXP_SPECIAL_IN_LIKES_MATCH); + const inFilter = this.get('searchedTerms.special.in.likes'); + let searchTerm = this.get('searchTerm') || ''; + + if (inFilter) { + if (match.length === 0) { + searchTerm += ` in:likes`; + this.set('searchTerm', searchTerm.trim()); + } + } else if (match.length !== 0) { + searchTerm = searchTerm.replace(match, ''); + this.set('searchTerm', searchTerm.trim()); + } + }, + + @observes('searchedTerms.special.in.private') + updateSearchTermForSpecialInPrivate() { + const match = this.filterBlocks(REGEXP_SPECIAL_IN_PRIVATE_MATCH); + const inFilter = this.get('searchedTerms.special.in.private'); + let searchTerm = this.get('searchTerm') || ''; + + if (inFilter) { + if (match.length === 0) { + searchTerm += ` in:private`; + this.set('searchTerm', searchTerm.trim()); + } + } else if (match.length !== 0) { + searchTerm = searchTerm.replace(match, ''); + this.set('searchTerm', searchTerm.trim()); + } + }, + + @observes('searchedTerms.special.in.wiki') + updateSearchTermForSpecialInWiki() { + const match = this.filterBlocks(REGEXP_SPECIAL_IN_WIKI_MATCH); + const inFilter = this.get('searchedTerms.special.in.wiki'); + let searchTerm = this.get('searchTerm') || ''; + + if (inFilter) { + if (match.length === 0) { + searchTerm += ` in:wiki`; + this.set('searchTerm', searchTerm.trim()); + } + } else if (match.length !== 0) { + searchTerm = searchTerm.replace(match, ''); + this.set('searchTerm', searchTerm.trim()); + } }, @observes('searchedTerms.status') - updateStatus() { - let searchTerm = this.get('searchTerm'); - const match = this.findSearchTerm(REGEXP_STATUS_PREFIX, searchTerm); + updateSearchTermForStatus() { + const match = this.filterBlocks(REGEXP_STATUS_PREFIX); const statusFilter = this.get('searchedTerms.status'); + let searchTerm = this.get('searchTerm') || ''; if (statusFilter) { if (match.length !== 0) { - searchTerm = searchTerm.replace(match, `status:${statusFilter}`); + searchTerm = searchTerm.replace(match[0], `status:${statusFilter}`); } else { searchTerm += ` status:${statusFilter}`; } - this.set('searchTerm', searchTerm); + this.set('searchTerm', searchTerm.trim()); } else if (match.length !== 0) { - searchTerm = searchTerm.replace(match, ''); - this.set('searchTerm', searchTerm); - } - }, - - findPostsCount(searchTerm) { - const match = this.findSearchTerm(REGEXP_POST_COUNT_PREFIX, searchTerm); - if (match.length !== 0) { - let existingInput = this.get('searchedTerms.posts_count'); - let userInput = match.replace(REGEXP_POST_COUNT_PREFIX, ''); - if (userInput.length !== 0 && existingInput !== userInput) - this.set('searchedTerms.posts_count', userInput); - } else - this.set('searchedTerms.posts_count', ''); - }, - - @observes('searchedTerms.posts_count') - updatePostsCount() { - let searchTerm = this.get('searchTerm'); - const match = this.findSearchTerm(REGEXP_POST_COUNT_PREFIX, searchTerm); - const postsCountFilter = this.get('searchedTerms.posts_count'); - - if (postsCountFilter) { - if (match.length !== 0) { - searchTerm = searchTerm.replace(match, `posts_count:${postsCountFilter}`); - } else { - searchTerm += ` posts_count:${postsCountFilter}`; - } - - this.set('searchTerm', searchTerm); - } else if (match.length !== 0) { - searchTerm = searchTerm.replace(match, ''); - this.set('searchTerm', searchTerm); - } - }, - - findPostTime(searchTerm) { - const match = this.findSearchTerm(REGEXP_POST_TIME_WHEN, searchTerm); - - if (match.length !== 0) { - let existingInputWhen = this.get('searchedTerms.time.when'); - let userInputWhen = match.match(REGEXP_POST_TIME_WHEN)[0]; - let existingInputDays = this.get('searchedTerms.time.days'); - let userInputDays = match.replace(REGEXP_POST_TIME_PREFIX, ''); - - if (userInputWhen.length !== 0 && existingInputWhen !== userInputWhen) { - this.set('searchedTerms.time.when', userInputWhen); - } - - if (userInputDays.length !== 0 && - existingInputDays !== userInputDays && - userInputDays !== match) { - this.set('searchedTerms.time.days', userInputDays); - } - } else { - this.set('searchedTerms.time.days', ''); + searchTerm = searchTerm.replace(match[0], ''); + this.set('searchTerm', searchTerm.trim()); } }, @observes('searchedTerms.time.when', 'searchedTerms.time.days') - updatePostTime() { - let searchTerm = this.get('searchTerm'); - const match = this.findSearchTerm(REGEXP_POST_TIME_PREFIX, searchTerm); + updateSearchTermForPostTime() { + const match = this.filterBlocks(REGEXP_POST_TIME_PREFIX); const timeDaysFilter = this.get('searchedTerms.time.days'); + let searchTerm = this.get('searchTerm') || ''; if (timeDaysFilter) { const when = this.get('searchedTerms.time.when'); if (match.length !== 0) { - searchTerm = searchTerm.replace(match, `${when}:${timeDaysFilter}`); + searchTerm = searchTerm.replace(match[0], `${when}:${timeDaysFilter}`); } else { searchTerm += ` ${when}:${timeDaysFilter}`; } - this.set('searchTerm', searchTerm); + this.set('searchTerm', searchTerm.trim()); } else if (match.length !== 0) { - searchTerm = searchTerm.replace(match, ''); - this.set('searchTerm', searchTerm); + searchTerm = searchTerm.replace(match[0], ''); + this.set('searchTerm', searchTerm.trim()); + } + }, + + @observes('searchedTerms.posts_count') + updateSearchTermForPostsCount() { + const match = this.filterBlocks(REGEXP_POST_COUNT_PREFIX); + const postsCountFilter = this.get('searchedTerms.posts_count'); + let searchTerm = this.get('searchTerm') || ''; + + if (postsCountFilter) { + if (match.length !== 0) { + searchTerm = searchTerm.replace(match[0], `posts_count:${postsCountFilter}`); + } else { + searchTerm += ` posts_count:${postsCountFilter}`; + } + + this.set('searchTerm', searchTerm.trim()); + } else if (match.length !== 0) { + searchTerm = searchTerm.replace(match[0], ''); + this.set('searchTerm', searchTerm.trim()); } }, diff --git a/app/assets/javascripts/discourse/templates/components/search-advanced-options.hbs b/app/assets/javascripts/discourse/templates/components/search-advanced-options.hbs index 1fc985d4d25..554a2d689cf 100644 --- a/app/assets/javascripts/discourse/templates/components/search-advanced-options.hbs +++ b/app/assets/javascripts/discourse/templates/components/search-advanced-options.hbs @@ -50,6 +50,11 @@
+
+ + + +
{{combo-box id="in" valueAttribute="value" content=inOptions value=searchedTerms.in none="user.locale.any"}}
diff --git a/app/assets/stylesheets/common/base/search.scss b/app/assets/stylesheets/common/base/search.scss index ba279d4718b..7fa038db9c1 100644 --- a/app/assets/stylesheets/common/base/search.scss +++ b/app/assets/stylesheets/common/base/search.scss @@ -114,6 +114,10 @@ .control-group.pull-left { width: 50%; } + + input[type="checkbox"] { + height: auto; + } } } diff --git a/app/assets/stylesheets/mobile/search.scss b/app/assets/stylesheets/mobile/search.scss index 1dbce919d8a..bb4ea638c3f 100644 --- a/app/assets/stylesheets/mobile/search.scss +++ b/app/assets/stylesheets/mobile/search.scss @@ -13,7 +13,12 @@ } .controls { - input,select { + label { + display: block; + margin-bottom: 5px; + } + + input:not([type="checkbox"]),select { width: 75%; } } diff --git a/test/javascripts/acceptance/search-full-test.js.es6 b/test/javascripts/acceptance/search-full-test.js.es6 index 4cf6e65e895..29d863912d7 100644 --- a/test/javascripts/acceptance/search-full-test.js.es6 +++ b/test/javascripts/acceptance/search-full-test.js.es6 @@ -71,7 +71,7 @@ test("open advanced search", assert => { test("validate population of advanced search", assert => { visit("/search"); - fillIn('.search input.full-page-search', 'test user:admin #bug group:moderators badge:Reader tags:monkey in:likes status:open after:2016-10-05 posts_count:10'); + fillIn('.search input.full-page-search', 'test user:admin #bug group:moderators badge:Reader tags:monkey in:likes in:private in:wiki in:bookmarks status:open after:2016-10-05 posts_count:10'); click('.search-advanced-btn'); andThen(() => { @@ -80,7 +80,10 @@ test("validate population of advanced search", assert => { //assert.ok(exists('.search-advanced-options span:contains("moderators")'), 'has "moderators" pre-populated'); //assert.ok(exists('.search-advanced-options span:contains("Reader")'), 'has "Reader" pre-populated'); assert.ok(exists('.search-advanced-options .tag-chooser .tag-monkey'), 'has "monkey" pre-populated'); - assert.ok(exists('.search-advanced-options .combobox .select2-choice .select2-chosen:contains("I liked")'), 'has "I liked" pre-populated'); + assert.ok(exists('.search-advanced-options .in-likes:checked'), 'has "I liked" pre-populated'); + assert.ok(exists('.search-advanced-options .in-private:checked'), 'has "are in my messages" pre-populated'); + assert.ok(exists('.search-advanced-options .in-wiki:checked'), 'has "are wiki" pre-populated'); + assert.ok(exists('.search-advanced-options .combobox .select2-choice .select2-chosen:contains("I\'ve bookmarked")'), 'has "I\'ve bookmarked" pre-populated'); assert.ok(exists('.search-advanced-options .combobox .select2-choice .select2-chosen:contains("are open")'), 'has "are open" pre-populated'); assert.ok(exists('.search-advanced-options .combobox .select2-choice .select2-chosen:contains("after")'), 'has "after" pre-populated'); assert.equal(find('.search-advanced-options #search-post-date').val(), "2016-10-05", 'has "2016-10-05" pre-populated'); @@ -190,16 +193,52 @@ test("update category through advanced search ui", assert => { // }); // }); +test("update in:likes filter through advanced search ui", assert => { + visit("/search"); + fillIn('.search input.full-page-search', 'none'); + click('.search-advanced-btn'); + click('.search-advanced-options .in-likes'); + + andThen(() => { + assert.ok(exists('.search-advanced-options .in-likes:checked'), 'has "I liked" populated'); + assert.equal(find('.search input.full-page-search').val(), "none in:likes", 'has updated search term to "none in:likes"'); + }); +}); + +test("update in:private filter through advanced search ui", assert => { + visit("/search"); + fillIn('.search input.full-page-search', 'none'); + click('.search-advanced-btn'); + click('.search-advanced-options .in-private'); + + andThen(() => { + assert.ok(exists('.search-advanced-options .in-private:checked'), 'has "are in my messages" populated'); + assert.equal(find('.search input.full-page-search').val(), "none in:private", 'has updated search term to "none in:private"'); + }); +}); + +test("update in:wiki filter through advanced search ui", assert => { + visit("/search"); + fillIn('.search input.full-page-search', 'none'); + click('.search-advanced-btn'); + click('.search-advanced-options .in-wiki'); + + andThen(() => { + assert.ok(exists('.search-advanced-options .in-wiki:checked'), 'has "are wiki" populated'); + assert.equal(find('.search input.full-page-search').val(), "none in:wiki", 'has updated search term to "none in:wiki"'); + }); +}); + test("update in filter through advanced search ui", assert => { visit("/search"); fillIn('.search input.full-page-search', 'none'); click('.search-advanced-btn'); - selectDropdown('.search-advanced-options #s2id_in', 'likes'); - fillIn('.search-advanced-options #in', 'likes'); + selectDropdown('.search-advanced-options #s2id_in', 'bookmarks'); + fillIn('.search-advanced-options #in', 'bookmarks'); andThen(() => { - assert.ok(exists('.search-advanced-options #s2id_in .select2-choice .select2-chosen:contains("I liked")'), 'has "I liked" populated'); - assert.equal(find('.search input.full-page-search').val(), "none in:likes", 'has updated search term to "none in:likes"'); + assert.ok(exists('.search-advanced-options #s2id_in .select2-choice .select2-chosen:contains("I\'ve bookmarked")'), 'has "I\'ve bookmarked" populated'); + assert.equal(find('.search input.full-page-search').val(), "none in:bookmarks", 'has updated search term to "none in:bookmarks"'); }); }); @@ -242,3 +281,13 @@ test("update posts count through advanced search ui", assert => { assert.equal(find('.search input.full-page-search').val(), "none posts_count:5", 'has updated search term to "none posts_count:5"'); }); }); + +test("validate advanced search when initially empty", assert => { + visit("/search?expanded=true"); + click('.search-advanced-options .in-likes'); + + andThen(() => { + assert.ok(exists('.search-advanced-options .in-likes:checked'), 'has "I liked" populated'); + assert.equal(find('.search input.full-page-search').val(), "in:likes", 'has updated search term to "in:likes"'); + }); +});