Skip to content

Commit

Permalink
refactor(top-app-bar): Remove [de]registerEventHandler methods from a…
Browse files Browse the repository at this point in the history
…dapters (#4701)

BREAKING CHANGE: Replaced adapter methods getParentElement, getSelectedElementIndex with getSelectedSiblingOfItemAtIndex, isSelectableItemAtIndex.
  • Loading branch information
Matt Goo authored and abhiomkar committed Jun 11, 2019
1 parent 1108307 commit 34bba89
Show file tree
Hide file tree
Showing 12 changed files with 244 additions and 466 deletions.
11 changes: 3 additions & 8 deletions packages/mdc-top-app-bar/README.md
Expand Up @@ -219,12 +219,6 @@ Method Signature | Description
`getViewportScrollY() => number` | Gets the number of pixels that the content of body is scrolled from the top of the page.
`getTotalActionItems() => number` | Gets the number of action items in the top app bar.
`notifyNavigationIconClicked() => void` | Emits a custom event `MDCTopAppBar:nav` when the navigation icon is clicked.
`registerNavigationIconInteractionHandler(evtType: string, handler: EventListener) => void` | Registers an event listener on the native navigation icon element for a given event.
`deregisterNavigationIconInteractionHandler(evtType: string, handler: EventListener) => void` | Deregisters an event listener on the native navigation icon element for a given event.
`registerScrollHandler(handler: EventListener) => void` | Registers a handler to be called when user scrolls. Our default implementation adds the handler as a listener to the window's `scroll` event.
`deregisterScrollHandler(handler: EventListener) => void` | Unregisters a handler to be called when user scrolls. Our default implementation removes the handler as a listener to the window's `scroll` event.
`registerResizeHandler(handler: EventListener) => void` | Registers a handler to be called when the surface (or its viewport) resizes. Our default implementation adds the handler as a listener to the window's `resize` event.
`deregisterResizeHandler(handler: EventListener) => void` | Unregisters a handler to be called when the surface (or its viewport) resizes. Our default implementation removes the handler as a listener to the window's `resize` event.

### Foundations

Expand All @@ -234,8 +228,9 @@ All foundations provide the following methods:

Method Signature | Description
--- | ---
`initScrollHandler(handler: EventListener) => void` | Registers a scroll handler on a specific target element.
`destroyScrollHandler(handler: EventListener) => void` | Deregisters the current scroll handler set by the foundation.
`handleTargetScroll() => void` | Handles `scroll` event on specified scrollTarget (defaults to `window`).
`handleWindowResize() => void` | Handles `resize` event on window.
`handleNavigationClick() => void` | Handles `click` event on navigation icon.

#### `MDCShortTopAppBarFoundation`

Expand Down
20 changes: 0 additions & 20 deletions packages/mdc-top-app-bar/adapter.ts
Expand Up @@ -21,8 +21,6 @@
* THE SOFTWARE.
*/

import {EventType, SpecificEventListener} from '@material/base/types';

/**
* Defines the shape of the adapter expected by the foundation.
* Implement this adapter for your framework of choice to delegate updates to
Expand Down Expand Up @@ -64,22 +62,4 @@ export interface MDCTopAppBarAdapter {
* Emits an event when the navigation icon is clicked.
*/
notifyNavigationIconClicked(): void;

/**
* Registers an event handler on the navigation icon element for a given event.
*/
registerNavigationIconInteractionHandler<K extends EventType>(type: K, handler: SpecificEventListener<K>): void;

/**
* Deregisters an event handler on the navigation icon element for a given event.
*/
deregisterNavigationIconInteractionHandler<K extends EventType>(type: K, handler: SpecificEventListener<K>): void;

registerScrollHandler(handler: SpecificEventListener<'scroll'>): void;

deregisterScrollHandler(handler: SpecificEventListener<'scroll'>): void;

registerResizeHandler(handler: SpecificEventListener<'resize'>): void;

deregisterResizeHandler(handler: SpecificEventListener<'resize'>): void;
}
51 changes: 35 additions & 16 deletions packages/mdc-top-app-bar/component.ts
Expand Up @@ -22,6 +22,7 @@
*/

import {MDCComponent} from '@material/base/component';
import {SpecificEventListener} from '@material/base/types';
import {MDCRipple, MDCRippleFactory} from '@material/ripple/component';
import {MDCTopAppBarAdapter} from './adapter';
import {cssClasses, strings} from './constants';
Expand All @@ -35,6 +36,9 @@ export class MDCTopAppBar extends MDCComponent<MDCTopAppBarBaseFoundation> {
return new MDCTopAppBar(root);
}

