DEV: PluginApi function to customize search menu assistant item behavior (#24992)

This commit is contained in:
Mark VanLandingham 2023-12-20 15:25:45 -06:00 committed by GitHub
parent 87883a1963
commit 3c6362bb26
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 89 additions and 8 deletions

View File

@ -4,6 +4,7 @@
class="search-menu-assistant-item"
{{on "keydown" this.onKeydown}}
{{on "click" this.onClick}}
data-usage={{@usage}}
>
<a class="search-link" href={{this.href}}>
<span aria-label={{i18n "search.title"}}>

View File

@ -5,6 +5,15 @@ import { focusSearchInput } from "discourse/components/search-menu";
import getURL from "discourse-common/lib/get-url";
import { debounce } from "discourse-common/utils/decorators";
const _itemSelectCallbacks = [];
export function addItemSelectCallback(fn) {
_itemSelectCallbacks.push(fn);
}
export function resetItemSelectCallbacks() {
_itemSelectCallbacks.length = 0;
}
export default class AssistantItem extends Component {
@service search;
@service appEvents;
@ -85,16 +94,32 @@ export default class AssistantItem extends Component {
@debounce(100)
itemSelected() {
let updatedValue = "";
let updatedTerm = "";
if (this.args.slug) {
updatedValue = this.prefix.concat(this.args.slug);
updatedTerm = this.prefix.concat(this.args.slug);
} else {
updatedValue = this.prefix.trim();
updatedTerm = this.prefix.trim();
}
const inTopicContext = this.search.searchContext?.type === "topic";
this.args.searchTermChanged(updatedValue, {
searchTopics: !inTopicContext || this.search.activeGlobalSearchTerm,
const searchTopics = !inTopicContext || this.search.activeGlobalSearchTerm;
if (
_itemSelectCallbacks.length &&
!_itemSelectCallbacks.some((fn) =>
fn({
updatedTerm,
searchTermChanged: this.args.searchTermChanged,
usage: this.args.usage,
})
)
) {
// Return early if any callbacks return false
return;
}
this.args.searchTermChanged(updatedTerm, {
searchTopics,
...(inTopicContext &&
!this.args.searchAllTopics && { setTopicContext: true }),
});

View File

@ -48,7 +48,9 @@
/>
{{/if}}
{{else}}
<SearchMenu::Results::RandomQuickTip />
<SearchMenu::Results::RandomQuickTip
@searchTermChanged={{@searchTermChanged}}
/>
{{#if (and this.currentUser this.siteSettings.log_search_queries)}}
<SearchMenu::Results::RecentSearches
@closeSearchMenu={{@closeSearchMenu}}

View File

@ -64,7 +64,7 @@ export default class RandomQuickTip extends Component {
@action
tipSelected(e) {
if (e.target.classList.contains("tip-clickable")) {
this.search.activeGlobalSearchTerm = this.randomTip.label;
this.args.searchTermChanged(this.randomTip.label);
focusSearchInput();
e.stopPropagation();

View File

@ -17,6 +17,7 @@
@slug={{slug}}
@closeSearchMenu={{@closeSearchMenu}}
@searchTermChanged={{@searchTermChanged}}
@usage="recent-search"
/>
{{/each}}
</div>

View File

@ -18,6 +18,7 @@ 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 { addItemSelectCallback as addSearchMenuAssistantSelectCallback } from "discourse/components/search-menu/results/assistant-item";
import {
addQuickSearchRandomTip,
removeDefaultQuickSearchRandomTips,
@ -143,7 +144,7 @@ import { modifySelectKit } from "select-kit/mixins/plugin-api";
// docs/CHANGELOG-JAVASCRIPT-PLUGIN-API.md whenever you change the version
// using the format described at https://keepachangelog.com/en/1.0.0/.
export const PLUGIN_API_VERSION = "1.19.0";
export const PLUGIN_API_VERSION = "1.20.0";
// This helper prevents us from applying the same `modifyClass` over and over in test mode.
function canModify(klass, type, resolverName, changes) {
@ -1830,6 +1831,26 @@ class PluginApi {
addGlimmerSearchSuggestion(value);
}
/**
* Add a callback that will be evaluated when search menu assistant-items are clicked. Function
* takes an object as it's only argument. This object includes the updated term, searchTermChanged function,
* and the usage. If any callbacks return false, the core logic will be halted
*
* ```
* api.addSearchMenuAssistantSelectCallback((args) => {
* if (args.usage !== "recent-search") {
* return true;
* }
* args.searchTermChanged(args.updatedTerm)
* return false;
* })
* ```
*
*/
addSearchMenuAssistantSelectCallback(fn) {
addSearchMenuAssistantSelectCallback(fn);
}
/**
* Force a given menu panel (search-menu, user-menu) to be displayed as dropdown if ANY of the passed `classNames` are included in the `classList` of a menu panel.
* This can be useful for plugins as the default behavior is to add a 'slide-in' behavior to a menu panel if you are viewing on a small screen. eg. mobile.

View File

@ -7,6 +7,7 @@ import {
} from "@ember/test-helpers";
import { test } from "qunit";
import { DEFAULT_TYPE_FILTER } from "discourse/components/search-menu";
import { withPluginApi } from "discourse/lib/plugin-api";
import searchFixtures from "discourse/tests/fixtures/search-fixtures";
import {
acceptance,
@ -716,6 +717,28 @@ acceptance("Search - Glimmer - Authenticated", function (needs) {
"shows second recent search"
);
});
test("initial options - overriding behavior with addSearchMenuAssistantSelectCallback", async function (assert) {
await visit("/");
await click("#search-button");
withPluginApi("1.20.0", (api) => {
api.addSearchMenuAssistantSelectCallback((args) => {
if (args.usage === "recent-search") {
args.searchTermChanged("hijacked!");
return false;
}
return true;
});
});
await click(
".search-menu .search-menu-recent li:nth-of-type(1) .search-link"
);
assert.strictEqual(query("#search-term").value, "hijacked!");
});
});
acceptance("Search - Glimmer - with tagging enabled", function (needs) {

View File

@ -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 { resetItemSelectCallbacks } from "discourse/components/search-menu/results/assistant-item";
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";
@ -229,6 +230,7 @@ export function testCleanup(container, app) {
clearExtraHeaderIcons();
resetOnKeyDownCallbacks();
resetOnKeyUpCallbacks();
resetItemSelectCallbacks();
resetUserMenuTabs();
resetLinkLookup();
resetModelTransformers();

View File

@ -7,6 +7,12 @@ in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.20.0] - 2023-12-20
### Added
- Added `addSearchMenuAssistantSelectCallback` function, which is used to override the behavior of clicking a search menu assistant item. If any callback returns false, the core behavior will not be executed.
## [1.19.0] - 2023-12-13
### Added