We were using a placeholder to indicate content which should be part of
a label.
It might be better to actually use "Link address" as a label instead of
"URL". I'm using "URL" because it's used in other places in the admin
section.
We were using a paragraph before the field, and then a field with no
label and a redundant placeholder. This causes accessibility issues for
screen reader users, who will not hear the label being announced when
entering the field, and to users who click on the label expecting it to
automatically focus on its related field (which is the standard browser
behavior).
Using placeholders having similar (or identical) text as already present
as a label has a few issues.
First, it's a distraction. Reading the same information twice is
useless, requires an extra effort, and might even frustrate users.
Second, if users start typing before reading the placeholder and see it
disappear, they might think they're missing relevant information,
delete what they typed, and read the placeholder. That will get them
nowhere.
Finally, we display placeholders using a text offering very low contrast
against the background, so users don't think the placeholder is an
actual value entered in the field. Using such low contrast makes the
text hard to read, particularly for users with visual impairments.
So we're removing these placeholders.
This commit only deals with placeholder texts with similar (or
identical) texts as the label text. There might be other places where we
should replace placeholder texts with labels, but that's a different
topic.
A button cannot be inside an anchor tag, and it might confuse some
browsers or screen readers.
We're also making it clear in the tests that the intention is to use a
button there by using `click_button` instead of `click_on` since the
latter also clicks on links.
We were using an `@extend` selector inside a `@supports` condition,
which didn't generate the `@supports` clause as we intended to, so
browsers with no support for mask images were still applying properties
which were meant for browsers with support for mask images.
Nowadays there are many users with a screen of 1920px (or higher) width
but who don't change their font-size preferences and keep them at 16px,
which is the default in most browsers.
On pages which use the whole window width, that results in unreasonably
long lines which are very hard to read. That's the main reason why many
sites (including CONSUL) use rules like `max-width: 75rem` for the body
or other elements.
However, on extra large screens this causes the content to be in the
middle of the screen while most of the screen is empty, and the text
might also be too small for that resolution, making it harder to read.
There are a few approaches to solve this problem.
Using just viewport units like `font-size: calc(4vw + 4vh + 2vmin);` is
indeed responsive, but it's got an important flaw: it ignores user
preferences, and so the font size will be the same for users who prefer
a 16px size and for users who prefer a 32px size.
Using `calc(1em + 0.2vw)` or similar might make the text too big on
small screens.
Finally, using `max(1em, 1vw)` would work in a similar way to what we're
doing, but zooming in and out would only work when the viewport width is
less than 100em (at that moment, 1em == 1vw).
So we're taking an approach where zooming in and out always works at
least to a certain degree (due to the 0.25em part) and the font size is
increased gradually when we reach the point where the viewport width is
bigger than 100em. We're using 0.25em since it will be exactly 4px with
the default browser configuration, and so calculations are easier than
with (for example) 0.3em.
Disclaimer: I've tested this feature on several devices with different
screen sizes and resolutions, but I must admit there might be cases I'm
unaware of where there are side effects for certain combinations of
screen size/resolution/dpi. In general, though, the side effects should
be similar to what happens when users increase the font size in their
browser's preferences.
Note we're using `Max` instead of `max` because Sass can't handle the
CSS `max` function, as mentioned in commit cdfa23fc6.
When the "Or fill the following form" text was translated to another
language or customized by administrators, the text could span over two
lines. Since the element had a fixed height, it could overlap with the
text below it.
So now we're using an element with a relative position to achieve the
same effect (have the contents of the elements on top of its border).
Using pixels to define font sizes has an important problem: it ignores
user settings. No matter whether users set their font size to 16px (the
default font size in most browsers), to 18px (like I do) or to 32 px
(like users with huge screens or with a visual disability); the size
will not change.
Even if most browsers can zoom to somehow overcome this issue, it's
still annoying. And, in our case, we use relative units most of the time
but absolute units in some places. This leads to situations where some
of the text gets larger when users increase their font size while some
of the text remains the same. Sometimes this results in titles having a
smaller size than regular text below it.
The solution is using relative units everywhere. Quoting the Web
Accessibility Initiative guide for styles [1]:
> The user needs to be able to resize the text to 200% of its size
> anywhere on the page, without the text being cut off or overlapping
> other text. The font size should be defined in relative units, such as
> percentages, em or rem. It is not possible to zoom text set in pixels
> independently from the rest of the page in some browsers.
[1] https://www.w3.org/WAI/tutorials/page-structure/styling/
Note we don't cast negative votes when users remove their support. That
way we provide compatibility for institutions who have implemented real
negative votes (in case there are / will be any), and we also keep the
database meaningful: it's not that users downvoted something; they
simply removed their upvote.
Co-Authored-By: Javi Martín <javim@elretirao.net>
Co-Authored-By: Julian Nicolas Herrero <microweb10@gmail.com>
This way it's easier to find the keys: keys related to the
`Budgets::Investments::VotesComponent` class are in the
`budgets.investments.votes` namespace.
We're making a couple of exceptions; we're not modifying the `supports`
nor the `support_title` keys because they're used in other places.
Since we're going to add an action to remove supports, having a separate
controller makes things easier.
Note there was a strange piece of code which assumed users were not
verified if they couldn't vote investments. Now the code is also
strange, since it assumes users are not verified if they can't create
votes. We might need to revisit these conditions if our logic changes in
the future.
It was hard to notice what was going on when supporting one investment
which was at the bottom of the investment index page.
I wonder whether we should add the title of the investment to this text;
I'm not doing so because we don't do that anywhere else.
In the previous commit I mentioned:
> If I'm right, the `investment_votes` instance variable only exists to
> avoid several database queries to get whether the current user has
> supported each of the investments.
>
> However, that doesn't make much sense when only one investment is
> shown.
Now let's discuss the case when there are several investments, like in
the investments index:
* There are 10 investments per page by default
* Each query takes less than a millisecond
* We still make a query per investment to check whether the current user
voted in a different group
* AFAIK, there have been no performance tests showing these
optimizations make the request to the investments index significantly
faster
* These optimizations make the code way more complex than it is without
them
Considering all these points, I'm removing the optimizations. I'm fine
with adding `includes` calls to preload records and avoid N+1 queries
even if there are no performance tests showing they make the application
faster because the effect on the code complexity is negligible. But
that's not the case here.
Note we're using `defined?` instead of the `||=` operator because the
`||=` operator will not serve its purpose when the result of the
operation returns `false`.
If I'm right, the `investment_votes` instance variable only exists to
avoid several database queries to get whether the current user has
supported each of the investments.
However, that doesn't make much sense when only one investment is shown.
In this case, the number of queries stays the same, and so we can
simplify the code by rendering the component with an optional parameter.
Using links combined with JavaScript to generate POST requests to the
browser has a few issues.
An obvious one is that it doesn't work for users without JavaScript
enabled (which lately I've noticed are more common than I thought, even
though I've been one of them for years). These users will reach a 404
page.
Since CONSUL isn't currently designed to work without JavaScript
enabled, let's ignore this one for now.
A not so obvious issue is screen reader users might expect the link to
take them somewhere instead of performing an action (in this case,
sending a form to the server).
There might be more issues I'm unaware of. Quoting DHH [1]:
"Turning ahrefs into POSTs is a bit of an anti-pattern, especially for
a11y reasons. Better to use button_to with a styling."
So we're using a button instead. This way we can also simplify the code
and make the button disabled for unidentified users, which automatically
makes it impossible to focus it using the keyboard.
A possible disadvantage of using `button_to` is it will create a form
tag which will be announced to screen readers as a form landmark. I've
tested it with my screen reader and everything worked fine for me, but
some screen reader users might interact with these forms in a different
way and find it confusing, particularly in the case where the button is
disabled.
With this change, we're only changing links for buttons in one place.
There are other places where we should do similar changes.
[1] See issue 33 in https://github.com/hotwired/turbo-rails/
This way blind screen reader users will know which project they're
supporting. In a list of investments, context might not be clear when a
link saying "Support" or "Support this project" is announced, but a link
saying "Support Renovate sidewalks in Main Street" is less ambiguous.
When identified users accessed the investments page, we were using the
`aria-hidden` attribute to hide this link from screen readers since
unidentified users can't support investments.
However, the link was still focusable using keyboard navigation. This
resulted in screen reader users reaching the link and being able to
click it, but getting no feedback at all about where they were or what
they were clicking on.
This is why the fourth ARIA rule says: "Do not use role="presentation" or
aria-hidden="true" on a focusable element" [1].
So we're replacing the link with a non-interactive element instead, like
we do in other places like proposals.
The accessibility of this part of the page for unidentified users still
has some issues; here we're only improving it up to a certain point.
[1] https://www.w3.org/TR/using-aria/#4thrule
The `js-` prefix (which I admit I'm not fond of) is usually used to
indicate the class is used by JavaScript files, not for using it in test
files. And in all the other similar tests, we're using the `in-favor`
class instead of the `js-in-favor` class.
This reverts commit 83fe74d53.
When supporting an investment in the management section through the
investment view, we were accessing an action in the public investments
controller. This meant the manager was the one supporting the investment
(as they'd be the `current_user` in this controller) and not the managed
user.
In the case of groups with many headings, voting the first time requires
a confirmation and then a regular (non-AJAX) request takes place. In
this case, users were redirected to the public area instead of remaining
in the management area.
Using the proper URL to vote solves the problem.
Note there was a comment about one of these tests failing in Travis.
Most probably the test failed because there was no expectation after
clicking the link with the investment title, so the "Support" button
(which is also present in the index page) was clicked before the
investment view was loaded.
The key was declared twice and so the first one ("Support this project")
was overwritten.
We're grouping all keys related to the investment list together in order
to reduce the chances of this issue happening again (or, at least, in
this part of the code).
The color we used offered a contrast of 3.94 against the background. The
minimum requirement for AA level is a contrast of 4.5, and we usually
aim for a contrast of 5 at least.
So we're making the text slightly darker so it's easier to read.
An image without an alt text is invalid HTML and is confusing for screen
reader users.
This is just a quick patch which partially solves this problem. The
image doesn't necessarily need to be a decorative one, so administrators
should have the option to provide an alternative text for the images.
Note one of the tests dealing with random results is a bit flaky; since
it's a permutation selecting 7 objects out of 12, it will fail about
once every 4 million times. We think this is acceptable.
Co-Authored-By: Julian Nicolas Herrero <microweb10@gmail.com>
In the form of creating a new investment was hiding the name of the
group if it had only one heading, but could be confusing to users if
there are, for example, five different groups of one heading.
The solution:
- If the budget has one group and one heading, the heading selector is
hidden.
- If the budget has one group and more than one heading, the group name
is hidden.
- If the budget has more than one group, the group name appears
regardless of the number of headings.
Note we're using an extra `<span>` element but we could use a CSS grid
layout instead. We're not using it because browser compatibility is only
94.56% at the time of writing.