Commit Graph

588 Commits

Author SHA1 Message Date
Javi Martín
3d5696aff5 Apply no-redeclare ESLint rule
This rule is part of the `eslint:recommended` package. It was the only
rule we weren't following 100% of the time (other than the line length).
2024-06-18 18:27:32 +02:00
Javi Martín
5fa6db2226 Rename HTML attributes referencing poll options
Since now poll question answers have been renamed to poll question
options, using HTML IDs, classes and data attributes named `answer` was
confusing.
2024-06-13 19:13:05 +02:00
Javi Martín
8997ed316c Rename variables describing poll options as answers
Since we've renamed the class to `Option`, having variables, methods and
texts refering to it as `answer` was confusing.
2024-06-13 19:13:05 +02:00
Javi Martín
38b38d1fcc Rename Poll::Question::Answer to Poll::Question::Option
Having a class named `Poll::Question::Answer` and another class named
`Poll::Answer` was so confusing that no developer working on the project
has ever been capable of remembering which is which for more than a few
seconds.

Furthermore, we're planning to add open answers to polls, and we might
add a reference from the `poll_answers` table to the
`poll_question_answers` table to property differentiate between open
answers and closed answers. Having yet another thing named answer would
be more than what our brains can handle (we know it because we did this
once in a prototype).

So we're renaming `Poll::Question::Answer` to `Poll::Question::Option`.
Hopefully that'll make it easier to remember. The name is also (more or
less) consistent with the `Legislation::QuestionOption` class, which is
similar.

We aren't changing the table or columns names for now in order to avoid
possible issues when upgrading (old code running with the new database
tables/columns after running the migrations but before deployment has
finished, for instance). We might do it in the future.

I've tried not to change the internationalization keys either so
existing translations would still be valid. However, since we have to
change the keys in `activerecord.yml` so methods like
`human_attribute_name` keep working, I'm also changing them in places
where similar keys were used (like `poll_question_answer` or
`poll/question/answer`).

Note that it isn't clear whether we should use `option` or
`question_option` in some cases. In order to keep things simple, we're
using `option` where we were using `answer` and `question_option` where
we were using `question_answer`.

Also note we're adding tests for the admin menu component, since at
first I forgot to change the `answers` reference there and all tests
passed.
2024-06-13 19:13:01 +02:00
Javi Martín
c367f21705 Add buttons to check all/none available languages
Although most Consul Democracy installations will only have a few
available languages using `config.i18n.available_locales`, there's a
chance some installation will keep every language as available and will
enable the desired ones using the admin interface. In these cases,
enabling (or disabling) every language would be tedious, particularly
when casually experimenting in a staging environment or while using the
official Consul Democracy demo.

So we're adding buttons to simplify the process. Since some
installations might have only a couple of available languages, and in
this case these buttons would be pretty much useless, we're only showing
them when there are many languages available.
2024-06-06 16:28:19 +02:00
Javi Martín
a911b0dec7 Extract function in "check all/none" JavaScript file 2024-06-06 16:28:19 +02:00
Javi Martín
f47179ff68 Use buttons to check/uncheck all options
People using screen readers usually expect links to take them somewhere
else in the page on to a different page, while they expect buttons to
change something on the page.

Since we're in the latter scenario, using a button is more accessible.
It's also more natural; with a button, we don't need to provide `#` as
the URL or stop the default event when the button is clicked. And,
unlike links, buttons can be activated with either the space or the
enter key. Finally, clicking a link pointing to `#` with the middle
mouse button opens a useless new tab, while buttons do nothing in this
case.

Now that we only have one "All" link on the page, we no longer need to
specify which "All" link we're clicking or which "All" link we are
checking, so we're simplifying the code doing so.
2024-06-06 16:18:33 +02:00
Javi Martín
14454bdd45 Include data in chart tags instead of using AJAX
Now that we've moved the logic to generate the events data to a model,
and we've got access to the model in the component rendering the chart,
we can render the data inside the chart instead of doing an extra AJAX
request to get the same data.

Originally, this was problaby done this way so the page wouldn't take
several seconds to load while preparing the data for the chart when
there are thousands of dates being displayed. With an AJAX call, the
page would load as fast as usual, and then the chart would render after
a few seconds. However, we can have an even better performance
improvement in this scenario if we use a Set instead of an Array. The
method `Array#include?`, which we were calling for every date in the
data, is much slower that `Set#merge`. So now both the page and the
chart load as fast as expected.

We could also use something like:

