Commit 90a3b3ab authored by Fatih Acet's avatar Fatih Acet

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
parents c17d8d55 8c4f4afd
...@@ -53,6 +53,26 @@ ...@@ -53,6 +53,26 @@
} else { } else {
return value; 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) { setup: _.debounce(function(input) {
...@@ -91,10 +111,12 @@ ...@@ -91,10 +111,12 @@
})(this), })(this),
insertTpl: ':${name}:', insertTpl: ':${name}:',
data: ['loading'], data: ['loading'],
startWithSpace: false,
callbacks: { callbacks: {
sorter: this.DefaultOptions.sorter, sorter: this.DefaultOptions.sorter,
filter: this.DefaultOptions.filter, filter: this.DefaultOptions.filter,
beforeInsert: this.DefaultOptions.beforeInsert beforeInsert: this.DefaultOptions.beforeInsert,
matcher: this.DefaultOptions.matcher
} }
}); });
// Team Members // Team Members
...@@ -112,11 +134,13 @@ ...@@ -112,11 +134,13 @@
insertTpl: '${atwho-at}${username}', insertTpl: '${atwho-at}${username}',
searchKey: 'search', searchKey: 'search',
data: ['loading'], data: ['loading'],
startWithSpace: false,
alwaysHighlightFirst: true, alwaysHighlightFirst: true,
callbacks: { callbacks: {
sorter: this.DefaultOptions.sorter, sorter: this.DefaultOptions.sorter,
filter: this.DefaultOptions.filter, filter: this.DefaultOptions.filter,
beforeInsert: this.DefaultOptions.beforeInsert, beforeInsert: this.DefaultOptions.beforeInsert,
matcher: this.DefaultOptions.matcher,
beforeSave: function(members) { beforeSave: function(members) {
return $.map(members, function(m) { return $.map(members, function(m) {
let title = ''; let title = '';
...@@ -157,10 +181,12 @@ ...@@ -157,10 +181,12 @@
})(this), })(this),
data: ['loading'], data: ['loading'],
insertTpl: '${atwho-at}${id}', insertTpl: '${atwho-at}${id}',
startWithSpace: false,
callbacks: { callbacks: {
sorter: this.DefaultOptions.sorter, sorter: this.DefaultOptions.sorter,
filter: this.DefaultOptions.filter, filter: this.DefaultOptions.filter,
beforeInsert: this.DefaultOptions.beforeInsert, beforeInsert: this.DefaultOptions.beforeInsert,
matcher: this.DefaultOptions.matcher,
beforeSave: function(issues) { beforeSave: function(issues) {
return $.map(issues, function(i) { return $.map(issues, function(i) {
if (i.title == null) { if (i.title == null) {
...@@ -190,7 +216,9 @@ ...@@ -190,7 +216,9 @@
})(this), })(this),
insertTpl: '${atwho-at}"${title}"', insertTpl: '${atwho-at}"${title}"',
data: ['loading'], data: ['loading'],
startWithSpace: false,
callbacks: { callbacks: {
matcher: this.DefaultOptions.matcher,
sorter: this.DefaultOptions.sorter, sorter: this.DefaultOptions.sorter,
beforeSave: function(milestones) { beforeSave: function(milestones) {
return $.map(milestones, function(m) { return $.map(milestones, function(m) {
...@@ -220,11 +248,13 @@ ...@@ -220,11 +248,13 @@
}; };
})(this), })(this),
data: ['loading'], data: ['loading'],
startWithSpace: false,
insertTpl: '${atwho-at}${id}', insertTpl: '${atwho-at}${id}',
callbacks: { callbacks: {
sorter: this.DefaultOptions.sorter, sorter: this.DefaultOptions.sorter,
filter: this.DefaultOptions.filter, filter: this.DefaultOptions.filter,
beforeInsert: this.DefaultOptions.beforeInsert, beforeInsert: this.DefaultOptions.beforeInsert,
matcher: this.DefaultOptions.matcher,
beforeSave: function(merges) { beforeSave: function(merges) {
return $.map(merges, function(m) { return $.map(merges, function(m) {
if (m.title == null) { if (m.title == null) {
...@@ -245,7 +275,9 @@ ...@@ -245,7 +275,9 @@
searchKey: 'search', searchKey: 'search',
displayTpl: this.Labels.template, displayTpl: this.Labels.template,
insertTpl: '${atwho-at}${title}', insertTpl: '${atwho-at}${title}',
startWithSpace: false,
callbacks: { callbacks: {
matcher: this.DefaultOptions.matcher,
sorter: this.DefaultOptions.sorter, sorter: this.DefaultOptions.sorter,
beforeSave: function(merges) { beforeSave: function(merges) {
var sanitizeLabelTitle; var sanitizeLabelTitle;
......
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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment