jellyfin-web/dashboard-ui/bower_components/paper-drawer-panel/paper-drawer-panel.html

774 lines
21 KiB
HTML
Raw Normal View History

2015-06-20 17:49:42 -07:00
<!--
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<link rel="import" href="../polymer/polymer.html">
<link rel="import" href="../iron-media-query/iron-media-query.html">
<link rel="import" href="../iron-selector/iron-selector.html">
2015-12-14 08:43:03 -07:00
<link rel="import" href="../iron-resizable-behavior/iron-resizable-behavior.html">
2015-06-20 17:49:42 -07:00
<!--
2015-12-14 08:43:03 -07:00
Material design: [Navigation drawer](https://www.google.com/design/spec/patterns/navigation-drawer.html)
2015-06-20 17:49:42 -07:00
`paper-drawer-panel` contains a drawer panel and a main panel. The drawer
and the main panel are side-by-side with drawer on the left. When the browser
window size is smaller than the `responsiveWidth`, `paper-drawer-panel`
changes to narrow layout. In narrow layout, the drawer will be stacked on top
of the main panel. The drawer will slide in/out to hide/reveal the main
panel.
Use the attribute `drawer` to indicate that the element is the drawer panel and
`main` to indicate that the element is the main panel.
Example:
<paper-drawer-panel>
<div drawer> Drawer panel... </div>
<div main> Main panel... </div>
</paper-drawer-panel>
The drawer and the main panels are not scrollable. You can set CSS overflow
property on the elements to make them scrollable or use `paper-header-panel`.
Example:
<paper-drawer-panel>
<paper-header-panel drawer>
<paper-toolbar></paper-toolbar>
<div> Drawer content... </div>
</paper-header-panel>
<paper-header-panel main>
<paper-toolbar></paper-toolbar>
<div> Main content... </div>
</paper-header-panel>
</paper-drawer-panel>
An element that should toggle the drawer will automatically do so if it's
given the `paper-drawer-toggle` attribute. Also this element will automatically
be hidden in wide layout.
Example:
<paper-drawer-panel>
<paper-header-panel drawer>
<paper-toolbar>
<div>Application</div>
</paper-toolbar>
<div> Drawer content... </div>
</paper-header-panel>
<paper-header-panel main>
<paper-toolbar>
<paper-icon-button icon="menu" paper-drawer-toggle></paper-icon-button>
<div>Title</div>
</paper-toolbar>
<div> Main content... </div>
</paper-header-panel>
</paper-drawer-panel>
To position the drawer to the right, add `right-drawer` attribute.
<paper-drawer-panel right-drawer>
<div drawer> Drawer panel... </div>
<div main> Main panel... </div>
</paper-drawer-panel>
2015-12-14 08:43:03 -07:00
### Styling
2015-06-20 17:49:42 -07:00
To change the main container:
2015-07-09 20:00:03 -07:00
paper-drawer-panel {
--paper-drawer-panel-main-container: {
background-color: gray;
};
}
2015-06-20 17:49:42 -07:00
To change the drawer container when it's in the left side:
2015-07-09 20:00:03 -07:00
paper-drawer-panel {
--paper-drawer-panel-left-drawer-container: {
background-color: white;
};
}
2015-06-20 17:49:42 -07:00
To change the drawer container when it's in the right side:
2015-07-09 20:00:03 -07:00
paper-drawer-panel {
--paper-drawer-panel-right-drawer-container: {
background-color: white;
};
}
2015-06-20 17:49:42 -07:00
2015-12-14 08:43:03 -07:00
To customize the scrim:
paper-drawer-panel {
--paper-drawer-panel-scrim: {
background-color: red;
};
}
The following custom properties and mixins are available for styling:
Custom property | Description | Default
----------------|-------------|----------
`--paper-drawer-panel-scrim-opacity` | Scrim opacity | 1
`--paper-drawer-panel-drawer-container` | Mixin applied to drawer container | {}
`--paper-drawer-panel-left-drawer-container` | Mixin applied to container when it's in the left side | {}
`--paper-drawer-panel-main-container` | Mixin applied to main container | {}
`--paper-drawer-panel-right-drawer-container` | Mixin applied to container when it's in the right side | {}
`--paper-drawer-panel-scrim` | Mixin applied to scrim | {}
2015-06-20 17:49:42 -07:00
@group Paper elements
@element paper-drawer-panel
@demo demo/index.html
@hero hero.svg
-->
<dom-module id="paper-drawer-panel">
2015-07-09 20:00:03 -07:00
<template>
2015-12-14 08:43:03 -07:00
<style>
:host {
display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
iron-selector > #drawer {
position: absolute;
top: 0;
left: 0;
height: 100%;
background-color: white;
-moz-box-sizing: border-box;
box-sizing: border-box;
@apply(--paper-drawer-panel-drawer-container);
}
.transition > #drawer {
transition: -webkit-transform ease-in-out 0.3s, width ease-in-out 0.3s, visibility 0.3s;
transition: transform ease-in-out 0.3s, width ease-in-out 0.3s, visibility 0.3s;
}
.left-drawer > #drawer {
@apply(--paper-drawer-panel-left-drawer-container);
}
.right-drawer > #drawer {
left: auto;
right: 0;
@apply(--paper-drawer-panel-right-drawer-container);
}
iron-selector > #main {
position: absolute;
top: 0;
right: 0;
bottom: 0;
@apply(--paper-drawer-panel-main-container);
}
.transition > #main {
transition: left ease-in-out 0.3s, padding ease-in-out 0.3s;
}
.right-drawer > #main {
left: 0;
}
.right-drawer.transition > #main {
transition: right ease-in-out 0.3s, padding ease-in-out 0.3s;
}
#main > ::content > [main] {
height: 100%;
}
#drawer > ::content > [drawer] {
height: 100%;
}
#scrim {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
visibility: hidden;
opacity: 0;
transition: opacity ease-in-out 0.38s, visibility ease-in-out 0.38s;
background-color: rgba(0, 0, 0, 0.3);
@apply(--paper-drawer-panel-scrim);
}
.narrow-layout > #drawer {
will-change: transform;
}
.narrow-layout > #drawer.iron-selected {
box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.15);
}
.right-drawer.narrow-layout > #drawer.iron-selected {
box-shadow: -2px 2px 4px rgba(0, 0, 0, 0.15);
}
.narrow-layout > #drawer > ::content > [drawer] {
border: 0;
}
.left-drawer.narrow-layout > #drawer:not(.iron-selected) {
-webkit-transform: translateX(-100%);
transform: translateX(-100%);
}
.right-drawer.narrow-layout > #drawer:not(.iron-selected) {
left: auto;
visibility: hidden;
-webkit-transform: translateX(100%);
transform: translateX(100%);
}
.right-drawer.narrow-layout.dragging > #drawer:not(.iron-selected),
.right-drawer.narrow-layout.peeking > #drawer:not(.iron-selected) {
visibility: visible;
}
.narrow-layout > #main {
padding: 0;
}
.right-drawer.narrow-layout > #main {
left: 0;
right: 0;
}
.narrow-layout > #main:not(.iron-selected) > #scrim,
.dragging > #main > #scrim {
visibility: visible;
opacity: var(--paper-drawer-panel-scrim-opacity, 1);
}
.narrow-layout > #main > * {
margin: 0;
min-height: 100%;
left: 0;
right: 0;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
iron-selector:not(.narrow-layout) #main ::content [paper-drawer-toggle] {
display: none;
}
</style>
2015-07-09 20:00:03 -07:00
<iron-media-query
id="mq"
on-query-matches-changed="_onQueryMatchesChanged"
query="[[_computeMediaQuery(forceNarrow, responsiveWidth)]]">
</iron-media-query>
2015-06-20 17:49:42 -07:00
2015-07-09 20:00:03 -07:00
<iron-selector
attr-for-selected="id"
2015-12-14 08:43:03 -07:00
class$="[[_computeIronSelectorClass(narrow, _transition, dragging, rightDrawer, peeking)]]"
2015-07-09 20:00:03 -07:00
activate-event=""
selected="[[selected]]">
2015-06-20 17:49:42 -07:00
2015-12-14 08:43:03 -07:00
<div id="main" style$="[[_computeMainStyle(narrow, rightDrawer, drawerWidth)]]" on-transitionend="_onMainTransitionEnd">
2015-07-09 20:00:03 -07:00
<content select="[main]"></content>
<div id="scrim" on-tap="closeDrawer"></div>
</div>
2015-06-20 17:49:42 -07:00
2015-07-09 20:00:03 -07:00
<div id="drawer" style$="[[_computeDrawerStyle(drawerWidth)]]">
<content select="[drawer]"></content>
</div>
2015-06-20 17:49:42 -07:00
2015-07-09 20:00:03 -07:00
</iron-selector>
</template>
2015-06-20 17:49:42 -07:00
2015-12-14 08:43:03 -07:00
<script>
(function() {
'use strict';
2015-06-20 17:49:42 -07:00
2015-12-14 08:43:03 -07:00
// this would be the only `paper-drawer-panel` in
// the whole app that can be in `dragging` state
var sharedPanel = null;
2015-06-20 17:49:42 -07:00
2015-12-14 08:43:03 -07:00
function classNames(obj) {
var classes = [];
for (var key in obj) {
if (obj.hasOwnProperty(key) && obj[key]) {
classes.push(key);
}
2015-07-09 20:00:03 -07:00
}
2015-12-14 08:43:03 -07:00
return classes.join(' ');
2015-07-09 20:00:03 -07:00
}
2015-12-14 08:43:03 -07:00
Polymer({
2015-07-09 20:00:03 -07:00
2015-12-14 08:43:03 -07:00
is: 'paper-drawer-panel',
2015-07-09 20:00:03 -07:00
2015-12-14 08:43:03 -07:00
behaviors: [Polymer.IronResizableBehavior],
2015-07-09 20:00:03 -07:00
/**
2015-12-14 08:43:03 -07:00
* Fired when the narrow layout changes.
*
* @event paper-responsive-change {{narrow: boolean}} detail -
* narrow: true if the panel is in narrow layout.
2015-07-09 20:00:03 -07:00
*/
/**
2015-12-14 08:43:03 -07:00
* Fired when the a panel is selected.
*
* Listening for this event is an alternative to observing changes in the `selected` attribute.
* This event is fired both when a panel is selected.
*
* @event iron-select {{item: Object}} detail -
* item: The panel that the event refers to.
2015-07-09 20:00:03 -07:00
*/
/**
2015-12-14 08:43:03 -07:00
* Fired when a panel is deselected.
*
* Listening for this event is an alternative to observing changes in the `selected` attribute.
* This event is fired both when a panel is deselected.
*
* @event iron-deselect {{item: Object}} detail -
* item: The panel that the event refers to.
2015-07-09 20:00:03 -07:00
*/
2015-12-14 08:43:03 -07:00
properties: {
/**
* The panel to be selected when `paper-drawer-panel` changes to narrow
* layout.
*/
defaultSelected: {
type: String,
value: 'main'
},
/**
* If true, swipe from the edge is disabled.
*/
disableEdgeSwipe: {
type: Boolean,
value: false
},
/**
* If true, swipe to open/close the drawer is disabled.
*/
disableSwipe: {
type: Boolean,
value: false
},
/**
* Whether the user is dragging the drawer interactively.
*/
dragging: {
type: Boolean,
value: false,
readOnly: true,
notify: true
},
/**
* Width of the drawer panel.
*/
drawerWidth: {
type: String,
value: '256px'
},
/**
* How many pixels on the side of the screen are sensitive to edge
* swipes and peek.
*/
edgeSwipeSensitivity: {
type: Number,
value: 30
},
/**
* If true, ignore `responsiveWidth` setting and force the narrow layout.
*/
forceNarrow: {
type: Boolean,
value: false
},
/**
* Whether the browser has support for the transform CSS property.
*/
hasTransform: {
type: Boolean,
value: function() {
return 'transform' in this.style;
}
},
/**
* Whether the browser has support for the will-change CSS property.
*/
hasWillChange: {
type: Boolean,
value: function() {
return 'willChange' in this.style;
}
},
/**
* Returns true if the panel is in narrow layout. This is useful if you
* need to show/hide elements based on the layout.
*/
narrow: {
reflectToAttribute: true,
type: Boolean,
value: false,
readOnly: true,
notify: true
},
/**
* Whether the drawer is peeking out from the edge.
*/
peeking: {
type: Boolean,
value: false,
readOnly: true,
notify: true
},
/**
* Max-width when the panel changes to narrow layout.
*/
responsiveWidth: {
type: String,
value: '600px'
},
/**
* If true, position the drawer to the right.
*/
rightDrawer: {
type: Boolean,
value: false
},
/**
* The panel that is being selected. `drawer` for the drawer panel and
* `main` for the main panel.
*/
selected: {
reflectToAttribute: true,
notify: true,
type: String,
value: null
},
/**
* The attribute on elements that should toggle the drawer on tap, also elements will
* automatically be hidden in wide layout.
*/
drawerToggleAttribute: {
type: String,
value: 'paper-drawer-toggle'
},
/**
* Whether the transition is enabled.
*/
_transition: {
type: Boolean,
value: false
},
2015-07-09 20:00:03 -07:00
},
2015-12-14 08:43:03 -07:00
listeners: {
tap: '_onTap',
track: '_onTrack',
down: '_downHandler',
up: '_upHandler'
2015-07-09 20:00:03 -07:00
},
2015-12-14 08:43:03 -07:00
observers: [
'_forceNarrowChanged(forceNarrow, defaultSelected)'
],
2015-07-09 20:00:03 -07:00
/**
2015-12-14 08:43:03 -07:00
* Toggles the panel open and closed.
*
* @method togglePanel
2015-07-09 20:00:03 -07:00
*/
2015-12-14 08:43:03 -07:00
togglePanel: function() {
if (this._isMainSelected()) {
this.openDrawer();
} else {
this.closeDrawer();
2015-07-09 20:00:03 -07:00
}
},
/**
2015-12-14 08:43:03 -07:00
* Opens the drawer.
*
* @method openDrawer
2015-07-09 20:00:03 -07:00
*/
2015-12-14 08:43:03 -07:00
openDrawer: function() {
this.selected = 'drawer';
2015-07-09 20:00:03 -07:00
},
/**
2015-12-14 08:43:03 -07:00
* Closes the drawer.
*
* @method closeDrawer
2015-07-09 20:00:03 -07:00
*/
2015-12-14 08:43:03 -07:00
closeDrawer: function() {
this.selected = 'main';
2015-07-09 20:00:03 -07:00
},
2015-12-14 08:43:03 -07:00
ready: function() {
// Avoid transition at the beginning e.g. page loads and enable
// transitions only after the element is rendered and ready.
this._transition = true;
2015-07-09 20:00:03 -07:00
},
2015-12-14 08:43:03 -07:00
_onMainTransitionEnd: function (e) {
if (e.currentTarget === this.$.main && (e.propertyName === 'left' || e.propertyName === 'right')) {
this.notifyResize();
}
2015-07-09 20:00:03 -07:00
},
2015-12-14 08:43:03 -07:00
_computeIronSelectorClass: function(narrow, transition, dragging, rightDrawer, peeking) {
return classNames({
dragging: dragging,
'narrow-layout': narrow,
'right-drawer': rightDrawer,
'left-drawer': !rightDrawer,
transition: transition,
peeking: peeking
});
2015-07-09 20:00:03 -07:00
},
2015-12-14 08:43:03 -07:00
_computeDrawerStyle: function(drawerWidth) {
return 'width:' + drawerWidth + ';';
2015-07-09 20:00:03 -07:00
},
2015-12-14 08:43:03 -07:00
_computeMainStyle: function(narrow, rightDrawer, drawerWidth) {
var style = '';
style += 'left:' + ((narrow || rightDrawer) ? '0' : drawerWidth) + ';';
if (rightDrawer) {
style += 'right:' + (narrow ? '' : drawerWidth) + ';';
}
return style;
2015-07-09 20:00:03 -07:00
},
2015-12-14 08:43:03 -07:00
_computeMediaQuery: function(forceNarrow, responsiveWidth) {
return forceNarrow ? '' : '(max-width: ' + responsiveWidth + ')';
2015-07-09 20:00:03 -07:00
},
2015-12-14 08:43:03 -07:00
_computeSwipeOverlayHidden: function(narrow, disableEdgeSwipe) {
return !narrow || disableEdgeSwipe;
},
2015-07-09 20:00:03 -07:00
2015-12-14 08:43:03 -07:00
_onTrack: function(event) {
if (sharedPanel && this !== sharedPanel) {
return;
}
switch (event.detail.state) {
case 'start':
this._trackStart(event);
break;
case 'track':
this._trackX(event);
break;
case 'end':
this._trackEnd(event);
break;
}
2015-07-09 20:00:03 -07:00
2015-12-14 08:43:03 -07:00
},
2015-07-09 20:00:03 -07:00
2015-12-14 08:43:03 -07:00
_responsiveChange: function(narrow) {
this._setNarrow(narrow);
2015-07-09 20:00:03 -07:00
2015-12-14 08:43:03 -07:00
if (this.narrow) {
this.selected = this.defaultSelected;
}
2015-07-09 20:00:03 -07:00
2015-12-14 08:43:03 -07:00
this.setScrollDirection(this._swipeAllowed() ? 'y' : 'all');
this.fire('paper-responsive-change', {narrow: this.narrow});
},
2015-06-20 17:49:42 -07:00
2015-12-14 08:43:03 -07:00
_onQueryMatchesChanged: function(event) {
this._responsiveChange(event.detail.value);
},
2015-07-09 20:00:03 -07:00
2015-12-14 08:43:03 -07:00
_forceNarrowChanged: function() {
// set the narrow mode only if we reached the `responsiveWidth`
this._responsiveChange(this.forceNarrow || this.$.mq.queryMatches);
},
2015-07-09 20:00:03 -07:00
2015-12-14 08:43:03 -07:00
_swipeAllowed: function() {
return this.narrow && !this.disableSwipe;
},
2015-07-09 20:00:03 -07:00
2015-12-14 08:43:03 -07:00
_isMainSelected: function() {
return this.selected === 'main';
},
2015-07-09 20:00:03 -07:00
2015-12-14 08:43:03 -07:00
_startEdgePeek: function() {
this.width = this.$.drawer.offsetWidth;
this._moveDrawer(this._translateXForDeltaX(this.rightDrawer ?
-this.edgeSwipeSensitivity : this.edgeSwipeSensitivity));
this._setPeeking(true);
},
2015-07-09 20:00:03 -07:00
2015-12-14 08:43:03 -07:00
_stopEdgePeek: function() {
if (this.peeking) {
this._setPeeking(false);
this._moveDrawer(null);
}
},
2015-07-09 20:00:03 -07:00
2015-12-14 08:43:03 -07:00
_downHandler: function(event) {
if (!this.dragging && this._isMainSelected() && this._isEdgeTouch(event) && !sharedPanel) {
this._startEdgePeek();
// cancel selection
event.preventDefault();
// grab this panel
sharedPanel = this;
2015-07-09 20:00:03 -07:00
}
2015-12-14 08:43:03 -07:00
},
2015-07-09 20:00:03 -07:00
2015-12-14 08:43:03 -07:00
_upHandler: function() {
this._stopEdgePeek();
// release the panel
sharedPanel = null;
},
_onTap: function(event) {
var targetElement = Polymer.dom(event).localTarget;
var isTargetToggleElement = targetElement &&
this.drawerToggleAttribute &&
targetElement.hasAttribute(this.drawerToggleAttribute);
if (isTargetToggleElement) {
this.togglePanel();
2015-07-09 20:00:03 -07:00
}
2015-12-14 08:43:03 -07:00
},
2015-07-09 20:00:03 -07:00
2015-12-14 08:43:03 -07:00
_isEdgeTouch: function(event) {
var x = event.detail.x;
2015-07-09 20:00:03 -07:00
2015-12-14 08:43:03 -07:00
return !this.disableEdgeSwipe && this._swipeAllowed() &&
(this.rightDrawer ?
x >= this.offsetWidth - this.edgeSwipeSensitivity :
x <= this.edgeSwipeSensitivity);
},
2015-06-20 17:49:42 -07:00
2015-12-14 08:43:03 -07:00
_trackStart: function(event) {
if (this._swipeAllowed()) {
sharedPanel = this;
this._setDragging(true);
2015-07-09 20:00:03 -07:00
2015-12-14 08:43:03 -07:00
if (this._isMainSelected()) {
this._setDragging(this.peeking || this._isEdgeTouch(event));
2015-06-21 14:31:21 -07:00
}
2015-06-20 17:49:42 -07:00
2015-12-14 08:43:03 -07:00
if (this.dragging) {
this.width = this.$.drawer.offsetWidth;
this._transition = false;
}
2015-07-09 20:19:14 -07:00
}
2015-12-14 08:43:03 -07:00
},
2015-07-09 20:19:14 -07:00
2015-12-14 08:43:03 -07:00
_translateXForDeltaX: function(deltaX) {
var isMain = this._isMainSelected();
2015-07-09 20:00:03 -07:00
if (this.rightDrawer) {
2015-12-14 08:43:03 -07:00
return Math.max(0, isMain ? this.width + deltaX : deltaX);
2015-07-09 20:00:03 -07:00
} else {
2015-12-14 08:43:03 -07:00
return Math.min(0, isMain ? deltaX - this.width : deltaX);
2015-07-09 20:00:03 -07:00
}
2015-12-14 08:43:03 -07:00
},
2015-07-09 20:00:03 -07:00
2015-12-14 08:43:03 -07:00
_trackX: function(event) {
if (this.dragging) {
var dx = event.detail.dx;
if (this.peeking) {
if (Math.abs(dx) <= this.edgeSwipeSensitivity) {
// Ignore trackx until we move past the edge peek.
return;
}
this._setPeeking(false);
}
var dy = event.detail.dy;
var absDy = Math.abs(dy);
if (absDy >= 70) {
// Ignore trackx until we move past the edge peek.
return;
}
2015-07-09 20:00:03 -07:00
2015-12-14 08:43:03 -07:00
this._moveDrawer(this._translateXForDeltaX(dx));
}
},
2015-07-09 20:00:03 -07:00
2015-12-14 08:43:03 -07:00
_trackEnd: function(event) {
if (this.dragging) {
var xDirection = event.detail.dx > 0;
this._setDragging(false);
this._transition = true;
sharedPanel = null;
this._moveDrawer(null);
var dx = event.detail.dx;
var dy = event.detail.dy;
var absDy = Math.abs(dy);
if (this.rightDrawer) {
this[xDirection ? 'closeDrawer' : 'openDrawer']();
} else {
this[xDirection || dx > -80 || absDy >= 70 ? 'openDrawer' : 'closeDrawer']();
}
}
},
2015-07-09 20:00:03 -07:00
2015-12-14 08:43:03 -07:00
_transformForTranslateX: function(translateX) {
if (translateX === null) {
return '';
}
2015-06-20 17:49:42 -07:00
2015-12-14 08:43:03 -07:00
return this.hasWillChange ? 'translateX(' + translateX + 'px)' :
'translate3d(' + translateX + 'px, 0, 0)';
},
2015-06-20 17:49:42 -07:00
2015-12-14 08:43:03 -07:00
_moveDrawer: function(translateX) {
this.transform(this._transformForTranslateX(translateX), this.$.drawer);
}
});
}());
</script>
</dom-module>