diff --git a/app/helpers/profile_helper.rb b/app/helpers/profile_helper.rb
index 34627e4e5..333971607 100644
--- a/app/helpers/profile_helper.rb
+++ b/app/helpers/profile_helper.rb
@@ -15,4 +15,13 @@ module ProfileHelper
{ github: urls["GitHub"], twitter: urls["Twitter"], facebook: urls["Facebook"] }.compact
end
+
+ def character_count_denominator(field_type)
+ case field_type
+ when "text_field"
+ "100"
+ when "text_area"
+ "200"
+ end
+ end
end
diff --git a/app/javascript/packs/userProfileSettings.js b/app/javascript/packs/userProfileSettings.js
new file mode 100644
index 000000000..8013fd49e
--- /dev/null
+++ b/app/javascript/packs/userProfileSettings.js
@@ -0,0 +1,32 @@
+const userFieldIds = ['user[name]', 'user[email]', 'user[username]'];
+const profileFieldIds = Array.from(
+ document.querySelectorAll('[id^="profile["]'),
+).map((node) => node.id);
+const allFieldIds = [...userFieldIds, ...profileFieldIds];
+
+export function fieldCharacterLimits() {
+ window.addEventListener('load', () => {
+ allFieldIds.forEach((field_id) => {
+ const field = document.getElementById(field_id);
+ const fieldValueLength = field.value.length;
+ const fieldCharacterSpan = document.getElementById(
+ field.dataset.characterSpanId,
+ );
+ fieldCharacterSpan.innerHTML = fieldValueLength;
+ });
+
+ document
+ .getElementById('user-profile-form')
+ .addEventListener('keyup', (event) => {
+ if (!event.target.dataset.characterSpanId) {
+ return;
+ }
+
+ document.getElementById(
+ event.target.dataset.characterSpanId,
+ ).innerHTML = event.target.value.length;
+ });
+ });
+}
+
+fieldCharacterLimits();
diff --git a/app/views/users/_profile.html.erb b/app/views/users/_profile.html.erb
index 9ea4bf46e..14976e153 100644
--- a/app/views/users/_profile.html.erb
+++ b/app/views/users/_profile.html.erb
@@ -1,20 +1,40 @@
-<%= javascript_packs_with_chunks_tag "colorPreview", "validateFileInputs", "stickySaveFooter", defer: true %>
+<%= javascript_packs_with_chunks_tag "colorPreview", "stickySaveFooter", "userProfileSettings", "validateFileInputs", defer: true %>
<%= render "users/additional_authentication" %>
-<%= form_with(url: profile_path(@user.profile_id), method: "put", html: { class: "sticky-footer-form" }) do |f| %>
+<%= form_with(url: profile_path(@user.profile_id), method: "put", html: { class: "sticky-footer-form", id: "user-profile-form" }) do |f| %>
User
<%= f.label :name, for: "user[name]", class: "crayons-field__label" %>
- <%= f.text_field "user[name]", maxlength: 30, class: "crayons-textfield", placeholder: "John Doe", value: @user.name %>
+ <%= f.text_field "user[name]",
+ maxlength: 30,
+ class: "crayons-textfield",
+ placeholder: "John Doe",
+ value: @user.name,
+ aria: { describedby: "name-description" },
+ data: { character_span_id: "name-characters" } %>
+
+ Available characters used:
+ /30
+
<%= f.label :email, for: "user[email]", class: "crayons-field__label" %>
- <%= f.text_field "user[email]", class: "crayons-textfield", placeholder: "john.doe@example.com", value: @user.email %>
+ <%= f.text_field "user[email]",
+ maxlength: 50,
+ class: "crayons-textfield",
+ placeholder: "john.doe@example.com",
+ value: @user.email,
+ aria: { describedby: "email-description" },
+ data: { character_span_id: "email-characters" } %>
+
+ Available characters used:
+ /50
+
@@ -24,7 +44,17 @@
<%= f.label :username, for: "user[username]", class: "crayons-field__label" %>
- <%= f.text_field "user[username]", maxlength: 30, class: "crayons-textfield", placeholder: "johndoe", value: @user.username %>
+ <%= f.text_field "user[username]",
+ maxlength: 30,
+ class: "crayons-textfield",
+ placeholder: "johndoe",
+ value: @user.username,
+ aria: { describedby: "username-description" },
+ data: { character_span_id: "username-characters" } %>
+
+ Available characters used:
+ /30
+
@@ -51,9 +81,16 @@
<%= t("views.users.profile_fields.website.label") %>
<%= f.url_field "profile[website_url]",
+ maxlength: 100,
value: profile.website_url,
placeholder: "https://yoursite.com",
- class: "crayons-textfield js-color-field" %>
+ class: "crayons-textfield",
+ aria: { describedby: "url-description" },
+ data: { character_span_id: "url-characters" } %>
+
+ Available characters used:
+ /100
+
@@ -61,9 +98,16 @@
<%= t("views.users.profile_fields.location.label") %>
<%= f.text_field "profile[location]",
+ maxlength: 100,
value: profile.location,
placeholder: t("views.users.profile_fields.location.placeholder"),
- class: "crayons-textfield js-color-field" %>
+ class: "crayons-textfield",
+ aria: { describedby: "location-description" },
+ data: { character_span_id: "location-characters" } %>
+
+ Available characters used:
+ /100
+
@@ -71,9 +115,16 @@
<%= t("views.users.profile_fields.bio.label") %>
<%= f.text_area "profile[summary]",
+ maxlength: 200,
value: profile.summary,
placeholder: t("views.users.profile_fields.bio.placeholder"),
- class: "crayons-textfield js-color-field" %>
+ class: "crayons-textfield",
+ aria: { describedby: "summary-description" },
+ data: { character_span_id: "summary-characters" } %>
+
+ Available characters used:
+ /200
+
@@ -103,7 +154,13 @@
"profile[#{field.attribute_name}]",
value: profile.public_send(field.attribute_name),
placeholder: field["placeholder_text"],
+ aria: { describedby: "#{field.attribute_name}-description" },
+ data: { character_span_id: "#{field.attribute_name}-characters" },
class: "crayons-textfield") %>
+
+ Available characters used:
+ /<%= character_count_denominator(field["input_type"]) %>
+
<% end %>
<% if field.description.present? %>
<%= field.description %>
diff --git a/spec/helpers/profile_helper_spec.rb b/spec/helpers/profile_helper_spec.rb
index 6d45b9d63..74c28d493 100644
--- a/spec/helpers/profile_helper_spec.rb
+++ b/spec/helpers/profile_helper_spec.rb
@@ -68,4 +68,14 @@ describe ProfileHelper do
end
end
end
+
+ describe "character_count_denominator" do
+ it "returns '100' when the field_type is 'text_field'" do
+ expect(helper.character_count_denominator("text_field")).to eq("100")
+ end
+
+ it "returns '200' when the field_type is 'text_area'" do
+ expect(helper.character_count_denominator("text_area")).to eq("200")
+ end
+ end
end