diff options
author | Fatih Acet <acetfatih@gmail.com> | 2016-11-25 09:17:47 +0000 |
---|---|---|
committer | Fatih Acet <acetfatih@gmail.com> | 2016-11-25 09:17:47 +0000 |
commit | 90a3b3ab5680d6b62de0aa446da52e01d378f81e (patch) | |
tree | bc806d11023a3cc8566c2a5340f56402030fb8ce | |
parent | c17d8d556f3ac60375f02789eb9f3cb85e85a028 (diff) | |
parent | 8c4f4afd6dd6d382aab2d6b992b6ffe3e60f91af (diff) | |
download | gitlab-ce-90a3b3ab5680d6b62de0aa446da52e01d378f81e.tar.gz |
Merge branch 'autocomplete-space-prefix' into 'master'
Allow GFM autocomplete to be trigger without the preceding space
## What does this MR do?
Gives the ability to GFM autocomplete to be trigger even if there is no preceding space.
I've taken the regex from the at.js plugin & tweaked it to allow the leading character to be a special character.
## What are the relevant issue numbers?
Closes #19975
## Screenshots (if relevant)
![Screen_Shot_2016-07-21_at_14.41.34](/uploads/19684ba286baeedb754e7457945480a8/Screen_Shot_2016-07-21_at_14.41.34.png)![Screen_Shot_2016-07-21_at_14.41.40](/uploads/a77349bce599ae93b4bcddd355087f5c/Screen_Shot_2016-07-21_at_14.41.40.png)![Screen_Shot_2016-07-21_at_14.41.46](/uploads/c35df17b678b24b73c94b181f0784188/Screen_Shot_2016-07-21_at_14.41.46.png)
See merge request !5395
-rw-r--r-- | app/assets/javascripts/gfm_auto_complete.js.es6 | 34 | ||||
-rw-r--r-- | spec/features/issues/gfm_autocomplete_spec.rb | 43 |
2 files changed, 76 insertions, 1 deletions
diff --git a/app/assets/javascripts/gfm_auto_complete.js.es6 b/app/assets/javascripts/gfm_auto_complete.js.es6 index 5d9ac4d350a..89fe13b7a45 100644 --- a/app/assets/javascripts/gfm_auto_complete.js.es6 +++ b/app/assets/javascripts/gfm_auto_complete.js.es6 @@ -53,6 +53,26 @@ } else { return value; } + }, + matcher: function (flag, subtext) { + // The below is taken from At.js source + // Tweaked to commands to start without a space only if char before is a non-word character + // https://github.com/ichord/At.js + var _a, _y, regexp, match; + flag = flag.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); + + _a = decodeURI("%C3%80"); + _y = decodeURI("%C3%BF"); + + regexp = new RegExp("(?:\\B|\\W|\\s)" + flag + "([A-Za-z" + _a + "-" + _y + "0-9_\'\.\+\-]*)|([^\\x00-\\xff]*)$", 'gi'); + + match = regexp.exec(subtext); + + if (match) { + return match[2] || match[1]; + } else { + return null; + } } }, setup: _.debounce(function(input) { @@ -91,10 +111,12 @@ })(this), insertTpl: ':${name}:', data: ['loading'], + startWithSpace: false, callbacks: { sorter: this.DefaultOptions.sorter, filter: this.DefaultOptions.filter, - beforeInsert: this.DefaultOptions.beforeInsert + beforeInsert: this.DefaultOptions.beforeInsert, + matcher: this.DefaultOptions.matcher } }); // Team Members @@ -112,11 +134,13 @@ insertTpl: '${atwho-at}${username}', searchKey: 'search', data: ['loading'], + startWithSpace: false, alwaysHighlightFirst: true, callbacks: { sorter: this.DefaultOptions.sorter, filter: this.DefaultOptions.filter, beforeInsert: this.DefaultOptions.beforeInsert, + matcher: this.DefaultOptions.matcher, beforeSave: function(members) { return $.map(members, function(m) { let title = ''; @@ -157,10 +181,12 @@ })(this), data: ['loading'], insertTpl: '${atwho-at}${id}', + startWithSpace: false, callbacks: { sorter: this.DefaultOptions.sorter, filter: this.DefaultOptions.filter, beforeInsert: this.DefaultOptions.beforeInsert, + matcher: this.DefaultOptions.matcher, beforeSave: function(issues) { return $.map(issues, function(i) { if (i.title == null) { @@ -190,7 +216,9 @@ })(this), insertTpl: '${atwho-at}"${title}"', data: ['loading'], + startWithSpace: false, callbacks: { + matcher: this.DefaultOptions.matcher, sorter: this.DefaultOptions.sorter, beforeSave: function(milestones) { return $.map(milestones, function(m) { @@ -220,11 +248,13 @@ }; })(this), data: ['loading'], + startWithSpace: false, insertTpl: '${atwho-at}${id}', callbacks: { sorter: this.DefaultOptions.sorter, filter: this.DefaultOptions.filter, beforeInsert: this.DefaultOptions.beforeInsert, + matcher: this.DefaultOptions.matcher, beforeSave: function(merges) { return $.map(merges, function(m) { if (m.title == null) { @@ -245,7 +275,9 @@ searchKey: 'search', displayTpl: this.Labels.template, insertTpl: '${atwho-at}${title}', + startWithSpace: false, callbacks: { + matcher: this.DefaultOptions.matcher, sorter: this.DefaultOptions.sorter, beforeSave: function(merges) { var sanitizeLabelTitle; diff --git a/spec/features/issues/gfm_autocomplete_spec.rb b/spec/features/issues/gfm_autocomplete_spec.rb new file mode 100644 index 00000000000..c421da97d76 --- /dev/null +++ b/spec/features/issues/gfm_autocomplete_spec.rb @@ -0,0 +1,43 @@ +require 'rails_helper' + +feature 'GFM autocomplete', feature: true, js: true do + include WaitForAjax + let(:user) { create(:user) } + let(:project) { create(:project) } + let(:issue) { create(:issue, project: project) } + + before do + project.team << [user, :master] + login_as(user) + visit namespace_project_issue_path(project.namespace, project, issue) + + wait_for_ajax + end + + it 'opens autocomplete menu when field starts with text' do + page.within '.timeline-content-form' do + find('#note_note').native.send_keys('') + find('#note_note').native.send_keys('@') + end + + expect(page).to have_selector('.atwho-container') + end + + it 'opens autocomplete menu when field is prefixed with non-text character' do + page.within '.timeline-content-form' do + find('#note_note').native.send_keys('') + find('#note_note').native.send_keys('@') + end + + expect(page).to have_selector('.atwho-container') + end + + it 'doesnt open autocomplete menu character is prefixed with text' do + page.within '.timeline-content-form' do + find('#note_note').native.send_keys('testing') + find('#note_note').native.send_keys('@') + end + + expect(page).not_to have_selector('.atwho-view') + end +end |