```
def add
  (...)
  shared_keys.push(*collection.keys)
end

def build
  (...)
  shared_keys.uniq.each do |k|
  (...)
end

def shared_keys
  @shared_keys ||= []
end
```

Or other approaches to avoid using `Array#include?`. The performance
would be similar to the one we get when using `Set`. We're using a `Set`
because it makes more obvious that `shared_keys` is supposed to contain
unique elements.

We've had some tests failing in the past due to these AJAX requests
being triggered automatically during the tests and no expectations
checking the requests have finished, so now we're reducing the amount of
flaky tests.
2024-05-09 14:28:32 +02:00
Javi Martín
db25dc13e1 Use buttons to open/close admin navigation submenus
We were using Foundation's accordion menu to open/close nested lists of
links. Unfortunately, Foundation's accordion makes it impossible to
access links in nested links using the keyboard [1] (note the issue is
closed, but in the latest version of Foundation, 6.8.1, it's still
present, and Foundation's development is mostly discontinued).
Furtheremore, it adds the `menuitem` role to links, but ARIA menus are
not ment for navigation but for application behavior and, since it
doesn't add the `menubar` or `menu` roles to the parent elements, it
results in accessibility issues for people using screen readers (also
reported by the Axe accessibility testing engine).

So we need to implement our own solution. We're using the most commonly
used pattern: a buttton with the `aria-expanded` attribute. And, for
people using browsers where JavaScript hasn't loaded, we're keeping the
submenus open at all times (just like we were doing until now), and
we're disabling the buttons (since they do nothing without JavaScript).
This might not be an ideal solution, but it's probably good enough, and
way better than what we had until now.

We've also considered using the <details> and <summary> elements instead
of using buttons to open/close items on the list. However, these
elements still present some accessibility issues [2], and the transition
between open and closed can't be animated unless we overwrite the
`click` event with JavaScript. The pattern of using these elements to
open/close a nested list of links isn't common either, and some people
using screen readers might get confused when entering/leaving the nested
list.

We tried other approaches to get the animation effect, all of them based
on adding `[aria-expanded="false"]:not([disabled]) + * { display: none;
}` to the CSS file.

Unfortunately, animation using CSS isn't feasible right now because
browsers can't animate a change form `height: 0` to `height: auto`.
There are some hacks like animating the `max-height` or the `flex-grow`
property, but the resulting animation is inconsistent. A perfect
animation can be done using the `grid-template-rows` property [3], but
it requires adding a grid container and only works in Firefox and recent
versions of Chrome and similar browsers.

Getting to a solution with JavaScript was also tricky. With the
following approach, `slideToggle()` opened the menu the first time, even
if it was already open (not sure why):

```
toggle_buttons.on("click", function() {
  $(this).attr("aria-expanded", !JSON.parse($(this).attr("aria-expanded")));
  $(this).next().slideToggle();
});
```

This made the arrow turn after the menu had slided instead of doing it
at the same time:

```
toggle_buttons.on("click", function() {
  var button = $(this);

  button.next().slideToggle(function() {
    button.attr("aria-expanded",
    !JSON.parse(button.attr("aria-expanded")));
  });
}
```

With this, everything disappeared quickly:

```
toggle_buttons.on("click", function() {
  var expanded = JSON.parse($(this).attr("aria-expanded"));

  if (expanded) {
    $(this).next().slideUp();
  } else {
    $(this).next().slideDown();
  }

  $(this).attr("aria-expanded", !expanded);
}
```

So, in the end, we're hiding the nested link lists with JavaScript
instead of CSS.

[1] Issue 12046 in https://github.com/foundation/foundation-sites
[2] https://www.scottohara.me/blog/2022/09/12/details-summary.html
[3] https://css-tricks.com/css-grid-can-do-auto-height-transitions
2024-04-18 16:10:58 +02:00
Javi Martín
cb3bea8eec Simplify code to ask for send newsletter confirmation
Using the standard `confirm` parameter, we can remove all the custom
code we added to do the same thing.

Since the code is similar, we're doing the same when asking for
confirmation to send notifications.
2024-04-17 16:44:09 +02:00
Javi Martín
35659d4419 Replace initialjs-rails with custom avatar code
The initialjs-rails gem hasn't been maintained for years, and it
currently requires `railties < 7.0`, meaning we can't upgrade to Rails 7
while we depend on it.

Since the code in the gem is simple, and we were already rewriting its
most complex part (generating a background color), we can implement the
same code, only we're using Ruby instead of JavaScript. This way, the
avatars will be shown on browsers without JavaScript as well. Since
we're adding a component test that checks SVG images are displayed even
without JavaScript, we no longer need the test that checked images were
displayed after AJAX requests.

Now the tests show the user experience better; people don't care about
the internal name used to select the initial (which is what we were
checking); they care about the initial actually displayed.

Note initialjs generated an <img> tag using a `src="data:image/svg+xml;`
attribute. We're generating an <svg> tag instead, because it's easier.
For this reason, we need to change the code slightly, giving the <svg>
tag the `img` role and using `aria-label` so its contents won't be read
aloud by screen readers. We could give it a `presentation` role instead
and forget about `aria-label`, but then screen readers would read the
text anyway (or, at least, some of them would).
2024-04-11 18:48:33 +02:00
Javi Martín
bee00db34f Use a node package to install jquery-fileupload
Although the gem is called jquery-fileupload-rails, the node package is
called blueimp-file-upload.

Note we're using the same version as provided by the gem.

The jquery-fileupload gem provided a `basic.js` file (which we were
requiring), which had the following content:

```
//= require jquery-fileupload/vendor/jquery.ui.widget
//= require jquery-fileupload/jquery.iframe-transport
//= require jquery-fileupload/jquery.fileupload
``

This file isn't available in the Node.js package, so we're adapting its
contents in our application.js file. Since we're already requiring
jQuery UI widget, we're omitting that line.
2024-04-03 00:15:48 +02:00
Javi Martín
2fa713c644 Use node packages to install Foundation
Since Foundation hasn't released a new gem for years, we haven't been
able to upgrade Foundation to its most recent version.

Thanks to this change, we'll be able to do so.

Note we're using motion-ui version 2.0.3 because version 2.0.5 (the
latest at the moment) requires Dart Sass.
2024-04-02 14:41:42 +02:00
Javi Martín
f46558b4dd Replace rails-assets.org with Node.js packages
Now that we use NPM, we don't need the wrapper provided by rails-assets
anymore.
2024-03-30 05:10:13 +01:00
Senén Rodero Rodríguez
3e9f2b8319 Load markers cluster layer by chunks
In order to avoid locking the browser for a long time.
when there are a lot of markers in the map:

https://github.com/Leaflet/Leaflet.markercluster#handling-lots-of-markers
2024-01-29 17:56:54 +01:00
Pierre Mesure
e5a6a5bf1d Adding clustering 2024-01-29 17:56:54 +01:00
Senén Rodero Rodríguez
ef14636b6c Sort variables alphabetically 2024-01-29 17:56:54 +01:00
Senén Rodero Rodríguez
0186484fac Use leaflet npm version instead of the gem 2024-01-29 17:56:54 +01:00
Julian Herrero
60a0fcfea5 Refresh CSRF Token when using Turbolinks 2023-11-30 18:57:29 +01:00
taitus
7c771b28b5 Add password complexity 2023-10-24 19:00:43 +02:00
Javi Martín
a8bd5eb192 Rename document/image fields HTML classes
Using the `document` or `documents` classes meant styles defined for the
public list of documents conflict with these ones.

So now we're using HTML classes that match the name of the Ruby
component classes, as we usually do.
2023-10-23 15:49:01 +02:00
Javi Martín
3b6fb85c51 Use node packages to install jQuery and jQuery UI
Other packages depend on jQuery, so that's why these are the first one
we move from the Gemfile to the package.json file.

This way we can also test whether dependabot correctly opens pull
requests to update Node packages.

I've tried several configuration options for the asset pipeline in order
to be able to include images referenced in jQuery UI CSS files. So far,
adding the `node_modules/jquery-ui/themes/base` folder to the assets
paths is the only way I've found to make it work. Hopefully we can find
a better solution in the future so we don't have to study the internals
of every Node package in order to integrate it with the assets pipeline.
2023-10-17 13:12:20 +02:00
Javi Martín
21a268ab96 Remove alert for Internet Explorer 8 and below
Internet Explorer 8 was released in 2009 and people using it already
know that most web pages look broken on it, so we don't need to warn
them.

Removing it makes our application layout file much easier to read and
modify.
2023-09-07 19:44:54 +02:00
Javi Martín
175c1a752b Remove old comment referencing the project name
It was obvious which project the comment was about. Also, no point
having a TODO referencing what to do after upgrading to Rails 5.1, since
we did it years ago.
2023-07-12 16:05:33 +02:00
Javi Martín
629756dd15 Change URLs referencing our GitHub repositories 2023-07-12 16:05:26 +02:00
Javi Martín
970a64e276 Enable mousewheel when focusing on the map
Zooming with the mousewheel is useful when you want to use it, but
annoying when you don't want to.

Here we're taking an intermediary approach: by default, the mousewheel
isn't active, but it will be active after focusing on the map, so it can
be used both to scroll and to zoom.

This behavior presents usability issues, though, since we aren't making
users aware of the way the mousewheel works, and even if they were
aware, it could be confusing anyway. However, I currently think it's
better than always enabling or always disabling the mousewheel (might
change my mind, though).

Note that the "focus" event is only used on the map, so if we click on a
marker or navigate to a marker with the keyboard without focusing on the
map first, the mousewheel isn't enabled. The same would happen if we
used the "click" event.

We might use the Leaflet.GestureHandling plugin in the future to deal
with this issue and the scroll on touch screens.
2023-06-29 15:54:07 +02:00
Senén Rodero Rodríguez
3fa3c90db6 Fix map markers navigation for keyboard users
By using the bindPopup function instead of the click event
popups work when using the keyboard.

Note that now we are loading all the map markers in the first
request in a single query to the database (needed when there
is a lot or markers to show). Because of that we removed the
AJAX endpoint.
2023-06-26 20:33:35 +02:00
Javi Martín
a9029be93d Include heading geozone in investments sidebar map
Note that, in this case, we aren't binding a popup to the polygon
because the link would point to the same page we're already in.
2023-05-31 16:56:15 +02:00
Matheus Miranda
de13e789dd Add polygon geographies to Budgets' map
Note that in the budgets wizard test we now create district with no
associated geozone, so the text "all city" will appear in the districts
table too, meaning we can't use `within "section", text: "All city" do`
anymore since it would result in an ambiguous match.

Co-Authored-By: Julian Herrero <microweb10@gmail.com>
Co-Authored-By: Javi Martín <javim@elretirao.net>
2023-05-31 16:56:15 +02:00
Javi Martín
8b14522bf5 Use a button instead of a link to remove a marker
Using a button for interactive elements is better, as explained in
commit 5311daadf.

Since buttons with "type=button" do nothing by default, we no longer
need to call `preventDefault()` when clicking it.
2023-05-04 15:32:33 +02:00
Javi Martín
b0680628ba Extract function to add investment markers 2023-05-04 15:27:15 +02:00
Javi Martín
21ce7689c2 Don't overwrite marker when creating investment markers
The `marker` variable is like a global variable inside the
`initializeMap` function, so assigning it inside the `createMarker`
function was changing its value in other places.

So we're using different variable names like `newMarker` in order to
make the code easier to follow. Now we "only" change the `marker`
variable in functions that modify the marker.
2023-05-04 15:27:15 +02:00
Javi Martín
74d165ae7a Extract function to create a map 2023-05-04 15:27:15 +02:00
Javi Martín
2e8bc11c2a Extract functions to update map form fields 2023-05-04 15:27:15 +02:00
Javi Martín
f8053c9532 Extract function to get popup in map JavaScript 2023-05-04 15:27:15 +02:00
Javi Martín
4087066c59 Extract function to add map attribution 2023-05-04 15:27:15 +02:00
Javi Martín
00cd91c6b2 Extract functions to get coordinates in map JS
We had 130 lines long function, and we're trying to reduce its size so
it's easier to follow the code.
2023-05-04 15:27:15 +02:00
Senén Rodero Rodríguez
c3439ab539 Keep the same attribution as it was in previous versions 2023-04-14 14:38:53 +02:00
Senén Rodero Rodríguez
3341c45e61 Disable scroll wheel for zooming in favor of map zoom buttons
It's causing annoying behaviour for desktop users when scrolling
the page to the bottom and there is more content below the
map.

The behaviour of touchable devices does not seem to be
affected by this change and keeps behaving the same.
2023-03-28 12:15:26 +02:00
Javi Martín
e1e16d21c3 Allow having tenants with different domains
Some institutions using CONSUL have expressed interest in this feature
since some of their tenants might already have their own domains.

We've considered many options for the user interface to select whether
we're using a subdomain or a domain, like having two separate fields,
using a check box, ... In the end we've chosen radio buttons because
they make it easier to follow a logical sequence: first you decide
whether you're introducing a domain or subdomain, and then you enter it.

We've also considered hiding this option and assuming "if it's got a
dot, it's a domain". However, this wouldn't work with nested subdomains
and it wouldn't work with domains which are simply machine names.

Note that a group of radio buttons (or check boxes) is difficult to
style when the text of the label might expand over more than one line
(as is the case here on small screens); in this case, most solutions
result in the second line of the label appearing immediately under the
radio button, instead of being aligned with the first line of the label.
That's why I've added a container for the input+label combination.
2022-12-13 13:10:02 +01:00
decabeza
815a526d78 Add VotationType fields to admin poll question form 2022-10-18 10:38:59 +02:00
decabeza
d2cc110678 Use this instead of the CSS selector .sortable
In this context, `this` already points to the element, so there is no
need to search it again.
2022-10-18 10:38:59 +02:00
Senén Rodero Rodríguez
64676be246 Remove token column from poll_voters table
As it is no longer used as originally pretended [1][2].

[1] Check consul/consul pull request 1994
[2] Check consul/consul pull request 3539
2022-09-22 10:34:07 +02:00
Javi Martín
5a0fde4048 Allow selecting the time when a poll starts/ends
We were already saving it as a time, but we didn't offer an interface to
select the time due to lack of decent browser support for this field
back when this feature was added.

However, nowadays all major browsers support this field type and, at the
time of writing, at least 86.5% of the browsers support it [1]. This
percentage could be much higher, since support in 11.25% of the browsers
is unknown.

Note we still need to support the case where this field isn't supported,
and so we offer a fallback and on the server side we don't assume we're
always getting a time. We're doing a strange hack so we set the field
type to text before changing its value; otherwise old Firefox browsers
crashed.

Also note that, until now, we were storing end dates in the database as
a date with 00:00 as its time, but we were considering the poll to be
open until 23:59 that day. So, in order to keep backwards compatibility,
we're adding a task to update the dates of existing polls so we get the
same behavior we had until now.

This also means budget polls are now created so they end at the
beginning of the day when the balloting phase ends. This is consistent
with the dates we display in the budget phases table.

Finally, there's one test where we're using `beginning_of_minute` when
creating a poll. That's because Chrome provides an interface to enter a
time in a `%H:%M` format when the "seconds" value of the provided time
is zero. However, when the "seconds" value isn't zero, Chrome provides
an interface to enter a time in a `%H:%M:%S` format. Since Capybara
doesn't enter the seconds when using `fill_in` with a time, the test
failed when Capybara tried to enter a time in the `%H:%M` format when
Chrome expected a time in the `%H:%M:%S` format.

To solve this last point, an alternative would be to manually provide
the format when using `fill_in` so it includes the seconds.

[1] https://caniuse.com/mdn-html_elements_input_type_datetime-local
2022-09-14 15:14:23 +02:00
Senén Rodero
3ecf2feb2e Merge pull request #4601 from consul/budgets_hide_money
Add hide money option for approval budgets
2022-03-30 09:58:29 +02:00
decabeza
80e64590b7 Allow enable 'hide_money' check on admin budget form
Add new 'hide_money' field to admin budget form.

Only display new field 'hide_money' when voting style is 'approval'
2022-03-29 14:49:25 +02:00
Javi Martín
ea026dbe5e Require custom JavaScript after everything else
This way we make sure the custom JavaScript will overwrite anything in
the original code.
2022-03-18 17:20:33 +01:00
Javi Martín
95c1999cca Make it easier to customize JavaScript functions
When there was a custom JavaScript file, we weren't loading the original
one, meaning that, in order to customize it, it was necessary to copy
the whole original file and then changing it.

Now we're loading both the original and the custom file, so the custom
file can simply add more functions or overwrite the ones we'd like to
customize, without copying the whole file.

Existing copies of original files will still overwrite the whole file
and won't be affected.
2022-03-18 16:43:14 +01:00
Javi Martín
abec716308 Show "not allowed" message on click
Defining a behavior on hover means making it different for people using
a keyboard or a touchscreen (most of the population, nowadays).

In this case, we had an accessibility issue where the message wouldn't
disappear once it appeared. That meant that, after tabbing through all
the links and buttons in, for instance, the debates index, the page
would be filled with "participation not allowed" messages, and in order
to see the information about how many people have voted, reloading the
page was required.

For touchscreen users the behavior was similar to what we get on hover,
although we've found some inconsistencies when trying to support several
elements on the same page.

We think in proposals it makes sense to hide the "support" button when
users click on it, and the same applies to the buttonsto support and
vote investment projects. However, we aren't hiding the buttons to
agree/disagree with a debate in order to keep the information about the
current number of people agreeing and disagreeing visible.

Note we're removing some support spec methods because after these
changes the duplication isn't as obvious as it was in the past.
2022-02-23 16:43:37 +01:00
Javi Martín
a0b4e35dbd Show login to comment message in annotations
This way it's consistent with what we get when there are no comments. It
only appears once on the page so it isn't overwhelming.
2022-02-21 18:48:09 +01:00