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 fe6db1a0fd2..48d272baad4 100644 --- a/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 +++ b/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 @@ -12,7 +12,7 @@ const REGEXP_IN_PREFIX = /^in:/ig; const REGEXP_STATUS_PREFIX = /^status:/ig; const REGEXP_MIN_POST_COUNT_PREFIX = /^min_post_count:/ig; const REGEXP_POST_TIME_PREFIX = /^(before|after):/ig; -const REGEXP_TAGS_SUFFIX = /::tag\s?$/ig; +const REGEXP_TAGS_REPLACE = /(^(tags?:|#(?=[a-z0-9\-]+::tag))|::tag\s?$)/ig; const REGEXP_IN_MATCH = /^in:(posted|watching|tracking|bookmarks|first|pinned|unpinned)/ig; @@ -230,7 +230,7 @@ export default Em.Component.extend({ if (match.length !== 0) { const existingInput = _.isArray(tags) ? tags.join(',') : tags; - const userInput = match[0].replace(REGEXP_TAGS_PREFIX, '').replace(REGEXP_TAGS_SUFFIX, ''); + const userInput = match[0].replace(REGEXP_TAGS_REPLACE, ''); if (existingInput !== userInput) { this.set('searchedTerms.tags', (userInput.length !== 0) ? userInput.split(',') : []); diff --git a/app/assets/javascripts/discourse/components/search-text-field.js.es6 b/app/assets/javascripts/discourse/components/search-text-field.js.es6 index 339545bf86d..85547425795 100644 --- a/app/assets/javascripts/discourse/components/search-text-field.js.es6 +++ b/app/assets/javascripts/discourse/components/search-text-field.js.es6 @@ -1,12 +1,7 @@ import computed from 'ember-addons/ember-computed-decorators'; import { on } from 'ember-addons/ember-computed-decorators'; import TextField from 'discourse/components/text-field'; -import { findRawTemplate } from 'discourse/lib/raw-templates'; -import { TAG_HASHTAG_POSTFIX } from 'discourse/lib/tag-hashtags'; -import { SEPARATOR } from 'discourse/lib/category-hashtags'; -import Category from 'discourse/models/category'; -import { search as searchCategoryTag } from 'discourse/lib/category-tag-search'; -import userSearch from 'discourse/lib/user-search'; +import { applySearchAutocomplete } from "discourse/lib/search"; export default TextField.extend({ @computed('searchService.searchContextEnabled') @@ -16,51 +11,13 @@ export default TextField.extend({ @on("didInsertElement") becomeFocused() { + const $searchInput = this.$(); + applySearchAutocomplete($searchInput, this.siteSettings); + if (!this.get('hasAutofocus')) { return; } // iOS is crazy, without this we will not be // at the top of the page $(window).scrollTop(0); - this.$().focus(); - }, - - @on("didInsertElement") - applyAutoComplete() { - this._super(); - - const $searchInput = this.$(); - this._applyCategoryHashtagAutocomplete($searchInput); - this._applyUsernameAutocomplete($searchInput); - }, - - _applyCategoryHashtagAutocomplete($searchInput) { - const siteSettings = this.siteSettings; - - $searchInput.autocomplete({ - template: findRawTemplate('category-tag-autocomplete'), - key: '#', - width: '100%', - treatAsTextarea: true, - transformComplete(obj) { - if (obj.model) { - return Category.slugFor(obj.model, SEPARATOR); - } else { - return `${obj.text}${TAG_HASHTAG_POSTFIX}`; - } - }, - dataSource(term) { - return searchCategoryTag(term, siteSettings); - } - }); - }, - - _applyUsernameAutocomplete($searchInput) { - $searchInput.autocomplete({ - template: findRawTemplate('user-selector-autocomplete'), - dataSource: term => userSearch({ term, undefined, includeGroups: true }), - key: "@", - width: '100%', - treatAsTextarea: true, - transformComplete: v => v.username || v.name - }); + $searchInput.focus(); } }); diff --git a/app/assets/javascripts/discourse/lib/autocomplete.js.es6 b/app/assets/javascripts/discourse/lib/autocomplete.js.es6 index c96ca3fb133..c30a1071039 100644 --- a/app/assets/javascripts/discourse/lib/autocomplete.js.es6 +++ b/app/assets/javascripts/discourse/lib/autocomplete.js.es6 @@ -247,6 +247,13 @@ export default function(options) { }; vOffset = -32; hOffset = 0; + } if (options.treatAsTextarea) { + pos = me.caretPosition({ + pos: completeStart, + key: options.key + }); + hOffset = 27; + vOffset = -32; } else { pos = me.caretPosition({ pos: completeStart, diff --git a/app/assets/javascripts/discourse/lib/search.js.es6 b/app/assets/javascripts/discourse/lib/search.js.es6 index 9dc3b38e2f1..fea2dd7f136 100644 --- a/app/assets/javascripts/discourse/lib/search.js.es6 +++ b/app/assets/javascripts/discourse/lib/search.js.es6 @@ -1,9 +1,14 @@ import { ajax } from 'discourse/lib/ajax'; +import { findRawTemplate } from 'discourse/lib/raw-templates'; +import { TAG_HASHTAG_POSTFIX } from 'discourse/lib/tag-hashtags'; +import { SEPARATOR } from 'discourse/lib/category-hashtags'; +import Category from 'discourse/models/category'; +import { search as searchCategoryTag } from 'discourse/lib/category-tag-search'; +import userSearch from 'discourse/lib/user-search'; export function translateResults(results, opts) { const User = require('discourse/models/user').default; - const Category = require('discourse/models/category').default; const Post = require('discourse/models/post').default; const Topic = require('discourse/models/topic').default; @@ -124,3 +129,31 @@ export function isValidSearchTerm(searchTerm) { return false; } }; + +export function applySearchAutocomplete($input, siteSettings) { + $input.autocomplete({ + template: findRawTemplate('category-tag-autocomplete'), + key: '#', + width: '100%', + treatAsTextarea: true, + transformComplete(obj) { + if (obj.model) { + return Category.slugFor(obj.model, SEPARATOR); + } else { + return `${obj.text}${TAG_HASHTAG_POSTFIX}`; + } + }, + dataSource(term) { + return searchCategoryTag(term, siteSettings); + } + }); + + $input.autocomplete({ + template: findRawTemplate('user-selector-autocomplete'), + dataSource: term => userSearch({ term, undefined, includeGroups: true }), + key: "@", + width: '100%', + treatAsTextarea: true, + transformComplete: v => v.username || v.name + }); +}; diff --git a/app/assets/javascripts/discourse/widgets/header.js.es6 b/app/assets/javascripts/discourse/widgets/header.js.es6 index 7f349ff3f22..fb8a4df32ce 100644 --- a/app/assets/javascripts/discourse/widgets/header.js.es6 +++ b/app/assets/javascripts/discourse/widgets/header.js.es6 @@ -3,12 +3,7 @@ import { iconNode } from 'discourse/helpers/fa-icon-node'; import { avatarImg } from 'discourse/widgets/post'; import DiscourseURL from 'discourse/lib/url'; import { wantsNewWindow } from 'discourse/lib/intercept-click'; -import { findRawTemplate } from 'discourse/lib/raw-templates'; -import { TAG_HASHTAG_POSTFIX } from 'discourse/lib/tag-hashtags'; -import { SEPARATOR } from 'discourse/lib/category-hashtags'; -import Category from 'discourse/models/category'; -import { search as searchCategoryTag } from 'discourse/lib/category-tag-search'; -import userSearch from 'discourse/lib/user-search'; +import { applySearchAutocomplete } from "discourse/lib/search"; import { h } from 'virtual-dom'; @@ -265,7 +260,7 @@ export default createWidget('header', { Ember.run.schedule('afterRender', () => { const $searchInput = $('#search-term'); $searchInput.focus().select(); - this.applyAutocomplete($searchInput); + applySearchAutocomplete($searchInput, this.siteSettings); }); } }, @@ -350,36 +345,6 @@ export default createWidget('header', { return Ember.get(ctx, 'type'); } } - }, - - applyAutocomplete($searchInput) { - const siteSettings = this.siteSettings; - - $searchInput.autocomplete({ - template: findRawTemplate('category-tag-autocomplete'), - key: '#', - width: '100%', - treatAsTextarea: true, - transformComplete(obj) { - if (obj.model) { - return Category.slugFor(obj.model, SEPARATOR); - } else { - return `${obj.text}${TAG_HASHTAG_POSTFIX}`; - } - }, - dataSource(term) { - return searchCategoryTag(term, siteSettings); - } - }); - - $searchInput.autocomplete({ - template: findRawTemplate('user-selector-autocomplete'), - dataSource: term => userSearch({ term, undefined, includeGroups: true }), - key: "@", - width: '100%', - treatAsTextarea: true, - transformComplete: v => v.username || v.name - }); } });