Skip to content

Commit

Permalink
Merge pull request #4 from arv/expand-menu
Browse files Browse the repository at this point in the history
Add popup menu with animation.
  • Loading branch information
ojanvafai committed Feb 14, 2014
2 parents d9e0463 + aadb07c commit efd7c72
Show file tree
Hide file tree
Showing 3 changed files with 205 additions and 17 deletions.
184 changes: 183 additions & 1 deletion app-widgets.html
Expand Up @@ -268,7 +268,7 @@
}

Polymer('app-scrollarea-toolbar', {
'for': null,
for: null,
location: 'top',
enteredView: function() {
if (this.location == 'top')
Expand Down Expand Up @@ -322,3 +322,185 @@
});
</script>
</polymer-element>
<polymer-element name="app-expand-menu">
<template>
<style>

#flyOut {
bottom: 10px;
display: none;
position: absolute;
right: 10px;
left: 0;
}

#expandButton {
background: #f2f2f2;
bottom: 11px;
height: 38px;
position: absolute;
right: 11px;
}

#mask {
-webkit-transform: translate3d(0,0,0);
background: linear-gradient(to top, #FFFFFF 200px, rgba(255, 255, 255, .5) 100%);
bottom: 0;
display: none;
left: 0;
position: absolute;
right: 0;
top: 0;
}

</style>
<div id="mask" on-tap="{{hide}}"></div>
<div id="flyOut" on-tap="{{hide}}">
<content select="*"></content>
</div>
<polymer-ui-icon-button icon="add" id="expandButton" on-tap="{{show}}"
theme="polymer-ui-light-theme"></polymer-ui-icon-button>
</template>
<script>

(function() {
'use strict';

var DURATION = 200;

function setOpacity(element, value) {
// FIXME: We should animate the opacity from zero, but that triggers http://crbug.com/328106
element.style.opacity = Math.max(.01, value);
}

function setDisplayNone(element) {
element.style.display = 'none';
}

function fadeInAnimation(element, initialDisplay) {
element.style.display = initialDisplay;

new AnimationController({
onAnimate: setOpacity.bind(null, element),
onAnimateComplete: function() {},
duration: DURATION,
targetPosition: 1,
startPosition: 0,
curve: 'ease-in-out'
});
}

function fadeOutAnimation(element) {
new AnimationController({
onAnimate: setOpacity.bind(null, element),
onAnimateComplete: setDisplayNone.bind(null, element),
duration: DURATION,
targetPosition: 0,
startPosition: 1,
curve: 'ease-in-out'
});
}

Polymer('app-expand-menu', {
show: function() {
this.$.flyOut.style.display = 'block';
this.$.mask.style.display = 'block';

var items = this.children;
var translateY = 0;
for (var i = items.length - 1; i >= 0; i--) {
var item = items[i];

item.animationController = new AnimationController({
onAnimate: this.onItemAnimate.bind(this, item),
onAnimateComplete: function() {},
duration: DURATION,
targetPosition: translateY,
startPosition: 0,
curve: 'ease-in-out'
});

fadeInAnimation(item, 'flex');
translateY -= 45;
}

fadeOutAnimation(this.$.expandButton);
fadeInAnimation(this.$.mask, 'block');
},

hide: function() {
var items = this.children;
var translateY = 0;
for (var i = items.length - 1; i >= 0; i--) {
var item = items[i];
if (i !== items.length - 1) {
new AnimationController({
onAnimate: this.onItemAnimate.bind(this, item),
onAnimateComplete: setDisplayNone.bind(null, item),
duration: DURATION,
targetPosition: 0,
startPosition: translateY,
curve: 'ease-in-out'
});
}

fadeOutAnimation(item);
translateY -= 45;
}

fadeInAnimation(this.$.expandButton, 'block');
fadeOutAnimation(this.$.mask);
},

onItemAnimate: function(item, position) {
item.style.WebkitTransform = 'translate3d(0,' + position + 'px,0)';
}
});

})();
</script>
</polymer-element>

<polymer-element name="app-expand-menu-item" attributes="label icon">
<template>
<style>

:host {
-webkit-transform: translate3d(0,0,0);
bottom: 2px;
cursor: pointer;
font-family: sans-serif;
left: 0;
position: absolute;
right: 0;
white-space: nowrap;
}

