diff --git a/packages/ilios-common/.lint-todo b/packages/ilios-common/.lint-todo
index 2912ff5299..c704b8d52b 100644
--- a/packages/ilios-common/.lint-todo
+++ b/packages/ilios-common/.lint-todo
@@ -40,8 +40,6 @@ add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|23cd787c79c34a628da
add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|32658810aa13672f5981281c562729112a89788f|1731542400000|1762646400000|1793750400000|addon/components/course/header.hbs
add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|23cd787c79c34a628dadb6e96dd4004d42eebb79|1731542400000|1762646400000|1793750400000|addon/components/course/objective-list.hbs
add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|84076f8cf85c554eaf0d9fdec26154bae5bceeb2|1731542400000|1762646400000|1793750400000|addon/components/course/objective-list.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|28|6|28|6|1ef231a97c0ec761eaafb3e76093515e5523ff27|1731542400000|1762646400000|1793750400000|addon/components/course/publication-menu.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|29|6|29|6|df94e6558ff62dea69f6f656f668f29b56bcc378|1731542400000|1762646400000|1793750400000|addon/components/course/publication-menu.hbs
add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|2bbf15957242a9a3c1e26e14e5d022c858199fde|1731542400000|1762646400000|1793750400000|addon/components/course/rollover-date-picker.hbs
add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|167e8d9ede488c7f199cb748e81bc09b97617e71|1731542400000|1762646400000|1793750400000|addon/components/course/rollover-date-picker.hbs
add|ember-template-lint|no-at-ember-render-modifiers|3|2|3|2|1009d3843f6aed52099f0e7fbd4eebb52bc176e5|1731542400000|1762646400000|1793750400000|addon/components/course/rollover.hbs
@@ -55,5 +53,3 @@ add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|23cd787c79c34a628da
add|ember-template-lint|no-at-ember-render-modifiers|3|2|3|2|23cd787c79c34a628dadb6e96dd4004d42eebb79|1731542400000|1762646400000|1793750400000|addon/components/dashboard/courses-calendar-filter.hbs
add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|a90be151f45cd8ab32827e9247a9a9eb7f1baef2|1731542400000|1762646400000|1793750400000|addon/components/dashboard/courses-calendar-filter.hbs
add|ember-template-lint|no-at-ember-render-modifiers|24|10|24|10|2ed3ce70b879732dc85047f9f546c5dbd5376dba|1731542400000|1762646400000|1793750400000|addon/components/dashboard/courses-calendar-filter.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|28|6|28|6|1ef231a97c0ec761eaafb3e76093515e5523ff27|1731542400000|1762646400000|1793750400000|addon/components/session/publication-menu.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|29|6|29|6|df94e6558ff62dea69f6f656f668f29b56bcc378|1731542400000|1762646400000|1793750400000|addon/components/session/publication-menu.hbs
diff --git a/packages/ilios-common/addon/components/course/publication-menu.hbs b/packages/ilios-common/addon/components/course/publication-menu.hbs
index 5afd59ea65..1eef71f587 100644
--- a/packages/ilios-common/addon/components/course/publication-menu.hbs
+++ b/packages/ilios-common/addon/components/course/publication-menu.hbs
@@ -1,107 +1,101 @@
-
+
+
+ {{this.title}}
+
+
+
+ {{#if this.isOpen}}
+
+ {{/if}}
+
+{{/let}}
\ No newline at end of file
diff --git a/packages/ilios-common/addon/components/course/publication-menu.js b/packages/ilios-common/addon/components/course/publication-menu.js
index 71f89bd589..31a5e494ff 100644
--- a/packages/ilios-common/addon/components/course/publication-menu.js
+++ b/packages/ilios-common/addon/components/course/publication-menu.js
@@ -2,6 +2,7 @@ import Component from '@glimmer/component';
import { service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
+import { task, timeout } from 'ember-concurrency';
export default class CoursePublicationMenuComponent extends Component {
@service router;
@@ -63,53 +64,67 @@ export default class CoursePublicationMenuComponent extends Component {
return 'notpublished';
}
- focusOnFirstItem(menuElement) {
- menuElement.querySelector('button:first-of-type').focus();
+ focusFirstLink = task(async (item) => {
+ await timeout(1);
+ item.querySelector('.menu button:first-of-type').focus();
+ });
+
+ handleArrowUp(item) {
+ if (item?.previousElementSibling) {
+ item.previousElementSibling.focus();
+ } else {
+ item?.parentElement.lastElementChild.focus();
+ }
+ }
+
+ async handleArrowDown(item) {
+ if (item.classList.value == 'toggle') {
+ this.isOpen = true;
+ await this.focusFirstLink.perform(item.parentElement);
+ } else {
+ if (item.nextElementSibling) {
+ item.nextElementSibling.focus();
+ } else {
+ await this.focusFirstLink.perform(item.parentElement);
+ }
+ }
}
@action
- moveFocus({ key, target }) {
+ async toggleMenu({ target }) {
+ this.isOpen = !this.isOpen;
+
+ if (this.isOpen) {
+ await this.focusFirstLink.perform(target.parentElement.parentElement);
+ }
+ }
+ @action
+ keyUp({ key, target }) {
switch (key) {
case 'ArrowDown':
- if (target.nextElementSibling) {
- target.nextElementSibling.focus();
- } else {
- this.menuElement.querySelector('button:nth-of-type(1)').focus();
- }
+ this.handleArrowDown(target);
break;
case 'ArrowUp':
- if (target.previousElementSibling) {
- target.previousElementSibling.focus();
- } else {
- this.menuElement.querySelector('button:last-of-type').focus();
- }
+ this.handleArrowUp(target);
break;
case 'Escape':
case 'Tab':
case 'ArrowRight':
case 'ArrowLeft':
- this.isOpen = false;
+ this.close();
break;
}
+
+ return false;
}
@action
- clearFocus() {
- const buttons = this.menuElement.querySelectorAll('button');
- buttons.forEach((el) => el.blur());
+ clearFocus({ target }) {
+ const menu = target.parentElement.parentElement;
+ menu.querySelectorAll('button').forEach((el) => el.blur());
}
@action
- toggleMenu({ key }) {
- switch (key) {
- case 'ArrowDown':
- this.isOpen = true;
- break;
- case 'Escape':
- case 'Tab':
- case 'ArrowRight':
- case 'ArrowLeft':
- this.isOpen = false;
- break;
- }
+ close() {
+ this.isOpen = false;
}
@action
diff --git a/packages/ilios-common/addon/components/session/publication-menu.hbs b/packages/ilios-common/addon/components/session/publication-menu.hbs
index 705fef5540..04fd6fb819 100644
--- a/packages/ilios-common/addon/components/session/publication-menu.hbs
+++ b/packages/ilios-common/addon/components/session/publication-menu.hbs
@@ -1,107 +1,101 @@
-
+
+
+ {{this.title}}
+
+
+
+ {{#if this.isOpen}}
+
+ {{/if}}
+
+{{/let}}
\ No newline at end of file
diff --git a/packages/ilios-common/addon/components/session/publication-menu.js b/packages/ilios-common/addon/components/session/publication-menu.js
index 9917ed4e9b..997ee5729e 100644
--- a/packages/ilios-common/addon/components/session/publication-menu.js
+++ b/packages/ilios-common/addon/components/session/publication-menu.js
@@ -2,6 +2,7 @@ import Component from '@glimmer/component';
import { service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
+import { task, timeout } from 'ember-concurrency';
export default class SessionPublicationMenuComponent extends Component {
@service router;
@@ -67,53 +68,67 @@ export default class SessionPublicationMenuComponent extends Component {
return 'notpublished';
}
- focusOnFirstItem(menuElement) {
- menuElement.querySelector('button:first-of-type').focus();
+ focusFirstLink = task(async (item) => {
+ await timeout(1);
+ item.querySelector('.menu button:first-of-type').focus();
+ });
+
+ handleArrowUp(item) {
+ if (item?.previousElementSibling) {
+ item.previousElementSibling.focus();
+ } else {
+ item?.parentElement.lastElementChild.focus();
+ }
+ }
+
+ async handleArrowDown(item) {
+ if (item.classList.value == 'toggle') {
+ this.isOpen = true;
+ await this.focusFirstLink.perform(item.parentElement);
+ } else {
+ if (item.nextElementSibling) {
+ item.nextElementSibling.focus();
+ } else {
+ await this.focusFirstLink.perform(item.parentElement);
+ }
+ }
}
@action
- moveFocus({ key, target }) {
+ async toggleMenu({ target }) {
+ this.isOpen = !this.isOpen;
+
+ if (this.isOpen) {
+ await this.focusFirstLink.perform(target.parentElement.parentElement);
+ }
+ }
+ @action
+ keyUp({ key, target }) {
switch (key) {
case 'ArrowDown':
- if (target.nextElementSibling) {
- target.nextElementSibling.focus();
- } else {
- this.menuElement.querySelector('button:nth-of-type(1)').focus();
- }
+ this.handleArrowDown(target);
break;
case 'ArrowUp':
- if (target.previousElementSibling) {
- target.previousElementSibling.focus();
- } else {
- this.menuElement.querySelector('button:last-of-type').focus();
- }
+ this.handleArrowUp(target);
break;
case 'Escape':
case 'Tab':
case 'ArrowRight':
case 'ArrowLeft':
- this.isOpen = false;
+ this.close();
break;
}
+
+ return true;
}
@action
- clearFocus() {
- const buttons = this.menuElement.querySelectorAll('button');
- buttons.forEach((el) => el.blur());
+ clearFocus({ target }) {
+ const menu = target.parentElement.parentElement;
+ menu.querySelectorAll('button').forEach((el) => el.blur());
}
@action
- toggleMenu({ key }) {
- switch (key) {
- case 'ArrowDown':
- this.isOpen = true;
- break;
- case 'Escape':
- case 'Tab':
- case 'ArrowRight':
- case 'ArrowLeft':
- this.isOpen = false;
- break;
- }
+ close() {
+ this.isOpen = false;
}
@action