not really known
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

312 lines
8.4 KiB

/**
Slideable is a control that can be dragged either horizontally or vertically
between a minimum and a maximum value. When released from dragging, a
Slideable will animate to its minimum or maximum position, depending on the
direction of the drag.
The *min* value specifies a position left of or above the initial position,
to which the Slideable may be dragged.
The *max* value specifies a position right of or below the initial position,
to which the Slideable may be dragged.
The *value* property specifies the current position of the Slideable,
between the minimum and maximum positions.
*min*, *max*, and *value* may be specified in units of "px" or "%".
The *axis* property controls whether the Slideable slides left-right (h) or
up-down (v).
The following control is placed 90% off the screen to the right, and slides
to its natural position.
{kind: "enyo.Slideable", value: -90, min: -90, unit: "%",
classes: "enyo-fit", style: "width: 300px;",
components: [
{content: "stuff"}
]
}
*/
enyo.kind({
name: "enyo.Slideable",
kind: "Control",
published: {
//* Direction of sliding; can be "h" or "v"
axis: "h",
//* A value between min and max to position the Slideable
value: 0,
//* Unit for min, max, and value; can be "px" or "%"
unit: "px",
//* A minimum value to slide to
min: 0,
//* A maximum value to slide to
max: 0,
accelerated: "auto",
//* Set to false to prevent the Slideable from dragging with elasticity past its min/max value.
overMoving: true,
//* Set to false to disable dragging.
draggable: true
},
events: {
//* Fires when the Slideable finishes animating.
onAnimateFinish: "",
onChange: ""
},
// Set to true to prevent a drag from bubbling beyond the Slideable.
preventDragPropagation: false,
//* @protected
tools: [
{kind: "Animator", onStep: "animatorStep", onEnd: "animatorComplete"}
],
handlers: {
ondragstart: "dragstart",
ondrag: "drag",
ondragfinish: "dragfinish"
},
kDragScalar: 1,
dragEventProp: "dx",
unitModifier: false,
canTransform: false,
//* @protected
create: function() {
this.inherited(arguments);
this.acceleratedChanged();
this.transformChanged();
this.axisChanged();
this.valueChanged();
this.addClass("enyo-slideable");
},
initComponents: function() {
this.createComponents(this.tools);
this.inherited(arguments);
},
rendered: function() {
this.inherited(arguments);
this.canModifyUnit();
this.updateDragScalar();
},
resizeHandler: function() {
this.inherited(arguments);
this.updateDragScalar();
},
canModifyUnit: function() {
if (!this.canTransform) {
var b = this.getInitialStyleValue(this.hasNode(), this.boundary);
// If inline style of "px" exists, while unit is "%"
if (b.match(/px/i) && (this.unit === "%")) {
// Set unitModifier - used to over-ride "%"
this.unitModifier = this.getBounds()[this.dimension];
}
}
},
getInitialStyleValue: function(inNode, inBoundary) {
var s = enyo.dom.getComputedStyle(inNode);
if (s) {
return s.getPropertyValue(inBoundary);
} else if (inNode && inNode.currentStyle) {
return inNode.currentStyle[inBoundary];
}
return "0";
},
updateBounds: function(inValue, inDimensions) {
var inBounds = {};
inBounds[this.boundary] = inValue;
this.setBounds(inBounds, this.unit);
this.setInlineStyles(inValue, inDimensions);
},
updateDragScalar: function() {
if (this.unit == "%") {
var d = this.getBounds()[this.dimension];
this.kDragScalar = d ? 100 / d : 1;
if (!this.canTransform) {
this.updateBounds(this.value, 100);
}
}
},
transformChanged: function() {
this.canTransform = enyo.dom.canTransform();
},
acceleratedChanged: function() {
if (!(enyo.platform.android > 2)) {
enyo.dom.accelerate(this, this.accelerated);
}
},
axisChanged: function() {
var h = this.axis == "h";
this.dragMoveProp = h ? "dx" : "dy";
this.shouldDragProp = h ? "horizontal" : "vertical";
this.transform = h ? "translateX" : "translateY";
this.dimension = h ? "width" : "height";
this.boundary = h ? "left" : "top";
},
setInlineStyles: function(inValue, inDimensions) {
var inBounds = {};
if (this.unitModifier) {
inBounds[this.boundary] = this.percentToPixels(inValue, this.unitModifier);
inBounds[this.dimension] = this.unitModifier;
this.setBounds(inBounds);
} else {
if (inDimensions) {
inBounds[this.dimension] = inDimensions;
} else {
inBounds[this.boundary] = inValue;
}
this.setBounds(inBounds, this.unit);
}
},
valueChanged: function(inLast) {
var v = this.value;
if (this.isOob(v) && !this.isAnimating()) {
this.value = this.overMoving ? this.dampValue(v) : this.clampValue(v);
}
// FIXME: android cannot handle nested compositing well so apply acceleration only if needed
// desktop chrome doesn't like this code path so avoid...
if (enyo.platform.android > 2) {
if (this.value) {
if (inLast === 0 || inLast === undefined) {
enyo.dom.accelerate(this, this.accelerated);
}
} else {
enyo.dom.accelerate(this, false);
}
}
// If platform supports transforms
if (this.canTransform) {
enyo.dom.transformValue(this, this.transform, this.value + this.unit);
// else update inline styles
} else {
this.setInlineStyles(this.value, false);
}
this.doChange();
},
getAnimator: function() {
return this.$.animator;
},
isAtMin: function() {
return this.value <= this.calcMin();
},
isAtMax: function() {
return this.value >= this.calcMax();
},
calcMin: function() {
return this.min;
},
calcMax: function() {
return this.max;
},
clampValue: function(inValue) {
var min = this.calcMin();
var max = this.calcMax();
return Math.max(min, Math.min(inValue, max));
},
dampValue: function(inValue) {
return this.dampBound(this.dampBound(inValue, this.min, 1), this.max, -1);
},
dampBound: function(inValue, inBoundary, inSign) {
var v = inValue;
if (v * inSign < inBoundary * inSign) {
v = inBoundary + (v - inBoundary) / 4;
}
return v;
},
percentToPixels: function(value, dimension) {
return Math.floor((dimension / 100) * value);
},
pixelsToPercent: function(value) {
var boundary = this.unitModifier ? this.getBounds()[this.dimension] : this.container.getBounds()[this.dimension];
return (value / boundary) * 100;
},
// dragging
shouldDrag: function(inEvent) {
return this.draggable && inEvent[this.shouldDragProp];
},
isOob: function(inValue) {
return inValue > this.calcMax() || inValue < this.calcMin();
},
dragstart: function(inSender, inEvent) {
if (this.shouldDrag(inEvent)) {
inEvent.preventDefault();
this.$.animator.stop();
inEvent.dragInfo = {};
this.dragging = true;
this.drag0 = this.value;
this.dragd0 = 0;
return this.preventDragPropagation;
}
},
drag: function(inSender, inEvent) {
if (this.dragging) {
inEvent.preventDefault();
var d = this.canTransform ? inEvent[this.dragMoveProp] * this.kDragScalar : this.pixelsToPercent(inEvent[this.dragMoveProp]);
var v = this.drag0 + d;
var dd = d - this.dragd0;
this.dragd0 = d;
if (dd) {
inEvent.dragInfo.minimizing = dd < 0;
}
this.setValue(v);
return this.preventDragPropagation;
}
},
dragfinish: function(inSender, inEvent) {
if (this.dragging) {
this.dragging = false;
this.completeDrag(inEvent);
inEvent.preventTap();
return this.preventDragPropagation;
}
},
completeDrag: function(inEvent) {
if (this.value !== this.calcMax() && this.value != this.calcMin()) {
this.animateToMinMax(inEvent.dragInfo.minimizing);
}
},
// animation
isAnimating: function() {
return this.$.animator.isAnimating();
},
play: function(inStart, inEnd) {
this.$.animator.play({
startValue: inStart,
endValue: inEnd,
node: this.hasNode()
});
},
//* @public
//* Animates to the given value.
animateTo: function(inValue) {
this.play(this.value, inValue);
},
//* Animates to the minimum value.
animateToMin: function() {
this.animateTo(this.calcMin());
},
//* Animates to the maximum value.
animateToMax: function() {
this.animateTo(this.calcMax());
},
//* @protected
animateToMinMax: function(inMin) {
if (inMin) {
this.animateToMin();
} else {
this.animateToMax();
}
},
animatorStep: function(inSender) {
this.setValue(inSender.value);
return true;
},
animatorComplete: function(inSender) {
this.doAnimateFinish(inSender);
return true;
},
//* @public
//* Toggles between min and max with animation.
toggleMinMax: function() {
this.animateToMinMax(!this.isAtMin());
}
});