219 lines
8.8 KiB
JavaScript
219 lines
8.8 KiB
JavaScript
/**
|
|
* Off-canvas menu
|
|
* @module Ink.UI.Drawer_1
|
|
* @version 1
|
|
*/
|
|
|
|
Ink.createModule('Ink.UI.Drawer', '1', ['Ink.UI.Common_1', 'Ink.Dom.Loaded_1', 'Ink.Dom.Selector_1', 'Ink.Dom.Element_1', 'Ink.Dom.Event_1', 'Ink.Dom.Css_1'], function(Common, Loaded, Selector, Element, Event, Css) {
|
|
'use strict';
|
|
|
|
function elNotFound(el) {
|
|
Ink.warn( 'Ink.UI.Drawer_1: Could not find the "' +
|
|
el + '" element on this page. Please make sure it exists.' );
|
|
}
|
|
|
|
function Drawer(options) {
|
|
Common.BaseUIComponent.apply(this, [document.body, options]);
|
|
}
|
|
|
|
Drawer._name = 'Drawer_1';
|
|
|
|
Drawer._optionDefinition = {
|
|
parentSelector: ['String', '.ink-drawer'],
|
|
leftDrawer: ['String', '.left-drawer'],
|
|
leftTrigger: ['String', '.left-drawer-trigger'],
|
|
rightDrawer: ['String', '.right-drawer'],
|
|
rightTrigger: ['String', '.right-drawer-trigger'],
|
|
contentDrawer: ['String', '.content-drawer'],
|
|
closeOnContentClick: ['Boolean', true],
|
|
closeOnLinkClick: ['Boolean', true],
|
|
mode: ['String', 'push'],
|
|
sides: ['String', 'both']
|
|
};
|
|
|
|
Drawer.prototype = {
|
|
/**
|
|
* Displays off-canvas content which can be triggered by clicking elements with the 'left-drawer-trigger' and 'right-drawer-trigger', respectively.
|
|
* The left drawer has the 'left-drawer' class, and the right drawer has the 'right-drawer' class. The content drawer (EG your `<div id="main">`) must have the 'content-drawer' class. For more, see the example below, or try the sample.
|
|
* @class Ink.UI.Drawer_1
|
|
* @constructor
|
|
*
|
|
* @param {Object} [options] Configuration options.
|
|
* @xparam {String} [options.parentSelector] The class you are using in your wrapper (in the example below, it's the `body` tag.)
|
|
* @xparam {String} [options.leftDrawer] Selector for the left drawer element. This element is placed outside the screen and shown when you click the `leftTrigger` element.
|
|
* @xparam {String} [options.leftTrigger] Selector for the left drawer trigger(s). When you click this trigger, the `leftDrawer` is shown.
|
|
* @xparam {String} [options.rightDrawer] Right drawer selector. (see `options.leftDrawer`)
|
|
* @xparam {String} [options.rightTrigger] Right trigger selector (see `options.leftTrigger`)
|
|
* @xparam {String} [options.contentDrawer] Selector for the content drawer.
|
|
* @param {Boolean} [options.closeOnContentClick] Flag to close the drawer when someone clicks on the `.contentDrawer`
|
|
* @param {String} [options.mode] This can be 'push' or 'over'.
|
|
* @param {String} [options.sides] Can be 'left', 'right', or 'both'. Controls what sides have a drawer.
|
|
*
|
|
* @example
|
|
* <body class="ink-drawer">
|
|
* <div class="left-drawer">
|
|
* Right drawer content...
|
|
* </div>
|
|
* <div class="right-drawer">
|
|
* Left drawer content...
|
|
* </div>
|
|
* <div id="main-content" class="content-drawer ink-grid">
|
|
* <a class="left-drawer-trigger" href="">Open left drawer</a>
|
|
* <a class="right-drawer-trigger" href="">Open right drawer</a>
|
|
* Content...
|
|
* </div>
|
|
* </body>
|
|
*
|
|
* <script>
|
|
* Ink.requireModules(['Ink.UI.Drawer_1'], function (Drawer) {
|
|
* new Drawer();
|
|
* });
|
|
* </script>
|
|
*/
|
|
_init: function () {
|
|
// make sure we have the required elements acording to the config options
|
|
|
|
this._contentDrawers = Ink.ss(this._options.contentDrawer);
|
|
|
|
this._leftDrawer = Ink.s(this._options.leftDrawer);
|
|
this._leftTriggers = Ink.ss(this._options.leftTrigger);
|
|
|
|
this._rightDrawer = Ink.s(this._options.rightDrawer);
|
|
this._rightTriggers = Ink.ss(this._options.rightTrigger);
|
|
|
|
// The body might not have it
|
|
Css.addClassName(document.body, 'ink-drawer');
|
|
|
|
if(this._contentDrawers.length === 0) {
|
|
throw new Error('Ink.UI.Drawer_1: Could not find any "' +
|
|
this._options.contentDrawer + '" elements on this page. ' +
|
|
'Please make sure you have at least one.' );
|
|
}
|
|
|
|
switch (this._options.sides) {
|
|
case 'both':
|
|
this._triggers =
|
|
this._options.leftTrigger + ', ' +
|
|
this._options.rightTrigger + ', ' +
|
|
this._options.contentDrawer;
|
|
break;
|
|
|
|
case 'left':
|
|
this._triggers =
|
|
this._options.leftTrigger + ', ' +
|
|
this._options.contentDrawer;
|
|
break;
|
|
|
|
case 'right':
|
|
this._triggers =
|
|
this._options.rightTrigger + ', ' +
|
|
this._options.contentDrawer;
|
|
break;
|
|
}
|
|
|
|
if (this._options.sides === 'left' || this._options.sides === 'both') {
|
|
if( !this._leftDrawer ){
|
|
elNotFound(this._options.leftDrawer);
|
|
}
|
|
|
|
if(this._leftTriggers.length === 0){
|
|
elNotFound(this._options.leftTrigger);
|
|
}
|
|
} else {
|
|
if( !this._rightDrawer ){
|
|
elNotFound(this._options.rightDrawer);
|
|
}
|
|
|
|
if( this._rightTriggers.length === 0 ){
|
|
elNotFound(this._options.rightTrigger);
|
|
}
|
|
}
|
|
|
|
this._isOpen = false;
|
|
this._direction = undefined;
|
|
|
|
this._handlers = {
|
|
click: Ink.bindEvent(this._onClick, this),
|
|
afterTransition: Ink.bindEvent(this._afterTransition, this)
|
|
};
|
|
this._delay = 10;
|
|
this._addEvents();
|
|
},
|
|
|
|
/**
|
|
* Click event handler.
|
|
* Listens to the body's click event
|
|
*
|
|
* @method _onClick
|
|
* @private
|
|
**/
|
|
_onClick: function(ev){
|
|
var triggerClicked = Ink.bind(function (side) {
|
|
// When clicking on the trigger, the corresponding side is toggled.
|
|
if (this._isOpen) {
|
|
this.close();
|
|
} else {
|
|
this.open(side);
|
|
}
|
|
ev.preventDefault();
|
|
}, this);
|
|
|
|
if(Element.findUpwardsBySelector(ev.currentTarget,this._options.leftTrigger)){
|
|
// Clicked on the left trigger
|
|
triggerClicked('left');
|
|
} else if(Element.findUpwardsBySelector(ev.currentTarget,this._options.rightTrigger)){
|
|
triggerClicked('right');
|
|
} else if(Element.findUpwardsBySelector(ev.currentTarget,this._options.contentDrawer)){
|
|
// Clicked on the rest of the body
|
|
if(this._options.closeOnContentClick) {
|
|
this.close();
|
|
}
|
|
} else if (this._options.closeOnLinkClick && Element.isLink(ev.target)) {
|
|
this.close();
|
|
// No preventDefault() here
|
|
}
|
|
},
|
|
|
|
_afterTransition: function(){
|
|
if(!this._isOpen){
|
|
if(this._direction === 'left') {
|
|
Css.removeClassName(this._leftDrawer, 'show');
|
|
} else {
|
|
Css.removeClassName(this._rightDrawer, 'show');
|
|
}
|
|
}
|
|
},
|
|
|
|
_addEvents: function(){
|
|
Event.on(document.body, 'click', this._triggers + ', a[href*="#"]', this._handlers.click);
|
|
},
|
|
|
|
open: function(direction) {
|
|
this._isOpen = true;
|
|
this._direction = direction;
|
|
|
|
var open = direction === 'left' ?
|
|
this._leftDrawer :
|
|
this._rightDrawer;
|
|
|
|
Css.addClassName(open,'show');
|
|
setTimeout(Ink.bind(function(){
|
|
Css.addClassName(document.body, [this._options.mode, direction]);
|
|
},this), this._delay);
|
|
},
|
|
|
|
close: function() {
|
|
if (this._isOpen === false) { return; }
|
|
this._isOpen = false;
|
|
// TODO detect transitionEnd exists, otherwise don't rely on it
|
|
Event.one(document.body, 'transitionend oTransitionEnd webkitTransitionEnd', this._handlers.afterTransition);
|
|
Css.removeClassName(document.body, [this._options.mode, this._direction]);
|
|
}
|
|
|
|
};
|
|
|
|
Common.createUIComponent(Drawer);
|
|
|
|
return Drawer;
|
|
});
|