Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

fix(menu): Updated menu to use list's custom event #4151

Merged
merged 31 commits into from
Jan 31, 2019
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
b39a6b1
fix(list): Add notifyAction adapter for action on list item.
abhiomkar Dec 5, 2018
1d4f896
fix(list): Added unit tests for component and foundation
abhiomkar Dec 6, 2018
5001d91
fix(menu): Updated menu to use list custom event
abhiomkar Dec 6, 2018
a7e8edd
fix(list): removed the need of followHref
abhiomkar Dec 7, 2018
5c93287
fix(list): Fixed unit tests
abhiomkar Dec 7, 2018
f998467
fix(menu): Removed redundant / unused handleSelection method
abhiomkar Dec 7, 2018
f96068f
Merge remote-tracking branch 'origin/master' into list_custom_event_i…
abhiomkar Jan 3, 2019
e725fbc
fix(list): preventDefault regardless of list variant & updated tests
abhiomkar Jan 7, 2019
1bfa55c
fix(list): water
abhiomkar Jan 7, 2019
0bde2ae
fix(menu): water
abhiomkar Jan 7, 2019
20d069e
fix(list): Removed merge conflict additions
abhiomkar Jan 7, 2019
8ef0272
Merge branch 'list_custom_event_issue3481' into list_custom_event_men…
abhiomkar Jan 7, 2019
4d48086
fix(menu): Happy New Year 🎉
abhiomkar Jan 25, 2019
674fa82
Merge remote-tracking branch 'origin/master' into list_custom_event_m…
abhiomkar Jan 25, 2019
920da47
fix(menu): dummy commit
abhiomkar Jan 25, 2019
30e3db6
fix(menu): review comments
abhiomkar Jan 25, 2019
4083ecd
fix(menu): rename test CSS class names
abhiomkar Jan 28, 2019
3494923
Merge remote-tracking branch 'origin/master' into list_custom_event_m…
abhiomkar Jan 28, 2019
9859d39
fix(menu): fix lint
abhiomkar Jan 29, 2019
eecb1fc
fix(menu): fix closure tests
abhiomkar Jan 29, 2019
e184dcb
feat(menu): Updated golden.json
abhiomkar Jan 29, 2019
eccb2d4
Merge branch 'master' into list_custom_event_menu_update_issue3481
abhiomkar Jan 29, 2019
9cba1a8
fix(menu): Update unit tests WIP
abhiomkar Jan 30, 2019
4c450ed
fix(menu): Updated unit tests
abhiomkar Jan 30, 2019
ee14502
Merge remote-tracking branch 'origin/list_custom_event_menu_update_is…
abhiomkar Jan 30, 2019
b3b4f0b
Merge remote-tracking branch 'origin/master' into list_custom_event_m…
abhiomkar Jan 30, 2019
c834e84
Merge branch 'master' into list_custom_event_menu_update_issue3481
abhiomkar Jan 31, 2019
f19cba1
fix(menu): increase screen shot test area
abhiomkar Jan 31, 2019
d7107bf
Merge remote-tracking branch 'origin/list_custom_event_menu_update_is…
abhiomkar Jan 31, 2019
1f5220d
fix(menu): Update golden screenshots
abhiomkar Jan 31, 2019
ae0ac81
Merge branch 'master' into list_custom_event_menu_update_issue3481
abhiomkar Jan 31, 2019
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
2 changes: 2 additions & 0 deletions packages/mdc-list/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,7 @@ Method Signature | Description
`getListItemCount() => Number` | Returns the total number of list items (elements with `mdc-list-item` class) that are direct children of the `root_` element.
`getFocusedElementIndex() => Number` | Returns the `index` value of the currently focused element.
`getListItemIndex(ele: Element) => Number` | Returns the `index` value of the provided `ele` element.
`getAttributeForElementIndex(index: number, attr: string) => string` | Gets the `attr` attribute value for the list item at `index`.
`setAttributeForElementIndex(index: Number, attr: String, value: String) => void` | Sets the `attr` attribute to `value` for the list item at `index`.
`addClassForElementIndex(index: Number, className: String) => void` | Adds the `className` class to the list item at `index`.
`removeClassForElementIndex(index: Number, className: String) => void` | Removes the `className` class to the list item at `index`.
Expand All @@ -509,6 +510,7 @@ Method Signature | Description
`hasCheckboxAtIndex(index: number) => boolean` | Returns true if checkbox is present at given list item index.
`isCheckboxCheckedAtIndex(index: number) => boolean` | Returns true if checkbox inside a list item is checked.
`setCheckedCheckboxOrRadioAtIndex(index: number, isChecked: boolean) => void` | Sets the checked status of checkbox or radio at given list item index.
`notifyAction(index: number) => void` | Notifies user action on list item including keyboard and mouse actions.