private handleNavigationClick_!: SpecificEventListener<'click'>; // assigned in initialSyncWithDOM()
private handleWindowResize_!: SpecificEventListener<'resize'>; // assigned in initialSyncWithDOM()
private handleTargetScroll_!: SpecificEventListener<'scroll'>; // assigned in initialSyncWithDOM()
private navIcon_!: Element | null;
private iconRipples_!: MDCRipple[];
private scrollTarget_!: EventTarget;
Expand All @@ -57,19 +61,48 @@ export class MDCTopAppBar extends MDCComponent<MDCTopAppBarBaseFoundation> {
this.scrollTarget_ = window;
}

initialSyncWithDOM() {
this.handleNavigationClick_ = this.foundation_.handleNavigationClick.bind(this.foundation_);
this.handleWindowResize_ = this.foundation_.handleWindowResize.bind(this.foundation_);
this.handleTargetScroll_ = this.foundation_.handleTargetScroll.bind(this.foundation_);

this.scrollTarget_.addEventListener('scroll', this.handleTargetScroll_ as EventListener);

if (this.navIcon_) {
this.navIcon_.addEventListener('click', this.handleNavigationClick_ as EventListener);
}

const isFixed = this.root_.classList.contains(cssClasses.FIXED_CLASS);
const isShort = this.root_.classList.contains(cssClasses.SHORT_CLASS);
if (!isShort && !isFixed) {
window.addEventListener('resize', this.handleWindowResize_ as EventListener);
}
}

destroy() {
this.iconRipples_.forEach((iconRipple) => iconRipple.destroy());
this.scrollTarget_.removeEventListener('scroll', this.handleTargetScroll_ as EventListener);
if (this.navIcon_) {
this.navIcon_.removeEventListener('click', this.handleNavigationClick_ as EventListener);
}
const isFixed = this.root_.classList.contains(cssClasses.FIXED_CLASS);
const isShort = this.root_.classList.contains(cssClasses.SHORT_CLASS);
if (!isShort && !isFixed) {
window.removeEventListener('resize', this.handleWindowResize_ as EventListener);
}
super.destroy();
}

setScrollTarget(target: EventTarget) {
// Remove scroll handler from the previous scroll target
this.foundation_.destroyScrollHandler();
this.scrollTarget_.removeEventListener('scroll', this.handleTargetScroll_ as EventListener);

this.scrollTarget_ = target;

// Initialize scroll handler on the new scroll target
this.foundation_.initScrollHandler();
this.handleTargetScroll_ =
this.foundation_.handleTargetScroll.bind(this.foundation_);
this.scrollTarget_.addEventListener('scroll', this.handleTargetScroll_ as EventListener);
}

