[Small Wins] Show character limits for profile inputs (#15255)
* Start implementation * Extend raw implementation; will refactor later * still building * basic implementation * create JS pack * Rename JS pack; use existing CSS property * complete implementation for profile fields * Add guard againt irrelevant profile fields * extract view logic to helper and add specs
This commit is contained in:
parent
2f42bc46d4
commit
4f1bdcda22
4 changed files with 116 additions and 8 deletions
|
|
@ -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
|
||||
|
|
|
|||
32
app/javascript/packs/userProfileSettings.js
Normal file
32
app/javascript/packs/userProfileSettings.js
Normal file
|
|
@ -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();
|
||||
|
|
@ -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| %>
|
||||
|
||||
<div class="crayons-card crayons-card--content-rows">
|
||||
<h2>User</h2>
|
||||
|
||||
<div class="crayons-field">
|
||||
<%= 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" } %>
|
||||
<div id="name-description" class="self-end fs-s">
|
||||
<span class="screen-reader-only">Available characters used: </span>
|
||||
<span id="name-characters"></span>/30
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="crayons-field">
|
||||
<%= 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" } %>
|
||||
<div id="email-description" class="self-end fs-s">
|
||||
<span class="screen-reader-only">Available characters used: </span>
|
||||
<span id="email-characters"></span>/50
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="crayons-field crayons-field--checkbox">
|
||||
|
|
@ -24,7 +44,17 @@
|
|||
|
||||
<div class="crayons-field">
|
||||
<%= 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" } %>
|
||||
<div id="username-description" class="self-end fs-s">
|
||||
<span class="screen-reader-only">Available characters used: </span>
|
||||
<span id="username-characters"></span>/30
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="crayons-field">
|
||||
|
|
@ -51,9 +81,16 @@
|
|||
<%= t("views.users.profile_fields.website.label") %>
|
||||
</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" } %>
|
||||
<div id="url-description" class="self-end fs-s">
|
||||
<span class="screen-reader-only">Available characters used: </span>
|
||||
<span id="url-characters"></span>/100
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="crayons-field">
|
||||
|
|
@ -61,9 +98,16 @@
|
|||
<%= t("views.users.profile_fields.location.label") %>
|
||||
</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" } %>
|
||||
<div id="location-description" class="self-end fs-s">
|
||||
<span class="screen-reader-only">Available characters used: </span>
|
||||
<span id="location-characters"></span>/100
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="crayons-field">
|
||||
|
|
@ -71,9 +115,16 @@
|
|||
<%= t("views.users.profile_fields.bio.label") %>
|
||||
</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" } %>
|
||||
<div id="summary-description" class="self-end fs-s">
|
||||
<span class="screen-reader-only">Available characters used: </span>
|
||||
<span id="summary-characters"></span>/200
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -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") %>
|
||||
<div id="<%= field.attribute_name %>-description" class="self-end fs-s">
|
||||
<span class="screen-reader-only">Available characters used: </span>
|
||||
<span id="<%= field.attribute_name %>-characters"></span>/<%= character_count_denominator(field["input_type"]) %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% if field.description.present? %>
|
||||
<p class="crayons-field__description"><%= field.description %></p>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue