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
This commit is contained in:
commit
90a3b3ab56
2 changed files with 76 additions and 1 deletions
|
@ -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;
|
||||
|
|
43
spec/features/issues/gfm_autocomplete_spec.rb
Normal file
43
spec/features/issues/gfm_autocomplete_spec.rb
Normal file
|
@ -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
|
Loading…
Reference in a new issue