From ca3ad6305ec0655ad8475a12ac2228b61cdd9ba0 Mon Sep 17 00:00:00 2001 From: Lionel LASKE Date: Sat, 25 Aug 2012 20:23:36 +0000 Subject: Init commit --- (limited to 'html/lib/layout/slideable/source/Slideable.js') diff --git a/html/lib/layout/slideable/source/Slideable.js b/html/lib/layout/slideable/source/Slideable.js new file mode 100644 index 0000000..4ef0a08 --- /dev/null +++ b/html/lib/layout/slideable/source/Slideable.js @@ -0,0 +1,312 @@ +/** + 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()); + } +}); -- cgit v0.9.1