mirror of
https://github.com/mastodon/mastodon.git
synced 2025-10-05 16:42:47 +00:00
Fix hashtags not being picked up when full-width hash sign is used
Some checks are pending
Chromatic / Run Chromatic (push) Waiting to run
Some checks are pending
Chromatic / Run Chromatic (push) Waiting to run
This commit is contained in:
parent
06803422da
commit
1f80082f6d
|
@ -620,6 +620,7 @@ export function fetchComposeSuggestions(token) {
|
||||||
fetchComposeSuggestionsEmojis(dispatch, getState, token);
|
fetchComposeSuggestionsEmojis(dispatch, getState, token);
|
||||||
break;
|
break;
|
||||||
case '#':
|
case '#':
|
||||||
|
case '#':
|
||||||
fetchComposeSuggestionsTags(dispatch, getState, token);
|
fetchComposeSuggestionsTags(dispatch, getState, token);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -661,11 +662,11 @@ export function selectComposeSuggestion(position, token, suggestion, path) {
|
||||||
|
|
||||||
dispatch(useEmoji(suggestion));
|
dispatch(useEmoji(suggestion));
|
||||||
} else if (suggestion.type === 'hashtag') {
|
} else if (suggestion.type === 'hashtag') {
|
||||||
completion = `#${suggestion.name}`;
|
completion = suggestion.name.slice(token.length - 1);
|
||||||
startPosition = position - 1;
|
startPosition = position + token.length;
|
||||||
} else if (suggestion.type === 'account') {
|
} else if (suggestion.type === 'account') {
|
||||||
completion = getState().getIn(['accounts', suggestion.id, 'acct']);
|
completion = `@${getState().getIn(['accounts', suggestion.id, 'acct'])}`;
|
||||||
startPosition = position;
|
startPosition = position - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't want to replace hashtags that vary only in case due to accessibility, but we need to fire off an event so that
|
// We don't want to replace hashtags that vary only in case due to accessibility, but we need to fire off an event so that
|
||||||
|
@ -725,7 +726,7 @@ function insertIntoTagHistory(recognizedTags, text) {
|
||||||
// complicated because of new normalization rules, it's no longer just
|
// complicated because of new normalization rules, it's no longer just
|
||||||
// a case sensitivity issue
|
// a case sensitivity issue
|
||||||
const names = recognizedTags.map(tag => {
|
const names = recognizedTags.map(tag => {
|
||||||
const matches = text.match(new RegExp(`#${tag.name}`, 'i'));
|
const matches = text.match(new RegExp(`[#|#]${tag.name}`, 'i'));
|
||||||
|
|
||||||
if (matches && matches.length > 0) {
|
if (matches && matches.length > 0) {
|
||||||
return matches[0].slice(1);
|
return matches[0].slice(1);
|
||||||
|
|
|
@ -61,7 +61,7 @@ export default class AutosuggestInput extends ImmutablePureComponent {
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
autoFocus: true,
|
autoFocus: true,
|
||||||
searchTokens: ['@', ':', '#'],
|
searchTokens: ['@', '@', ':', '#', '#'],
|
||||||
};
|
};
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
|
|
|
@ -25,7 +25,7 @@ const textAtCursorMatchesToken = (str, caretPosition) => {
|
||||||
word = str.slice(left, right + caretPosition);
|
word = str.slice(left, right + caretPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!word || word.trim().length < 3 || ['@', ':', '#'].indexOf(word[0]) === -1) {
|
if (!word || word.trim().length < 3 || ['@', '@', ':', '#', '#'].indexOf(word[0]) === -1) {
|
||||||
return [null, null];
|
return [null, null];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ module Extractor
|
||||||
end
|
end
|
||||||
|
|
||||||
def extract_hashtags_with_indices(text, _options = {})
|
def extract_hashtags_with_indices(text, _options = {})
|
||||||
return [] unless text&.index('#')
|
return [] unless text&.index(/[##]/)
|
||||||
|
|
||||||
possible_entries = []
|
possible_entries = []
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ class Tag < ApplicationRecord
|
||||||
HASHTAG_LAST_SEQUENCE = '([[:word:]_]*[[:alpha:]][[:word:]_]*)'
|
HASHTAG_LAST_SEQUENCE = '([[:word:]_]*[[:alpha:]][[:word:]_]*)'
|
||||||
HASHTAG_NAME_PAT = "#{HASHTAG_FIRST_SEQUENCE}|#{HASHTAG_LAST_SEQUENCE}".freeze
|
HASHTAG_NAME_PAT = "#{HASHTAG_FIRST_SEQUENCE}|#{HASHTAG_LAST_SEQUENCE}".freeze
|
||||||
|
|
||||||
HASHTAG_RE = %r{(?<![=/)\p{Alnum}])#(#{HASHTAG_NAME_PAT})}
|
HASHTAG_RE = %r{(?<![=/)\p{Alnum}])[#|#](#{HASHTAG_NAME_PAT})}
|
||||||
HASHTAG_NAME_RE = /\A(#{HASHTAG_NAME_PAT})\z/i
|
HASHTAG_NAME_RE = /\A(#{HASHTAG_NAME_PAT})\z/i
|
||||||
HASHTAG_INVALID_CHARS_RE = /[^[:alnum:]\u0E47-\u0E4E#{HASHTAG_SEPARATORS}]/
|
HASHTAG_INVALID_CHARS_RE = /[^[:alnum:]\u0E47-\u0E4E#{HASHTAG_SEPARATORS}]/
|
||||||
|
|
||||||
|
|
|
@ -35,12 +35,24 @@ RSpec.describe Extractor do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'extract_hashtags_with_indices' do
|
describe 'extract_hashtags_with_indices' do
|
||||||
it 'returns an empty array if it does not have #' do
|
it 'returns an empty array if it does not have # or #' do
|
||||||
text = 'a string without hash sign'
|
text = 'a string without hash sign'
|
||||||
extracted = described_class.extract_hashtags_with_indices(text)
|
extracted = described_class.extract_hashtags_with_indices(text)
|
||||||
expect(extracted).to eq []
|
expect(extracted).to eq []
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'returns hashtags preceded by an ASCII hash' do
|
||||||
|
text = 'hello #world'
|
||||||
|
extracted = described_class.extract_hashtags_with_indices(text)
|
||||||
|
expect(extracted).to eq [{ hashtag: 'world', indices: [6, 12] }]
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns hashtags preceded by a full-width hash' do
|
||||||
|
text = 'hello #world'
|
||||||
|
extracted = described_class.extract_hashtags_with_indices(text)
|
||||||
|
expect(extracted).to eq [{ hashtag: 'world', indices: [6, 12] }]
|
||||||
|
end
|
||||||
|
|
||||||
it 'does not exclude normal hash text before ://' do
|
it 'does not exclude normal hash text before ://' do
|
||||||
text = '#hashtag://'
|
text = '#hashtag://'
|
||||||
extracted = described_class.extract_hashtags_with_indices(text)
|
extracted = described_class.extract_hashtags_with_indices(text)
|
||||||
|
|
|
@ -84,6 +84,10 @@ RSpec.describe Tag do
|
||||||
expect(subject.match('this is #aesthetic').to_s).to eq '#aesthetic'
|
expect(subject.match('this is #aesthetic').to_s).to eq '#aesthetic'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'matches #foo' do
|
||||||
|
expect(subject.match('this is #foo').to_s).to eq '#foo'
|
||||||
|
end
|
||||||
|
|
||||||
it 'matches digits at the start' do
|
it 'matches digits at the start' do
|
||||||
expect(subject.match('hello #3d').to_s).to eq '#3d'
|
expect(subject.match('hello #3d').to_s).to eq '#3d'
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue
Block a user