Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,15 @@
{% endblock %}
<div class="container">
{# The .header-image class hides the main text and uses image replacement for the title #}
<label tabindex="0" for="hb__trigger" class="nav-trigger" type="button" aria-label="Menu" aria-controls="navigation" aria-expanded="false">
<label tabindex="0" for="hb__trigger" class="nav-trigger">
<div class="hb">
<span class="hb__box">
<span class="hb__inner"></span>
</span>
<span class="hb__label">Menu</span>
<span class="hb__label">
<span class="sr-only">{{ _('Toggle') }}</span>
Menu
</span>
</div>
</label>
<div class="{{ g.header_class }} navbar-left">
Expand All @@ -62,7 +65,7 @@
</div>
<div class="collapse navbar-collapse" id="main-navigation-toggle">
{% block header_site_navigation %}
<nav class="section navigation">
<nav class="section navigation" aria-label="{{ _('Navigation') }}">
<ul class="nav nav-pills">
{% block header_site_navigation_tabs %}
{{ h.build_nav_main(
Expand All @@ -75,11 +78,11 @@
<a href="/pages/ckan-training-videos">Tips</a>
</li>
{% endblock %}
{% block header_site_search %}
{{ super() }}
{% endblock %}
</ul>
</nav>
{% block header_site_search %}
{{ super() }}
{% endblock %}
{% endblock %}
</div>
</div>
Expand Down
119 changes: 59 additions & 60 deletions ckanext/opendata_theme/extended_themes/bostonma/templates/page.html
Original file line number Diff line number Diff line change
@@ -1,70 +1,73 @@
{% ckan_extends %}

{%- block page -%}
{% block skip %}
{{ super() }}
{% endblock %}
<input type="checkbox" id="hb__trigger" class="hb__trigger" aria-hidden="true">
<div class="main-navigation">
<nav class="main-navigation" aria-label="{{ _('Main Navigation') }}">
<div class="main-navigation-title"></div>
<div class="region region-navigation">
<div class="side-nav-account">
{% block header_account %}
{% block header_account_container_content %}
{% if g.userobj %}
<div class="account avatar authed" data-module="me" data-me="{{ g.userobj.id }}">
<ul class="list-unstyled unstyled">
{% block header_account_logged %}
{% if g.userobj.sysadmin %}
<li>
<a href="{{ h.url_for(controller='admin', action='index') }}" title="{{ _('Sysadmin settings') }}">
<span class="text">{{ _('Admin') }}</span>
</a>
</li>
{% endif %}
<div class="region region-navigation">
<div class="side-nav-account">
{% block header_account %}
{% block header_account_container_content %}
{% if g.userobj %}
<div class="account avatar authed" data-module="me" data-me="{{ g.userobj.id }}">
<ul class="list-unstyled unstyled">
{% block header_account_logged %}
{% if g.userobj.sysadmin %}
<li>
<a href="{{ h.url_for('user.read', id=g.userobj.name) }}" title="{{ _('View profile') }}">
<span class="username">{{ g.userobj.display_name }}</span>
</a>
</li>
{% set new_activities = h.new_activities() %}
<li class="notifications {% if new_activities > 0 %}notifications-important{% endif %}">
{% set notifications_tooltip = ngettext('Dashboard (%(num)d new item)', 'Dashboard (%(num)d new items)', new_activities) %}
<a href="{{ h.url_for('dashboard.index') }}" title="{{ notifications_tooltip }}">
<span class="text">{{ _('Dashboard') }}</span>
<a href="{{ h.url_for(controller='admin', action='index') }}" title="{{ _('Sysadmin settings') }}">
<span class="text">{{ _('Admin') }}</span>
</a>
</li>
{% endif %}
<li>
<a href="{{ h.url_for('user.read', id=g.userobj.name) }}" title="{{ _('View profile') }}">
<span class="username">{{ g.userobj.display_name }}</span>
</a>
</li>
{% set new_activities = h.new_activities() %}
<li class="notifications {% if new_activities > 0 %}notifications-important{% endif %}">
{% set notifications_tooltip = ngettext('Dashboard (%(num)d new item)', 'Dashboard (%(num)d new items)', new_activities) %}
<a href="{{ h.url_for('dashboard.index') }}" title="{{ notifications_tooltip }}">
<span class="text">{{ _('Dashboard') }}</span>
</a>
</li>

{% block header_account_settings_link %}
<li>
<a href="{{ h.url_for('user.edit', id=g.userobj.name) }}" title="{{ _('Profile settings') }}">
<span class="text">{{ _('Profile settings') }}</span>
</a>
</li>
{% endblock %}
{% block header_account_log_out_link %}
<li class="logout">
<a href="{{ h.url_for('/user/_logout') }}" title="{{ _('Log out') }}">
<span class="text">{{ _('Log out') }}</span>
</a>
</li>
{% endblock %}
{% block header_account_settings_link %}
<li>
<a href="{{ h.url_for('user.edit', id=g.userobj.name) }}" title="{{ _('Profile settings') }}">
<span class="text">{{ _('Profile settings') }}</span>
</a>
</li>
{% endblock %}
</ul>
</div>
{% else %}
<nav class="account not-authed">
<ul class="list-unstyled unstyled">
{% block header_account_notlogged %}
<li>{% link_for _('Log in'), named_route='user.login' %}</li>
{% if h.check_access('user_create') %}
<li>{% link_for _('Register'), named_route='user.register', class_='sub' %}</li>
{% endif %}
{% block header_account_log_out_link %}
<li class="logout">
<a href="{{ h.url_for('/user/_logout') }}" title="{{ _('Log out') }}">
<span class="text">{{ _('Log out') }}</span>
</a>
</li>
{% endblock %}
</ul>
</nav>
{% endif %}
{% endblock %}
{% endblock %}
</ul>
</div>
{% else %}
<nav class="account not-authed">
<ul class="list-unstyled unstyled">
{% block header_account_notlogged %}
<li>{% link_for _('Log in'), named_route='user.login' %}</li>
{% if h.check_access('user_create') %}
<li>{% link_for _('Register'), named_route='user.register', class_='sub' %}</li>
{% endif %}
{% endblock %}
</ul>
</nav>
{% endif %}
{% endblock %}
</div>
<ul class="menu list-unstyled unstyled">
{% endblock %}
</div>
<ul class="menu list-unstyled unstyled">
<li class="menu__item is-leaf first leaf secondary-menu-item">
<a href="{{ h.url_for('/') }}" class="menu__link">{{ _('Home') }}</a>
</li>
Expand Down Expand Up @@ -97,12 +100,8 @@
</li>
</ul>
</div>
</div>
</nav>
<div class="page" id="page">
{% block skip %}
{{ super() }}
{% endblock %}

{%- block header %}
{% include "header.html" %}
{% endblock -%}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

{% if header_layout_type=='sidebar' %}
<input type="checkbox" id="hb__trigger" class="hb__trigger" aria-hidden="true">
<nav class="main-navigation" aria-label="{{ _('Navigation') }}">
<nav class="main-navigation" aria-label="{{ _('Main Navigation') }}">
<div class="main-navigation-title">
{{ _('Menu') }}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@
{% endblock %}
<div class="container">
<div class="{{ g.header_class }} navbar-left">
<label tabindex="0" for="hb__trigger" class="nav-trigger" type="button" aria-label="Menu">
<span class="sr-only">{{ _('Toggle Menu') }}</span>
<label tabindex="0" for="hb__trigger" class="nav-trigger">
<div class="hb">
<span class="hb__box">
<span class="hb__inner"></span>
</span>
<span class="hb__label">Menu</span>
<span class="hb__label">
<span class="sr-only">{{ _('Toggle') }}</span>
Menu
</span>
</div>
</label>
{% block header_logo %}
Expand Down
85 changes: 73 additions & 12 deletions ckanext/opendata_theme/opengov_custom_theme/assets/js/theme.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,21 +146,82 @@ $(document).ready(function () {
});
});

// Sidebar menu
$(document).on('keydown', function(event) {
const $menuTrigger = $('#hb__trigger');
const $navLabel = $('label[for="hb__trigger"]');

// Check if the focused element is the label
if ($(document.activeElement).is($navLabel)) {
// Open or close the menu with the Enter key (event.key === 'Enter')
if (event.key === 'Enter') {
$menuTrigger.prop('checked', !$menuTrigger.prop('checked'));
// Sidebar menu: keyboard (Enter/Escape), focus first link when opened, skip tab when closed
$(document).ready(function () {
var $menuTrigger = $('#hb__trigger');
var $navLabel = $('label[for="hb__trigger"]');

if (!$menuTrigger.length) return;

function setSidebarFocusable(focusable) {
var $nav = $('.main-navigation');
var $focusables = $nav.find('a, button');
if (focusable) {
$nav.removeAttr('aria-hidden');
$focusables.removeAttr('tabindex');
} else {
$nav.attr('aria-hidden', 'true');
$focusables.attr('tabindex', '-1');
}
}

function focusSidebarFirstLink() {
var $nav = $('.main-navigation');
var $firstLink = $nav.find('.menu a').first();
if (!$firstLink.length) {
$firstLink = $nav.find('a').first();
}
if (!$firstLink.length) return;
setTimeout(function () {
requestAnimationFrame(function () {
$firstLink[0].focus();
});
}, 400);
}

// Close the menu with the Escape key (event.key === 'Escape')
if (event.key === 'Escape' && $menuTrigger.prop('checked')) {
function openSidebar() {
$menuTrigger.prop('checked', true);
setSidebarFocusable(true);
focusSidebarFirstLink();
}

function closeSidebar() {
var focusWasInside = $('.main-navigation').has(document.activeElement).length > 0;
$menuTrigger.prop('checked', false);
setSidebarFocusable(false);
if (focusWasInside) {
$navLabel.focus();
}
}

// Set initial tab order based on whether the sidebar starts open
setSidebarFocusable($menuTrigger.prop('checked'));

// Enter toggles the sidebar; Escape closes it
$navLabel.on('keydown', function (event) {
if (event.key === 'Enter') {
event.preventDefault();
if ($menuTrigger.prop('checked')) {
closeSidebar();
} else {
openSidebar();
}
}
});

$(document).on('keydown', function (event) {
if (event.key === 'Escape' && $menuTrigger.prop('checked')) {
closeSidebar();
}
});

// Handle click (label click fires a change event on the checkbox)
$menuTrigger.on('change', function () {
if ($(this).prop('checked')) {
setSidebarFocusable(true);
focusSidebarFirstLink();
} else {
closeSidebar();
}
});
});
Loading