diff --git a/app/assets/javascripts/discourse/app/controllers/keyboard-shortcuts-help.js b/app/assets/javascripts/discourse/app/controllers/keyboard-shortcuts-help.js index 65eacc5cdfe..03864510566 100644 --- a/app/assets/javascripts/discourse/app/controllers/keyboard-shortcuts-help.js +++ b/app/assets/javascripts/discourse/app/controllers/keyboard-shortcuts-help.js @@ -232,6 +232,10 @@ export default Controller.extend(ModalFunctionality, { insert_url: buildShortcut("search_menu.insert_url", { keys1: ["a"], }), + full_page_search: buildShortcut("search_menu.full_page_search", { + keys1: [translateModKey("Meta"), "Enter"], + keysDelimiter: PLUS, + }), }, }); }, diff --git a/app/assets/javascripts/discourse/app/templates/modal/keyboard-shortcuts-help.hbs b/app/assets/javascripts/discourse/app/templates/modal/keyboard-shortcuts-help.hbs index 60edf99f9f9..9488750a378 100644 --- a/app/assets/javascripts/discourse/app/templates/modal/keyboard-shortcuts-help.hbs +++ b/app/assets/javascripts/discourse/app/templates/modal/keyboard-shortcuts-help.hbs @@ -100,6 +100,7 @@ diff --git a/app/assets/javascripts/discourse/app/widgets/search-menu.js b/app/assets/javascripts/discourse/app/widgets/search-menu.js index ad03c11b4a6..e5366f5be63 100644 --- a/app/assets/javascripts/discourse/app/widgets/search-menu.js +++ b/app/assets/javascripts/discourse/app/widgets/search-menu.js @@ -16,6 +16,7 @@ import { cancel } from "@ember/runloop"; const CATEGORY_SLUG_REGEXP = /(\#[a-zA-Z0-9\-:]*)$/gi; const USERNAME_REGEXP = /(\@[a-zA-Z0-9\-\_]*)$/gi; const SUGGESTIONS_REGEXP = /(in:|status:|order:|:)([a-zA-Z]*)$/gi; +const SECOND_ENTER_MAX_DELAY = 15000; export const MODIFIER_REGEXP = /.*(\#|\@|:).*$/gi; export const DEFAULT_TYPE_FILTER = "exclude_topics"; @@ -111,14 +112,14 @@ const SearchHelper = { if (!term) { searchData.noResults = false; - searchData.results = []; + searchData.results = {}; searchData.loading = false; searchData.invalidTerm = false; widget.scheduleRerender(); } else if (!isValidSearchTerm(term, widget.siteSettings)) { searchData.noResults = true; - searchData.results = []; + searchData.results = {}; searchData.loading = false; searchData.invalidTerm = true; @@ -191,6 +192,7 @@ export default createWidget("search-menu", { defaultState(attrs) { return { inTopicContext: attrs.inTopicContext, + _lastEnterTimestamp: null, _debouncer: null, }; }, @@ -418,13 +420,23 @@ export default createWidget("search-menu", { const searchInput = document.querySelector("#search-term"); if (e.which === 13 && e.target === searchInput) { + const recentEnterHit = + this.state._lastEnterTimestamp && + Date.now() - this.state._lastEnterTimestamp < SECOND_ENTER_MAX_DELAY; + // same combination as key-enter-escape mixin - if (e.ctrlKey || e.metaKey || (isiPad() && e.altKey)) { + if ( + e.ctrlKey || + e.metaKey || + (isiPad() && e.altKey) || + (searchData.typeFilter !== DEFAULT_TYPE_FILTER && recentEnterHit) + ) { this.fullSearch(); } else { searchData.typeFilter = null; this.triggerSearch(); } + this.state._lastEnterTimestamp = Date.now(); } if (e.target === searchInput && e.which === 8 /* backspace */) { @@ -477,7 +489,6 @@ export default createWidget("search-menu", { }, fullSearch() { - searchData.results = []; searchData.loading = false; SearchHelper.cancel(); const url = this.fullSearchUrl(); diff --git a/app/assets/javascripts/discourse/tests/acceptance/search-test.js b/app/assets/javascripts/discourse/tests/acceptance/search-test.js index d3f39aeff8d..6be320421a7 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/search-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/search-test.js @@ -480,6 +480,31 @@ acceptance("Search - Authenticated", function (needs) { `${window.location.origin}${firstLink}`, "hitting A when focused on a search result copies link to composer" ); + + await click("#search-button"); + await triggerKeyEvent("#search-term", "keydown", keyEnter); + + assert.ok( + exists(query(`${container} .search-result-topic`)), + "has topic results" + ); + + await triggerKeyEvent("#search-term", "keydown", keyEnter); + + assert.ok( + exists(query(`.search-container`)), + "second Enter hit goes to full page search" + ); + assert.ok( + !exists(query(`.search-menu`)), + "search dropdown is collapsed after second Enter hit" + ); + + // new search launched, Enter key should be reset + await click("#search-button"); + assert.ok(exists(query(`${container} ul li`)), "has a list of items"); + await triggerKeyEvent("#search-term", "keydown", keyEnter); + assert.ok(exists(query(`.search-menu`)), "search dropdown is visible"); }); }); diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 2a35962d3e0..bb9066166bf 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -3720,6 +3720,7 @@ en: title: "Search Menu" prev_next: "%{shortcut} Move selection up and down" insert_url: "%{shortcut} Insert selection into open composer" + full_page_search: "%{shortcut} Launches full page search" badges: earned_n_times: