Commit 60b4c88e3a175fa8b1fdebede4a5c5f73df0eee5

Authored by Dmitriy Zaporozhets
2 parents a100c578 4d843d2c

Merge pull request #1664 from riyad/auto-complete-everywhere

Cleanup auto-completion and add it to all GFM inputs
app/assets/javascripts/gfm_auto_complete.js.coffee 0 → 100644
@@ -0,0 +1,57 @@ @@ -0,0 +1,57 @@
  1 +
  2 +###
  3 + Creates the variables for setting up GFM auto-completion
  4 +###
  5 +# Emoji
  6 +window.autocompleteEmojiData = [];
  7 +window.autocompleteEmojiTemplate = "<li data-value='${insert}'>${name} <img alt='${name}' height='20' src='${image}' width='20' /></li>";
  8 +
  9 +# Team Members
  10 +window.autocompleteMembersUrl = "";
  11 +window.autocompleteMembersParams =
  12 + private_token: ""
  13 + page: 1
  14 +window.autocompleteMembersData = [];
  15 +
  16 +
  17 +
  18 +###
  19 + Add GFM auto-completion to all input fields, that accept GFM input.
  20 +###
  21 +window.setupGfmAutoComplete = ->
  22 + ###
  23 + Emoji
  24 + ###
  25 + $('.gfm-input').atWho ':',
  26 + data: autocompleteEmojiData,
  27 + tpl: autocompleteEmojiTemplate
  28 +
  29 + ###
  30 + Team Members
  31 + ###
  32 + $('.gfm-input').atWho '@', (query, callback) ->
  33 + (getMoreMembers = ->
  34 + $.getJSON(autocompleteMembersUrl, autocompleteMembersParams)
  35 + .success (members) ->
  36 + # pick the data we need
  37 + newMembersData = $.map members, (m) -> m.name
  38 +
  39 + # add the new page of data to the rest
  40 + $.merge autocompleteMembersData, newMembersData
  41 +
  42 + # show the pop-up with a copy of the current data
  43 + callback autocompleteMembersData[..]
  44 +
  45 + # are we past the last page?
  46 + if newMembersData.length == 0
  47 + # set static data and stop callbacks
  48 + $('.gfm-input').atWho '@',
  49 + data: autocompleteMembersData
  50 + callback: null
  51 + else
  52 + # get next page
  53 + getMoreMembers()
  54 +
  55 + # so the next request gets the next page
  56 + autocompleteMembersParams.page += 1;
  57 + ).call();
0 \ No newline at end of file 58 \ No newline at end of file
app/assets/javascripts/issues.js
@@ -6,6 +6,7 @@ function switchToNewIssue(form){ @@ -6,6 +6,7 @@ function switchToNewIssue(form){
6 $("#new_issue_dialog").show("fade", { direction: "right" }, 150); 6 $("#new_issue_dialog").show("fade", { direction: "right" }, 150);
7 $('.top-tabs .add_new').hide(); 7 $('.top-tabs .add_new').hide();
8 disableButtonIfEmptyField("#issue_title", ".save-btn"); 8 disableButtonIfEmptyField("#issue_title", ".save-btn");
  9 + setupGfmAutoComplete();
9 }); 10 });
10 } 11 }
11 12
@@ -17,6 +18,7 @@ function switchToEditIssue(form){ @@ -17,6 +18,7 @@ function switchToEditIssue(form){
17 $("#edit_issue_dialog").show("fade", { direction: "right" }, 150); 18 $("#edit_issue_dialog").show("fade", { direction: "right" }, 150);
18 $('.add_new').hide(); 19 $('.add_new').hide();
19 disableButtonIfEmptyField("#issue_title", ".save-btn"); 20 disableButtonIfEmptyField("#issue_title", ".save-btn");
  21 + setupGfmAutoComplete();
20 }); 22 });
21 } 23 }
22 24
app/helpers/application_helper.rb
@@ -98,6 +98,12 @@ module ApplicationHelper @@ -98,6 +98,12 @@ module ApplicationHelper
98 [projects, default_nav, project_nav].flatten.to_json 98 [projects, default_nav, project_nav].flatten.to_json
99 end 99 end
100 100
  101 + def emoji_autocomplete_source
  102 + # should be an array of strings
  103 + # so to_s can be called, because it is sufficient and to_json is too slow
  104 + Emoji::NAMES.to_s
  105 + end
  106 +
101 def ldap_enable? 107 def ldap_enable?
102 Devise.omniauth_providers.include?(:ldap) 108 Devise.omniauth_providers.include?(:ldap)
103 end 109 end
app/helpers/notes_helper.rb
@@ -14,10 +14,4 @@ module NotesHelper @@ -14,10 +14,4 @@ module NotesHelper
14 "vote downvote" 14 "vote downvote"
15 end 15 end
16 end 16 end
17 -  
18 - def emoji_for_completion  
19 - # should be an array of strings  
20 - # so to_s can be called, because it is sufficient and to_json is too slow  
21 - Emoji::NAMES  
22 - end  
23 end 17 end
app/views/issues/_form.html.haml
@@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@
12 = f.label :title do 12 = f.label :title do
13 %strong= "Subject *" 13 %strong= "Subject *"
14 .input 14 .input
15 - = f.text_field :title, maxlength: 255, class: "xxlarge" 15 + = f.text_field :title, maxlength: 255, class: "xxlarge gfm-input"
16 .issue_middle_block 16 .issue_middle_block
17 .issue_assignee 17 .issue_assignee
18 = f.label :assignee_id do 18 = f.label :assignee_id do
@@ -37,7 +37,7 @@ @@ -37,7 +37,7 @@
37 .clearfix 37 .clearfix
38 = f.label :description, "Details" 38 = f.label :description, "Details"
39 .input 39 .input
40 - = f.text_area :description, maxlength: 2000, class: "xxlarge", rows: 14 40 + = f.text_area :description, maxlength: 2000, class: "xxlarge gfm-input", rows: 14
41 %p.hint Issues are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}. 41 %p.hint Issues are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.
42 42
43 43
app/views/layouts/_head_panel.html.haml
@@ -28,6 +28,8 @@ @@ -28,6 +28,8 @@
28 My profile 28 My profile
29 = link_to 'Logout', destroy_user_session_path, class: "logout", method: :delete 29 = link_to 'Logout', destroy_user_session_path, class: "logout", method: :delete
30 30
  31 += render "layouts/init_auto_complete"
  32 +
