mirror of
https://github.com/discourse/discourse.git
synced 2025-04-19 21:29:05 +08:00
DEV: Support search menu APIs in glimmer version (#24061)
This commit is contained in:
parent
2b7ecee06e
commit
1e0de818e6
@ -18,6 +18,11 @@
|
||||
/>
|
||||
{{/if}}
|
||||
|
||||
<PluginOutlet
|
||||
@name="search-menu-before-term-input"
|
||||
@outletArgs={{hash openSearchMenu=this.open}}
|
||||
/>
|
||||
|
||||
<SearchMenu::SearchTerm
|
||||
@searchTermChanged={{this.searchTermChanged}}
|
||||
@typeFilter={{this.typeFilter}}
|
||||
|
@ -79,6 +79,10 @@ export default class SearchMenu extends Component {
|
||||
classes.push("menu-panel-results");
|
||||
}
|
||||
|
||||
if (this.loading) {
|
||||
classes.push("loading");
|
||||
}
|
||||
|
||||
return classes.join(" ");
|
||||
}
|
||||
|
||||
@ -266,6 +270,7 @@ export default class SearchMenu extends Component {
|
||||
this.loading = false;
|
||||
this.invalidTerm = true;
|
||||
} else {
|
||||
this.loading = true;
|
||||
this.invalidTerm = false;
|
||||
|
||||
this._activeSearch = searchForTerm(this.search.activeGlobalSearchTerm, {
|
||||
|
@ -1 +1,3 @@
|
||||
{{html-safe @string}}
|
||||
<span {{did-insert this.highlight}}>
|
||||
{{html-safe @string}}
|
||||
</span>
|
@ -1,15 +1,13 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { action } from "@ember/object";
|
||||
import { inject as service } from "@ember/service";
|
||||
import highlightSearch from "discourse/lib/highlight-search";
|
||||
|
||||
export default class HighlightedSearch extends Component {
|
||||
@service search;
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
const span = document.createElement("span");
|
||||
span.textContent = this.args.string;
|
||||
|
||||
highlightSearch(span, this.search.activeGlobalSearchTerm);
|
||||
@action
|
||||
highlight(element) {
|
||||
highlightSearch(element, this.search.activeGlobalSearchTerm);
|
||||
}
|
||||
}
|
||||
|
@ -19,38 +19,55 @@
|
||||
@searchTermChanged={{@searchTermChanged}}
|
||||
/>
|
||||
{{else}}
|
||||
{{#if @searchTopics}}
|
||||
{{#if (and (not @searchTopics) (not @inPMInboxContext))}}
|
||||
{{! render the first couple suggestions before a search has been performed}}
|
||||
<SearchMenu::Results::InitialOptions
|
||||
@closeSearchMenu={{@closeSearchMenu}}
|
||||
@searchTermChanged={{@searchTermChanged}}
|
||||
/>
|
||||
{{/if}}
|
||||
|
||||
<PluginOutlet
|
||||
@name="search-menu-results-top"
|
||||
@outletArgs={{hash closeSearchMenu=@closeSearchMenu}}
|
||||
/>
|
||||
|
||||
{{#if (and @searchTopics this.resultTypesWithComponent)}}
|
||||
{{! render results after a search has been performed }}
|
||||
{{#if this.resultTypesWithComponent}}
|
||||
<SearchMenu::Results::Types
|
||||
@resultTypes={{this.resultTypesWithComponent}}
|
||||
@topicResultsOnly={{true}}
|
||||
@closeSearchMenu={{@closeSearchMenu}}
|
||||
/>
|
||||
<SearchMenu::Results::MoreLink
|
||||
@updateTypeFilter={{@updateTypeFilter}}
|
||||
@triggerSearch={{@triggerSearch}}
|
||||
@resultTypes={{this.resultTypesWithComponent}}
|
||||
@closeSearchMenu={{@closeSearchMenu}}
|
||||
@searchTermChanged={{@searchTermChanged}}
|
||||
/>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
{{#unless @inPMInboxContext}}
|
||||
{{! render the first couple suggestions before a search has been performed}}
|
||||
<SearchMenu::Results::InitialOptions
|
||||
@closeSearchMenu={{@closeSearchMenu}}
|
||||
@searchTermChanged={{@searchTermChanged}}
|
||||
/>
|
||||
{{#if this.resultTypesWithComponent}}
|
||||
<SearchMenu::Results::Types
|
||||
@resultTypes={{this.resultTypesWithComponent}}
|
||||
@closeSearchMenu={{@closeSearchMenu}}
|
||||
@searchTermChanged={{@searchTermChanged}}
|
||||
/>
|
||||
{{/if}}
|
||||
{{/unless}}
|
||||
<SearchMenu::Results::Types
|
||||
@resultTypes={{this.resultTypesWithComponent}}
|
||||
@topicResultsOnly={{true}}
|
||||
@closeSearchMenu={{@closeSearchMenu}}
|
||||
/>
|
||||
<SearchMenu::Results::MoreLink
|
||||
@updateTypeFilter={{@updateTypeFilter}}
|
||||
@triggerSearch={{@triggerSearch}}
|
||||
@resultTypes={{this.resultTypesWithComponent}}
|
||||
@closeSearchMenu={{@closeSearchMenu}}
|
||||
@searchTermChanged={{@searchTermChanged}}
|
||||
/>
|
||||
{{else if
|
||||
(and
|
||||
(not @inPMInboxContext)
|
||||
(not @searchTopics)
|
||||
this.resultTypesWithComponent
|
||||
)
|
||||
}}
|
||||
<SearchMenu::Results::Types
|
||||
@resultTypes={{this.resultTypesWithComponent}}
|
||||
@closeSearchMenu={{@closeSearchMenu}}
|
||||
@searchTermChanged={{@searchTermChanged}}
|
||||
/>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
<PluginOutlet
|
||||
@name="search-menu-results-bottom"
|
||||
@outletArgs={{hash
|
||||
inTopicContext=this.search.inTopicContext
|
||||
searchTermChanged=@searchTermChanged
|
||||
searchTopics=@searchTopics
|
||||
closeSearchMenu=@closeSearchMenu
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{{/if}}
|
@ -1,10 +1,10 @@
|
||||
<span class="blurb">
|
||||
{{format-age @result.created_at}}
|
||||
<span> - </span>
|
||||
<span class="blurb__separator"> - </span>
|
||||
{{#if this.siteSettings.use_pg_headlines_for_excerpt}}
|
||||
<span>{{@result.blurb}}</span>
|
||||
{{else}}
|
||||
<span>
|
||||
<span class="blurb__text">
|
||||
<SearchMenu::HighlightedSearch @string={{@result.blurb}} />
|
||||
</span>
|
||||
{{/if}}
|
||||
|
@ -1,45 +1,61 @@
|
||||
<ul class="search-menu-initial-options">
|
||||
{{#if this.termMatchesContextTypeKeyword}}
|
||||
<SearchMenu::Results::AssistantItem
|
||||
@slug={{this.slug}}
|
||||
@extraHint={{true}}
|
||||
@closeSearchMenu={{@closeSearchMenu}}
|
||||
@searchTermChanged={{@searchTermChanged}}
|
||||
@suggestionKeyword={{this.contextTypeKeyword}}
|
||||
/>
|
||||
{{else}}
|
||||
{{#if (or this.search.activeGlobalSearchTerm this.search.searchContext)}}
|
||||
{{#if this.search.activeGlobalSearchTerm}}
|
||||
<SearchMenu::Results::AssistantItem
|
||||
@suffix={{i18n "search.in_topics_posts"}}
|
||||
@closeSearchMenu={{@closeSearchMenu}}
|
||||
@searchAllTopics={{true}}
|
||||
@extraHint={{true}}
|
||||
@searchTermChanged={{@searchTermChanged}}
|
||||
@suggestionKeyword={{this.contextTypeKeyword}}
|
||||
/>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.search.searchContext}}
|
||||
<this.contextTypeComponent
|
||||
@slug={{this.slug}}
|
||||
@suggestionKeyword={{this.contextTypeKeyword}}
|
||||
@results={{this.initialResults}}
|
||||
@withInLabel={{this.withInLabel}}
|
||||
@suffix={{this.suffix}}
|
||||
@label={{this.label}}
|
||||
@closeSearchMenu={{@closeSearchMenu}}
|
||||
@searchTermChanged={{@searchTermChanged}}
|
||||
/>
|
||||
{{/if}}
|
||||
<PluginOutlet
|
||||
@name="search-menu-initial-options"
|
||||
@outletArgs={{hash
|
||||
termMatchesContextTypeKeyword=this.termMatchesContextTypeKeyword
|
||||
contextTypeComponent=this.contextTypeComponent
|
||||
slug=this.slug
|
||||
suggestionKeyword=this.contextTypeKeyword
|
||||
results=this.initialResults
|
||||
withInLabel=this.withInLabel
|
||||
suffix=this.suffix
|
||||
label=this.label
|
||||
closeSearchMenu=@closeSearchMenu
|
||||
searchTermChanged=@searchTermChanged
|
||||
}}
|
||||
>
|
||||
{{#if this.termMatchesContextTypeKeyword}}
|
||||
<SearchMenu::Results::AssistantItem
|
||||
@slug={{this.slug}}
|
||||
@extraHint={{true}}
|
||||
@closeSearchMenu={{@closeSearchMenu}}
|
||||
@searchTermChanged={{@searchTermChanged}}
|
||||
@suggestionKeyword={{this.contextTypeKeyword}}
|
||||
/>
|
||||
{{else}}
|
||||
<SearchMenu::Results::RandomQuickTip />
|
||||
{{#if (and this.currentUser this.siteSettings.log_search_queries)}}
|
||||
<SearchMenu::Results::RecentSearches
|
||||
@closeSearchMenu={{@closeSearchMenu}}
|
||||
@searchTermChanged={{@searchTermChanged}}
|
||||
/>
|
||||
{{#if (or this.search.activeGlobalSearchTerm this.search.searchContext)}}
|
||||
{{#if this.search.activeGlobalSearchTerm}}
|
||||
<SearchMenu::Results::AssistantItem
|
||||
@suffix={{i18n "search.in_topics_posts"}}
|
||||
@closeSearchMenu={{@closeSearchMenu}}
|
||||
@searchAllTopics={{true}}
|
||||
@extraHint={{true}}
|
||||
@searchTermChanged={{@searchTermChanged}}
|
||||
@suggestionKeyword={{this.contextTypeKeyword}}
|
||||
/>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.search.searchContext}}
|
||||
<this.contextTypeComponent
|
||||
@slug={{this.slug}}
|
||||
@suggestionKeyword={{this.contextTypeKeyword}}
|
||||
@results={{this.initialResults}}
|
||||
@withInLabel={{this.withInLabel}}
|
||||
@suffix={{this.suffix}}
|
||||
@label={{this.label}}
|
||||
@closeSearchMenu={{@closeSearchMenu}}
|
||||
@searchTermChanged={{@searchTermChanged}}
|
||||
/>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<SearchMenu::Results::RandomQuickTip />
|
||||
{{#if (and this.currentUser this.siteSettings.log_search_queries)}}
|
||||
<SearchMenu::Results::RecentSearches
|
||||
@closeSearchMenu={{@closeSearchMenu}}
|
||||
@searchTermChanged={{@searchTermChanged}}
|
||||
/>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</PluginOutlet>
|
||||
</ul>
|
@ -34,9 +34,7 @@ export default class InitialOptions extends Component {
|
||||
}
|
||||
|
||||
get termMatchesContextTypeKeyword() {
|
||||
return this.search.activeGlobalSearchTerm?.match(MODIFIER_REGEXP)
|
||||
? true
|
||||
: false;
|
||||
return this.search.activeGlobalSearchTerm?.match(MODIFIER_REGEXP);
|
||||
}
|
||||
|
||||
setAttributesForSearchContextType(type) {
|
||||
|
@ -47,6 +47,10 @@ export function resetQuickSearchRandomTips() {
|
||||
QUICK_TIPS = [].concat(DEFAULT_QUICK_TIPS);
|
||||
}
|
||||
|
||||
export function removeDefaultQuickSearchRandomTips() {
|
||||
QUICK_TIPS = QUICK_TIPS.filter((tip) => !DEFAULT_QUICK_TIPS.includes(tip));
|
||||
}
|
||||
|
||||
resetQuickSearchRandomTips();
|
||||
|
||||
export default class RandomQuickTip extends Component {
|
||||
|
@ -1,5 +1,9 @@
|
||||
{{#each this.filteredResultTypes as |resultType|}}
|
||||
<div class={{resultType.componentName}}>
|
||||
<PluginOutlet
|
||||
@name="search-menu-results-type-top"
|
||||
@outletArgs={{hash resultType=resultType}}
|
||||
/>
|
||||
<ul
|
||||
class="list"
|
||||
aria-label={{concat (i18n "search.results") " " resultType.type}}
|
||||
|
@ -10,6 +10,15 @@ import { isiPad } from "discourse/lib/utilities";
|
||||
|
||||
const SECOND_ENTER_MAX_DELAY = 15000;
|
||||
|
||||
const onKeyUpCallbacks = [];
|
||||
|
||||
export function addOnKeyUpCallback(fn) {
|
||||
onKeyUpCallbacks.push(fn);
|
||||
}
|
||||
export function resetOnKeyUpCallbacks() {
|
||||
onKeyUpCallbacks.clear();
|
||||
}
|
||||
|
||||
export default class SearchTerm extends Component {
|
||||
@service search;
|
||||
@service appEvents;
|
||||
@ -42,6 +51,14 @@ export default class SearchTerm extends Component {
|
||||
|
||||
@action
|
||||
onKeyup(e) {
|
||||
if (
|
||||
onKeyUpCallbacks.length &&
|
||||
!onKeyUpCallbacks.some((fn) => fn(this, e))
|
||||
) {
|
||||
// Return early if any callbacks return false
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.key === "Escape") {
|
||||
this.args.closeSearchMenu();
|
||||
e.preventDefault();
|
||||
|
@ -18,6 +18,11 @@ import {
|
||||
} from "discourse/components/reviewable-item";
|
||||
import { addAdvancedSearchOptions } from "discourse/components/search-advanced-options";
|
||||
import { addSearchSuggestion as addGlimmerSearchSuggestion } from "discourse/components/search-menu/results/assistant";
|
||||
import {
|
||||
addQuickSearchRandomTip,
|
||||
removeDefaultQuickSearchRandomTips,
|
||||
} from "discourse/components/search-menu/results/random-quick-tip";
|
||||
import { addOnKeyUpCallback } from "discourse/components/search-menu/search-term";
|
||||
import { REFRESH_COUNTS_APP_EVENT_NAME as REFRESH_USER_SIDEBAR_CATEGORIES_SECTION_COUNTS_APP_EVENT_NAME } from "discourse/components/sidebar/user/categories-section";
|
||||
import { addTopicTitleDecorator } from "discourse/components/topic-title";
|
||||
import { addUserMenuProfileTabItem } from "discourse/components/user-menu/profile-tab-content";
|
||||
@ -107,9 +112,9 @@ import {
|
||||
import { disableNameSuppression } from "discourse/widgets/poster-name";
|
||||
import { addOnKeyDownCallback } from "discourse/widgets/search-menu";
|
||||
import {
|
||||
addQuickSearchRandomTip,
|
||||
addQuickSearchRandomTip as addWidgetQuickSearchRandomTip,
|
||||
addSearchSuggestion,
|
||||
removeDefaultQuickSearchRandomTips,
|
||||
removeDefaultQuickSearchRandomTips as removeWidgetDefaultQuickSearchRandomTips,
|
||||
} from "discourse/widgets/search-menu-results";
|
||||
import { addTopicParticipantClassesCallback } from "discourse/widgets/topic-map";
|
||||
import {
|
||||
@ -1863,6 +1868,7 @@ class PluginApi {
|
||||
*/
|
||||
addSearchMenuOnKeyDownCallback(fn) {
|
||||
addOnKeyDownCallback(fn);
|
||||
addOnKeyUpCallback(fn);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1882,6 +1888,7 @@ class PluginApi {
|
||||
*/
|
||||
addQuickSearchRandomTip(tip) {
|
||||
addQuickSearchRandomTip(tip);
|
||||
addWidgetQuickSearchRandomTip(tip);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1893,8 +1900,9 @@ class PluginApi {
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
removeDefaultQuickSearchRandomTips(tip) {
|
||||
removeDefaultQuickSearchRandomTips(tip);
|
||||
removeDefaultQuickSearchRandomTips() {
|
||||
removeDefaultQuickSearchRandomTips();
|
||||
removeWidgetDefaultQuickSearchRandomTips();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -21,6 +21,7 @@ import { clearToolbarCallbacks } from "discourse/components/d-editor";
|
||||
import { clearBulkButtons } from "discourse/components/modal/topic-bulk-actions";
|
||||
import { resetWidgetCleanCallbacks } from "discourse/components/mount-widget";
|
||||
import { resetDecorators as resetPluginOutletDecorators } from "discourse/components/plugin-connector";
|
||||
import { resetOnKeyUpCallbacks } from "discourse/components/search-menu/search-term";
|
||||
import { resetTopicTitleDecorators } from "discourse/components/topic-title";
|
||||
import { resetUserMenuProfileTabItems } from "discourse/components/user-menu/profile-tab-content";
|
||||
import { resetCustomPostMessageCallbacks } from "discourse/controllers/topic";
|
||||
@ -227,6 +228,7 @@ export function testCleanup(container, app) {
|
||||
resetSidebarPanels();
|
||||
clearExtraHeaderIcons();
|
||||
resetOnKeyDownCallbacks();
|
||||
resetOnKeyUpCallbacks();
|
||||
resetUserMenuTabs();
|
||||
resetLinkLookup();
|
||||
resetModelTransformers();
|
||||
|
Loading…
x
Reference in New Issue
Block a user