polymer-ui-menu-item {
display: flex;
flex-direction: row-reverse;
padding: 0;
width: 100%;
}

polymer-ui-menu-item ^ #label {
overflow: hidden;
text-overflow: ellipsis;
text-align: end;
width: 100%;
flex: 1;
align-self: center;
}

polymer-ui-menu-item ^ polymer-ui-icon {
align-self: center;
margin-right: 9px
}

</style>
<polymer-ui-menu-item icon="{{icon}}" label="{{label}}"></polymer-ui-menu-item>
</template>
<script>
Polymer('app-expand-menu-item', {});
</script>
</polymer-element>
16 changes: 9 additions & 7 deletions demo.html
Expand Up @@ -126,13 +126,6 @@
<polymer-ui-icon-button icon="gplus" flex></polymer-ui-icon-button>
</polymer-ui-toolbar>
</app-scrollarea-toolbar>
<app-scrollarea-toolbar for="messages" location="bottom">
<polymer-ui-toolbar theme="polymer-ui-dark-theme">
<polymer-ui-icon-button icon="add" flex></polymer-ui-icon-button>
<polymer-ui-icon-button icon="sort" flex></polymer-ui-icon-button>
<polymer-ui-icon-button icon="gplus" flex></polymer-ui-icon-button>
</polymer-ui-toolbar>
</app-scrollarea-toolbar>
<app-drawer id="nav-drawer">
<polymer-ui-menu selected="0" theme="polymer-ui-light-theme" active="false">
<template repeat>
Expand All @@ -141,6 +134,15 @@
</polymer-ui-menu>
</app-drawer>
</app-column>

<app-expand-menu>
<app-expand-menu-item icon="dialog" label="Adam"></app-expand-menu-item>
<app-expand-menu-item icon="dialog" label="Ojan"></app-expand-menu-item>
<app-expand-menu-item icon="dialog" label="Elliott"></app-expand-menu-item>
<app-expand-menu-item icon="dialog" label="Chris"></app-expand-menu-item>
<app-expand-menu-item icon="settings" label="Settings"></app-expand-menu-item>
</app-expand-menu>

</app-frame>
<script>
document.addEventListener('WebComponentsReady', function() {
Expand Down
22 changes: 13 additions & 9 deletions dynamics.js
Expand Up @@ -537,7 +537,7 @@ ScrollAreaToolbarController.prototype.onAnimation = function(timeStamp) {

function AnimationController(options) {
this.animateCallback = options.onAnimate;
this.animateCompleteCollback = options.onAnimateComplete;
this.animateCompleteCallback = options.onAnimateComplete;
this.animationDuration = options.duration;
this.targetPosition = options.targetPosition;
this.startPosition = options.startPosition;
Expand All @@ -548,30 +548,34 @@ function AnimationController(options) {
this.animator.startAnimation();
}

AnimationController.prototype.restrictToBounds = function(position) {
if (this.targetPosition > 0)
return Math.min(position, this.targetPosition);
return Math.max(position, this.targetPosition);
function clamp(min, val, max) {
if (max < min)
return Math.min(Math.max(max, val), min);
return Math.min(Math.max(min, val), max);
}

AnimationController.prototype.restrictToBounds = function(position) {
return clamp(this.startPosition, position, this.targetPosition);
};

AnimationController.prototype.onAnimation = function(timeStamp) {
var deltaT = timeStamp - this.animator.startTimeStamp;
var targetFraction = this.curve.scaleTime(deltaT / this.animationDuration);
var position = this.restrictToBounds(this.startPosition + (this.targetPosition - this.startPosition) * targetFraction);
this.isComplete = position == this.targetPosition;
this.animateCallback(position);
if (this.isComplete)
this.animateCompleteCollback();
this.animateCompleteCallback();
return !this.isComplete;
}
};

AnimationController.prototype.stopAnimation = function() {
this.animator.stopAnimation();
}
};

AnimationController.prototype.isAnimationComplete = function() {
return this.isComplete;
}
};

exports.DrawerController = DrawerController;
exports.DismissController = DismissController;
Expand Down

0 comments on commit efd7c72

Please sign in to comment.