g-panels: small fixes

- selected panel moniker is now id or name
- don't rely on hidden attribute to show/hide (it's overridden by display)
- canTransition() now indirected to transitionNode
- flow transition aborts layout if panels are hidden.
This commit is contained in:
Steve Orvell
2012-11-05 12:54:20 -08:00
parent a46b52c502
commit c5083d5453
4 changed files with 111 additions and 34 deletions

View File

@@ -3,14 +3,14 @@
* Use of this source code is governed by a BSD-style * Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file. * license that can be found in the LICENSE file.
*/ */
@host { @host, g-panels {
display: block; display: block;
position: relative; position: relative;
outline: none; outline: none;
overflow: hidden; overflow: hidden;
} }
@host > * { @host > *, g-panels > * {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
@@ -21,11 +21,11 @@
/* TODO(sorvell): note: this is a workaround for reference combinators /* TODO(sorvell): note: this is a workaround for reference combinators
approach defined in shadowDom spec */ approach defined in shadowDom spec */
/* TODO(sorvell): expose animation timing via css variable */ /* TODO(sorvell): expose animation timing via css variable */
@host > .transition { @host > .transition, g-panels > .transition {
-webkit-transition: all 0.5s ease-in-out; -webkit-transition: all 0.5s ease-in-out;
} }
@host > .animate { @host > .animate, g-panels > .animate {
-webkit-animation-duration: 0.5s; -webkit-animation-duration: 0.5s;
-webkit-animation-fill-mode: both; -webkit-animation-fill-mode: both;
} }
@@ -39,12 +39,17 @@ approach defined in shadowDom spec */
*/ */
/* fade */ /* fade */
@host.g-panels-fade > .panels-ascending-from, @host > .panels-ascending-from,
@host.g-panels-fade > .panels-descending-from { @host > .panels-descending-from,
g-panels > .panels-ascending-from,
g-panels > .panels-descending-from,
{
-webkit-animation-name: g-panels-fadeOut; -webkit-animation-name: g-panels-fadeOut;
} }
@host.g-panels-fade > .panels-ascending-to, @host > .panels-ascending-to,
@host.g-panels-fade > .panels-descending-to { @host > .panels-descending-to,
g-panels > .panels-ascending-to,
g-panels > .panels-descending-to {
-webkit-animation-name: g-panels-fadeIn; -webkit-animation-name: g-panels-fadeIn;
} }
@@ -62,6 +67,19 @@ approach defined in shadowDom spec */
-webkit-animation-name: g-panels-slideFromLeft; -webkit-animation-name: g-panels-slideFromLeft;
} }
g-panels.g-panels-hslide > .panels-ascending-from {
-webkit-animation-name: g-panels-slideLeft;
}
g-panels.g-panels-hslide > .panels-ascending-to {
-webkit-animation-name: g-panels-slideFromRight;
}
g-panels.g-panels-hslide > .panels-descending-from {
-webkit-animation-name: g-panels-slideRight;
}
g-panels.g-panels-hslide > .panels-descending-to {
-webkit-animation-name: g-panels-slideFromLeft;
}
/* vslide */ /* vslide */
@host.g-panels-vslide > .panels-ascending-from { @host.g-panels-vslide > .panels-ascending-from {
-webkit-animation-name: g-panels-slideTop; -webkit-animation-name: g-panels-slideTop;
@@ -77,6 +95,10 @@ approach defined in shadowDom spec */
} }
/* hslideover */ /* hslideover */
@host.g-panels-hslideover > .panels-ascending-from,
@host.g-panels-hslideover > .panels-descending-from {
-webkit-animation-name: none;
}
@host.g-panels-hslideover > .panels-ascending-to { @host.g-panels-hslideover > .panels-ascending-to {
-webkit-animation-name: g-panels-slideFromRight; -webkit-animation-name: g-panels-slideFromRight;
} }
@@ -85,6 +107,10 @@ approach defined in shadowDom spec */
} }
/* vslideover */ /* vslideover */
@host.g-panels-vslideover > .panels-ascending-from,
@host.g-panels-vslideover > .panels-descending-from {
-webkit-animation-name: none;
}
@host.g-panels-vslideover > .panels-ascending-to { @host.g-panels-vslideover > .panels-ascending-to {
-webkit-animation-name: g-panels-slideFromBottom; -webkit-animation-name: g-panels-slideFromBottom;
} }

View File