getDefaultFoundation() {
Expand All @@ -82,21 +115,7 @@ export class MDCTopAppBar extends MDCComponent<MDCTopAppBarBaseFoundation> {
removeClass: (className) => this.root_.classList.remove(className),
setStyle: (property, value) => (this.root_ as HTMLElement).style.setProperty(property, value),
getTopAppBarHeight: () => this.root_.clientHeight,
registerNavigationIconInteractionHandler: (evtType, handler) => {
if (this.navIcon_) {
this.navIcon_.addEventListener(evtType, handler);
}
},
deregisterNavigationIconInteractionHandler: (evtType, handler) => {
if (this.navIcon_) {
this.navIcon_.removeEventListener(evtType, handler);
}
},
notifyNavigationIconClicked: () => this.emit(strings.NAVIGATION_EVENT, {}),
registerScrollHandler: (handler) => this.scrollTarget_.addEventListener('scroll', handler as EventListener),
deregisterScrollHandler: (handler) => this.scrollTarget_.removeEventListener('scroll', handler as EventListener),
registerResizeHandler: (handler) => window.addEventListener('resize', handler),
deregisterResizeHandler: (handler) => window.removeEventListener('resize', handler),
getViewportScrollY: () => {
const win = this.scrollTarget_ as Window;
const el = this.scrollTarget_ as Element;
Expand Down
11 changes: 2 additions & 9 deletions packages/mdc-top-app-bar/fixed/foundation.ts
Expand Up @@ -21,7 +21,6 @@
* THE SOFTWARE.
*/

import {MDCTopAppBarAdapter} from '../adapter';
import {cssClasses} from '../constants';
import {MDCTopAppBarFoundation} from '../standard/foundation';

Expand All @@ -31,17 +30,11 @@ export class MDCFixedTopAppBarFoundation extends MDCTopAppBarFoundation {
*/
private wasScrolled_ = false;

/* istanbul ignore next: optional argument is not a branch statement */
constructor(adapter?: Partial<MDCTopAppBarAdapter>) {
super(adapter);

this.scrollHandler_ = () => this.fixedScrollHandler_();
}

/**
* Scroll handler for applying/removing the modifier class on the fixed top app bar.
* @override
*/
private fixedScrollHandler_() {
handleTargetScroll() {
const currentScroll = this.adapter_.getViewportScrollY();

if (currentScroll <= 0) {
Expand Down
52 changes: 6 additions & 46 deletions packages/mdc-top-app-bar/foundation.ts
Expand Up @@ -22,7 +22,6 @@
*/

import {MDCFoundation} from '@material/base/foundation';
import {SpecificEventListener} from '@material/base/types';
import {MDCTopAppBarAdapter} from './adapter';
import {cssClasses, numbers, strings} from './constants';

Expand Down Expand Up @@ -50,64 +49,25 @@ export class MDCTopAppBarBaseFoundation extends MDCFoundation<MDCTopAppBarAdapte
hasClass: () => false,
setStyle: () => undefined,
getTopAppBarHeight: () => 0,
registerNavigationIconInteractionHandler: () => undefined,
deregisterNavigationIconInteractionHandler: () => undefined,
notifyNavigationIconClicked: () => undefined,
registerScrollHandler: () => undefined,
deregisterScrollHandler: () => undefined,
registerResizeHandler: () => undefined,
deregisterResizeHandler: () => undefined,
getViewportScrollY: () => 0,
getTotalActionItems: () => 0,
};
// tslint:enable:object-literal-sort-keys
}

protected scrollHandler_?: SpecificEventListener<'scroll'>;
protected resizeHandler_?: SpecificEventListener<'resize'>;
private readonly navClickHandler_: SpecificEventListener<'click'>;

/* istanbul ignore next: optional argument is not a branch statement */
constructor(adapter?: Partial<MDCTopAppBarAdapter>) {
super({...MDCTopAppBarBaseFoundation.defaultAdapter, ...adapter});

this.navClickHandler_ = () => this.adapter_.notifyNavigationIconClicked();
}

init() {
this.initScrollHandler();
this.initResizeHandler_();
this.adapter_.registerNavigationIconInteractionHandler('click', this.navClickHandler_);
}

destroy() {
this.destroyScrollHandler();
this.destroyResizeHandler_();
this.adapter_.deregisterNavigationIconInteractionHandler('click', this.navClickHandler_);
}

initScrollHandler() {
if (this.scrollHandler_) {
this.adapter_.registerScrollHandler(this.scrollHandler_);
}
}

destroyScrollHandler() {
if (this.scrollHandler_) {
this.adapter_.deregisterScrollHandler(this.scrollHandler_);
}
}

private initResizeHandler_() {
if (this.resizeHandler_) {
this.adapter_.registerResizeHandler(this.resizeHandler_);
}
}
/** Other variants of TopAppBar foundation overrides this method */
handleTargetScroll() {} // tslint:disable-line:no-empty
/** Other variants of TopAppBar foundation overrides this method */
handleWindowResize() {} // tslint:disable-line:no-empty

private destroyResizeHandler_() {
if (this.resizeHandler_) {
this.adapter_.deregisterResizeHandler(this.resizeHandler_);
}
handleNavigationClick() {
this.adapter_.notifyNavigationIconClicked();
}
}

Expand Down
18 changes: 8 additions & 10 deletions packages/mdc-top-app-bar/short/foundation.ts
Expand Up @@ -45,21 +45,19 @@ export class MDCShortTopAppBarFoundation extends MDCTopAppBarBaseFoundation {
this.adapter_.addClass(cssClasses.SHORT_HAS_ACTION_ITEM_CLASS);
}

if (!this.adapter_.hasClass(cssClasses.SHORT_COLLAPSED_CLASS)) {
this.scrollHandler_ = () => this.shortAppBarScrollHandler_();
this.adapter_.registerScrollHandler(this.scrollHandler_);
this.shortAppBarScrollHandler_();
}
}

destroy() {
super.destroy();
// this is intended as the short variant must calculate if the
// page starts off from the top of the page.
this.handleTargetScroll();
}

/**
* Scroll handler for applying/removing the collapsed modifier class on the short top app bar.
* @override
*/
private shortAppBarScrollHandler_() {
handleTargetScroll() {
if (this.adapter_.hasClass(cssClasses.SHORT_COLLAPSED_CLASS)) {
return;
}
const currentScroll = this.adapter_.getViewportScrollY();

if (currentScroll <= 0) {
Expand Down

0 comments on commit 34bba89

Please sign in to comment.