Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
54a5fa1
commit 48a446f
Showing
5 changed files
with
321 additions
and
87 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
'use strict'; | ||
|
||
// Required modules. | ||
var EventObserver = require( '../modules/util/EventObserver' ); | ||
|
||
/** | ||
* FlyoutMenu | ||
* @class | ||
* | ||
* @classdesc Initializes a new FlyoutMenu molecule. | ||
* | ||
* @param {HTMLNode} element | ||
* The DOM element within which to search for the molecule. | ||
* @param {string} triggerSel - The selector for the menu trigger. | ||
* @param {string} contentSel - The selector for the menu content. | ||
* @param {string} altTriggerSel - The selector for a second menu trigger. | ||
* @returns {Object} A FlyoutMenu instance. | ||
*/ | ||
function FlyoutMenu( element, triggerSel, contentSel, altTriggerSel ) { | ||
|
||
var _isExpanded = false; | ||
|
||
var _triggerDom = element.querySelector( triggerSel ); | ||
var _contentDom = element.querySelector( contentSel ); | ||
var _altTriggerDom = element.querySelector( altTriggerSel ); | ||
|
||
var _transitionEndEvent = _getTransitionEndEvent( _contentDom ); | ||
|
||
/** | ||
* @returns {Object} The FlyoutMenu instance. | ||
*/ | ||
function init() { | ||
_triggerDom.addEventListener( 'click', _triggerClicked.bind( this ) ); | ||
|
||
if ( altTriggerSel ) { | ||
_altTriggerDom.addEventListener( 'click', _triggerClicked.bind( this ) ); | ||
} | ||
|
||
return this; | ||
} | ||
|
||
/** | ||
* Event handler for when the search input trigger is clicked, | ||
* which opens/closes the search input. | ||
* @param {MouseEvent} event - The flyout trigger was clicked. | ||
*/ | ||
function _triggerClicked( event ) { | ||
event.preventDefault(); | ||
this.dispatchEvent( 'triggerClick', { target: event.target } ); | ||
if ( _isExpanded ) { | ||
this.collapse(); | ||
} else { | ||
this.expand(); | ||
} | ||
} | ||
|
||
/** | ||
* Open the search box. | ||
* @returns {Object} A FlyoutMenu instance. | ||
*/ | ||
function expand() { | ||
if ( !_isExpanded ) { | ||
this.dispatchEvent( 'expandBegin', { target: this } ); | ||
_isExpanded = true; | ||
_addTransitionListener( this, _contentDom, _expandEnd ); | ||
_triggerDom.setAttribute( 'aria-expanded', 'true' ); | ||
_contentDom.setAttribute( 'aria-expanded', 'true' ); | ||
} | ||
|
||
return this; | ||
} | ||
|
||
/** | ||
* Close the search box. | ||
* @returns {Object} A FlyoutMenu instance. | ||
*/ | ||
function collapse() { | ||
if ( _isExpanded ) { | ||
this.dispatchEvent( 'collapseBegin', { target: this } ); | ||
_isExpanded = false; | ||
_addTransitionListener( this, _contentDom, _collapseEnd ); | ||
_triggerDom.setAttribute( 'aria-expanded', 'false' ); | ||
_contentDom.setAttribute( 'aria-expanded', 'false' ); | ||
} | ||
|
||
return this; | ||
} | ||
|
||
/** | ||
* Transition height property and call a callback function. | ||
* Call callback directly if CSS transitions aren't supported. | ||
* @param {FlyoutMenu} target - Reference to this instance. | ||
* @param {HTMLNode} dom - Element on which to listen for transition event. | ||
* @param {Function} | ||
* callback - Callback function for completion of transition. | ||
*/ | ||
function _addTransitionListener( target, dom, callback ) { | ||
if ( _transitionEndEvent ) { | ||
dom.addEventListener( _transitionEndEvent, callback.bind( target ) ); | ||
} else { | ||
// TODO: Remove callback-return ESLint ignore | ||
callback(); // eslint-disable-line callback-return, inline-comments, max-len | ||
} | ||
} | ||
|
||
/** | ||
* Expand animation has completed. | ||
*/ | ||
function _expandEnd() { | ||
_contentDom.removeEventListener( _transitionEndEvent, _expandEnd ); | ||
this.dispatchEvent( 'expandEnd', { target: this } ); | ||
} | ||
|
||
/** | ||
* Collapse animation has completed. | ||
*/ | ||
function _collapseEnd() { | ||
_contentDom.removeEventListener( _transitionEndEvent, _collapseEnd ); | ||
this.dispatchEvent( 'collapseEnd', { target: this } ); | ||
} | ||
|
||
// Attach public events. | ||
var eventObserver = new EventObserver(); | ||
this.addEventListener = eventObserver.addEventListener; | ||
this.removeEventListener = eventObserver.removeEventListener; | ||
this.dispatchEvent = eventObserver.dispatchEvent; | ||
|
||
this.init = init; | ||
this.expand = expand; | ||
this.collapse = collapse; | ||
|
||
return this; | ||
} | ||
|
||
// TODO: Move to a utility module and share this between Expandables and here. | ||
/** | ||
* @param {HTMLNode} elm | ||
* The element to check for support of transition end event. | ||
* @returns {string} The browser-prefixed transition end event. | ||
*/ | ||
function _getTransitionEndEvent( elm ) { | ||
var transition; | ||
var transitions = { | ||
WebkitTransition: 'webkitTransitionEnd', | ||
MozTransition: 'transitionend', | ||
OTransition: 'oTransitionEnd otransitionend', | ||
transition: 'transitionend' | ||
}; | ||
|
||
for ( var t in transitions ) { | ||
if ( transitions.hasOwnProperty( t ) && | ||
typeof elm.style[t] !== 'undefined' ) { | ||
transition = transitions[t]; | ||
break; | ||
} | ||
} | ||
return transition; | ||
} | ||
|
||
module.exports = FlyoutMenu; |
Oops, something went wrong.