@@ -26,18 +26,29 @@
} }
// TODO(sorvell): need key table // TODO(sorvell): need key table
var KEY_RIGHT_ARROW = 39; var RIGHT_ARROW_KEY = 39;
var KEY_LEFT_ARROW = 37; var LEFT_ARROW_KEY = 37;
this.component({ this.component({
created: function() { created: function() {
// ensure default transition
if (!this.transition) {
this.transition = this.defaultTransition;
if (this.index != null) {
this.indexChanged();
}
}
// make focusable; note that default tabIndex == -1 but node is
// only focusable if tabIndex attr is set.
if (this.tabIndex < 0) {
this.tabIndex = -1;
}
this.initPanels(); this.initPanels();
if (!this.index) { if (!this.index) {
this.index = 0; this.index = 0;
} }
}, },
prototype: { prototype: {
tabIndex: -1,
defaultTransition: 'keyframe', defaultTransition: 'keyframe',
initPanels: function() { initPanels: function() {
this.getPanels().forEach(function(p, i) { this.getPanels().forEach(function(p, i) {
@@ -62,20 +73,24 @@
} else { } else {
this.finishTransition(fromPanel, toPanel, forward); this.finishTransition(fromPanel, toPanel, forward);
} }
// TODO(sorvell): replace with getter/setter for selected when
// g-component does not override these on instances.
this.selected = this.getSelectedValue();
} }
}, },
clampIndex: function(inIndex) { clampIndex: function(inIndex) {
return Math.max(0, Math.min(this.count-1, inIndex)); return Math.max(0, Math.min(this.count-1, inIndex));
}, },
// selected is a virtual property so override getter getSelectedValue: function() {
get selected() {
var selected = this.getSelectedPanel(); var selected = this.getSelectedPanel();
var name = selected && selected.getAttribute('name'); var name = selected && (selected.getAttribute('id') ||
selected.getAttribute('name'));
return name || this.index; return name || this.index;
}, },
// selected is the name property of the panel to select // selected is the name property of the panel to select
selectedChanged: function(inOldValue) { selectedChanged: function(inOldValue) {
var index = this.indexOfName(this.selected); var index = this.indexOfPropValue('id', this.selected);
index = index >= 0 ? index : this.indexOfPropValue('name', this.selected);
if (index >= 0) { if (index >= 0) {
this.index = index; this.index = index;
} }
@@ -95,23 +110,23 @@
this.makeTransitionNode(this.defaultTransition); this.makeTransitionNode(this.defaultTransition);
}, },
tagNameForTransition: function(inName) { tagNameForTransition: function(inName) {
return "g-" + inName + (inName ? "-" : "") + "panel-transition"; return 'g-' + inName + (inName ? '-' : '') + 'panel-transition';
}, },
// TODO: consider selecting something more specific so we don't need to // TODO: consider selecting something more specific so we don't need to
// filter out style/templates children. // filter out style/templates children.
getPanels: function() { getPanels: function() {
var n$ = this.$.content.getDistributedNodes(); var n$ = this.$.content.getDistributedNodes();
return Array.prototype.filter.call(n$, function(c) { return Array.prototype.filter.call(n$, function(c) {
return c.tagName != "STYLE" && c.tagName != "TEMPLATE"; return c.tagName != 'STYLE' && c.tagName != 'TEMPLATE';
}); });
}, },
getSelectedPanel: function() { getSelectedPanel: function() {
return this.getPanels()[this.index]; return this.getPanels()[this.index];
}, },
indexOfName: function(inName) { indexOfPropValue: function(inProp, inValue) {
var c$ = this.getPanels(); var c$ = this.getPanels();
for (var i=0, c; c=c$[i]; i++) { for (var i=0, c; c=c$[i]; i++) {
if (c.getAttribute("name") == inName) { if (c.getAttribute(inProp) == inValue) {
return i; return i;
} }
} }
@@ -130,43 +145,57 @@
return this.getPanels().length; return this.getPanels().length;
}, },
canTransition: function() { canTransition: function() {
return Boolean(this.transitionNode); return Boolean(this.transitionNode &&
this.transitionNode.canTransition());
}, },
beginTransition: function(inFrom, inTo, inForward) { beginTransition: function(inFrom, inTo, inForward) {
if (this.transitionNode) { if (this.transitionNode) {
this.transitionNode.stop(); this.transitionNode.stop();
} }
webkitRequestAnimationFrame(function() { webkitRequestAnimationFrame(function() {
inFrom.hidden = false; this.enablePanelShowing(inFrom, true);
inTo.hidden = false; this.enablePanelShowing(inTo, true);
this.transitionNode.go(inFrom, inTo, inForward); this.transitionNode.go(inFrom, inTo, inForward);
}.bind(this)); }.bind(this));
}, },
finishTransition: function() { finishTransition: function() {
if (this.transitionNode && this.transitionNode.highlander) { if (this.transitionNode && this.transitionNode.highlander) {
this.getPanels().forEach(function(p, i) { this.getPanels().forEach(function(p, i) {
p.hidden = (i != this.index); this.enablePanelShowing(p, i == this.index);
}, this); }, this);
} }
}, },
// note: cannot use hidden attr for this since it's trumped by display
// setting e.g. hidden + display: -webkit-flex == showing.
enablePanelShowing: function(inPanel, inEnable) {
inPanel.style.display = inEnable ? null : 'none';
},
next: function() { next: function() {
this.index++; this.index++;
}, },
previous: function() { previous: function() {
this.index--; this.index--;
}, },
toggleBetween: function(inA, inB) {
this.selected = this.selected == inA ? inB : inA;
},
keydownHandler: function(e) { keydownHandler: function(e) {
if (!documentIsEditing()) { if (!documentIsEditing()) {
var beforeIndex = this.index; var beforeIndex = this.index;
if (e.keyCode == KEY_RIGHT_ARROW) { if (e.keyCode == RIGHT_ARROW_KEY) {
this.next(); this.next();
} else if (e.keyCode == KEY_LEFT_ARROW) { } else if (e.keyCode == LEFT_ARROW_KEY) {
this.previous(); this.previous();
} }
if (beforeIndex != this.index) { if (beforeIndex != this.index) {
e.stopPropagation(); e.stopPropagation();
} }
} }
},
refresh: function() {
if (this.transitionNode && this.transitionNode.canTransition()) {
this.transitionNode.refresh();
}
} }
} }
}); });

