OSDN Git Service

Refactor search autocomplete. Use ajax for source
authorDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
Sat, 18 Jan 2014 12:16:46 +0000 (14:16 +0200)
committerDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
Sat, 18 Jan 2014 12:16:46 +0000 (14:16 +0200)
Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
app/assets/javascripts/dispatcher.js.coffee
app/assets/javascripts/search_autocomplete.js.coffee
app/controllers/search_controller.rb
app/helpers/search_helper.rb
app/models/project.rb
app/views/layouts/_search.html.haml
config/routes.rb

index e264e28..8ea302f 100644 (file)
@@ -47,5 +47,9 @@ class Dispatcher
 
 
   initSearch: ->
-    autocomplete_json = $('.search-autocomplete-json').data('autocomplete-opts')
-    new SearchAutocomplete(autocomplete_json)
+    opts = $('.search-autocomplete-opts')
+    path = opts.data('autocomplete-path')
+    project_id = opts.data('autocomplete-project-id')
+    project_ref = opts.data('autocomplete-project-ref')
+
+    new SearchAutocomplete(path, project_id, project_ref)
index 3418690..e144dfa 100644 (file)
@@ -1,7 +1,12 @@
 class SearchAutocomplete
-  constructor: (json) ->
+  constructor: (search_autocomplete_path, project_id, project_ref) ->
+    project_id = '' unless project_id
+    project_ref = '' unless project_ref
+    query = "?project_id=" + project_id + "&project_ref=" + project_ref
+
     $("#search").autocomplete
-      source: json
+      source: search_autocomplete_path + query
+      minLength: 1
       select: (event, ui) ->
         location.href = ui.item.url
 
index e853c22..0152d53 100644 (file)
@@ -1,4 +1,6 @@
 class SearchController < ApplicationController
+  include SearchHelper
+
   def show
     @project = Project.find_by_id(params[:project_id]) if params[:project_id].present?
     @group = Group.find_by_id(params[:group_id]) if params[:group_id].present?
@@ -10,4 +12,12 @@ class SearchController < ApplicationController
       @search_results = Search::GlobalService.new(current_user, params).execute
     end
   end
+
+  def autocomplete
+    term = params[:term]
+    @project = Project.find(params[:project_id]) if params[:project_id].present?
+    @ref = params[:project_ref] if params[:project_ref].present?
+
+    render json: search_autocomplete_opts(term).to_json
+  end
 end
index f24156e..20b50de 100644 (file)
@@ -1,16 +1,22 @@
 module SearchHelper
-  def search_autocomplete_source
+  def search_autocomplete_opts(term)
     return unless current_user
+
+    resources_results = [
+      groups_autocomplete(term),
+      projects_autocomplete(term),
+      public_projects_autocomplete(term),
+    ].flatten
+
+    generic_results = project_autocomplete + default_autocomplete + help_autocomplete
+    generic_results.select! { |result| result[:label] =~ Regexp.new(term, "i") }
+
     [
-      groups_autocomplete,
-      projects_autocomplete,
-      public_projects_autocomplete,
-      default_autocomplete,
-      project_autocomplete,
-      help_autocomplete
+      resources_results,
+      generic_results
     ].flatten.uniq do |item|
       item[:label]
-    end.to_json
+    end
   end
 
   private
@@ -65,23 +71,36 @@ module SearchHelper
   end
 
   # Autocomplete results for the current user's groups
-  def groups_autocomplete
-    current_user.authorized_groups.map do |group|
-      { label: "group: #{simple_sanitize(group.name)}", url: group_path(group) }
+  def groups_autocomplete(term, limit = 5)
+    current_user.authorized_groups.search(term).limit(limit).map do |group|
+      {
+        label: "group: #{simple_sanitize(group.name)}",
+        url: group_path(group)
+      }
     end
   end
 
   # Autocomplete results for the current user's projects
-  def projects_autocomplete
-    current_user.authorized_projects.non_archived.map do |p|
-      { label: "project: #{simple_sanitize(p.name_with_namespace)}", url: project_path(p) }
+  def projects_autocomplete(term, limit = 5)
+    current_user.authorized_projects.search_by_title(term).non_archived.limit(limit).map do |p|
+      {
+        label: "project: #{simple_sanitize(p.name_with_namespace)}",
+        url: project_path(p)
+      }
     end
   end
 
   # Autocomplete results for the current user's projects
-  def public_projects_autocomplete
-    Project.public_or_internal_only(current_user).non_archived.map do |p|
-      { label: "project: #{simple_sanitize(p.name_with_namespace)}", url: project_path(p) }
+  def public_projects_autocomplete(term, limit = 5)
+    Project.public_or_internal_only(current_user).search_by_title(term).non_archived.limit(limit).map do |p|
+      {
+        label: "project: #{simple_sanitize(p.name_with_namespace)}",
+        url: project_path(p)
+      }
     end
   end
+
+  def simple_sanitize(str)
+    Sanitize.clean(str)
+  end
 end
index f322b5a..2a792f0 100644 (file)
@@ -138,6 +138,10 @@ class Project < ActiveRecord::Base
       joins(:namespace).where("projects.archived = ?", false).where("projects.name LIKE :query OR projects.path LIKE :query OR namespaces.name LIKE :query OR projects.description LIKE :query", query: "%#{query}%")
     end
 
+    def search_by_title query
+      where("projects.archived = ?", false).where("projects.name LIKE :query", query: "%#{query}%")
+    end
+
     def find_with_namespace(id)
       if id.include?("/")
         id = id.split("/")
index 9a0db99..a0e55b2 100644 (file)
@@ -7,4 +7,4 @@
       = hidden_field_tag :search_code, true
     = hidden_field_tag :repository_ref, @ref
     = submit_tag 'Go' if ENV['RAILS_ENV'] == 'test'
-    .search-autocomplete-json.hide{:'data-autocomplete-opts' => search_autocomplete_source }
+    .search-autocomplete-opts.hide{:'data-autocomplete-path' => search_autocomplete_path, :'data-autocomplete-project-id' => @project.try(:id), :'data-autocomplete-project-ref' => @ref }
index 734421e..315c339 100644 (file)
@@ -6,6 +6,7 @@ Gitlab::Application.routes.draw do
   # Search
   #
   get 'search' => "search#show"
+  get 'search/autocomplete' => "search#autocomplete", as: :search_autocomplete
 
   # API
   API::API.logger Rails.logger