### `MDCListFoundation`

Expand Down
11 changes: 11 additions & 0 deletions packages/mdc-list/adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ class MDCListAdapter {
* @return {number} */
getFocusedElementIndex() {}

/**
* @param {number} index
* @param {string} attribute
*/
getAttributeForElementIndex(index, attr) {}

/**
* @param {number} index
* @param {string} attribute
Expand Down Expand Up @@ -113,6 +119,11 @@ class MDCListAdapter {
* @param {boolean} isChecked
*/
setCheckedCheckboxOrRadioAtIndex(index, isChecked) {}

/**
* Notifies user action on list item.
*/
notifyAction(index) {}
}

export default MDCListAdapter;
1 change: 1 addition & 0 deletions packages/mdc-list/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const strings = {
.${cssClasses.LIST_ITEM_CLASS} input[type="radio"]:not(:disabled),
.${cssClasses.LIST_ITEM_CLASS} input[type="checkbox"]:not(:disabled)`,
ENABLED_ITEMS_SELECTOR: '.mdc-list-item:not(.mdc-list-item--disabled)',
ACTION_EVENT: 'MDCList:action',
};

export {strings, cssClasses};
10 changes: 9 additions & 1 deletion packages/mdc-list/foundation.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class MDCListFoundation extends MDCFoundation {
return /** @type {!MDCListAdapter} */ ({
getListItemCount: () => {},
getFocusedElementIndex: () => {},
getAttributeForElementIndex: () => {},
setAttributeForElementIndex: () => {},
removeAttributeForElementIndex: () => {},
addClassForElementIndex: () => {},
Expand All @@ -58,6 +59,7 @@ class MDCListFoundation extends MDCFoundation {
hasCheckboxAtIndex: () => {},
isCheckboxCheckedAtIndex: () => {},
setCheckedCheckboxOrRadioAtIndex: () => {},
notifyAction: () => {},
});
}

Expand Down Expand Up @@ -265,7 +267,11 @@ class MDCListFoundation extends MDCFoundation {
}

// Explicitly activate links, since we're preventing default on Enter, and Space doesn't activate them.
this.adapter_.followHref(currentIndex);
if (this.adapter_.getAttributeForElementIndex(currentIndex, 'href')) {
this.adapter_.followHref(currentIndex);
} else {
this.adapter_.notifyAction(currentIndex);
}
}
}
}
Expand All @@ -285,6 +291,8 @@ class MDCListFoundation extends MDCFoundation {
if (this.isSingleSelectionList_ || this.hasCheckboxOrRadioAtIndex_(index)) {
this.setSelectedIndex(index);
}

this.adapter_.notifyAction(index);
}

/**
Expand Down
4 changes: 4 additions & 0 deletions packages/mdc-list/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ class MDCList extends MDCComponent {
return new MDCListFoundation(/** @type {!MDCListAdapter} */ (Object.assign({
getListItemCount: () => this.listElements.length,
getFocusedElementIndex: () => this.listElements.indexOf(document.activeElement),
getAttributeForElementIndex: (index, attr) => this.listElements[index].getAttribute(attr),
setAttributeForElementIndex: (index, attr, value) => {
const element = this.listElements[index];
if (element) {
Expand Down Expand Up @@ -269,6 +270,9 @@ class MDCList extends MDCComponent {
event.initEvent('change', true, true);
toggleEl.dispatchEvent(event);
},
notifyAction: (index) => {
this.emit(strings.ACTION_EVENT, index, /** shouldBubble */ true);
},
})));
}
}
Expand Down
3 changes: 1 addition & 2 deletions packages/mdc-menu/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,7 @@ Method Signature | Description
Method Signature | Description
--- | ---
`handleKeydown(evt: Event) => void` | Event handler for the `keydown` events within the menu.
`handleClick(evt: Event) => void` | Event handler for the `click` events within the menu.
`handleSelection(listItem: Element) => void` | Handler for a selected list item. Use this instead of `handleClick` when you don't have access to list item click event.
`handleItemAction(index: number) => void` | Event handler for list's action event.

### Events

Expand Down
49 changes: 3 additions & 46 deletions packages/mdc-menu/foundation.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ import {cssClasses, strings} from './constants';
import {MDCMenuSurfaceFoundation} from '@material/menu-surface/foundation';
import MDCListFoundation from '@material/list/foundation';

const ELEMENTS_KEY_ALLOWED_IN = ['input', 'button', 'textarea', 'select', 'a'];

/**
* @extends {MDCFoundation<!MDCMenuAdapter>}
*/
Expand Down Expand Up @@ -85,44 +83,17 @@ class MDCMenuFoundation extends MDCFoundation {
*/
handleKeydown(evt) {
const {key, keyCode} = evt;

const isSpace = key === 'Space' || keyCode === 32;
const isEnter = key === 'Enter' || keyCode === 13;
const isTab = key === 'Tab' || keyCode === 9;

if (isSpace || isEnter) {
this.handleAction_(evt);
} else if (isTab) {
if (isTab) {
this.adapter_.closeSurface();
}
}

/**
* Handler function for the click events.
* @param {!Event} evt
* @param {!Element} listItem
*/
handleClick(evt) {
this.handleAction_(evt);
}

/**
* Combined action handling for click/keypress events.
* @param {!Event} evt
* @private
*/
handleAction_(evt) {
const listItem = this.getListItem_(/** @type {HTMLElement} */ (evt.target));
if (listItem) {
this.handleSelection(listItem);
this.preventDefaultEvent_(evt);
}
}

/**
* Handler for a selected list item.
* @param {?HTMLElement} listItem
*/
handleSelection(listItem) {
handleItemAction(listItem) {
const index = this.adapter_.getElementIndex(listItem);
if (index < 0) {
return;
Expand Down Expand Up @@ -203,20 +174,6 @@ class MDCMenuFoundation extends MDCFoundation {

return target;
}

/**
* Ensures that preventDefault is only called if the containing element doesn't
* consume the event, and it will cause an unintended scroll.
* @param {!Event} evt
* @private
*/
preventDefaultEvent_(evt) {
const target = /** @type {!HTMLElement} */ (evt.target);
const tagName = `${target.tagName}`.toLowerCase();
if (ELEMENTS_KEY_ALLOWED_IN.indexOf(tagName) === -1) {
evt.preventDefault();
}
}
}

export {MDCMenuFoundation};
11 changes: 7 additions & 4 deletions packages/mdc-menu/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {strings, cssClasses} from './constants';
import {MDCMenuSurface, Corner} from '@material/menu-surface/index';
import {MDCMenuSurfaceFoundation, AnchorMargin} from '@material/menu-surface/foundation';
import {MDCList} from '@material/list/index';
import {strings as listStrings} from '@material/list/constants';

/**
* @extends MDCComponent<!MDCMenuFoundation>
Expand All @@ -41,8 +42,10 @@ class MDCMenu extends MDCComponent {
this.list_;
/** @private {!Function} */
this.handleKeydown_;

/** @private {!Function} */
this.handleClick_;
this.handleItemAction_;

/** @private {!Function} */
this.afterOpenedCallback_;
}
Expand Down Expand Up @@ -70,11 +73,11 @@ class MDCMenu extends MDCComponent {
initialSyncWithDOM() {
this.afterOpenedCallback_ = () => this.handleAfterOpened_();
this.handleKeydown_ = (evt) => this.foundation_.handleKeydown(evt);
this.handleClick_ = (evt) => this.foundation_.handleClick(evt);
this.handleItemAction_ = (evt) => this.foundation_.handleItemAction(this.items[evt.detail]);

this.menuSurface_.listen(MDCMenuSurfaceFoundation.strings.OPENED_EVENT, this.afterOpenedCallback_);
this.listen('keydown', this.handleKeydown_);
this.listen('click', this.handleClick_);
this.listen(listStrings.ACTION_EVENT, this.handleItemAction_);
}

destroy() {
Expand All @@ -85,7 +88,7 @@ class MDCMenu extends MDCComponent {
this.menuSurface_.destroy();
this.menuSurface_.unlisten(MDCMenuSurfaceFoundation.strings.OPENED_EVENT, this.afterOpenedCallback_);
this.unlisten('keydown', this.handleKeydown_);
this.unlisten('click', this.handleClick_);
this.unlisten(listStrings.ACTION_EVENT, this.handleItemAction_);
super.destroy();
}

Expand Down
88 changes: 88 additions & 0 deletions test/screenshot/spec/mdc-menu/classes/baseline.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<!DOCTYPE html>
<!--
Copyright 2018 Google Inc.
abhiomkar marked this conversation as resolved.
Show resolved Hide resolved

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<html lang="en">
<head>
<meta charset="utf-8">
<title>Baseline Menu - MDC Web Screenshot Test</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="../../../out/mdc.menu.css">
<link rel="stylesheet" href="../../../out/mdc.menu-surface.css">
<link rel="stylesheet" href="../../../out/mdc.list.css">
<link rel="stylesheet" href="../../../out/mdc.button.css">
<link rel="stylesheet" href="../../../out/spec/fixture.css">
<link rel="stylesheet" href="../../../out/spec/mdc-menu/fixture.css">

<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-118996389-2"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-118996389-2');
</script>
</head>

<body class="test-container">
<main class="test-viewport test-viewport--mobile">
<div class="test-layout">
<div class="test-cell test-cell--menu">
<div class="menu-button-container">
<button class="mdc-button menu-button">Open menu</button>
<div class="mdc-menu mdc-menu-surface" tabindex="-1" id="demo-menu">
abhiomkar marked this conversation as resolved.
Show resolved Hide resolved
<ul class="mdc-list" role="menu" aria-hidden="true" aria-orientation="vertical">
<li>
<ul class="mdc-menu__selection-group">
<li class="mdc-list-item" role="menuitem">
<span class="mdc-menu__selection-group-icon">
<i class="material-icons">check</i>
</span>
<span class="mdc-list-item__text">Single</span>
</li>
<li class="mdc-list-item" role="menuitem">
<span class="mdc-menu__selection-group-icon">
<i class="material-icons">check</i>
</span>
<span class="mdc-list-item__text">1.15</span>
</li>
</ul>
</li>
<li class="mdc-list-divider" role="separator"></li>
<li class="mdc-list-item" role="menuitem">
<span class="mdc-list-item__text">Add space before paragraph</span>
</li>
</ul>
</div>
</div>
</div>
</div>
</main>

<!-- Automatically provides/replaces `Promise` if missing or broken. -->
<script src="https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.js"></script>
<script src="https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.auto.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fontfaceobserver/2.0.13/fontfaceobserver.standalone.js"></script>
<script src="../../../out/material-components-web.js"></script>
<script src="../../../out/spec/fixture.js"></script>
<script src="../../../out/spec/mdc-menu/fixture.js"></script>
</body>
</html>
37 changes: 37 additions & 0 deletions test/screenshot/spec/mdc-menu/fixture.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* @license
* Copyright 2018 Google Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

window.mdc.testFixture.fontsLoaded.then(() => {
const buttonEl = document.querySelector('.menu-button');
const menuEl = document.querySelector('.mdc-menu');
const menu = mdc.menu.MDCMenu.attachTo(menuEl);
menu.setAnchorCorner(mdc.menu.Corner.BOTTOM_LEFT);
menu.setAnchorElement(buttonEl);
menu.open = !menu.open;
abhiomkar marked this conversation as resolved.
Show resolved Hide resolved

buttonEl.addEventListener('click', () => {
menu.open = !menu.open;
});

window.mdc.testFixture.notifyDomReady();
});
Loading