diff --git a/app/assets/javascripts/admin/addon/routes/admin-search-logs-term.js b/app/assets/javascripts/admin/addon/routes/admin-search-logs-term.js index b9613fe04fa..9847f44d19a 100644 --- a/app/assets/javascripts/admin/addon/routes/admin-search-logs-term.js +++ b/app/assets/javascripts/admin/addon/routes/admin-search-logs-term.js @@ -20,7 +20,7 @@ export default DiscourseRoute.extend({ search_type: params.searchType, term: params.term, }, - }).then((json) => { + }).then(async (json) => { // Add zero values for missing dates if (json.term.data.length > 0) { const startDate = @@ -31,7 +31,9 @@ export default DiscourseRoute.extend({ json.term.data = fillMissingDates(json.term.data, startDate, endDate); } if (json.term.search_result) { - json.term.search_result = translateResults(json.term.search_result); + json.term.search_result = await translateResults( + json.term.search_result + ); } const model = EmberObject.create({ type: "search_log_term" }); diff --git a/app/assets/javascripts/discourse/app/controllers/full-page-search.js b/app/assets/javascripts/discourse/app/controllers/full-page-search.js index a7ba222f8c2..4fdd54a6fce 100644 --- a/app/assets/javascripts/discourse/app/controllers/full-page-search.js +++ b/app/assets/javascripts/discourse/app/controllers/full-page-search.js @@ -245,8 +245,8 @@ export default Controller.extend({ const searchKey = getSearchKey(args); ajax("/search", { data: args }) - .then((results) => { - const model = translateResults(results) || {}; + .then(async (results) => { + const model = (await translateResults(results)) || {}; if (results.grouped_search_result) { this.set("q", results.grouped_search_result.term); diff --git a/app/assets/javascripts/discourse/app/lib/plugin-api.js b/app/assets/javascripts/discourse/app/lib/plugin-api.js index 5f8a2ff4c44..5c25a4a0aee 100644 --- a/app/assets/javascripts/discourse/app/lib/plugin-api.js +++ b/app/assets/javascripts/discourse/app/lib/plugin-api.js @@ -72,9 +72,10 @@ import { registerTopicFooterButton } from "discourse/lib/register-topic-footer-b import { replaceFormatter } from "discourse/lib/utilities"; import { replaceTagRenderer } from "discourse/lib/render-tag"; import { setNewCategoryDefaultColors } from "discourse/routes/new-category"; +import { addSearchResultsCallback } from "discourse/lib/search"; // If you add any methods to the API ensure you bump up this number -const PLUGIN_API_VERSION = "0.11.4"; +const PLUGIN_API_VERSION = "0.11.5"; class PluginApi { constructor(version, container) { @@ -1281,6 +1282,21 @@ class PluginApi { setNewCategoryDefaultColors(backgroundColor, textColor) { setNewCategoryDefaultColors(backgroundColor, textColor); } + + /** + * Add a callback to modify search results before displaying them. + * + * ``` + * api.addSearchResultsCallback((results) => { + * results.topics.push(Topic.create({ ... })); + * return results; + * }); + * ``` + * + */ + addSearchResultsCallback(callback) { + addSearchResultsCallback(callback); + } } // from http://stackoverflow.com/questions/6832596/how-to-compare-software-version-number-using-js-only-number diff --git a/app/assets/javascripts/discourse/app/lib/search.js b/app/assets/javascripts/discourse/app/lib/search.js index e5b2002f0b9..635b16f592a 100644 --- a/app/assets/javascripts/discourse/app/lib/search.js +++ b/app/assets/javascripts/discourse/app/lib/search.js @@ -1,6 +1,7 @@ import Category from "discourse/models/category"; import EmberObject from "@ember/object"; import I18n from "I18n"; +import { Promise } from "rsvp"; import Post from "discourse/models/post"; import Topic from "discourse/models/topic"; import User from "discourse/models/user"; @@ -15,6 +16,12 @@ import { search as searchCategoryTag } from "discourse/lib/category-tag-search"; import { userPath } from "discourse/lib/url"; import userSearch from "discourse/lib/user-search"; +const translateResultsCallbacks = []; + +export function addSearchResultsCallback(callback) { + translateResultsCallbacks.push(callback); +} + export function translateResults(results, opts) { opts = opts || {}; @@ -84,9 +91,29 @@ export function translateResults(results, opts) { }) .compact(); - results.resultTypes = []; + return translateResultsCallbacks + .reduce( + (promise, callback) => promise.then((r) => callback(r)), + Promise.resolve(results) + ) + .then((results_) => { + translateGroupedSearchResults(results_, opts); - // TODO: consider refactoring front end to take a better structure + if ( + !results_.topics.length && + !results_.posts.length && + !results_.users.length && + !results_.categories.length + ) { + return null; + } + + return EmberObject.create(results_); + }); +} + +function translateGroupedSearchResults(results, opts) { + results.resultTypes = []; const groupedSearchResult = results.grouped_search_result; if (groupedSearchResult) { [ @@ -121,15 +148,6 @@ export function translateResults(results, opts) { } }); } - - const noResults = !!( - !results.topics.length && - !results.posts.length && - !results.users.length && - !results.categories.length - ); - - return noResults ? null : EmberObject.create(results); } export function searchForTerm(term, opts) { @@ -157,12 +175,9 @@ export function searchForTerm(term, opts) { }; } - let promise = ajax("/search/query", { data: data }); - - promise.then((results) => { - return translateResults(results, opts); - }); - + let ajaxPromise = ajax("/search/query", { data }); + const promise = ajaxPromise.then((res) => translateResults(res, opts)); + promise.abort = ajaxPromise.abort; return promise; } diff --git a/app/assets/javascripts/discourse/app/routes/full-page-search.js b/app/assets/javascripts/discourse/app/routes/full-page-search.js index 3c4fe847153..71ccb8fdbda 100644 --- a/app/assets/javascripts/discourse/app/routes/full-page-search.js +++ b/app/assets/javascripts/discourse/app/routes/full-page-search.js @@ -52,11 +52,11 @@ export default DiscourseRoute.extend({ } else { return null; } - }).then((results) => { + }).then(async (results) => { const grouped_search_result = results ? results.grouped_search_result : {}; - const model = (results && translateResults(results)) || { + const model = (results && (await translateResults(results))) || { grouped_search_result, }; setTransient("lastSearch", { searchKey, model }, 5); diff --git a/app/assets/javascripts/discourse/app/widgets/search-menu.js b/app/assets/javascripts/discourse/app/widgets/search-menu.js index 28d8ce506b4..246aeb4626b 100644 --- a/app/assets/javascripts/discourse/app/widgets/search-menu.js +++ b/app/assets/javascripts/discourse/app/widgets/search-menu.js @@ -55,12 +55,12 @@ const SearchHelper = { fullSearchUrl, }); this._activeSearch - .then((content) => { + .then((results) => { // we ensure the current search term is the one used // when starting the query - if (term === searchData.term) { - searchData.noResults = content.resultTypes.length === 0; - searchData.results = content; + if (results && term === searchData.term) { + searchData.noResults = results.resultTypes.length === 0; + searchData.results = results; if (searchContext && searchContext.type === "topic") { widget.appEvents.trigger("post-stream:refresh", { force: true }); diff --git a/app/assets/javascripts/discourse/tests/unit/lib/search-test.js b/app/assets/javascripts/discourse/tests/unit/lib/search-test.js index 61f9876011c..af28d03a39a 100644 --- a/app/assets/javascripts/discourse/tests/unit/lib/search-test.js +++ b/app/assets/javascripts/discourse/tests/unit/lib/search-test.js @@ -6,7 +6,7 @@ import { import I18n from "I18n"; module("Unit | Utility | search", function () { - test("unescapesEmojisInBlurbs", function (assert) { + test("unescapesEmojisInBlurbs", async function (assert) { const source = { posts: [ { @@ -28,7 +28,7 @@ module("Unit | Utility | search", function () { grouped_search_result: false, }; - const results = translateResults(source); + const results = await translateResults(source); const blurb = results.posts[0].get("blurb"); assert.ok(blurb.indexOf("thinking.png")); diff --git a/app/serializers/search_post_serializer.rb b/app/serializers/search_post_serializer.rb index bca2f7e04eb..4d58c06ae2a 100644 --- a/app/serializers/search_post_serializer.rb +++ b/app/serializers/search_post_serializer.rb @@ -21,6 +21,10 @@ class SearchPostSerializer < BasicPostSerializer options[:result].blurb(object) end + def include_blurb? + options[:result].present? + end + def include_cooked? false end