]> git.agnieray.net Git - galette.git/commitdiff
Fix keyboard navigation accessibility
authorGuillaume AGNIERAY <dev@agnieray.net>
Wed, 8 Nov 2023 14:38:03 +0000 (15:38 +0100)
committerJohan Cwiklinski <johan@x-tnd.be>
Mon, 13 Nov 2023 18:15:30 +0000 (19:15 +0100)
refs #1735

Fix keyboard navigation order
Emphasize focused elements outline style
Fix navigation accordion and dropdowns keyboard accessibility
Improve compact menu accessibility
Clean unused menus_macros.twig template
Remove/Replace onChange callbacks on selects and dropdowns:
- on members' list filters (removed)
- on records per page
- on batch actions
- on labels translation
- on email texts edition
- on contrib form
- on advanced search

23 files changed:
galette/lib/Galette/Controllers/TextController.php
galette/templates/default/elements/language.html.twig
galette/templates/default/elements/list.html.twig
galette/templates/default/elements/logged_user.html.twig
galette/templates/default/elements/navigation/menus_macros.twig [deleted file]
galette/templates/default/elements/navigation/navigation_aside.html.twig
galette/templates/default/elements/navigation/navigation_sidebar.html.twig
galette/templates/default/elements/navigation/navigation_topbar.html.twig
galette/templates/default/elements/navigation/public_pages.html.twig
galette/templates/default/macros.twig
galette/templates/default/pages/advanced_search.html.twig
galette/templates/default/pages/configuration_dynamic_translations.html.twig
galette/templates/default/pages/configuration_texts.html.twig
galette/templates/default/pages/contribution_form.html.twig
galette/templates/default/pages/member_form.html.twig
galette/templates/default/pages/members_list.html.twig
galette/templates/default/pages/transaction_form.html.twig
ui/js/common.js
ui/semantic/galette/collections/form.overrides
ui/semantic/galette/collections/menu.overrides
ui/semantic/galette/collections/menu.variables
ui/semantic/galette/globals/site.overrides
ui/semantic/galette/modules/dropdown.overrides

index 7219d4a5cb37555cbe6389512112d6d84b5e8afc..cd4f44e66d2466d1d0ffb7c5f6d473bb621a7b19 100644 (file)
@@ -93,6 +93,7 @@ class TextController extends AbstractController
                 'reflist'           => $texts->getRefs($lang),
                 'langlist'          => $this->i18n->getList(),
                 'cur_lang'          => $lang,
+                'cur_lang_name'     => $this->i18n->getNameFromId($lang),
                 'cur_ref'           => $ref,
                 'mtxt'              => $mtxt,
             ]
index 4f92c2b1865a785542a13b6a3b25660313a81775..23aa6616d90b29c87b1cdcb6276d11e5ca0b01a4 100644 (file)
@@ -3,8 +3,8 @@
         {% set component_classes = "tooltip language item" %}
         {% set content_classes = "content" %}
         {% set header = true %}
-    {%  elseif ui == 'dropdown' %}
-        {% set component_classes = "tooltip language ui dropdown right-aligned item" %}
+    {% elseif ui == 'dropdown' %}
+        {% set component_classes = "tooltip language ui dropdown navigation right-aligned item" %}
         {% set content_classes = "menu" %}
         {% set header = false %}
     {% endif %}
 
 <div class="{{ component_classes }}{% if i18n.isRtl() %} rtl{% endif %}" title="{{ _T("Choose your language") }}">
 {% if header == true %}
-<div class="image header title">
+    <div class="image header title"{% if ui == 'item'%}data-fold="fold-language" tabindex="0"{% endif %}>
 {% endif %}
-    <i class="icon language" aria-hidden="true"></i>
-    <span>{{ galette_lang }}</span>
-    <i class="dropdown icon" aria-hidden="true"></i>
+        <i class="icon language" aria-hidden="true"></i>
+        <span>{{ galette_lang }}</span>
+        <i class="dropdown icon" aria-hidden="true"></i>
 {% if header == true %}
-</div>
+    </div>
 {% endif %}
-<div class="{{ content_classes }}">
-    {% for langue in languages %}
-        {% if langue.getAbbrev() != galette_lang %}
-    <a href="?ui_pref_lang={{ langue.getID() }}"
-       title="{{ _T("Switch locale to '%locale'")|replace({"%locale": langue.getName()}) }}"
-       class="item"
-    >
-        {{ langue.getName() }} <span>({{ langue.getAbbrev() }})</span>
-    </a>
-        {% endif %}
-    {% endfor %}
-</div>
+    <div class="{{ content_classes }}">
+{% for langue in languages %}
+    {% if langue.getAbbrev() != galette_lang %}
+        <a href="?ui_pref_lang={{ langue.getID() }}"
+           title="{{ _T("Switch locale to '%locale'")|replace({"%locale": langue.getName()}) }}"
+           class="item"
+        >
+            {{ langue.getName() }} <span>({{ langue.getAbbrev() }})</span>
+        </a>
+    {% endif %}
+{% endfor %}
+    </div>
 </div>
index c5617bc8b0b04d7771a85c6bf6d6c3f799124eb1..5cc3357d907d68c4f5dbfdf7ebe9d76807a87cff 100644 (file)
                     <div class="ui basic right aligned fitted segment">
                         <div class="inline field">
                             <label for="nbshow">{{ _T('Records per page:') }}</label>
-                            <select name="nbshow" id="nbshow" class="ui dropdown nochosen">
+                            <div class="ui dropdown selection autosubmit">
+                                <input type="hidden" name="nbshow" value="{{ numrows }}">
+                                <i class="dropdown icon"></i>
+                                <div class="text">{% if numrows == 0 %}{{ _T('All') }}{% else %}{{ numrows }}{% endif %}</div>
+                                <div class="menu">
                                 {% for key, value in nbshow_options %}
-                                    <option value="{{ key }}"{% if key == numrows %} selected="selected"{% endif %}>{{ value }}</option>
+                                    <div class="item{% if key == numrows %} active selected {% endif %}" data-value="{{ key }}">{{ value }}</div>
                                 {% endfor %}