View File

@@ -8,13 +8,13 @@
<element name="g-flow-panel-transition" extends="g-panel-transition"> <element name="g-flow-panel-transition" extends="g-panel-transition">
<template> <template>
<style scoped> <style scoped>
x-flowpanels > .right { g-panels[transition='flow'] > .right {
left: auto; left: auto;
right: 0; right: 0;
} }
@media screen and (max-width: 800px) { @media screen and (max-width: 800px) {
x-flowpanels > * { g-panels[transition='flow'] > * {
width: 100% !important; width: 100% !important;
-webkit-box-shadow: none !important; -webkit-box-shadow: none !important;
} }
@@ -22,6 +22,11 @@
</style> </style>
</template> </template>
<script> <script>
var isNodeHidden = function(inNode) {
return (inNode.offsetWidth) == 0 && (inNode.offsetHeight == 0);
}
this.component({ this.component({
shadowRootCreated: function(inRoot) { shadowRootCreated: function(inRoot) {
this.sheet = inRoot.querySelector("style"); this.sheet = inRoot.querySelector("style");
@@ -33,6 +38,9 @@
this.base.setup.call(this, inPanels); this.base.setup.call(this, inPanels);
this.listenForMediaMatch(); this.listenForMediaMatch();
this.panels.appendChild(this.sheet); this.panels.appendChild(this.sheet);
// TODO(sorvell): hack, must fix better
// async refresh in case we need to wait for stylesheet to load
this.asyncMethod('refresh');
}, },
teardown: function() { teardown: function() {
this.base.teardown.call(this); this.base.teardown.call(this);
@@ -40,7 +48,6 @@
}, },
listenForMediaMatch: function() { listenForMediaMatch: function() {
var mq = window.matchMedia(this.narrowMedia); var mq = window.matchMedia(this.narrowMedia);
this.narrowLayout = mq.matches;
mq.addListener(this.layoutChange.bind(this)); mq.addListener(this.layoutChange.bind(this));
this.layoutChange(mq); this.layoutChange(mq);
}, },
@@ -53,9 +60,16 @@
p.style.webkitTransition = inEnable ? null : 'none'; p.style.webkitTransition = inEnable ? null : 'none';
}); });
}, },
canTransition: function() {
var hidden = isNodeHidden(this.panels);
return !hidden;
},
refresh: function() { refresh: function() {
this.enableTransitions(false); this.enableTransitions(false);
this.go(null, this.panels.getSelectedPanel()); this.to = this.panels.getSelectedPanel();
if (this.canTransition()) {
this.begin();
}
webkitRequestAnimationFrame(function() { webkitRequestAnimationFrame(function() {
this.enableTransitions(true); this.enableTransitions(true);
}.bind(this)); }.bind(this));

View File

@@ -21,9 +21,11 @@
}, },
setup: function(inPanels) { setup: function(inPanels) {
this.panels = inPanels; this.panels = inPanels;
inPanels.getPanels().forEach(function(p, i) { var showing;
this.panels.getPanels().forEach(function(p, i) {
p.classList.add(this.transitionClass); p.classList.add(this.transitionClass);
p.hidden = this.highlander && (i != inPanels.index); showing = !this.highlander || (i == inPanels.index);
this.panels.enablePanelShowing(p, showing);
}, this); }, this);
this.finishListener = this.finish.bind(this); this.finishListener = this.finish.bind(this);
}, },
@@ -32,10 +34,13 @@
p.classList.remove(this.transitionClass); p.classList.remove(this.transitionClass);
p.style.opacity = p.style.webkitTransform = null; p.style.opacity = p.style.webkitTransform = null;
if (this.highlander) { if (this.highlander) {
p.hidden = false; this.panels.enablePanelShowing(p, true);
}; };
}, this); }, this);
}, },
canTransition: function() {
return true;
},
go: function(inFrom, inTo, inForward) { go: function(inFrom, inTo, inForward) {
this.from = inFrom; this.from = inFrom;
this.to = inTo; this.to = inTo;
@@ -46,9 +51,9 @@
finish: function() { finish: function() {
if (this._transitioning) { if (this._transitioning) {
this.complete(); this.complete();
this.cancel();
this.panels.finishTransition();
} }
this.cancel();
this.panels.finishTransition();
}, },
cancel: function() { cancel: function() {
clearTimeout(this._transitioning); clearTimeout(this._transitioning);
@@ -61,6 +66,9 @@
begin: function() { begin: function() {
}, },
complete: function() { complete: function() {
},
// refresh the transition state
refresh: function() {
} }
} }
}); });