aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiquel Sabaté Solà <msabate@suse.com>2024-03-19 11:19:53 +0100
committerMiquel Sabaté Solà <msabate@suse.com>2024-03-19 11:19:53 +0100
commit2ae03c9852922ff23ce79910ce499bfb8c7644e6 (patch)
treea9ef466bb37c6705290aaaf761ce866cd74931f6
parent6c5f73b241d3b31123fbbc61cc4acf76adae8d5e (diff)
downloadoperum-2ae03c9852922ff23ce79910ce499bfb8c7644e6.tar.gz
operum-2ae03c9852922ff23ce79910ce499bfb8c7644e6.zip
thing: improved the UX on the form
The "target" field is not autocompleted unless users explicitely change its value themselves. The autocompletion is built from the authors last name combo plus the year (which is rather naive, but effective for most cases). Moreover, some fields have been moved and the "access" field will only appear if "url" is set. Signed-off-by: Miquel Sabaté Solà <msabate@suse.com>
-rw-r--r--app/javascript/controllers/thing_controller.js63
-rw-r--r--app/views/things/_form.html.erb48
2 files changed, 88 insertions, 23 deletions
diff --git a/app/javascript/controllers/thing_controller.js b/app/javascript/controllers/thing_controller.js
index 1518216..9c19eb6 100644
--- a/app/javascript/controllers/thing_controller.js
+++ b/app/javascript/controllers/thing_controller.js
@@ -2,6 +2,67 @@ import { Controller } from "@hotwired/stimulus"
// Gathers all the methods that are relevant when manipulating things.
export default class extends Controller {
+ static targets = ["identifier"];
+
+ connect() {
+ // The "target" completion is achieved by managing updates from authors
+ // (first part) and year (last one). We have to account when connecting that
+ // we might come from a reload of the page, which would contain partial
+ // data. Hence, this ought to be initialized with the current values from
+ // their respective inputs.
+ this.firstPart = document.getElementById("thing_authors").value.trim();
+ this.lastPart = document.getElementById("thing_year").value.trim();
+
+ // Whether autocompletion has been canceled or not. This will be forced to
+ // true when `#cancel` is called (i.e. the user has manually entered a value
+ // for "target"), or if we are coming from a page that already had data
+ // filled in.
+ this.canceled = this.firstPart !== '' && this.lastPart !== '' &&
+ document.getElementById("thing_target").value.trim() !== '';
+ }
+
+ // Update the information we get from the authors field so to autocomplete it
+ // into the "target" field if possible.
+ authorsUpdate() {
+ if (this.canceled) {
+ return;
+ }
+
+ const text = document.getElementById("thing_authors").value.trim();
+ if (text === '') {
+ return;
+ }
+
+ const authors = text.split(',').map(function(author) {
+ return author.split(' ').pop().trim();
+ });
+
+ this.firstPart = authors.join('');
+ this.identifierTarget.value = `${this.firstPart}${this.lastPart}`;
+ }
+
+ // Update the information we get from the year field so to autocomplete it
+ // into the "target" field if possible.
+ yearUpdate() {
+ if (this.canceled) {
+ return;
+ }
+
+ const text = document.getElementById("thing_year").value.trim();
+ if (text === '') {
+ return;
+ }
+
+ this.lastPart = text;
+ this.identifierTarget.value = `${this.firstPart}${this.lastPart}`;
+ }
+
+ // The user is writing into the "target" field directly: cancel autocompletion
+ // altogether.
+ cancel() {
+ this.canceled = true;
+ }
+
// Update the external link depending on the changed value. The link will also
// be hidden/shown depending if the current URL is empty or not.
updateLink() {
@@ -9,8 +70,10 @@ export default class extends Controller {
if (cur === "") {
document.getElementById("thing-external-url-id").classList.add('hidden');
+ document.getElementById("thing-access-div").classList.add('hidden');
} else {
document.getElementById("thing-external-url-id").classList.remove('hidden');
+ document.getElementById("thing-access-div").classList.remove('hidden');
document.getElementById("thing-external-url-id").href = cur;
}
}
diff --git a/app/views/things/_form.html.erb b/app/views/things/_form.html.erb
index 4aa3dc7..11d2230 100644
--- a/app/views/things/_form.html.erb
+++ b/app/views/things/_form.html.erb
@@ -1,7 +1,7 @@
<%= form_with(model: thing) do |form| %>
<%= render "layouts/errors", model: thing %>
- <div id="thing_form">
+ <div id="thing_form" data-controller="thing">
<div class="thing_large">
<%= form.label :title %>
<%= form.text_field :title, autofocus: true, autocapitalize: 'on', required: true %>
@@ -9,7 +9,7 @@
<div class="thing_large">
<%= form.label :authors %>
- <%= form.text_field :authors, autocapitalize: 'words', required: true %>
+ <%= form.text_field :authors, autocapitalize: 'words', "data-action": "thing#authorsUpdate", required: true %>
<%= form.check_box :editors %>
<%= form.label :editors %>
</div>
@@ -20,36 +20,18 @@
</div>
<div>
- <%= form.label :target %>
- <%= form.text_field :target, autocapitalize: 'on', required: true %>
- </div>
-
- <div>
<%= form.label :publisher %>
<%= form.text_field :publisher, autocapitalize: 'on' %>
</div>
<div>
<%= form.label :year %>
- <%= form.number_field :year %>
+ <%= form.number_field :year, "data-action": "thing#yearUpdate" %>
</div>
<div>
- <%= form.label :address %>
- <%= form.text_field :address, autocapitalize: 'on' %>
- </div>
-
- <div data-controller="thing">
- <%= form.label :url do %>
- <%= I18n.t('activerecord.attributes.thing.url') %>
- <a id="thing-external-url-id" href="<%= thing.url %>" target="_blank" title="<%= I18n.t('things.go-to') %>" class="<%= 'hidden' if thing.url.blank? %>"><i class="gg-external"></i></a>
- <% end %>
- <%= form.text_field :url, "data-action": "thing#updateLink" %>
- </div>
-
- <div>
- <%= form.label :access %>
- <%= form.date_field :access %>
+ <%= form.label :target %>
+ <%= form.text_field :target, autocapitalize: 'on', "data-action": "thing#cancel", "data-thing-target": "identifier", required: true %>
</div>
<div>
@@ -68,6 +50,26 @@
</div>
<div>
+ <%= form.label :address %>
+ <%= form.text_field :address, autocapitalize: 'on' %>
+ </div>
+
+ <div>
+ <%= form.label :url do %>
+ <%= I18n.t('activerecord.attributes.thing.url') %>
+ <a id="thing-external-url-id" href="<%= thing.url %>" target="_blank" title="<%= I18n.t('things.go-to') %>" class="<%= 'hidden' if thing.url.blank? %>"><i class="gg-external"></i></a>
+ <% end %>
+ <%= form.text_field :url, "data-action": "thing#updateLink" %>
+ </div>
+
+ <div>
+ <div id="thing-access-div" class="<%= 'hidden' if thing.url.blank? %>">
+ <%= form.label :access %>
+ <%= form.date_field :access %>
+ </div>
+ </div>
+
+ <div>
<%= form.label :status %>
<%= form.select :status, options_for_select(Thing.statuses.map { |k, _| [I18n.t("things.status.#{k}"), k] }.sort, thing.status) %>
</div>