improved search engine
* it's now possible to search for multiple words ("all words" or "one of the words" options) * added a fixed limit for result count git-svn-id: http://redmine.rubyforge.org/svn/trunk@321 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
parent
7a20a4d32b
commit
8b98ceb92c
|
@ -540,16 +540,24 @@ class ProjectsController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def search
|
def search
|
||||||
@token = params[:token]
|
@question = params[:q] || ""
|
||||||
|
@question.strip!
|
||||||
|
@all_words = params[:all_words] || (params[:submit] ? false : true)
|
||||||
@scope = params[:scope] || (params[:submit] ? [] : %w(issues news documents) )
|
@scope = params[:scope] || (params[:submit] ? [] : %w(issues news documents) )
|
||||||
|
if !@question.empty?
|
||||||
if @token and @token.length > 2
|
# tokens must be at least 3 character long
|
||||||
@token.strip!
|
@tokens = @question.split.uniq.select {|w| w.length > 2 }
|
||||||
like_token = "%#{@token}%"
|
# no more than 5 tokens to search for
|
||||||
|
@tokens.slice! 5..-1 if @tokens.size > 5
|
||||||
|
# strings used in sql like statement
|
||||||
|
like_tokens = @tokens.collect {|w| "%#{w}%"}
|
||||||
|
operator = @all_words ? " AND " : " OR "
|
||||||
|
limit = 10
|
||||||
@results = []
|
@results = []
|
||||||
@results += @project.issues.find(:all, :include => :author, :conditions => ["issues.subject like ? or issues.description like ?", like_token, like_token] ) if @scope.include? 'issues'
|
@results += @project.issues.find(:all, :limit => limit, :include => :author, :conditions => [ (["(LOWER(issues.subject) like ? OR LOWER(issues.description) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort] ) if @scope.include? 'issues'
|
||||||
@results += @project.news.find(:all, :conditions => ["news.title like ? or news.description like ?", like_token, like_token], :include => :author ) if @scope.include? 'news'
|
@results += @project.news.find(:all, :limit => limit, :conditions => [ (["(LOWER(news.title) like ? OR LOWER(news.description) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort], :include => :author ) if @scope.include? 'news'
|
||||||
@results += @project.documents.find(:all, :conditions => ["title like ? or description like ?", like_token, like_token] ) if @scope.include? 'documents'
|
@results += @project.documents.find(:all, :limit => limit, :conditions => [ (["(LOWER(title) like ? OR LOWER(description) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort] ) if @scope.include? 'documents'
|
||||||
|
@question = @tokens.join(" ")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,14 @@
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
module ProjectsHelper
|
module ProjectsHelper
|
||||||
def result_overview(text, token)
|
|
||||||
match = excerpt(text, token)
|
def highlight_tokens(text, tokens)
|
||||||
match ? highlight(match, token) : truncate(text, 150)
|
return text unless tokens && !tokens.empty?
|
||||||
|
regexp = Regexp.new "(#{tokens.join('|')})", Regexp::IGNORECASE
|
||||||
|
result = ''
|
||||||
|
text.split(regexp).each_with_index do |words, i|
|
||||||
|
result << (i.even? ? (words.length > 100 ? "#{words[0..44]} ... #{words[-45..-1]}" : words) : content_tag('span', words, :class => 'highlight'))
|
||||||
|
end
|
||||||
|
result
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,10 +2,11 @@
|
||||||
|
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<% form_tag({:action => 'search', :id => @project}, :method => :get) do %>
|
<% form_tag({:action => 'search', :id => @project}, :method => :get) do %>
|
||||||
<p><%= text_field_tag 'token', @token, :size => 30 %>
|
<p><%= text_field_tag 'q', @question, :size => 30 %>
|
||||||
<%= check_box_tag 'scope[]', 'issues', (@scope.include? 'issues') %> <label><%= l(:label_issue_plural) %></label>
|
<%= check_box_tag 'scope[]', 'issues', (@scope.include? 'issues') %> <label><%= l(:label_issue_plural) %></label>
|
||||||
<%= check_box_tag 'scope[]', 'news', (@scope.include? 'news') %> <label><%= l(:label_news_plural) %></label>
|
<%= check_box_tag 'scope[]', 'news', (@scope.include? 'news') %> <label><%= l(:label_news_plural) %></label>
|
||||||
<%= check_box_tag 'scope[]', 'documents', (@scope.include? 'documents') %> <label><%= l(:label_document_plural) %></label></p>
|
<%= check_box_tag 'scope[]', 'documents', (@scope.include? 'documents') %> <label><%= l(:label_document_plural) %></label><br />
|
||||||
|
<%= check_box_tag 'all_words', 1, @all_words %> <%= l(:label_all_words) %></p>
|
||||||
<%= submit_tag l(:button_submit), :name => 'submit' %>
|
<%= submit_tag l(:button_submit), :name => 'submit' %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
@ -16,16 +17,16 @@
|
||||||
<% @results.each do |e| %>
|
<% @results.each do |e| %>
|
||||||
<li><p>
|
<li><p>
|
||||||
<% if e.is_a? Issue %>
|
<% if e.is_a? Issue %>
|
||||||
<%= link_to "#{e.tracker.name} ##{e.id}", :controller => 'issues', :action => 'show', :id => e %>: <%= highlight(h(e.subject), @token) %><br />
|
<%= link_to "#{e.tracker.name} ##{e.id}", :controller => 'issues', :action => 'show', :id => e %>: <%= highlight_tokens(h(e.subject), @tokens) %><br />
|
||||||
<%= result_overview(e.description, @token) %><br />
|
<%= highlight_tokens(e.description, @tokens) %><br />
|
||||||
<i><%= e.author.name %>, <%= format_time(e.created_on) %></i>
|
<i><%= e.author.name %>, <%= format_time(e.created_on) %></i>
|
||||||
<% elsif e.is_a? News %>
|
<% elsif e.is_a? News %>
|
||||||
<%=l(:label_news)%>: <%= link_to highlight(h(e.title), @token), :controller => 'news', :action => 'show', :id => e %><br />
|
<%=l(:label_news)%>: <%= link_to highlight_tokens(h(e.title), @tokens), :controller => 'news', :action => 'show', :id => e %><br />
|
||||||
<%= result_overview(e.description, @token) %><br />
|
<%= highlight_tokens(e.description, @tokens) %><br />
|
||||||
<i><%= e.author.name %>, <%= format_time(e.created_on) %></i>
|
<i><%= e.author.name %>, <%= format_time(e.created_on) %></i>
|
||||||
<% elsif e.is_a? Document %>
|
<% elsif e.is_a? Document %>
|
||||||
<%=l(:label_document)%>: <%= link_to highlight(h(e.title), @token), :controller => 'documents', :action => 'show', :id => e %><br />
|
<%=l(:label_document)%>: <%= link_to highlight_tokens(h(e.title), @tokens), :controller => 'documents', :action => 'show', :id => e %><br />
|
||||||
<%= result_overview(e.description, @token) %><br />
|
<%= highlight_tokens(e.description, @tokens) %><br />
|
||||||
<i><%= format_time(e.created_on) %></i>
|
<i><%= format_time(e.created_on) %></i>
|
||||||
<% end %>
|
<% end %>
|
||||||
</p></li>
|
</p></li>
|
||||||
|
|
|
@ -321,6 +321,7 @@ label_roadmap: Roadmap
|
||||||
label_search: Suche
|
label_search: Suche
|
||||||
label_result: %d Resultat
|
label_result: %d Resultat
|
||||||
label_result_plural: %d Resultate
|
label_result_plural: %d Resultate
|
||||||
|
label_all_words: Alle Wörter
|
||||||
|
|
||||||
button_login: Einloggen
|
button_login: Einloggen
|
||||||
button_submit: Einreichen
|
button_submit: Einreichen
|
||||||
|
|
|
@ -321,6 +321,7 @@ label_roadmap: Roadmap
|
||||||
label_search: Search
|
label_search: Search
|
||||||
label_result: %d result
|
label_result: %d result
|
||||||
label_result_plural: %d results
|
label_result_plural: %d results
|
||||||
|
label_all_words: All words
|
||||||
|
|
||||||
button_login: Login
|
button_login: Login
|
||||||
button_submit: Submit
|
button_submit: Submit
|
||||||
|
|
|
@ -321,6 +321,7 @@ label_roadmap: Roadmap
|
||||||
label_search: Búsqueda
|
label_search: Búsqueda
|
||||||
label_result: %d resultado
|
label_result: %d resultado
|
||||||
label_result_plural: %d resultados
|
label_result_plural: %d resultados
|
||||||
|
label_all_words: Todas las palabras
|
||||||
|
|
||||||
button_login: Conexión
|
button_login: Conexión
|
||||||
button_submit: Someter
|
button_submit: Someter
|
||||||
|
|
|
@ -321,6 +321,7 @@ label_roadmap: Roadmap
|
||||||
label_search: Recherche
|
label_search: Recherche
|
||||||
label_result: %d résultat
|
label_result: %d résultat
|
||||||
label_result_plural: %d résultats
|
label_result_plural: %d résultats
|
||||||
|
label_all_words: Tous les mots
|
||||||
|
|
||||||
button_login: Connexion
|
button_login: Connexion
|
||||||
button_submit: Soumettre
|
button_submit: Soumettre
|
||||||
|
|
|
@ -322,6 +322,7 @@ label_roadmap: ロードマップ
|
||||||
label_search: 検索
|
label_search: 検索
|
||||||
label_result: %d 件の結果
|
label_result: %d 件の結果
|
||||||
label_result_plural: %d 件の結果
|
label_result_plural: %d 件の結果
|
||||||
|
label_all_words: すべての単語
|
||||||
|
|
||||||
button_login: ログイン
|
button_login: ログイン
|
||||||
button_submit: 変更
|
button_submit: 変更
|
||||||
|
|
|
@ -243,7 +243,7 @@ legend {color: #505050;}
|
||||||
hr { border:0; border-top: dotted 1px #fff; border-bottom: dotted 1px #c0c0c0; }
|
hr { border:0; border-top: dotted 1px #fff; border-bottom: dotted 1px #c0c0c0; }
|
||||||
table p {margin:0; padding:0;}
|
table p {margin:0; padding:0;}
|
||||||
|
|
||||||
strong.highlight { background-color: #FCFD8D;}
|
.highlight { background-color: #FCFD8D;}
|
||||||
|
|
||||||
div.square {
|
div.square {
|
||||||
border: 1px solid #999;
|
border: 1px solid #999;
|
||||||
|
|
Loading…
Reference in New Issue