diff --git a/framework/core/js/src/forum/compat.ts b/framework/core/js/src/forum/compat.ts index b9358ecfc4..f4fbceeec8 100644 --- a/framework/core/js/src/forum/compat.ts +++ b/framework/core/js/src/forum/compat.ts @@ -76,6 +76,7 @@ import routes from './routes'; import ForumApplication from './ForumApplication'; import isSafariMobile from './utils/isSafariMobile'; import AccessTokensList from './components/AccessTokensList'; +import DiscussionsSearchItem from './components/DiscussionsSearchItem'; export default Object.assign(compat, { 'utils/PostControls': PostControls, @@ -114,6 +115,7 @@ export default Object.assign(compat, { 'components/IndexPage': IndexPage, 'components/DiscussionRenamedNotification': DiscussionRenamedNotification, 'components/DiscussionsSearchSource': DiscussionsSearchSource, + 'components/DiscussionsSearchItem': DiscussionsSearchItem, 'components/HeaderSecondary': HeaderSecondary, 'components/ComposerButton': ComposerButton, 'components/DiscussionList': DiscussionList, diff --git a/framework/core/js/src/forum/components/DiscussionsSearchItem.tsx b/framework/core/js/src/forum/components/DiscussionsSearchItem.tsx new file mode 100644 index 0000000000..d54262218b --- /dev/null +++ b/framework/core/js/src/forum/components/DiscussionsSearchItem.tsx @@ -0,0 +1,61 @@ +import app from '../../forum/app'; +import Component, { ComponentAttrs } from '../../common/Component'; +import Link from '../../common/components/Link'; +import highlight from '../../common/helpers/highlight'; +import Discussion from '../../common/models/Discussion'; +import Post from '../../common/models/Post'; +import type Mithril from 'mithril'; +import ItemList from '../../common/utils/ItemList'; + +export interface DiscussionsSearchItemAttrs extends ComponentAttrs { + query: string; + discussion: Discussion; + mostRelevantPost: Post; +} + +export default class DiscussionsSearchItem extends Component { + query!: string; + discussion!: Discussion; + mostRelevantPost!: Post | null | undefined; + + oninit(vnode: Mithril.Vnode) { + super.oninit(vnode); + + this.query = this.attrs.query; + this.discussion = this.attrs.discussion; + this.mostRelevantPost = this.attrs.mostRelevantPost; + } + + view() { + return ( +
  • + + {this.viewItems().toArray()} + +
  • + ); + } + + discussionTitle() { + return this.discussion.title(); + } + + mostRelevantPostContent() { + return this.mostRelevantPost?.contentPlain(); + } + + viewItems(): ItemList { + const items = new ItemList(); + + items.add('discussion-title',
    {highlight(this.discussionTitle(), this.query)}
    , 90); + + !!this.mostRelevantPost && + items.add( + 'most-relevant', +
    {highlight(this.mostRelevantPostContent() ?? '', this.query, 100)}
    , + 80 + ); + + return items; + } +} diff --git a/framework/core/js/src/forum/components/DiscussionsSearchSource.tsx b/framework/core/js/src/forum/components/DiscussionsSearchSource.tsx index 3a42945c65..31443760e0 100644 --- a/framework/core/js/src/forum/components/DiscussionsSearchSource.tsx +++ b/framework/core/js/src/forum/components/DiscussionsSearchSource.tsx @@ -1,10 +1,9 @@ import app from '../../forum/app'; -import highlight from '../../common/helpers/highlight'; import LinkButton from '../../common/components/LinkButton'; -import Link from '../../common/components/Link'; import { SearchSource } from './Search'; import type Mithril from 'mithril'; import Discussion from '../../common/models/Discussion'; +import DiscussionsSearchItem from './DiscussionsSearchItem'; /** * The `DiscussionsSearchSource` finds and displays discussion search results in @@ -12,16 +11,19 @@ import Discussion from '../../common/models/Discussion'; */ export default class DiscussionsSearchSource implements SearchSource { protected results = new Map(); + queryString: string | null = null; async search(query: string): Promise { query = query.toLowerCase(); this.results.set(query, []); + this.setQueryString(query); + const params = { - filter: { q: query }, - page: { limit: 3 }, - include: 'mostRelevantPost', + filter: { q: this.queryString || query }, + page: { limit: this.limit() }, + include: this.includes().join(','), }; return app.store.find('discussions', params).then((results) => { @@ -36,26 +38,33 @@ export default class DiscussionsSearchSource implements SearchSource { const results = (this.results.get(query) || []).map((discussion) => { const mostRelevantPost = discussion.mostRelevantPost(); - return ( -
  • - -
    {highlight(discussion.title(), query)}
    - {!!mostRelevantPost && ( -
    {highlight(mostRelevantPost.contentPlain() ?? '', query, 100)}
    - )} - -
  • - ); + return ; }) as Array; return [
  • {app.translator.trans('core.forum.search.discussions_heading')}
  • ,
  • - + {app.translator.trans('core.forum.search.all_discussions_button', { query })}
  • , ...results, ]; } + + includes(): string[] { + return ['mostRelevantPost']; + } + + limit(): number { + return 3; + } + + queryMutators(): string[] { + return []; + } + + setQueryString(query: string): void { + this.queryString = query + ' ' + this.queryMutators().join(' '); + } }