mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-23 23:58:31 -05:00
Refactor search results to be components instead of views for reuse
This commit is contained in:
parent
76bfd723f6
commit
7ed309666b
21 changed files with 764 additions and 81 deletions
|
@ -0,0 +1,2 @@
|
||||||
|
import SearchResult from 'discourse/components/search-result';
|
||||||
|
export default SearchResult.extend();
|
|
@ -0,0 +1,2 @@
|
||||||
|
import SearchResult from 'discourse/components/search-result';
|
||||||
|
export default SearchResult.extend();
|
|
@ -0,0 +1,2 @@
|
||||||
|
import SearchResult from 'discourse/components/search-result';
|
||||||
|
export default SearchResult.extend();
|
|
@ -0,0 +1,2 @@
|
||||||
|
import SearchResult from 'discourse/components/search-result';
|
||||||
|
export default SearchResult.extend();
|
|
@ -0,0 +1,11 @@
|
||||||
|
export default Ember.Component.extend({
|
||||||
|
tagName: 'ul',
|
||||||
|
|
||||||
|
_highlightOnInsert: function() {
|
||||||
|
const term = this.get('controller.term');
|
||||||
|
if(!_.isEmpty(term)) {
|
||||||
|
this.$('.blurb').highlight(term.split(/\s+/), {className: 'search-highlight'});
|
||||||
|
this.$('.topic-title').highlight(term.split(/\s+/), {className: 'search-highlight'} );
|
||||||
|
}
|
||||||
|
}.on('didInsertElement')
|
||||||
|
});
|
|
@ -0,0 +1,7 @@
|
||||||
|
import TextField from 'discourse/components/text-field';
|
||||||
|
|
||||||
|
export default TextField.extend({
|
||||||
|
placeholder: function() {
|
||||||
|
return this.get('searchContextEnabled') ? "" : I18n.t('search.title');
|
||||||
|
}.property('searchContextEnabled')
|
||||||
|
});
|
|
@ -4,7 +4,7 @@ function searchForTerm(term, opts) {
|
||||||
if (!opts) opts = {};
|
if (!opts) opts = {};
|
||||||
|
|
||||||
// Only include the data we have
|
// Only include the data we have
|
||||||
var data = { term: term, include_blurbs: 'true' };
|
const data = { term: term, include_blurbs: 'true' };
|
||||||
if (opts.typeFilter) data.type_filter = opts.typeFilter;
|
if (opts.typeFilter) data.type_filter = opts.typeFilter;
|
||||||
if (opts.searchForId) data.search_for_id = true;
|
if (opts.searchForId) data.search_for_id = true;
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ function searchForTerm(term, opts) {
|
||||||
if (!results.posts) { results.posts = []; }
|
if (!results.posts) { results.posts = []; }
|
||||||
if (!results.categories) { results.categories = []; }
|
if (!results.categories) { results.categories = []; }
|
||||||
|
|
||||||
var topicMap = {};
|
const topicMap = {};
|
||||||
results.topics = results.topics.map(function(topic){
|
results.topics = results.topics.map(function(topic){
|
||||||
topic = Topic.create(topic);
|
topic = Topic.create(topic);
|
||||||
topicMap[topic.id] = topic;
|
topicMap[topic.id] = topic;
|
||||||
|
@ -44,23 +44,23 @@ function searchForTerm(term, opts) {
|
||||||
return Discourse.Category.list().findProperty('id', category.id);
|
return Discourse.Category.list().findProperty('id', category.id);
|
||||||
}).compact();
|
}).compact();
|
||||||
|
|
||||||
var r = results.grouped_search_result;
|
const r = results.grouped_search_result;
|
||||||
results.resultTypes = [];
|
results.resultTypes = [];
|
||||||
|
|
||||||
// TODO: consider refactoring front end to take a better structure
|
// TODO: consider refactoring front end to take a better structure
|
||||||
[['topic','posts'],['user','users'],['category','categories']].forEach(function(pair){
|
[['topic','posts'],['user','users'],['category','categories']].forEach(function(pair){
|
||||||
var type = pair[0], name = pair[1];
|
const type = pair[0], name = pair[1];
|
||||||
if (results[name].length > 0) {
|
if (results[name].length > 0) {
|
||||||
results.resultTypes.push({
|
results.resultTypes.push({
|
||||||
results: results[name],
|
results: results[name],
|
||||||
displayType: (opts.searchContext && opts.searchContext.type === 'topic' && type === 'topic') ? 'post' : type,
|
componentName: "search-result-" + ((opts.searchContext && opts.searchContext.type === 'topic' && type === 'topic') ? 'post' : type),
|
||||||
type: type,
|
type,
|
||||||
more: r['more_' + name]
|
more: r['more_' + name]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var noResults = !!(results.topics.length === 0 &&
|
const noResults = !!(results.topics.length === 0 &&
|
||||||
results.posts.length === 0 &&
|
results.posts.length === 0 &&
|
||||||
results.users.length === 0 &&
|
results.users.length === 0 &&
|
||||||
results.categories.length === 0);
|
results.categories.length === 0);
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
{{#each results as |result|}}
|
||||||
|
<li>
|
||||||
|
<a href='{{unbound result.url}}'>
|
||||||
|
{{category-badge result}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{/each}}
|
|
@ -0,0 +1,12 @@
|
||||||
|
{{#each results as |result|}}
|
||||||
|
<a class='search-link' href='{{unbound result.url}}'>
|
||||||
|
<span class='topic'>
|
||||||
|
{{i18n 'search.post_format' post_number=result.post_number username=result.username}}
|
||||||
|
</span>
|
||||||
|
{{#unless site.mobileView}}
|
||||||
|
<span class='blurb'>
|
||||||
|
{{{unbound result.blurb}}}
|
||||||
|
</span>
|
||||||
|
{{/unless}}
|
||||||
|
</a>
|
||||||
|
{{/each}}
|
|
@ -0,0 +1,14 @@
|
||||||
|
{{#each results as |result|}}
|
||||||
|
<li>
|
||||||
|
<a class='search-link' href='{{unbound url}}'>
|
||||||
|
<span class='topic'>
|
||||||
|
{{topic-status topic=result.topic disableActions=true}}<span class='topic-title'>{{unbound result.topic.title}}</span>{{category-badge result.topic.category}}
|
||||||
|
</span>
|
||||||
|
{{#unless site.mobileView}}
|
||||||
|
<span class='blurb'>
|
||||||
|
{{format-age result.created_at}} - {{{unbound result.blurb}}}
|
||||||
|
</span>
|
||||||
|
{{/unless}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{/each}}
|
|
@ -0,0 +1,8 @@
|
||||||
|
{{#each results as |result|}}
|
||||||
|
<li>
|
||||||
|
<a href='{{unbound result.path}}'>
|
||||||
|
{{avatar result imageSize="small"}}
|
||||||
|
{{unbound result.username}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{/each}}
|
|
@ -1,4 +1,5 @@
|
||||||
{{view "search-text-field" value=term searchContextEnabled=searchContextEnabled searchContext=searchContext id="search-term"}}
|
{{search-text-field value=term searchContextEnabled=searchContextEnabled id="search-term"}}
|
||||||
|
|
||||||
<div class="search-context">
|
<div class="search-context">
|
||||||
{{#if searchContext}}
|
{{#if searchContext}}
|
||||||
<label>
|
<label>
|
||||||
|
@ -16,10 +17,10 @@
|
||||||
{{i18n "search.no_results"}}
|
{{i18n "search.no_results"}}
|
||||||
</div>
|
</div>
|
||||||
{{else}}
|
{{else}}
|
||||||
{{#each resultType in content.resultTypes}}
|
{{#each content.resultTypes as |resultType|}}
|
||||||
<ul>
|
<ul>
|
||||||
<li class="heading row">{{resultType.name}}</li>
|
<li class="heading row">{{resultType.name}}</li>
|
||||||
{{view "search-results-type" type=resultType.type displayType=resultType.displayType content=resultType.results}}
|
{{component resultType.componentName results=resultType.results term=term}}
|
||||||
</ul>
|
</ul>
|
||||||
<div class="no-results">
|
<div class="no-results">
|
||||||
{{#if resultType.more}}
|
{{#if resultType.more}}
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
<a href='{{unbound url}}'>
|
|
||||||
{{category-badge this}}
|
|
||||||
</a>
|
|
|
@ -1,10 +0,0 @@
|
||||||
<a class='search-link' href='{{unbound url}}'>
|
|
||||||
<span class='topic'>
|
|
||||||
{{i18n 'search.post_format' post_number=post_number username=username}}
|
|
||||||
</span>
|
|
||||||
{{#unless controller.site.mobileView}}
|
|
||||||
<span class='blurb'>
|
|
||||||
{{{unbound blurb}}}
|
|
||||||
</span>
|
|
||||||
{{/unless}}
|
|
||||||
</a>
|
|
|
@ -1,10 +0,0 @@
|
||||||
<a class='search-link' href='{{unbound url}}'>
|
|
||||||
<span class='topic'>
|
|
||||||
{{topic-status topic=topic disableActions=true}}<span class='topic-title'>{{unbound topic.title}}</span>{{category-badge topic.category}}
|
|
||||||
</span>
|
|
||||||
{{#unless controller.site.mobileView}}
|
|
||||||
<span class='blurb'>
|
|
||||||
{{format-age created_at}} - {{{unbound blurb}}}
|
|
||||||
</span>
|
|
||||||
{{/unless}}
|
|
||||||
</a>
|
|
|
@ -1,4 +0,0 @@
|
||||||
<a href='{{unbound path}}'>
|
|
||||||
{{avatar this imageSize="small"}}
|
|
||||||
{{unbound username}}
|
|
||||||
</a>
|
|
|
@ -1,15 +0,0 @@
|
||||||
export default Ember.CollectionView.extend({
|
|
||||||
tagName: 'ul',
|
|
||||||
itemViewClass: Discourse.GroupedView.extend({
|
|
||||||
tagName: 'li',
|
|
||||||
classNameBindings: ['selected'],
|
|
||||||
templateName: Discourse.computed.fmt('parentView.displayType', "search/%@_result")
|
|
||||||
}),
|
|
||||||
didInsertElement: function(){
|
|
||||||
var term = this.get('controller.term');
|
|
||||||
if(!_.isEmpty(term)) {
|
|
||||||
this.$('.blurb').highlight(term.split(/\s+/), {className: 'search-highlight'});
|
|
||||||
this.$('.topic-title').highlight(term.split(/\s+/), {className: 'search-highlight'} );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,27 +0,0 @@
|
||||||
/**
|
|
||||||
This is a text field that supports a dynamic placeholder based on search context.
|
|
||||||
|
|
||||||
@class SearchTextField
|
|
||||||
@extends Discourse.TextField
|
|
||||||
@namespace Discourse
|
|
||||||
@module Discourse
|
|
||||||
**/
|
|
||||||
|
|
||||||
import TextField from 'discourse/components/text-field';
|
|
||||||
|
|
||||||
export default TextField.extend({
|
|
||||||
|
|
||||||
/**
|
|
||||||
A dynamic placeholder for the search field based on our context
|
|
||||||
|
|
||||||
@property placeholder
|
|
||||||
**/
|
|
||||||
placeholder: function() {
|
|
||||||
|
|
||||||
if(this.get('searchContextEnabled')){
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
return I18n.t('search.title');
|
|
||||||
}.property('searchContextEnabled')
|
|
||||||
});
|
|
|
@ -45,6 +45,7 @@
|
||||||
//= require ./discourse/views/cloaked
|
//= require ./discourse/views/cloaked
|
||||||
//= require ./discourse/components/combo-box
|
//= require ./discourse/components/combo-box
|
||||||
//= require ./discourse/views/button
|
//= require ./discourse/views/button
|
||||||
|
//= require ./discourse/components/search-result
|
||||||
//= require ./discourse/components/dropdown-button
|
//= require ./discourse/components/dropdown-button
|
||||||
//= require ./discourse/components/notifications-button
|
//= require ./discourse/components/notifications-button
|
||||||
//= require ./discourse/components/topic-notifications-button
|
//= require ./discourse/components/topic-notifications-button
|
||||||
|
|
18
test/javascripts/acceptance/search-test.js.es6
Normal file
18
test/javascripts/acceptance/search-test.js.es6
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import { acceptance } from "helpers/qunit-helpers";
|
||||||
|
acceptance("Search");
|
||||||
|
|
||||||
|
test("search", (assert) => {
|
||||||
|
visit("/");
|
||||||
|
|
||||||
|
click('#search-button');
|
||||||
|
|
||||||
|
andThen(() => {
|
||||||
|
assert.ok(exists('#search-term'), 'it shows the search bar');
|
||||||
|
assert.ok(!exists('#search-dropdown .results ul li'), 'no results by default');
|
||||||
|
});
|
||||||
|
|
||||||
|
fillIn('#search-term', 'dev');
|
||||||
|
andThen(() => {
|
||||||
|
assert.ok(exists('#search-dropdown .results ul li'), 'it shows results');
|
||||||
|
});
|
||||||
|
});
|
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue