diff --git a/app/assets/javascripts/initializers/initializeCommentsPage.js.erb b/app/assets/javascripts/initializers/initializeCommentsPage.js.erb
index a09cbb2a0..b67b60719 100644
--- a/app/assets/javascripts/initializers/initializeCommentsPage.js.erb
+++ b/app/assets/javascripts/initializers/initializeCommentsPage.js.erb
@@ -306,11 +306,8 @@ function handleFocus(event) {
area.blur();
} else {
var form = event.target.closest(".comment-form");
- if (form) {
- form.classList.add("comment-form--initiated");
- }
+ form.classList.add("comment-form--initiated");
handleSizeChange(event);
- window.Forem.initializeMentionAutocompleteTextArea(area);
}
}
@@ -437,13 +434,14 @@ function handleSizeChange(event) {
function handleButtonsActivation(event) {
var textarea = event.target;
- var commentForm = textarea.closest('.comment-form');
- if (commentForm) {
- var buttons = textarea.closest('.comment-form').getElementsByClassName('js-btn-enable');
- Array.from(buttons).forEach(function(button) {
- button.disabled = textarea.value.length === 0;
- });
- };
+ var buttons = textarea.closest('.comment-form').getElementsByClassName('js-btn-enable');
+ Array.from(buttons).forEach(function(button) {
+ if (textarea.value.length > 0) {
+ button.disabled = false;
+ } else {
+ button.disabled = true;
+ }
+ });
}
function validateField(event) {
diff --git a/app/javascript/crayons/MentionAutocompleteTextArea/MentionAutocompleteTextArea.jsx b/app/javascript/crayons/MentionAutocompleteTextArea/MentionAutocompleteTextArea.jsx
index 7327e76d5..e6fdb524b 100644
--- a/app/javascript/crayons/MentionAutocompleteTextArea/MentionAutocompleteTextArea.jsx
+++ b/app/javascript/crayons/MentionAutocompleteTextArea/MentionAutocompleteTextArea.jsx
@@ -35,8 +35,6 @@ const replaceTextArea = (originalNodeToReplace, newNode) => {
originalNodeToReplace,
'',
).cssText;
- // Make sure no transition replays when the new textarea is mounted
- newNode.style.transition = 'none';
// We need to manually remove the element, as Preact's diffing algorithm won't replace it in render
originalNodeToReplace.remove();
@@ -195,7 +193,7 @@ export const MentionAutocompleteTextArea = ({
const textWithSelection = `${textContent.substring(
0,
selectionInsertIndex,
- )}${username} ${textContent.substring(inputRef.current.selectionStart)}`;
+ )}${username}${textContent.substring(inputRef.current.selectionStart)}`;
// Clear the current search
setSearchTerm('');
@@ -205,8 +203,8 @@ export const MentionAutocompleteTextArea = ({
// Update the text area value
setTextContent(textWithSelection);
- // Update the cursor to directly after the selection (+2 accounts for the @ sign, and adding a space after the username)
- const newCursorPosition = selectionInsertIndex + username.length + 2;
+ // Update the cursor to directly after the selection
+ const newCursorPosition = selectionInsertIndex + username.length + 1;
setCursorPosition(newCursorPosition);
};
diff --git a/app/javascript/crayons/MentionAutocompleteTextArea/__tests__/__snapshots__/MentionAutocompleteTextArea.test.jsx.snap b/app/javascript/crayons/MentionAutocompleteTextArea/__tests__/__snapshots__/MentionAutocompleteTextArea.test.jsx.snap
index 8387988e6..9859b017f 100644
--- a/app/javascript/crayons/MentionAutocompleteTextArea/__tests__/__snapshots__/MentionAutocompleteTextArea.test.jsx.snap
+++ b/app/javascript/crayons/MentionAutocompleteTextArea/__tests__/__snapshots__/MentionAutocompleteTextArea.test.jsx.snap
@@ -1,3 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[` should render 1`] = `"
"`;
+exports[` should render 1`] = `""`;
diff --git a/app/javascript/packs/base.jsx b/app/javascript/packs/base.jsx
index 1b6b80583..b142edcb7 100644
--- a/app/javascript/packs/base.jsx
+++ b/app/javascript/packs/base.jsx
@@ -5,39 +5,6 @@ import {
initializeTouchDevice,
} from '../topNavigation/utilities';
-// Namespace for functions which need to be accessed in plain JS initializers
-window.Forem = {};
-
-window.Forem.initializeMentionAutocompleteTextArea = async (
- originalTextArea,
-) => {
- const parentContainer = originalTextArea.parentElement;
-
- const alreadyInitialized = parentContainer.id === 'combobox-container';
- if (alreadyInitialized) {
- return;
- }
-
- const [
- { MentionAutocompleteTextArea },
- { fetchSearch },
- { render, h },
- ] = await Promise.all([
- import('@crayons/MentionAutocompleteTextArea'),
- import('@utilities/search'),
- import('preact'),
- ]);
-
- render(
- fetchSearch('usernames', { username })}
- />,
- parentContainer,
- originalTextArea,
- );
-};
-
window.showModal = async ({
title,
contentSelector,
diff --git a/app/javascript/utilities/textAreaUtils.js b/app/javascript/utilities/textAreaUtils.js
index a5786e859..4768c44ed 100644
--- a/app/javascript/utilities/textAreaUtils.js
+++ b/app/javascript/utilities/textAreaUtils.js
@@ -101,7 +101,11 @@ const getIndexOfCurrentWordAutocompleteSymbol = (content, selectionIndex) => {
const currentCharacter = content.charAt(selectionIndex);
const previousCharacter = content.charAt(selectionIndex - 1);
- if (selectionIndex !== 0 && ![' ', '', '\n'].includes(previousCharacter)) {
+ if (
+ selectionIndex !== 0 &&
+ previousCharacter !== ' ' &&
+ previousCharacter !== ''
+ ) {
return getIndexOfCurrentWordAutocompleteSymbol(content, selectionIndex - 1);
}
diff --git a/app/views/notifications/shared/_comment_box.html.erb b/app/views/notifications/shared/_comment_box.html.erb
index fd2ffb306..7796e5ae4 100644
--- a/app/views/notifications/shared/_comment_box.html.erb
+++ b/app/views/notifications/shared/_comment_box.html.erb
@@ -76,7 +76,7 @@
<%= f.hidden_field :commentable_type, value: json_data["comment"]["commentable"]["class"]["name"] %>
<%= f.hidden_field :parent_id, value: json_data["comment"]["id"] %>
- <%= f.text_area :body_markdown, id: "comment-textarea-for-#{json_data['comment']['id']}", class: "crayons-textfield mb-2 resize-y", placeholder: "Reply...", 'aria-label': "Reply to a comment...", onfocus: "handleFocus(event)" %>
+ <%= f.text_area :body_markdown, id: "comment-textarea-for-#{json_data['comment']['id']}", class: "crayons-textfield mb-2 resize-y", placeholder: "Reply...", 'aria-label': "Reply to a comment..." %>
diff --git a/cypress/fixtures/search/emptyUsernamesSearch.json b/cypress/fixtures/search/emptyUsernamesSearch.json
deleted file mode 100644
index 6b2dcd458..000000000
--- a/cypress/fixtures/search/emptyUsernamesSearch.json
+++ /dev/null
@@ -1 +0,0 @@
-{ "result": [] }
diff --git a/cypress/fixtures/search/usernames.json b/cypress/fixtures/search/usernames.json
deleted file mode 100644
index 0f4c980f9..000000000
--- a/cypress/fixtures/search/usernames.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
- "result": [
- {
- "username": "search_user_1",
- "name": "Search user 1",
- "profile_image_90": "/images/apple-icon.png"
- },
- {
- "username": "search_user_2",
- "name": "Search user 2",
- "profile_image_90": "/images/apple-icon.png"
- },
- {
- "username": "search_user_3",
- "name": "Search user 3",
- "profile_image_90": "/images/apple-icon.png"
- },
- {
- "username": "search_user_4",
- "name": "Search user 4",
- "profile_image_90": "/images/apple-icon.png"
- },
- {
- "username": "search_user_5",
- "name": "Search user 5",
- "profile_image_90": "/images/apple-icon.png"
- },
- {
- "username": "search_user_6",
- "name": "Search user 6",
- "profile_image_90": "/images/apple-icon.png"
- },
- {
- "username": "search_user_7",
- "name": "Search user 7",
- "profile_image_90": "/images/apple-icon.png"
- }
- ]
-}
diff --git a/cypress/integration/articleFlows/commentOnArticle.spec.js b/cypress/integration/articleFlows/commentOnArticle.spec.js
deleted file mode 100644
index 06d93d316..000000000
--- a/cypress/integration/articleFlows/commentOnArticle.spec.js
+++ /dev/null
@@ -1,169 +0,0 @@
-describe('Comment on articles', () => {
- beforeEach(() => {
- cy.testSetup();
- cy.fixture('users/articleEditorV1User.json').as('user');
-
- cy.get('@user').then((user) => {
- cy.loginUser(user).then(() => {
- cy.visit('/');
- cy.findAllByText('Test article').last().click();
- });
- });
- });
-
- it('should comment on an article with user mention autocomplete suggesting max 6 users', () => {
- cy.intercept(
- { method: 'GET', url: '/search/usernames' },
- { fixture: 'search/usernames.json' },
- );
-
- cy.findByLabelText('Add a comment to the discussion').click();
- cy.findByRole('combobox');
-
- cy.findByLabelText('Add a comment to the discussion').as(
- 'autocompleteCommentBox',
- );
-
- cy.get('@autocompleteCommentBox').type('Some text @s');
- cy.findByText('Type to search for a user').should('exist');
-
- cy.get('@autocompleteCommentBox').type('earch');
-
- const expectedUsernames = [
- '@search_user_1',
- '@search_user_2',
- '@search_user_2',
- '@search_user_3',
- '@search_user_4',
- '@search_user_5',
- '@search_user_6',
- ];
-
- expectedUsernames.forEach((name) => cy.findByText(name).should('exist'));
- cy.findByText('@search_user_7').should('not.exist');
-
- cy.findByText('@search_user_3').click();
- cy.findByDisplayValue('Some text @search_user_3').should('exist');
- });
-
- it('should select a mention autocomplete suggestion by keyboard', () => {
- cy.intercept(
- { method: 'GET', url: '/search/usernames' },
- { fixture: 'search/usernames.json' },
- );
-
- cy.findByLabelText('Add a comment to the discussion').click();
- cy.findByRole('combobox');
-
- cy.findByLabelText('Add a comment to the discussion').type(
- 'Some text @search_user{downarrow}{enter}',
- );
-
- cy.findByDisplayValue('Some text @search_user_1').should('exist');
- });
-
- it('should accept entered comment text without user mention if no autocomplete suggestions', () => {
- cy.intercept(
- { method: 'GET', url: '/search/usernames' },
- { fixture: 'search/emptyUsernamesSearch.json' },
- );
-
- cy.findByLabelText('Add a comment to the discussion').click();
- cy.findByRole('combobox');
-
- cy.findByLabelText('Add a comment to the discussion').as(
- 'autocompleteCommentBox',
- );
-
- cy.get('@autocompleteCommentBox').type('Some text @user');
-
- cy.findByText('No results found').should('exist');
- cy.get('@autocompleteCommentBox').type(' ');
- cy.findByText('No results found').should('not.exist');
- cy.findByDisplayValue('Some text @user').should('exist');
- });
-
- it('should stop showing mention autocomplete suggestions on text delete', () => {
- cy.intercept(
- { method: 'GET', url: '/search/usernames' },
- { fixture: 'search/usernames.json' },
- );
-
- cy.findByLabelText('Add a comment to the discussion').click();
- cy.findByRole('combobox');
-
- cy.findByLabelText('Add a comment to the discussion').as(
- 'autocompleteCommentBox',
- );
-
- cy.get('@autocompleteCommentBox').type('Some text @se');
- cy.findByText('@search_user_1').should('exist');
-
- cy.get('@autocompleteCommentBox').type('{backspace}{backspace}{backspace}');
- cy.findByText('@search_user_1').should('not.exist');
- });
-
- it('should resume search suggestions when user types after deleting', () => {
- cy.intercept(
- { method: 'GET', url: '/search/usernames' },
- { fixture: 'search/usernames.json' },
- );
-
- cy.findByLabelText('Add a comment to the discussion').click();
- cy.findByRole('combobox');
-
- cy.findByLabelText('Add a comment to the discussion').as(
- 'autocompleteCommentBox',
- );
-
- cy.get('@autocompleteCommentBox').type('Some text @se');
- cy.get('@autocompleteCommentBox').type('{backspace}{backspace}');
- cy.findByText('@search_user_1').should('not.exist');
- cy.get('@autocompleteCommentBox').type('se');
- cy.findByText('@search_user_1').should('exist');
- });
-
- it('should close the autocomplete suggestions on Escape press', () => {
- cy.intercept(
- { method: 'GET', url: '/search/usernames' },
- { fixture: 'search/usernames.json' },
- );
-
- cy.findByLabelText('Add a comment to the discussion').click();
- cy.findByRole('combobox');
-
- cy.findByLabelText('Add a comment to the discussion').as(
- 'autocompleteCommentBox',
- );
-
- cy.get('@autocompleteCommentBox').type('Some text @search');
- cy.findByText('@search_user_1').should('be.visible');
-
- cy.get('@autocompleteCommentBox').type('{Esc}');
- cy.findByText('@search_user_1').should('not.be.visible');
- });
-
- it('should reply to a comment with user mention autocomplete', () => {
- cy.intercept(
- { method: 'GET', url: '/search/usernames' },
- { fixture: 'search/usernames.json' },
- );
-
- cy.findByLabelText('Add a comment to the discussion').click();
- cy.findByRole('combobox');
-
- cy.findByLabelText('Add a comment to the discussion').type('first comment');
- cy.findByRole('button', { name: /Submit/ }).click();
-
- cy.findByRole('link', { name: /Reply/ }).click();
-
- cy.findByRole('combobox', { name: /Reply to a comment/ }).as(
- 'replyCombobox',
- );
- cy.get('@replyCombobox').click();
- cy.get('@replyCombobox').type('Some text @search_user');
-
- cy.findByText('@search_user_1').click();
- cy.findByDisplayValue('Some text @search_user_1');
- });
-});