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

View File

@@ -26,18 +26,29 @@
}
// TODO(sorvell): need key table
var KEY_RIGHT_ARROW = 39;
var KEY_LEFT_ARROW = 37;
var RIGHT_ARROW_KEY = 39;
var LEFT_ARROW_KEY = 37;
this.component({
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();
if (!this.index) {
this.index = 0;
}
},
prototype: {
tabIndex: -1,
defaultTransition: 'keyframe',
initPanels: function() {
this.getPanels().forEach(function(p, i) {
@@ -62,20 +73,24 @@
} else {
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) {
return Math.max(0, Math.min(this.count-1, inIndex));
},
// selected is a virtual property so override getter
get selected() {
getSelectedValue: function() {
var selected = this.getSelectedPanel();
var name = selected && selected.getAttribute('name');
var name = selected && (selected.getAttribute('id') ||
selected.getAttribute('name'));
return name || this.index;
},
// selected is the name property of the panel to select
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) {
this.index = index;
}
@@ -95,23 +110,23 @@
this.makeTransitionNode(this.defaultTransition);
},
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
// filter out style/templates children.
getPanels: function() {
var n$ = this.$.content.getDistributedNodes();
return Array.prototype.filter.call(n$, function(c) {
return c.tagName != "STYLE" && c.tagName != "TEMPLATE";
return c.tagName != 'STYLE' && c.tagName != 'TEMPLATE';
});
},
getSelectedPanel: function() {
return this.getPanels()[this.index];
},
indexOfName: function(inName) {
indexOfPropValue: function(inProp, inValue) {
var c$ = this.getPanels();
for (var i=0, c; c=c$[i]; i++) {
if (c.getAttribute("name") == inName) {
if (c.getAttribute(inProp) == inValue) {
return i;
}
}
@@ -130,43 +145,57 @@
return this.getPanels().length;
},
canTransition: function() {
return Boolean(this.transitionNode);
return Boolean(this.transitionNode &&
this.transitionNode.canTransition());
},
beginTransition: function(inFrom, inTo, inForward) {
if (this.transitionNode) {
this.transitionNode.stop();
}
webkitRequestAnimationFrame(function() {
inFrom.hidden = false;
inTo.hidden = false;
this.enablePanelShowing(inFrom, true);
this.enablePanelShowing(inTo, true);
this.transitionNode.go(inFrom, inTo, inForward);
}.bind(this));
},
finishTransition: function() {
if (this.transitionNode && this.transitionNode.highlander) {
this.getPanels().forEach(function(p, i) {
p.hidden = (i != this.index);
this.enablePanelShowing(p, i == this.index);
}, 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() {
this.index++;
},
previous: function() {
this.index--;
},
toggleBetween: function(inA, inB) {
this.selected = this.selected == inA ? inB : inA;
},
keydownHandler: function(e) {
if (!documentIsEditing()) {
var beforeIndex = this.index;
if (e.keyCode == KEY_RIGHT_ARROW) {
if (e.keyCode == RIGHT_ARROW_KEY) {
this.next();
} else if (e.keyCode == KEY_LEFT_ARROW) {
} else if (e.keyCode == LEFT_ARROW_KEY) {
this.previous();
}
if (beforeIndex != this.index) {
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">
<template>
<style scoped>
x-flowpanels > .right {
g-panels[transition='flow'] > .right {
left: auto;
right: 0;
}
@media screen and (max-width: 800px) {
x-flowpanels > * {
g-panels[transition='flow'] > * {
width: 100% !important;
-webkit-box-shadow: none !important;
}
@@ -22,6 +22,11 @@
</style>
</template>
<script>
var isNodeHidden = function(inNode) {
return (inNode.offsetWidth) == 0 && (inNode.offsetHeight == 0);
}
this.component({
shadowRootCreated: function(inRoot) {
this.sheet = inRoot.querySelector("style");
@@ -33,6 +38,9 @@
this.base.setup.call(this, inPanels);
this.listenForMediaMatch();
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() {
this.base.teardown.call(this);
@@ -40,7 +48,6 @@
},
listenForMediaMatch: function() {
var mq = window.matchMedia(this.narrowMedia);
this.narrowLayout = mq.matches;
mq.addListener(this.layoutChange.bind(this));
this.layoutChange(mq);
},
@@ -53,9 +60,16 @@
p.style.webkitTransition = inEnable ? null : 'none';
});
},
canTransition: function() {
var hidden = isNodeHidden(this.panels);
return !hidden;
},
refresh: function() {
this.enableTransitions(false);
this.go(null, this.panels.getSelectedPanel());
this.to = this.panels.getSelectedPanel();
if (this.canTransition()) {
this.begin();
}
webkitRequestAnimationFrame(function() {
this.enableTransitions(true);
}.bind(this));

View File

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