-                            </select>
-                            <noscript><span><input type="submit" value="{{ _T('Change') }}" class="ui button" /></span></noscript>
+                                </div>
+                            </div>
                         </div>
                     </div>
         {% endif %}
             {% endif %}
                 $('.batch-select-action').before(_checklinks);
                 $('.batch-select-action').dropdown({
-                    onChange: function(value, text, $selectedItem) {
+                    action: function(text, value, element) {
                         if (!_checkselection()) {
                             return false;
                         }
+                        // Hide dropdown
+                        var element = element.parentElement !== undefined ? element : element[0];
+                        var dropdown = element.parentElement.parentElement;
+                        $(dropdown).dropdown('hide');
                         // Handle direct download actions.
                         if (value.endsWith('__directdownload')) {
                             const _value = value.split('__');
index 146fa73d7891abfc816134974dbc750b452a9164..92275b8a185edc9e7868174d445d2c8ffebad51e 100644 (file)
             </div>
             {% include "elements/modes.html.twig" %}
         {% else %}
-            {% set component_classes = "ui vertical centered tiny fluid icon menu" %}
+            {% set component_classes = "ui vertical centered tiny icon fluid menu" %}
             <div id="logoutmenu" class="{{ component_classes }}">
-                <div class="ui dropdown item no-touch tooltip" data-html="{{ login.loggedInAs()|raw }}" data-position="right center">
+                <div class="ui dropdown navigation item no-touch tooltip" data-html="{{ login.loggedInAs()|raw }}" data-position="right center">
                     <i class="user circle icon" aria-hidden="true"></i>
-                    <span class="text displaynone">{{ login.loggedInAs()|raw }}</span>
+                    <span class="displaynone">{{ login.loggedInAs()|raw }}</span>
+                    <i class="dropdown icon" aria-hidden="true"></i>
                     <div class="menu">
                         <div class="item">
                             <div class="ui basic center aligned fitted segment">
                             <div class="ui basic fitted segment">
                                 {% include "elements/modes.html.twig" %}
                             </div>
-                            <a
-                                href="#"
-                                class="ui darkmode{% if login.isDarkModeEnabled() %} black{% endif %} fluid icon button"
-                                title="{% if login.isDarkModeEnabled() %}{{ _T("Disable dark mode") }}{% else %}{{ _T("Enable dark mode") }}{% endif %}"
-                            >
-                                <i class="icon adjust" aria-hidden="true"></i>
-                                {% if login.isDarkModeEnabled() %}{{ _T("Disable dark mode") }}{% else %}{{ _T("Enable dark mode") }}{% endif %}
-                            </a>
-                            <a
-                                class="ui {% if login.isImpersonated() %}purple{% else %}red{% endif %} fluid icon button"
-                                href="{% if login.isImpersonated() %}{{ url_for("unimpersonate") }}{% else %}{{ url_for("logout") }}{% endif %}"
-                            >
-                                <i class="icon {% if login.isImpersonated() %}user secret{% else %}sign out alt{% endif %}" aria-hidden="true"></i>
-                                {% if login.isImpersonated() %}{{ _T("Unimpersonate") }}{% else %}{{ _T("Log off") }}{% endif %}
-                            </a>
                         </div>
                     </div>
                 </div>
+                <a
+                    href="#"
+                    class="item darkmode{% if login.isDarkModeEnabled() %} black{% endif %}"
+                    title="{% if login.isDarkModeEnabled() %}{{ _T("Disable dark mode") }}{% else %}{{ _T("Enable dark mode") }}{% endif %}"
+                    data-position="right center"
+                >
+                    <i class="icon adjust" aria-hidden="true"></i>
+                    <span class="displaynone">{% if login.isDarkModeEnabled() %}{{ _T("Disable dark mode") }}{% else %}{{ _T("Enable dark mode") }}{% endif %}</span>
+                </a>
+                <a
+                    class="item{% if login.isImpersonated() %} purple{% else %} red{% endif %}"
+                    href="{% if login.isImpersonated() %}{{ url_for("unimpersonate") }}{% else %}{{ url_for("logout") }}{% endif %}"
+                    title="{% if login.isImpersonated() %}{{ _T("Unimpersonate") }}{% else %}{{ _T("Log off") }}{% endif %}"
+                    data-position="right center"
+                >
+                    <i class="icon {% if login.isImpersonated() %}user secret{% else %}sign out alt{% endif %}" aria-hidden="true"></i>
+                    <span class="displaynone">{% if login.isImpersonated() %}{{ _T("Unimpersonate") }}{% else %}{{ _T("Log off") }}{% endif %}</span>
+                </a>
             </div>
         {% endif %}
     {% endif %}
diff --git a/galette/templates/default/elements/navigation/menus_macros.twig b/galette/templates/default/elements/navigation/menus_macros.twig
deleted file mode 100644 (file)
index 2f3baa3..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-{% macro renderMenu(title, icon, items) %}
-    {% set my_routes = [] %}
-    {% for item in items %}
-        {% set my_routes = my_routes|merge([item.route.name]) %}
-    {% endfor %}
-    <div class="item">
-        <div class="image header title{% if cur_route in my_routes %} active{% endif %}">
-            <i class="{{ icon }} icon" aria-hidden="true"></i>
-            {{ title }}
-            <i class="dropdown icon" aria-hidden="true"></i>
-        </div>
-        <div class="content{% if cur_route in my_routes %} active{% endif %}">
-            {% for item in items %}
-                {{ _self.renderMenuItem(item.label, item.title, item.route, item.icon ?? null) }}
-            {% endfor %}
-        </div>
-    </div>
-{% endmacro %}
-
-{% macro renderMenuItem(label, title, route, icon, class, tips_position) %}
-    {% if class is empty %}
-        {% if is_current_url(route.name, route.args|default([])) %}
-            {% set class = "active item" %}
-        {% else %}
-            {% set class = "item" %}
-        {% endif %}
-    {% endif %}
-    <a
-            href="{{ url_for(route.name, route.args|default([])) }}"
-            class="{{ class }}"
-            title="{{ title }}"
-            {% if tips_position %}data-position="{{ tips_position }}"{% endif %}
-    >
-        {% if icon %}
-            <i class="{{ icon }} icon" aria-hidden="true"></i>
-        {% endif %}
-        {{ label }}
-    </a>
-{% endmacro %}
index 7b85e62befeac94e88d4f0358d290d7bf3f1d886..67a6068cf8b047489f1b368172db4bb2dd5c6fd1 100644 (file)
@@ -14,7 +14,7 @@
 {% endif %}
 
     <div class="ui vertical{% if not login.getCompactMenu() %} accordion compact{% else %} tiny icon{% endif %} fluid menu">
-        {% set mode = login.getCompactMenu() ? "compact" : "accordion" %}
+        {% set mode = login.getCompactMenu() ? "compact" : "default" %}
         {% include "elements/navigation/navigation_items.html.twig" with {
                 mode: mode
         } %}
index 6b6d80fe413aac0d7656e96f9be176f943ae9ab0..cfcd65a2052573301674785a0f981762d581a72d 100644 (file)
@@ -1,4 +1,4 @@
-    <div class="ui simple left vertical accordion menu sidebar">
+    <div id="sidebarmenu" class="ui simple left vertical accordion menu sidebar">
 {% if not login.isLogged() %}
     {% if cur_route != "login" %}
         {% import "macros.twig" as menus_macros %}
 
     {% include "elements/navigation/public_pages.html.twig" with {
             tips_position: "right center",
-            sign_in: true
+            sign_in: true,
+            mode: "default"
     } %}
 {% else %}
-    {% include "elements/navigation/navigation_items.html.twig" %}
+    {% include "elements/navigation/navigation_items.html.twig" with {
+            mode: "default"
+    } %}
 {% endif %}
     {% include "elements/language.html.twig" with {
             ui: "item"
index 993b6e0171b2ad80b45a04f6e5de9f2d05742407..81a021799f8c5f3283fcc47c3d753a1a36865c52 100644 (file)
@@ -1,7 +1,8 @@
 <header id="top-navbar" class="ui top fixed menu">
     <div class="ui fluid container">
-        <a class="toc item">
+        <a class="toc item" tabindex="0">
             <i class="sidebar icon" aria-hidden="true"></i>
+            <span class="displaynone">{{ _T("Menu") }}</span>
         </a>
         {% if login.isLogged() and (cur_route != 'mailing' and existing_mailing == true) %}
             <a
@@ -23,7 +24,8 @@
         {% include "elements/navigation/public_pages.html.twig" with {
                 tips_position: "bottom center",
                 sign_in: true,
-                sign_in_side: 'right'
+                sign_in_side: 'right',
+                mode: "default"
         } %}
 
         {% include "elements/language.html.twig" with {
index 89b26c5c5c59321fc9c7dbfefc607b41efe7b55e..a6f92ed006c1b715c9117632ad1cde26aca16d5c 100644 (file)
@@ -4,7 +4,7 @@
     {% set public_menus = callstatic('\\Galette\\Core\\Galette', 'getPublicMenus') %}
     {% for public_menu in public_menus %}
         {% for public_item in public_menu.items %}
-            {{ menus_macros.renderMenuItem(public_item.label, public_item.title, public_item.route, public_item.icon ?? null, null, tips_position) }}
+            {{ menus_macros.renderMenuItem(public_item.label, public_item.title, public_item.route, public_item.icon ?? null, null, tips_position, mode) }}
         {% endfor %}
     {% endfor %}
 
@@ -30,7 +30,7 @@
     {% endif %}
 
     {% for public_item in public_items %}
-        {{ menus_macros.renderMenuItem(public_item.label, public_item.title, public_item.route, public_item.icon, public_item.class, tips_position) }}
+        {{ menus_macros.renderMenuItem(public_item.label, public_item.title, public_item.route, public_item.icon, public_item.class, tips_position, mode) }}
     {% endfor %}
         <a
             href="#"
index 93eb8c14cb1c199169cfeaa57f19c67ebe2c9a2f..90101d81a896fb009f57f43d66923aba56e0a2bb 100644 (file)
@@ -4,9 +4,10 @@
         {% set my_routes = my_routes|merge([item.route.name])|merge(item.route.aliases ?? []) %}
     {% endfor %}
     {% if mode == "compact" %}
-        <div class="ui{% if cur_route in my_routes %} active-menu{% endif %} dropdown item no-touch tooltip" data-html="{{ title }}" data-position="right center">
+        <div class="ui{% if cur_route in my_routes %} active-menu{% endif %} dropdown navigation item no-touch tooltip" data-html="{{ title }}" data-position="right center">
             <i class="{{ icon }} icon" aria-hidden="true"></i>
             <span class="displaynone">{{ title }}</span>
+            <i class="dropdown icon" aria-hidden="true"></i>
             <div class="menu">
                 {% for item in items %}
                     {{ _self.renderMenuItem(item.label, item.title, item.route, item.icon ?? null, null, 'right center') }}
         </div>
     {% else %}
         <div class="item">
-            <div class="image header title{% if cur_route in my_routes %} active{% endif %}">
+            <div class="image header title{% if cur_route in my_routes %} active{% endif %}" data-fold="fold-{{ icon|replace({' ': '-'}) }}" tabindex="0">
                 <i class="{{ icon }} icon" aria-hidden="true"></i>
                 {{ title }}
                 <i class="dropdown icon" aria-hidden="true"></i>
             </div>
             <div class="content{% if cur_route in my_routes %} active{% endif %}">
                 {% for item in items %}
-                    {{ _self.renderMenuItem(item.label, item.title, item.route, item.icon ?? null) }}
+                    {{ _self.renderMenuItem(item.label, item.title, item.route, item.icon ?? null, null, null, mode) }}
                 {% endfor %}
             </div>
         </div>
     {% endif %}
 {% endmacro %}
 
-{% macro renderMenuItem(label, title, route, icon, class, tips_position) %}
+{% macro renderMenuItem(label, title, route, icon, class, tips_position, mode) %}
     {% if class is empty %}
         {% if is_current_url(route.name, route.args|default([])) or (cur_route in route.aliases ?? [] and route.sub_select ?? true == true) %}
             {% set class = "active item" %}
@@ -42,6 +43,7 @@
             class="{{ class }}"
             title="{{ title }}"
             {% if tips_position %}data-position="{{ tips_position }}"{% endif %}
+            {% if mode != "default" %}tabindex="-1"{% endif %}
     >
         {% if icon %}
             <i class="{{ icon }} icon" aria-hidden="true"></i>
index f3f03307c4db109fac97f80a202779e113105d04..3765134bdb83a6712467eed1f4eeed40ab7a3e1f 100644 (file)
@@ -15,7 +15,7 @@
                         </div>
                         <div class="field">
                             <label for="field_filter">{{ _T('in:') }}</label>
-                            <select name="field_filter" class="ui search dropdown origselect nochosen">
+                            <select name="field_filter" class="ui search dropdown nochosen">
     {% for key, value in field_filter_options %}
                                 <option value="{{ key }}"{% if key == filters.field_filter %} selected="selected"{% endif %}>{{ value }}</option>
     {% endfor %}
@@ -23,7 +23,7 @@
                         </div>
                         <div class="field">
                             <label for="membership_filter">{{ _T('Membership status') }}</label>
-                            <select id="membership_filter" name="membership_filter" class="ui search dropdown origselect nochosen">
+                            <select id="membership_filter" name="membership_filter" class="ui search dropdown nochosen">
     {% for key, value in membership_filter_options %}
                                     <option value="{{ key }}"{% if key == filters.membership_filter %} selected="selected"{% endif %}>{{ value }}</option>
     {% endfor %}
@@ -31,7 +31,7 @@
                         </div>
                         <div class="field">
                             <label for="filter_account">{{ _T('Account activity') }}</label>
-                            <select id="filter_account" name="filter_account" class="ui search dropdown origselect nochosen">
+                            <select id="filter_account" name="filter_account" class="ui search dropdown nochosen">
     {% for key, value in filter_accounts_options %}
                                     <option value="{{ key }}"{% if key == filters.filter_account %} selected="selected"{% endif %}>{{ value }}</option>
     {% endfor %}
@@ -39,7 +39,7 @@
                         </div>
                         <div class="field">
                             <label for="group_filter">{{ _T('Member of group') }}</label>
-                            <select name="group_filter" id="group_filter" class="ui search dropdown origselect nochosen">
+                            <select name="group_filter" id="group_filter" class="ui search dropdown nochosen">
                                 <option value="0">{{ _T('Select a group') }}</option>
 {% for group in filter_groups_options %}
                                 <option value="{{ group.getId() }}"{% if filters.group_filter == group.getId() %} selected="selected"{% endif %}>{{ group.getIndentName()|raw }}</option>
                         </div>
                         <div class="field">
                             <label for="status">{{ _T('Status') }}</label>
-                            <select name="status[]" id="status" multiple="" class="ui search dropdown origselect nochosen">
+                            <select name="status[]" id="status" multiple="" class="ui search dropdown nochosen">
                                 <option value="">{{ _T('Status') }}</option>
     {% for key, value in statuts %}
-                                    <option value="{{ key }}"{% if key == filters.status %} selected="selected"{% endif %}>{{ value }}</option>
+                                    <option value="{{ key }}"{% if key in filters.status %} selected="selected"{% endif %}>{{ value }}</option>
     {% endfor %}
                             </select>
                         </div>
                 </div>
                 <div class="active content">
                     <div class="field">
-                        <select name="groups_logical_operator" class="operator_selector ui search dropdown origselect nochosen">
+                        <select name="groups_logical_operator" class="operator_selector ui search dropdown nochosen">
                           <option value="{{ constant("Galette\\Filters\\AdvancedMembersList::OP_AND") }}"{% if filters.groups_search_log_op == constant("Galette\\Filters\\AdvancedMembersList::OP_AND") %} selected="selected"{% endif %}>{{ _T('In all selected groups') }}</option>
                           <option value="{{ constant("Galette\\Filters\\AdvancedMembersList::OP_OR") }}"{% if filters.groups_search_log_op == constant("Galette\\Filters\\AdvancedMembersList::OP_OR") %} selected="selected"{% endif %}>{{ _T('In any of selected groups') }}</option>
                         </select>
                                     <i class="arrows alternate icon" aria-hidden="true"></i>
                                 </div>
                                 <div>
-                                    <select name="groups_search[]" class="group_selector ui search dropdown origselect nochosen">
+                                    <select name="groups_search[]" class="group_selector ui search dropdown nochosen">
                                         <option value="">{{ _T('Select a group') }}</option>
                         {% for group in filter_groups_options %}
                                         <option value="{{ group.getId() }}"{% if gs.group == group.getId() %} selected="selected"{% endif %}>{{ group.getName() }}</option>
                                         <i class="arrows alternate icon" aria-hidden="true"></i>
                                     </div>
                                     <div class="inline fields">
-                                        <select name="free_logical_operator[]" class="operator_selector ui search dropdown origselect nochosen">
+                                        <select name="free_logical_operator[]" class="operator_selector ui selection dropdown nochosen">
                                             <option value="{{ constant("Galette\\Filters\\AdvancedMembersList::OP_AND") }}"{% if fs.log_op == constant("Galette\\Filters\\AdvancedMembersList::OP_AND") %} selected="selected"{% endif %}>{{ _T('and') }}</option>
                                             <option value="{{ constant("Galette\\Filters\\AdvancedMembersList::OP_OR") }}"{% if fs.log_op == constant("Galette\\Filters\\AdvancedMembersList::OP_OR") %} selected="selected"{% endif %}>{{ _T('or') }}</option>
                                         </select>
-                                        <select name="free_field[]" class="field_selector ui search dropdown origselect nochosen">
-                                            <option value="">{{ _T('Select a field') }}</option>
+                                        <div class="field_selector ui search selection dropdown origselect nochosen">
+                                            <input type="hidden" name="free_field[]" value="{{ fs.field }}">
+                                            <i class="dropdown icon"></i>
+                                            <div class="text">{{ _T('Select a field') }}</div>
+                                            <div class="menu">
     {% for key, field in search_fields %}
         {% if fs.field == key %}
             {% if key starts with 'date_' or key == 'ddn_adh' %}
                 {% set type = constant("Galette\\DynamicFields\\DynamicField::LINE") %}
             {% endif %}
         {% endif %}
-                                            <option value="{{ key }}"{% if fs.field == key %} selected="selected"{% endif %}>{{ field.label }}</option>
+                                                <div class="item{% if fs.field == key %} active selected{% endif %}" data-value="{{ key }}">{{ field.label }}</div>
     {% endfor %}
     {% for field in adh_dynamics %}
         {% if get_class(field) != "Galette\\DynamicFields\\Separator" %}
                 {% set cur_field = field %}
             {% endif %}
         {% endif %}
-                                            <option value="dyn_{{ field.getId() }}"{% if fs.field == rid %} selected="selected"{% endif %}>{{ field.getName() }}</option>
+                                                <div class="item{% if fs.field == rid %} active selected{% endif %}" data-value="dyn_{{ field.getId() }}">{{ field.getName() }}</div>
     {% endfor %}
     {% for type, label in adh_socials %}
         {% set rid = "socials_" ~ type %}
         {% if fs.field == rid %}
             {% set cur_field = type %}
         {% endif %}
-                                            <option value="socials_{{ type }}"{% if fs.field == rid %} selected="selected"{% endif %}>{{ label }}</option>
+                                                <div class="item{% if fs.field == rid %} active selected{% endif %}" data-value="socials_{{ type }}">{{ label }}</div>
     {% endfor %}
-
-                                        </select>
+                                            </div>
+                                        </div>
     {# may not be defined #}
     {#  #}
     {% if type is not defined %}{% set type = null %}{% endif %}
-                                        <span class="data fields">
+                                        <div class="data inline fields">
                                             <input type="hidden" name="free_type[]" value="{% if cur_field is defined %}{{ cur_field.getType() }}{% endif %}"/>
     {% if cur_field is defined and (get_class(cur_field) == "Galette\\DynamicFields\\Choice" or type == constant("Galette\\DynamicFields\\DynamicField::CHOICE")) %}
-                                            <select name="free_query_operator[]" class="free_operator ui search dropdown origselect nochosen">
+                                            <select name="free_query_operator[]" class="free_operator ui selection dropdown nochosen">
                                                 <option value="{{ constant("Galette\\Filters\\AdvancedMembersList::OP_EQUALS") }}"{% if fs.qry_op == constant("Galette\\Filters\\AdvancedMembersList::OP_EQUALS") %} selected="selected"{% endif %}>{{ _T('is') }}</option>
                                                 <option value="{{ constant("Galette\\Filters\\AdvancedMembersList::OP_NOT_EQUALS") }}"{% if fs.qry_op == constant("Galette\\Filters\\AdvancedMembersList::OP_NOT_EQUALS") %} selected="selected"{% endif %}>{{ _T('is not') }}</option>
                                             </select>
-                                            <select name="free_text[]" class="free_text ui search dropdown origselect nochosen">
+                                            <select name="free_text[]" class="free_text ui search dropdown nochosen">
         {% if cur_field is defined and get_class(cur_field) == "Galette\\DynamicFields\\Choice" %}
             {% for key, value in cur_field.getValues() %}
                                                 <option value="{{ key }}"{% if key == fs.search %} selected="selected"{% endif %}>{{ value }}</option>
         {% endif %}
                                             </select>
     {% elseif cur_field is defined and (get_class(cur_field) == "Galette\\DynamicFields\\Date" or type == constant("Galette\\DynamicFields\\DynamicField::DATE")) %}
-                                            <select name="free_query_operator[]" class="free_operator ui search dropdown origselect nochosen">
+                                            <select name="free_query_operator[]" class="free_operator ui selection dropdown nochosen">
                                                 <option value="{{ constant("Galette\\Filters\\AdvancedMembersList::OP_EQUALS") }}"{% if fs.qry_op == constant("Galette\\Filters\\AdvancedMembersList::OP_EQUALS") %} selected="selected"{% endif %}>{{ _T('is') }}</option>
                                                 <option value="{{ constant("Galette\\Filters\\AdvancedMembersList::OP_BEFORE") }}"{% if fs.qry_op == constant("Galette\\Filters\\AdvancedMembersList::OP_BEFORE") %} selected="selected"{% endif %}>{{ _T('before') }}</option>
                                                 <option value="{{ constant("Galette\\Filters\\AdvancedMembersList::OP_AFTER") }}"{% if fs.qry_op == constant("Galette\\Filters\\AdvancedMembersList::OP_AFTER") %} selected="selected"{% endif %}>{{ _T('after') }}</option>
                                             <input type="text" name="free_text[]" value="{{ fs.search|date(_T('Y-m-d')) }}" class="modif_date" maxlength="10" size="10"/>
                                             <span class="exemple">{{ _T('(yyyy-mm-dd format)') }}</span>
     {% elseif cur_field is defined and (get_class(cur_field) == "Galette\\DynamicFields\\Boolean" or type == constant("Galette\\DynamicFields\\DynamicField::BOOLEAN")) %}
-                                            <select name="free_query_operator[]" class="free_operator ui search dropdown origselect nochosen">
+                                            <select name="free_query_operator[]" class="free_operator ui selection dropdown nochosen">
                                                 <option value="{{ constant("Galette\\Filters\\AdvancedMembersList::OP_EQUALS") }}"{% if fs.qry_op == constant("Galette\\Filters\\AdvancedMembersList::OP_EQUALS") %} selected="selected"{% endif %}>{{ _T('is') }}</option>
                                             </select>
                                             <input type="radio" name="free_text[]" id="free_text_yes" value="1"{% if fs.search == 1 %} checked="checked"{% endif %}/><label for="free_text_yes">{{ _T('Yes') }}</label>
                                             <input type="radio" name="free_text[]" id="free_text_no" value="0"{% if fs.search == 0 %} checked="checked"{% endif %}/><label for="free_text_no">{{ _T('No') }}</label>
     {% else %}
-                                            <select name="free_query_operator[]" class="free_operator ui search dropdown origselect nochosen">
+                                            <select name="free_query_operator[]" class="free_operator ui selection dropdown nochosen">
                                                 <option value="{{ constant("Galette\\Filters\\AdvancedMembersList::OP_EQUALS") }}"{% if fs.qry_op == constant("Galette\\Filters\\AdvancedMembersList::OP_EQUALS") %} selected="selected"{% endif %}>{{ _T('is') }}</option>
                                                 <option value="{{ constant("Galette\\Filters\\AdvancedMembersList::OP_CONTAINS") }}"{% if fs.qry_op == constant("Galette\\Filters\\AdvancedMembersList::OP_CONTAINS") %} selected="selected"{% endif %}>{{ _T('contains') }}</option>
                                                 <option value="{{ constant("Galette\\Filters\\AdvancedMembersList::OP_NOT_EQUALS") }}"{% if fs.qry_op == constant("Galette\\Filters\\AdvancedMembersList::OP_NOT_EQUALS") %} selected="selected"{% endif %}>{{ _T('is not') }}</option>
                                             </select>
                                             <input type="text" name="free_text[]" value="{{ fs.search }}"{% if cur_field is defined and get_class(cur_field) == "Galette\\DynamicFields\\Text" %} class="large"{% endif %}/>
     {% endif %}
-                                        </span>
+                                        </div>
                                         <a
                                             href="#"
                                             class="ui small compact red icon button filtered fright tooltip delete delcriteria"
                 }
 
                 $(selector).dropdown({
-                    onChange: function(value, text, option) {
+                    action: function(text, value, element) {
+                        var element = element.parentElement !== undefined ? element : element[0];
+                        var dropdown = element.parentElement.parentElement;
+                        $(dropdown).find('div.text').html(text);
+                        $(dropdown).dropdown('set selected', value);
+                        $(dropdown).dropdown('hide');
+
                         var _field = _fields[value];
                         var _type = _field.type;
                         var _html;
                                         _options += '<option value="' + key + '">' + _field.values[key] + '</option>';
                                     }
                                 }
-                                _html += '<select name="free_text[]" class="ui search dropdown origselect nochosen newselect">' + _options + '</select>';
+                                _html += '<select name="free_text[]" class="ui search selection dropdown nochosen">' + _options + '</select>';
                                 break;
                             case '{{ constant('Galette\\DynamicFields\\DynamicField::DATE') }}':
                                 _html  = _getOperatorSelector(['op_equals', 'op_before', 'op_after']);
 
                         }
                         _html += '<input type="hidden" name="free_type[]" value="' + _type + '"/>';
-                        option.parent().parent().parent().find('span.data').html(_html);
+                        _current_fields = element.parentElement.parentElement.parentElement;
+                        $(_current_fields).find('div.data').html(_html);
+                        $(_current_fields).find('div.data .ui.dropdown').dropdown('refresh');
                         _calendarWidget('.fs-calendar');
-                        _fs_dropdown('.newselect');
-                        $('.newselect').removeClass('newselect');
                     }
                 });
             }
 
             var _newFilter = function(elt) {
-                elt.find('span.data').html('');
-                elt.find('.item.active.selected').removeClass('active').removeClass('selected');
+                elt.find('div.data').html('');
+                elt.find('.item.selected').removeClass('active').removeClass('selected');
+                elt.find('.origselect').dropdown('set value', '');
+                elt.find('.origselect').find('div.text').html('{{ _T("Select a field") }}');
             }
             var _rmFilter = function(elt) {
                 if ( !elt ) {
                     var _operator = _operators[list[i]];
                     _options += '<option value="' + _operator.id + '">' + _operator.name + '</option>';
                 }
-                return '<select name="free_query_operator[]" class="free_operator ui search dropdown origselect nochosen newselect">' + _options + '</select>';
-                _fs_dropdown('.newselect');
-                $('.newselect').removeClass('newselect');
+                return '<select name="free_query_operator[]" class="free_operator ui selection dropdown nochosen">' + _options + '</select>';
             }
 
             var _initSortable = function(){
                     $('#gs_sortable li:first')
                             .clone() // copy
                             .insertAfter('#gs_sortable li:last'); // where
+                    $('#gs_sortable li:last .ui.dropdown').dropdown('refresh');
                     _fs_dropdown();
                     _rmFilter();
                     return false;
                     $('#fs_sortable li:first')
                             .clone() // copy
                             .insertAfter('#fs_sortable li:last'); // where
+                    $('#fs_sortable li:last .ui.dropdown:not(.origselect)').dropdown('refresh');
                     _fs_dropdown();
                     _rmFilter();
                     return false;
index 85673bdeb4d8b735b63c523cff1d5358018252e2..25ba2709bf96ace48c38a513f13bf08d3632ad3e 100644 (file)
@@ -8,13 +8,17 @@
         </div>
         <div class="ui bottom attached accordion-styled segment">
             <form action="{{ url_for('dynamicTranslations') }}" method="get" enctype="multipart/form-data" id="select_orig" class="ui form">
-                <div class="field inline">
-                    <select name="text_orig" id="text_orig" class="ui dropdown nochosen">
-                    {% for value in orig %}
-                        <option value="{{ value }}"{% if value == text_orig %} selected="selected"{% endif %}>{{ value }}</option>
-                    {% endfor %}
-                    </select>
-                    <noscript> <span><input type="submit" value="{{ _T("Change") }}" class="ui button" /></span></noscript>
+                <div class="inline field">
+                    <div class="ui dropdown selection autosubmit">
+                        <input type="hidden" name="text_orig" value="{{ text_orig }}">
+                        <i class="dropdown icon"></i>
+                        <div class="text">{{ text_orig }}</div>
+                        <div class="menu">
+                        {% for value in orig %}
+                            <div class="item{% if value == text_orig %} active selected {% endif %}" data-value="{{ value }}">{{ value }}</div>
+                        {% endfor %}
+                        </div>
+                    </div>
                     {% include "components/forms/csrf.html.twig" %}
                 </div>
             </form>
         <p>{{ _T("No fields to translate.") }}</p>
 {% endif %}
 {% endblock %}
-
-{% block javascripts %}
-{% if trans is defined and trans|length > 0 %}
-    {% if exists %}
-    <script type="text/javascript">
-        $('#text_orig').change(function(e) {
-            e.preventDefault();
-            var _selected  = $('#text_orig option:selected').val();
-            var _form = $('#select_orig');
-            _form.attr('action', _form.attr('action') + '/' + _selected)
-            $('#select_orig').submit();
-        });
-    </script>
-    {% endif %}
-{% endif %}
-{% endblock %}
index 62adfcb75762ad526f9a4463ff64002e66c04a29..605061303b6e1e2c5a3f27546868fe1ccb8058ee 100644 (file)
@@ -9,20 +9,29 @@
                 <div class="fields">
                     <div class="inline field">
                         <label for="sel_lang">{{ _T("Language:") }}</label>
-                        <select name="sel_lang" id="sel_lang" class="ui dropdown nochosen lang">
+                        <div class="ui dropdown selection autosubmit">
+                            <input type="hidden" name="sel_lang" value="{{ cur_lang }}">
+                            <i class="dropdown icon"></i>
+                            <div class="text">{{ cur_lang_name }}</div>
+                            <div class="menu">
                             {% for langue in langlist %}
-                                <option value="{{ langue.getID() }}" {% if cur_lang == langue.getID() %}selected="selected"{% endif %}>{{ langue.getName() }}</option>
+                                <div class="item{% if cur_lang == langue.getID() %} active selected {% endif %}" data-value="{{ langue.getID() }}">{{ langue.getName() }}</div>
                             {% endfor %}
-                        </select>
+                            </div>
+                        </div>
                     </div>
                     <div class="inline field">
                         <label for="sel_ref">{{ _T("Reference:") }}</label>
-                        <select name="sel_ref" id="sel_ref" class="ui dropdown nochosen">
+                        <div class="ui dropdown selection autosubmit">
+                            <input type="hidden" name="sel_ref" value="{{ cur_ref }}">
+                            <i class="dropdown icon"></i>
+                            <div class="text">{% for ref in reflist %}{% if cur_ref == ref.tref %}{{ ref.tcomment }}{% endif %}{% endfor %}</div>
+                            <div class="menu">
                             {% for ref in reflist %}
-                                <option value="{{ ref.tref }}" {% if cur_ref == ref.tref %}selected="selected"{% endif %} >{{ ref.tcomment }}</option>
+                                <div class="item{% if cur_ref == ref.tref %} active selected {% endif %}" data-value="{{ ref.tref }}">{{ ref.tcomment }}</div>
                             {% endfor %}
-                        </select>
-                        <noscript><span><input type="submit" value="{{ _T("Change") }}" class="ui button" /></span></noscript>
+                            </div>
+                        </div>
                     </div>
                     {% include 'components/forms/csrf.html.twig' %}
                 </div>
 {% block javascripts %}
         <script type="text/javascript">
             $(function() {
-                $('#sel_ref, #sel_lang').change(function() {
-                    $(':input[type="submit"]').attr('disabled', 'disabled');
-                    //Change the input[@id='value'] ; we do not want to validate, but to change lang/ref
-                    $('#valid').attr('value', (this.id === 'sel_lang') ? 'change_lang' : 'change_text');
-                    this.form.submit();
-                });
-
                 _addLegendButton('.ui.corner.label');
                 _handleLegend();
                 _bindFomanticComponents();
index 6f35e8684874329237e974c49d41b0e28fe43a92..1cbda3b790d4d43f7fcff6de73523ab2dc65bcdd 100644 (file)
     {% endif %}
                             <div class="inline field{% if required.id_type_cotis is defined and required.id_type_cotis == 1 %} required{% endif %}">
                                 <label for="id_type_cotis">{{ _T("Contribution type:") }}</label>
-                                <select name="id_type_cotis" id="id_type_cotis" class="ui dropdown nochosen"{% if required.id_type_cotis is defined and required.id_type_cotis == 1 %} required="required"{% endif %}>
+                                <div id="id_type_cotis" class="ui dropdown selection nochosen">
                                     {% if contribution.type %}
                                         {% set selectedid = contribution.type.id %}
                                     {% else %}
                                         {% set selectedid = null %}
                                     {% endif %}
+                                    <input id="id_type_cotis_input" type="hidden" name="id_type_cotis" value="{{ selectedid }}"{% if required.id_type_cotis is defined and required.id_type_cotis == 1 %} required="required"{% endif %}>
+                                    <i class="dropdown icon"></i>
+                                    <div class="text">{% for key, value in type_cotis_options %}{% if key == selectedid %}{{ value }}{% endif %}{% endfor %}</div>
+                                    <div class="menu">
                                     {% for key, value in type_cotis_options %}
-                                        <option value="{{ key }}"{% if key == selectedid %} selected="selected"{% endif %}>{{ value }}</option>
+                                        <div class="item{% if key == selectedid %} active selected{% endif %}" data-value="{{ key }}">{{ value }}</div>
                                     {% endfor %}
-                                </select>
-    {% if type == constant('Galette\\Entity\\Contribution::TYPE_FEE') %}
-                                <noscript>
-                                    <div class="ui basic fitted segment" id="reloadcont">
-                                        <input type="submit" id="btnreload" name="btnreload" value="{{ _T("Reload") }}" title="{{ _T("Reload date information according to selected member and contribution type") }}" class="ui button"/>
                                     </div>
-                                </noscript>
-    {% endif %}
+                                </div>
                             </div>
     {% if contribution.isTransactionPart() and contribution.transaction.getMissingAmount() %}
                             <div class="inline field">
     $(function() {
 
     {% if type == constant('Galette\\Entity\\Contribution::TYPE_FEE') and not contribution.id %}
-        $('#id_adh, #id_type_cotis').on('change', function() {
-            var _this = $(this);
-            var _member = $('#id_adh').val();
-            var _fee    = $('#id_type_cotis').val();
+        $('#id_adh, #id_type_cotis').dropdown({
+            action: function(text, value, element) {
+                var element = element.parentElement !== undefined ? element : element[0];
+                var dropdown = element.parentElement.parentElement;
+                $(dropdown).find('div.text').html(text);
+                $(dropdown).dropdown('set selected', value);
+                $(dropdown).dropdown('hide');
 
-            $.ajax({
-                type: 'POST',
-                dataType: 'json',
-                url : '{{ url_for("contributionDates") }}',
-                data: {
-                    member_id: _member,
-                    fee_id: _fee
-                },
-                {% include "elements/js/loader.js.twig" with {
-                    selector: '#contribdetails'
-                } %},
-                success: function(res){
-                    $('#date_debut_cotis').val(res.date_debut_cotis);
-                    $('#date_fin_cotis').val(res.date_fin_cotis);
-                },
-                error: function() {
-                    {% include "elements/js/modal.js.twig" with {
-                        modal_title_twig: _T("An error occurred retrieving dates :(")|e("js"),
-                        modal_without_content: true,
-                        modal_class: "mini",
-                        modal_deny_only: true,
-                        modal_cancel_text: _T("Close")|e("js"),
-                        modal_classname: "redalert",
-                    } %}
-                }
-            });
+                var _member = $('#id_adh_input').val();
+                var _fee    = $('#id_type_cotis_input').val();
 
+                $.ajax({
+                    type: 'POST',
+                    dataType: 'json',
+                    url : '{{ url_for("contributionDates") }}',
+                    data: {
+                        member_id: _member,
+                        fee_id: _fee
+                    },
+                    {% include "elements/js/loader.js.twig" with {
+                        selector: '#contribdetails'
+                    } %},
+                    success: function(res){
+                        $('#date_debut_cotis').val(res.date_debut_cotis);
+                        $('#date_fin_cotis').val(res.date_fin_cotis);
+                    },
+                    error: function() {
+                        {% include "elements/js/modal.js.twig" with {
+                            modal_title_twig: _T("An error occurred retrieving dates :(")|e("js"),
+                            modal_without_content: true,
+                            modal_class: "mini",
+                            modal_deny_only: true,
+                            modal_cancel_text: _T("Close")|e("js"),
+                            modal_classname: "redalert",
+                        } %}
+                    }
+                });
+
+            }
         });
     {% endif %}
 
index 9f3a7bd2367d0134f60923083e2a611a4a565ab4..59505d3e8631b8beb2d661c39a937ac924159711 100644 (file)
                 $('#company_field.nocompany').addClass('displaynone');
                 $('#is_company').change(function(){
                     $('#company_field').toggleClass('displaynone');
-                    $('#company_field').backgroundFade(
-                        {
-                            sColor:'#ffffff',
-                            eColor:'#DDDDFF',
-                            steps:10
-                        },
-                        function() {
-                            $(this).backgroundFade(
-                                {
-                                    sColor:'#DDDDFF',
-                                    eColor:'#ffffff'
-                                }
-                            );
-                        });
                 });
 
 {% if not self_adh %}
index 2e0dbc7f556a8923c69a2b539983742daa3673a7..c3ed3b15b7d0b7369cdd34172f10beafb6729736 100644 (file)
@@ -94,7 +94,7 @@
                 </div>
                 <div class="field">
                     <label for="filter_str">{{ _T('among:') }}</label>
-                    <select name="membership_filter" onchange="form.submit()" class="ui search dropdown nochosen">
+                    <select name="membership_filter" class="ui search dropdown nochosen">
                         {% for key, value in membership_filter_options %}
                             <option value="{{ key }}"{% if key == filters.membership_filter %} selected="selected"{% endif %}>{{ value }}</option>
                         {% endfor %}
                 </div>
                 <div class="flexend field">
                     <label for="filter_account" class="displaynone">{{ _T('among:') }}</label>
-                    <select name="filter_account" onchange="form.submit()" class="ui search dropdown nochosen">
+                    <select name="filter_account" class="ui search dropdown nochosen">
                         {% for key, value in filter_accounts_options %}
                             <option value="{{ key }}"{% if key == filters.filter_account %} selected="selected"{% endif %}>{{ value }}</option>
                         {% endfor %}
                 </div>
                 <div class="flexend field">
                     <label for="group_filter" class="displaynone">{{ _T('among:') }}</label>
-                    <select name="group_filter" onchange="form.submit()" class="ui search dropdown nochosen">
+                    <select name="group_filter" class="ui search dropdown nochosen">
                         <option value="0">{{ _T('Select a group') }}</option>
     {% for group in filter_groups_options %}
                         <option value="{{ group.getId() }}"{% if filters.group_filter == group.getId() %} selected="selected"{% endif %}>{{ group.getIndentName()|raw }}</option>
index 18ae06b2a0d30cf70fec135b37ab391066ed6b58..69766079d77e7d3bb424375c68f9ccab38283214 100644 (file)
                     return false;
                 });
 
-                _bindNbshow('.contributions-selection form');
+                _bindDropdownsAutosubmit();
 
                 //Bind pagination and ordering links
                 $('.contributions-selection .pagination a, .contributions-selection thead a').click(function() {
index c09db7feb123fe3163a3222dab430eb31262f32b..44af7339a0b04abe59aba447a9b7473be9bfbb8e 100644 (file)
@@ -34,7 +34,8 @@ var _bindFomanticComponents = function() {
 
     var
         $sidebar         = $('.ui.sidebar'),
-        $dropdown        = $('.ui.dropdown, select:not(.nochosen)'),
+        $dropdown        = $('.ui.dropdown:not(.navigation, .autosubmit), select:not(.nochosen)'),
+        $dropdownNav     = $('.ui.dropdown.navigation'),
         $accordion       = $('.ui.accordion'),
         $checkbox        = $('.ui.checkbox, .ui.radio.checkbox'),
         $tabulation      = $('.ui.tabbed .item'),
@@ -52,6 +53,15 @@ var _bindFomanticComponents = function() {
     $('.simple.dropdown').removeClass('simple');
     $dropdown.dropdown();
 
+    /* Required for keyboard accessibility on dropdowns used in navigation.
+     */
+    $dropdownNav.dropdown({
+        // Set default action : simply open the link selected.
+        action: function(text, value, element) {
+            location.href = element[0].href;
+        }
+    });
+
     $accordion.accordion();
 
     $checkbox.checkbox();
@@ -110,7 +120,48 @@ var _bindFomanticComponents = function() {
     ;
 }
 
-var _bind_check = function(boxelt){
+/* Required for keyboard navigation accessibility.
+ */
+var _keyboardNavigation = function() {
+    // Accordion menus
+    var _folds = document.querySelectorAll('[data-fold^="fold-"]');
+    _folds.forEach(item => {
+        item.addEventListener('keydown', event => {
+            if (event.keyCode == 13) {
+                event.target.click();
+            }
+        })
+    });
+    // Mobile menu trigger
+    var _mobile_menu_trigger = document.querySelector('#top-navbar a.toc.item');
+    _mobile_menu_trigger.addEventListener('keydown', event => {
+        if (event.keyCode == 13) {
+            // Open mobile menu
+            event.target.click();
+            // Jump to mobile menu
+            var url = location.href;
+            location.href = "#sidebarmenu";
+            history.replaceState(null,null,url);
+        }
+    });
+}
+
+/* Required for keyboard accessibility on simple dropdowns with autosubmit.
+ */
+var _bindDropdownsAutosubmit = function() {
+    $('.ui.dropdown.autosubmit').dropdown({
+        action: function(text, value, element) {
+            var element = element.parentElement !== undefined ? element : element[0];
+            var dropdown = element.closest('.ui.dropdown');
+            var form = element.closest('form');
+            $(dropdown).dropdown('set value', value);
+            $(dropdown).dropdown('hide');
+            $(form).trigger('submit');
+        }
+    });
+}
+
+var _bind_check = function(boxelt) {
     if (typeof(boxelt) == 'undefined') {
         boxelt = 'entries_sel'
     }
@@ -141,18 +192,6 @@ var _bind_check = function(boxelt){
     });
 };
 
-var _bindNbshow = function(selector) {
-    if (typeof(selector) == 'undefined') {
-        selector = '';
-    } else {
-        selector = selector + ' ';
-    }
-
-    $(selector + '#nbshow').change(function() {
-        $(this.form).trigger('submit');
-    });
-}
-
 /* Display tables legends in Fomantic UI modal */
 var _bind_legend = function() {
     $('.show_legend').click(function(e){
@@ -170,10 +209,12 @@ $(function() {
 
     $('#login').focus();
 
-    _bindNbshow();
-
     _bindFomanticComponents();
 
+    _bindDropdownsAutosubmit();
+
+    _keyboardNavigation();
+
     var _back2Top = document.getElementById("back2top");
     document.body.addEventListener('scroll', function() {
         if (document.body.scrollTop > 150 || document.documentElement.scrollTop > 150) {
index b6a7d0f05f6a787e44a401e64b7ff3213d4becc3..63b1492950242128840ccc42b342fde1302998b8 100644 (file)
   display: flex;
   align-items: flex-end;
 }
+
+/*--------------------------
+      Free search fields
+---------------------------*/
+.ui.form .data.inline.fields {
+  margin-bottom: 0;
+}
index 00c91669b04555a2245daeb86bebd3096e14a991..e368d4e722956b34c5ada4d9756bc109bbaba92f 100644 (file)
     width: 100%;
   }
 }
+
+/*----------------------------------
+     Compact mode logout menu
+-----------------------------------*/
+.compact_menu #logoutmenu {
+  & > a.item {
+    &.darkmode {
+      background-color: @darkmodeItemBackground;
+      &:hover,
+      &:focus {
+        background-color: @darkmodeHover;
+      }
+      &:active {
+        background-color: @darkmodeActive;
+      }
+      &.black {
+        background-color: @darkmodeItemBackgroundInverted;
+        color: @invertedTextColor;
+        &:hover,
+        &:focus {
+          background-color: @blackHover;
+        }
+        &:active {
+          background-color: @blackDown;
+        }
+      }
+    }
+    &.purple {
+      background-color: @logoutItemBackgroundImpersonated;
+      color: @invertedTextColor;
+      &:hover,
+      &:focus {
+        background-color: @purpleHover;
+      }
+      &:active {
+        background-color: @purpleDown;
+      }
+    }
+    &.red {
+      background-color: @logoutItemBackground;
+      color: @invertedTextColor;
+      &:hover,
+      &:focus {
+        background-color: @redHover;
+      }
+      &:active {
+        background-color: @redDown;
+      }
+    }
+  }
+}
index 960102d8dfbad94e5d11a5904289afea9d76ab7a..f006806a4aa377ef83e1bde53d3ca659bfbfb32f 100644 (file)
 @invertedActiveHoverBackground: @invertedActiveBackground;
 @invertedActiveHoverColor: darken(@textColor, 15);
 @invertedArrowActiveHoverColor: @invertedArrowActiveColor;
+
+/*----------------------------------
+     Compact mode logout menu
+-----------------------------------*/
+@darkmodeItemBackground: #e0e1e2;
+@darkmodeItemBackgroundInverted: @black;
+@darkmodeHover: #cacbcd;
+@darkmodeActive: #babbbc;
+@logoutItemBackground: @red;
+@logoutItemBackgroundImpersonated: @purple;
index d0f3b5da7ddf309f138a18e07be24eb152ad263b..e3453f1915f7c3bf544cc4dd433902660f90bfa3 100644 (file)
   overflow-x: auto;
 }
 
+/*---------------------------------------------------------------
+     Override outline on links and navigation elements
+----------------------------------------------------------------*/
+a,
+.ui.button:not(.tertiary),
+.compact_menu .ui.dropdown.item,
+.ui.dropdown.language,
+.infoline .ui.dropdown:not(.tertiary) {
+    &:focus-visible {
+        outline: 3px solid @blueFocus;
+    }
+}
+
 /*--------------------------------
      Base layout and navigation
 ---------------------------------*/
index 163af89bb1766329110ddec1141d09f3183b0cba..6a4c7d4b8f572edada50c5b7abea08b7530b2f6c 100644 (file)
@@ -9,6 +9,18 @@
   height: 7rem;
 }
 
+/*------------------------------
+     Compact menu dropdowns
+-------------------------------*/
+.compact_menu .ui.dropdown .dropdown.icon {
+    margin: 0;
+    float: none;
+    position: absolute;
+    right: 5px;
+    top: 50%;
+    transform: translateY(-50%);
+}
+
 /*--------------------------
      Language dropdown
 ---------------------------*/