foam-framework
Version:
MVC metaprogramming framework
251 lines (240 loc) • 6.66 kB
JavaScript
/**
* @license
* Copyright 2015 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
CLASS({
package: 'foam.ui.md',
name: 'OverlayDropdownView',
extends: 'foam.ui.SimpleView',
requires: [
'foam.ui.md.FlatButton',
],
imports: [
'document',
'window',
],
exports: [
'as dropdown',
],
properties: [
'data',
{
model_: 'ViewFactoryProperty',
name: 'delegate',
},
{
name: 'delegateView',
defaultValue: null,
},
{
model_: 'FloatProperty',
name: 'height',
defaultValue: 0,
postSet: function(old, nu) {
if ( ! this.$ || old === nu || Number.isNaN(nu) ) return;
if ( nu < 0 ) this.$.style.height = this.getFullHeight() + 'px';
else this.$.style.height = nu + 'px';
},
},
{
model_: 'foam.core.types.StringEnumProperty',
name: 'state',
defaultValue: 'CLOSED',
choices: [
['CLOSED', 'Closed'],
['OPEN', 'open'],
],
},
{
model_: 'foam.core.types.StringEnumProperty',
name: 'animationState',
defaultValue: 'CLOSED',
choices: [
['CLOSED', 'Closed'],
['OPEN', 'open'],
],
},
{
model_: 'BooleanProperty',
name: 'coverPage',
defaultValue: false,
postSet: function(old, nu) {
if ( ! this.$ || old === nu ) return;
var overlay = this.$overlay;
var style = overlay.style;
if ( nu ) {
style.top = style.bottom = style.left = style.right = '0';
} else {
style.top = style.bottom = style.left = style.right = 'initial';
}
}
},
{
name: '$overlay',
defaultValueFn: function() {
return this.document.querySelector('#' + this.id + '-overlay');
}
},
{
model_: 'BooleanProperty',
name: 'listeningForCancel_',
defaultValue: false
},
],
methods: [
function open() {
if ( this.state === 'OPEN' || ! this.$ ) return;
if ( ! this.delegateView ) {
this.delegateView = this.delegate({ data$: this.data$ }, this.Y);
var out = TemplateOutput.create(this);
this.delegateView.toHTML(out);
this.$.innerHTML = out.toString();
this.delegateView.initHTML();
}
this.height = -1;
this.coverPage = true;
this.state = 'OPEN';
this.listenForCancel();
},
function close() {
if ( this.state === 'CLOSED' || ! this.$ ) return;
this.height = 0;
this.coverPage = false;
this.state = 'CLOSED';
this.unlistenForCancel();
},
function getPositionStyle() {
return 'height:' +
(this.height < 0 ? this.getFullHeight() + 'px' : this.height + 'px');
},
function getFullHeight() {
if ( ! this.$ ) return 0;
var getComputedStyle = this.window.getComputedStyle.bind(this.window);
var myStyle = getComputedStyle(this.$);
var border = 0;
['border-top', 'border-bottom'].forEach(function(name) {
var match = myStyle[name].match(/^([0-9]+)px/);
if ( match ) border += parseInt(match[1]);
});
var last = this.$.lastElementChild;
var margin = parseInt(getComputedStyle(last)['margin-bottom']);
margin = Number.isNaN(margin) ? 0 : margin;
return Math.min(border + last.offsetTop + last.offsetHeight + margin,
this.document.body.clientHeight - this.$.getBoundingClientRect().top);
},
function initHTML() {
this.SUPER();
this.$.addEventListener('transitionend', this.onTransitionEnd);
this.$.addEventListener('mouseleave', this.onMouseLeave);
this.$.addEventListener('click', this.onClick);
},
function init() {
this.SUPER();
this.Y.registerModel(this.FlatButton.xbind({
displayMode: 'LABEL_ONLY',
color: 'black',
}), 'foam.ui.ActionButton');
},
],
listeners: [
{
name: 'listenForCancel',
isFramed: true,
code: function() {
if ( this.listeningForCancel_ || this.state !== 'OPEN' ) return;
this.document.body.addEventListener('click', this.onCancel);
this.listeningForCancel_ = true;
},
},
{
name: 'unlistenForCancel',
isFramed: true,
code: function() {
if ( ! this.listeningForCancel_ || this.state !== 'CLOSED' ) return;
this.document.body.removeEventListener('click', this.onCancel);
this.listeningForCancel_ = false;
},
},
{
name: 'onCancel',
code: function(e) { this.close(); },
},
{
name: 'onTransitionEnd',
code: function(e) { this.animationState = this.state; },
},
{
name: 'onMouseLeave',
code: function(e) {
if ( e.target !== this.$ ) return;
this.close();
},
},
{
name: 'onClick',
code: function(e) {
// Prevent clicks in the dropdown from closing the dropdown.
e.stopPropagation();
},
},
],
templates: [
function toHTML() {/*
<dropdown-overlay id="%%id-overlay"></dropdown-overlay>
<dropdown id="%%id" style="%%getPositionStyle()"></dropdown>
<% this.setClass(
'open',
function() {
this.state; this.animationState;
return this.state === 'OPEN' && this.animationState === 'OPEN';
}.bind(this),
this.id); %>
*/},
function CSS() {/*
dropdown-overlay {
position: fixed;
z-index: 1009;
}
dropdown {
background: white;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.38);
display: block;
font-size: 13px;
font-weight: 400;
overflow-x: hidden;
overflow-y: hidden;
position: absolute;
right: 3px;
top: 4px;
transition: height 0.25s cubic-bezier(0,.3,.8,1);
z-index: 1010;
}
dropdown.open {
overflow-y: auto;
}
dropdown action-list.vertical {
margin-top: 0;
}
dropdown action-list.vertical .md-button {
border-radius: 0;
}
dropdown action-list.vertical .md-button-label {
text-transform: none;
}
dropdown .label-only {
margin: 0;
padding: 0;
}
dropdown .label-only .md-button-label {
margin: auto;
font-weight: 400;
}
*/}
],
});