31 :javascript 33 :javascript
32 $(function(){ 34 $(function(){
33 $("#search").autocomplete({ 35 $("#search").autocomplete({
app/views/layouts/_init_auto_complete.html.haml 0 → 100644
@@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
  1 +:javascript
  2 + $(function() {
  3 + autocompleteMembersUrl = "#{ "/api/v2/projects/#{@project.code}/members" if @project }";
  4 + autocompleteMembersParams.private_token = "#{current_user.authentication_token}";
  5 +
  6 + autocompleteEmojiData = #{raw emoji_autocomplete_source};
  7 + // convert the list so that the items have the right format for completion
  8 + autocompleteEmojiData = $.map(autocompleteEmojiData, function(value) {
  9 + return {
  10 + name: value,
  11 + insert: value+':',
  12 + image: '#{image_path("emoji")}/'+value+'.png'
  13 + }
  14 + });
  15 +
  16 + setupGfmAutoComplete();
  17 + });
app/views/merge_requests/_form.html.haml
@@ -38,7 +38,7 @@ @@ -38,7 +38,7 @@
38 .top_box_content 38 .top_box_content
39 = f.label :title do 39 = f.label :title do
40 %strong= "Title *" 40 %strong= "Title *"
41 - .input= f.text_field :title, class: "input-xxlarge pad", maxlength: 255, rows: 5 41 + .input= f.text_field :title, class: "input-xxlarge pad gfm-input", maxlength: 255, rows: 5
42 .middle_box_content 42 .middle_box_content
43 = f.label :assignee_id do 43 = f.label :assignee_id do
44 %i.icon-user 44 %i.icon-user
app/views/notes/_common_form.html.haml
@@ -36,49 +36,3 @@ @@ -36,49 +36,3 @@
36 %a.file_upload.btn.small Upload File 36 %a.file_upload.btn.small Upload File
37 = f.file_field :attachment, class: "input-file" 37 = f.file_field :attachment, class: "input-file"
38 %span.hint Any file less than 10 MB 38 %span.hint Any file less than 10 MB
39 -  
40 -:javascript  
41 - $(function(){  
42 - // init auto-completion of team members  
43 - var membersUrl = "#{root_url}/api/v2/projects/#{@project.code}/members";  
44 - var membersParams = {  
45 - private_token: "#{current_user.authentication_token}",  
46 - page: 1,  
47 - };  
48 - var membersData = [];  
49 - $('.gfm-input').atWho('@', function(query, callback) {  
50 - (function getMoreMembers() {  
51 - $.getJSON(membersUrl, membersParams).  
52 - success(function(members) {  
53 - // pick the data we need  
54 - var newMembersData = $.map(members, function(member) { return member.name });  
55 -  
56 - // add the new page of data to the rest  
57 - $.merge(membersData, newMembersData);  
58 -  
59 - // show the pop-up with a copy of the current data  
60 - callback(membersData.slice(0));  
61 -  
62 - // are we past the last page?  
63 - if (newMembersData.length == 0) {  
64 - // set static data and stop callbacks  
65 - $('.gfm-input').atWho('@', { data: membersData, callback: null });  
66 - } else {  
67 - // get next page  
68 - getMoreMembers();  
69 - }  
70 - });  
71 - // next request will get the next page  
72 - membersParams.page += 1;  
73 - })();  
74 - });  
75 -  
76 - // init auto-completion of emoji  
77 - var emoji = #{emoji_for_completion};  
78 - // convert the list so that the items have the right format for completion  
79 - emoji = $.map(emoji, function(value) {return { key: value+':', name: value }});  
80 - $('.gfm-input').atWho(':', {  
81 - data: emoji,  
82 - tpl: "<li data-value='${key}'>${name} #{escape_javascript image_tag('emoji/${name}.png', :size => '20x20')}</li>"  
83 - });  
84 - });  
app/views/notes/_create_common_note.js.haml
@@ -10,4 +10,5 @@ @@ -10,4 +10,5 @@
10 - else 10 - else
11 :plain 11 :plain
12 $(".note-form-holder").replaceWith("#{escape_javascript(render 'form')}"); 12 $(".note-form-holder").replaceWith("#{escape_javascript(render 'form')}");
  13 + setupGfmAutoComplete();
13 14
app/views/wikis/_form.html.haml
@@ -21,7 +21,7 @@ @@ -21,7 +21,7 @@
21 21
22 .bottom_box_content 22 .bottom_box_content
23 = f.label :content 23 = f.label :content
24 - .input= f.text_area :content, class: 'span8' 24 + .input= f.text_area :content, class: 'span8 gfm-input'
25 .actions 25 .actions
26 = f.submit 'Save', class: "save-btn btn" 26 = f.submit 'Save', class: "save-btn btn"
27 = link_to "Cancel", project_wiki_path(@project, :index), class: "btn cancel-btn" 27 = link_to "Cancel", project_wiki_path(@project, :index), class: "btn cancel-btn"
spec/helpers/notes_helper_spec.rb
@@ -1,10 +0,0 @@ @@ -1,10 +0,0 @@
1 -require 'spec_helper'  
2 -  
3 -describe NotesHelper do  
4 - describe "#emoji_for_completion" do  
5 - it "should be an Array of Strings" do  
6 - emoji_for_completion.should be_a(Array)  
7 - emoji_for_completion.each { |emoji| emoji.should be_a(String) }  
8 - end  
9 - end  
10 -end