New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.
Already on GitHub? Sign in to your account
馃悰 Update event listeners for mega menu #25091
Conversation
* @private | ||
*/ | ||
registerMenuItemListeners_() { | ||
this.items_.forEach(item => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably be better to use event delegation here, rather than adding a listener per item. That will allow for handling of changed DOM content (e.g. new headings added) automatically.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually the DOM update listener might still be necessary since we need to add several a11y attributes when first registering each menu item. Looking at the code again, since we're adding separate event listeners to the screen reader buttons anyway, maybe it's ok to keep the existing listeners on heading elements rather than using event delegation?
'keydown', | ||
this.documentKeyDownHandler_ | ||
); | ||
this.unregisterMenuItemListeners_(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no reason to remove event listeners on unlayout.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Talked offline; will remove the unregister function and add/remove the event listeners for documentElement inside the expand/collapse methods since these listeners are only needed when a menu is open.
} | ||
const heading = | ||
scopedQuerySelector(item, '> button') || | ||
scopedQuerySelector(item, '> [role=button]'); | ||
const content = scopedQuerySelector(item, '> [role=dialog]'); | ||
// register item only if heading element is present. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think when @kristoferbaxter suggested use of a filter function, he meant use the filter function to filter down to only the items in the array you want to operate on. For example, you could also write this as:
this.items_ = toArray(scopedQuerySelectorAll(this.element, 'nav > * > li'));
this.items_.filter(item => !item.classList.contains('i-amphtml-mega-menu-item'))
.foreach(item => {
const heading = ...
...
this.registerMenuItem_(item, heading, content);
});
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm the thing is I only want this.items_
to include items with heading elements; so i can filter out the elements without headings first, but then in the foreach
I'll need to get a reference to heading
again to pass to registerMenuItem_
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've made some changes that should allow me to use the filter and foreach pattern now. For any <li>
that conforms to the specs laid out in #25210, we'll register it as a menu item and include it in this.items_
. The only case not covered by validation but should be disallowed is when there're two elements under an item and neither is a button/role=button, in which case I've added a userAssert
to warn against this. Hopefully the documentation will make it clear.
* @return {!Element} the mask that was created. | ||
* @private | ||
*/ | ||
createMaskElement_() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice commenting!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approving to unblock.
Nit: I would recommend making the registerMenuItems
function idempotent to simplify your DOM_UPDATE code. But feel free to do this if you have extra time.
* add manual test file * simplify event listener code * update logic for registering menu items
Resolves #25047
Update the event listener logic in
amp-mega-menu
to:documentElement
and add/remove them when menu is opened/closed (added unit tests);shouldhandleClick
method fromamp-accordion
;amp-video
inside the menu);updated firebase demo
Also added file under manual tests: pr-deployed link (must turn on the experiment
amp-mega-menu
)