Feature #33820 » feature-33820-v2.diff
| app/controllers/auto_completes_controller.rb | ||
|---|---|---|
| 42 | 42 |
render :json => format_issues_json(issues) |
| 43 | 43 |
end |
| 44 | 44 | |
| 45 |
def wiki_pages |
|
| 46 |
q = params[:q].to_s.strip |
|
| 47 |
wiki = Wiki.find_by(project: @project) |
|
| 48 |
scope = (@project && wiki ? wiki.pages : WikiPage.all).reorder(id: :desc) |
|
| 49 |
wiki_pages = |
|
| 50 |
if q.present? |
|
| 51 |
scope.where("LOWER(#{WikiPage.table_name}.title) LIKE LOWER(?)", "%#{q}%").limit(10).to_a
|
|
| 52 |
else |
|
| 53 |
scope.limit(10).to_a |
|
| 54 |
end |
|
| 55 |
render :json => format_wiki_pages_json(wiki_pages) |
|
| 56 |
end |
|
| 57 | ||
| 45 | 58 |
private |
| 46 | 59 | |
| 47 | 60 |
def find_project |
| ... | ... | |
| 61 | 74 |
} |
| 62 | 75 |
end |
| 63 | 76 |
end |
| 77 | ||
| 78 |
def format_wiki_pages_json(wiki_pages) |
|
| 79 |
wiki_pages.map {|wiki_page|
|
|
| 80 |
{
|
|
| 81 |
'id' => wiki_page.id, |
|
| 82 |
'label' => wiki_page.title.to_s.truncate(255), |
|
| 83 |
'value' => wiki_page.title |
|
| 84 |
} |
|
| 85 |
} |
|
| 86 |
end |
|
| 64 | 87 |
end |
| app/helpers/application_helper.rb | ||
|---|---|---|
| 1743 | 1743 | |
| 1744 | 1744 |
def autocomplete_data_sources(project) |
| 1745 | 1745 |
{
|
| 1746 |
issues: auto_complete_issues_path(:project_id => project, :q => '') |
|
| 1746 |
issues: auto_complete_issues_path(:project_id => project, :q => ''), |
|
| 1747 |
wiki_pages: auto_complete_wiki_pages_path(:project_id => project, :q => '') |
|
| 1747 | 1748 |
} |
| 1748 | 1749 |
end |
| 1749 | 1750 | |
| config/routes.rb | ||
|---|---|---|
| 46 | 46 |
post 'boards/:board_id/topics/:id/edit', :to => 'messages#edit' |
| 47 | 47 |
post 'boards/:board_id/topics/:id/destroy', :to => 'messages#destroy' |
| 48 | 48 | |
| 49 |
# Misc issue routes. TODO: move into resources
|
|
| 49 |
# Auto complate routes
|
|
| 50 | 50 |
match '/issues/auto_complete', :to => 'auto_completes#issues', :via => :get, :as => 'auto_complete_issues' |
| 51 |
match '/wiki_pages/auto_complete', :to => 'auto_completes#wiki_pages', :via => :get, :as => 'auto_complete_wiki_pages' |
|
| 52 | ||
| 53 |
# Misc issue routes. TODO: move into resources |
|
| 51 | 54 |
match '/issues/context_menu', :to => 'context_menus#issues', :as => 'issues_context_menu', :via => [:get, :post] |
| 52 | 55 |
match '/issues/changes', :to => 'journals#index', :as => 'issue_changes', :via => :get |
| 53 | 56 |
match '/issues/:id/quoted', :to => 'journals#new', :id => /\d+/, :via => :post, :as => 'quoted_issue' |
| lib/redmine.rb | ||
|---|---|---|
| 162 | 162 |
end |
| 163 | 163 | |
| 164 | 164 |
map.project_module :wiki do |map| |
| 165 |
map.permission :view_wiki_pages, {:wiki => [:index, :show, :special, :date_index]}, :read => true
|
|
| 165 |
map.permission :view_wiki_pages, {:wiki => [:index, :show, :special, :date_index], :auto_complete => [:wiki_pages]}, :read => true
|
|
| 166 | 166 |
map.permission :view_wiki_edits, {:wiki => [:history, :diff, :annotate]}, :read => true
|
| 167 | 167 |
map.permission :export_wiki_pages, {:wiki => [:export]}, :read => true
|
| 168 | 168 |
map.permission :edit_wiki_pages, :wiki => [:new, :edit, :update, :preview, :add_attachment], :attachments => :upload |
| public/javascripts/application.js | ||
|---|---|---|
| 1080 | 1080 |
}; |
| 1081 | 1081 | |
| 1082 | 1082 |
const tribute = new Tribute({
|
| 1083 |
trigger: '#', |
|
| 1084 |
values: function (text, cb) {
|
|
| 1085 |
if (event.target.type === 'text' && $(element).attr('autocomplete') != 'off') {
|
|
| 1086 |
$(element).attr('autocomplete', 'off');
|
|
| 1083 |
collection: [ |
|
| 1084 |
{
|
|
| 1085 |
trigger: '#', |
|
| 1086 |
values: function (text, cb) {
|
|
| 1087 |
if (event.target.type === 'text' && $(element).attr('autocomplete') != 'off') {
|
|
| 1088 |
$(element).attr('autocomplete', 'off');
|
|
| 1089 |
} |
|
| 1090 |
remoteSearch(getDataSource('issues') + text, function (issues) {
|
|
| 1091 |
return cb(issues); |
|
| 1092 |
}); |
|
| 1093 |
}, |
|
| 1094 |
lookup: 'label', |
|
| 1095 |
fillAttr: 'label', |
|
| 1096 |
requireLeadingSpace: true, |
|
| 1097 |
selectTemplate: function (issue) {
|
|
| 1098 |
return '#' + issue.original.id; |
|
| 1099 |
}, |
|
| 1100 |
noMatchTemplate: function () {
|
|
| 1101 |
return '<span style:"visibility: hidden;"></span>'; |
|
| 1102 |
} |
|
| 1103 |
}, |
|
| 1104 |
{
|
|
| 1105 |
trigger: '[[', |
|
| 1106 |
values: function (text, cb) {
|
|
| 1107 |
remoteSearch(getDataSource('wiki_pages') + text, function (wikiPages) {
|
|
| 1108 |
return cb(wikiPages); |
|
| 1109 |
}); |
|
| 1110 |
}, |
|
| 1111 |
lookup: 'label', |
|
| 1112 |
fillAttr: 'label', |
|
| 1113 |
requireLeadingSpace: true, |
|
| 1114 |
selectTemplate: function (wikiPage) {
|
|
| 1115 |
return '[[' + wikiPage.original.value + ']]'; |
|
| 1116 |
}, |
|
| 1117 |
noMatchTemplate: function () {
|
|
| 1118 |
return '<span style:"visibility: hidden;"></span>'; |
|
| 1119 |
} |
|
| 1087 | 1120 |
} |
| 1088 |
remoteSearch(getDataSource('issues') + text, function (issues) {
|
|
| 1089 |
return cb(issues); |
|
| 1090 |
}); |
|
| 1091 |
}, |
|
| 1092 |
lookup: 'label', |
|
| 1093 |
fillAttr: 'label', |
|
| 1094 |
requireLeadingSpace: true, |
|
| 1095 |
selectTemplate: function (issue) {
|
|
| 1096 |
return '#' + issue.original.id; |
|
| 1097 |
}, |
|
| 1098 |
noMatchTemplate: function () {
|
|
| 1099 |
return '<span style:"visibility: hidden;"></span>'; |
|
| 1100 |
} |
|
| 1121 |
] |
|
| 1101 | 1122 |
}); |
| 1102 | 1123 | |
| 1103 | 1124 |
tribute.attach(element); |
| test/functional/auto_completes_controller_test.rb | ||
|---|---|---|
| 28 | 28 |
:member_roles, |
| 29 | 29 |
:members, |
| 30 | 30 |
:enabled_modules, |
| 31 |
:journals, :journal_details |
|
| 31 |
:journals, :journal_details, |
|
| 32 |
:wikis, :wiki_pages, :wiki_contents, :wiki_content_versions |
|
| 32 | 33 | |
| 33 | 34 |
def test_issues_should_not_be_case_sensitive |
| 34 | 35 |
get( |
| ... | ... | |
| 196 | 197 |
assert_equal 10, json.count |
| 197 | 198 |
assert_equal Issue.last.id, json.first['id'].to_i |
| 198 | 199 |
end |
| 200 | ||
| 201 |
def test_wiki_pages_should_not_be_case_sensitive |
|
| 202 |
get( |
|
| 203 |
:wiki_pages, |
|
| 204 |
params: {
|
|
| 205 |
project_id: 'ecookbook', |
|
| 206 |
q: 'pAgE' |
|
| 207 |
} |
|
| 208 |
) |
|
| 209 |
assert_response :success |
|
| 210 |
assert_include "Page_with_an_inline_image", response.body |
|
| 211 |
end |
|
| 212 | ||
| 213 |
def test_wiki_pages_without_project_should_search_all_projects |
|
| 214 |
get(:wiki_pages, params: {q: 'pAgE'})
|
|
| 215 |
assert_response :success |
|
| 216 |
assert_include "Page_with_an_inline_image", response.body # project eCookbook |
|
| 217 |
assert_include "Start_page", response.body # project OnlineStore |
|
| 218 |
end |
|
| 219 | ||
| 220 |
def test_wiki_pages_should_return_json |
|
| 221 |
get( |
|
| 222 |
:wiki_pages, |
|
| 223 |
params: {
|
|
| 224 |
project_id: 'ecookbook', |
|
| 225 |
q: 'Page_with_an_inline_image' |
|
| 226 |
} |
|
| 227 |
) |
|
| 228 |
assert_response :success |
|
| 229 |
json = ActiveSupport::JSON.decode(response.body) |
|
| 230 |
assert_kind_of Array, json |
|
| 231 |
issue = json.first |
|
| 232 |
assert_kind_of Hash, issue |
|
| 233 |
assert_equal 4, issue['id'] |
|
| 234 |
assert_equal 'Page_with_an_inline_image', issue['value'] |
|
| 235 |
assert_equal 'Page_with_an_inline_image', issue['label'] |
|
| 236 |
end |
|
| 237 | ||
| 238 |
def test_wiki_pages_should_return_json_content_type_response |
|
| 239 |
get( |
|
| 240 |
:wiki_pages, |
|
| 241 |
params: {
|
|
| 242 |
project_id: 'ecookbook', |
|
| 243 |
q: 'Page_with_an_inline_image' |
|
| 244 |
} |
|
| 245 |
) |
|
| 246 |
assert_response :success |
|
| 247 |
assert_include 'application/json', response.headers['Content-Type'] |
|
| 248 |
end |
|
| 249 | ||
| 250 |
def test_wiki_pages_without_q_params_should_return_last_10_pages |
|
| 251 |
# There are 8 pages generated by fixtures |
|
| 252 |
# and we need three more to test the 10 limit |
|
| 253 |
wiki = Wiki.find_by(project: Project.first) |
|
| 254 |
3.times do |n| |
|
| 255 |
WikiPage.create(wiki: wiki, title: "test#{n}")
|
|
| 256 |
end |
|
| 257 |
get :wiki_pages, params: { project_id: 'ecookbook' }
|
|
| 258 |
assert_response :success |
|
| 259 |
json = ActiveSupport::JSON.decode(response.body) |
|
| 260 |
assert_equal 10, json.count |
|
| 261 |
assert_equal wiki.pages[-2].id, json.first['id'].to_i |
|
| 262 |
end |
|
| 199 | 263 |
end |