|
|
- /**
- _enyo.Arranger_ is an <a href="#enyo.Layout">enyo.Layout</a> that considers
- one of the controls it lays out as active. The other controls are placed
- relative to the active control as makes sense for the layout.
-
- Arranger supports dynamic layouts, meaning it's possible to transition
- between its layouts via animation. Typically, arrangers should lay out
- controls using CSS transforms, since these are optimized for animation. To
- support this, the controls in an Arranger are absolutely positioned, and
- the Arranger kind has an `accelerated` property, which marks controls for
- CSS compositing. The default setting of "auto" ensures that this will occur
- if enabled by the platform.
-
- For more information, see the documentation on
- [Arrangers](https://github.com/enyojs/enyo/wiki/Arrangers)
- in the Enyo Developer Guide.
- */
- enyo.kind({
- name: "enyo.Arranger",
- kind: "Layout",
- layoutClass: "enyo-arranger",
- /**
- Sets controls being laid out to use CSS compositing. A setting of "auto"
- will mark controls for compositing if the platform supports it.
- */
- accelerated: "auto",
- //* Property of the drag event used to calculate the amount a drag moves the layout
- dragProp: "ddx",
- //* Property of the drag event used to calculate the direction of a drag
- dragDirectionProp: "xDirection",
- //* Property of the drag event used to calculate whether a drag should occur
- canDragProp: "horizontal",
- /**
- If set to true, transitions between non-adjacent arrangements will go
- through the intermediate arrangements. This is useful when direct
- transitions between arrangements would be visually jarring.
- */
- incrementalPoints: false,
- /**
- Called when removing an arranger (for example, when switching a Panels
- control to a different arrangerKind). Subclasses should implement this
- function to reset whatever properties they've changed on child controls.
- You *must* call the superclass implementation in your subclass's
- _destroy_ function.
- */
- destroy: function() {
- var c$ = this.container.getPanels();
- for (var i=0, c; c=c$[i]; i++) {
- c._arranger = null;
- }
- this.inherited(arguments);
- },
- //* @public
- /**
- Arranges the given array of controls (_inC_) in the layout specified by
- _inName_. When implementing this method, rather than apply styling
- directly to controls, call _arrangeControl(inControl, inArrangement)_
- with an _inArrangement_ object with styling settings. These will then be
- applied via the _flowControl(inControl, inArrangement)_ method.
- */
- arrange: function(inC, inName) {
- },
- /**
- Sizes the controls in the layout. This method is called only at reflow
- time. Note that sizing is separated from other layout done in the
- _arrange_ method because it is expensive and not suitable for dynamic
- layout.
- */
- size: function() {
- },
- /**
- Called when a layout transition begins. Implement this method to perform
- tasks that should only occur when a transition starts; for example, some
- controls could be shown or hidden. In addition, the _transitionPoints_
- array may be set on the container to dictate the named arrangments
- between which the transition occurs.
- */
- start: function() {
- var f = this.container.fromIndex, t = this.container.toIndex;
- var p$ = this.container.transitionPoints = [f];
- // optionally add a transition point for each index between from and to.
- if (this.incrementalPoints) {
- var d = Math.abs(t - f) - 2;
- var i = f;
- while (d >= 0) {
- i = i + (t < f ? -1 : 1);
- p$.push(i);
- d--;
- }
- }
- p$.push(this.container.toIndex);
- },
- /**
- Called when a layout transition completes. Implement this method to
- perform tasks that should only occur when a transition ends; for
- example, some controls could be shown or hidden.
- */
- finish: function() {
- },
- //* @protected
- canDragEvent: function(inEvent) {
- return inEvent[this.canDragProp];
- },
- calcDragDirection: function(inEvent) {
- return inEvent[this.dragDirectionProp];
- },
- calcDrag: function(inEvent) {
- return inEvent[this.dragProp];
- },
- drag: function(inDp, inAn, inA, inBn, inB) {
- var f = this.measureArrangementDelta(-inDp, inAn, inA, inBn, inB);
- return f;
- },
- measureArrangementDelta: function(inX, inI0, inA0, inI1, inA1) {
- var d = this.calcArrangementDifference(inI0, inA0, inI1, inA1);
- var s = d ? inX / Math.abs(d) : 0;
- s = s * (this.container.fromIndex > this.container.toIndex ? -1 : 1);
- //enyo.log("delta", s);
- return s;
- },
- //* @public
- /**
- Called when dragging the layout, this method returns the difference in
- pixels between the arrangement _inA0_ for layout setting _inI0_ and
- arrangement _inA1_ for layout setting _inI1_. This data is used to calculate
- the percentage that a drag should move the layout between two active states.
- */
- calcArrangementDifference: function(inI0, inA0, inI1, inA1) {
- },
- //* @protected
- _arrange: function(inIndex) {
- var c$ = this.getOrderedControls(inIndex);
- this.arrange(c$, inIndex);
- },
- arrangeControl: function(inControl, inArrangement) {
- inControl._arranger = enyo.mixin(inControl._arranger || {}, inArrangement);
- },
- flow: function() {
- this.c$ = [].concat(this.container.getPanels());
- this.controlsIndex = 0;
- for (var i=0, c$=this.container.getPanels(), c; c=c$[i]; i++) {
- enyo.dom.accelerate(c, this.accelerated);
- if (enyo.platform.safari) {
- // On Safari-desktop, sometimes having the panel's direct child set to accelerate isn't sufficient
- // this is most often the case with Lists contained inside another control, inside a Panels
- var grands=c.children;
- for (var j=0, kid; kid=grands[j]; j++) {
- enyo.dom.accelerate(kid, this.accelerated);
- }
- }
- }
- },
- reflow: function() {
- var cn = this.container.hasNode();
- this.containerBounds = cn ? {width: cn.clientWidth, height: cn.clientHeight} : {};
- this.size();
- },
- flowArrangement: function() {
- var a = this.container.arrangement;
- if (a) {
- for (var i=0, c$=this.container.getPanels(), c; c=c$[i]; i++) {
- this.flowControl(c, a[i]);
- }
- }
- },
- //* @public
- /**
- Lays out the control (_inControl_) according to the settings stored in
- the _inArrangment_ object. By default, _flowControl_ will apply settings
- of left, top, and opacity. This method should only be implemented to
- apply other settings made via _arrangeControl_.
- */
- flowControl: function(inControl, inArrangement) {
- enyo.Arranger.positionControl(inControl, inArrangement);
- var o = inArrangement.opacity;
- if (o != null) {
- enyo.Arranger.opacifyControl(inControl, o);
- }
- },
- //* @protected
- // Gets an array of controls arranged in state order.
- // note: optimization, dial around a single array.
- getOrderedControls: function(inIndex) {
- var whole = Math.floor(inIndex);
- var a = whole - this.controlsIndex;
- var sign = a > 0;
- var c$ = this.c$ || [];
- for (var i=0; i<Math.abs(a); i++) {
- if (sign) {
- c$.push(c$.shift());
- } else {
- c$.unshift(c$.pop());
- }
- }
- this.controlsIndex = whole;
- return c$;
- },
- statics: {
- // Positions a control via transform: translateX/Y if supported and falls back to left/top if not.
- positionControl: function(inControl, inBounds, inUnit) {
- var unit = inUnit || "px";
- if (!this.updating) {
- if (enyo.dom.canTransform() && !enyo.platform.android) {
- var l = inBounds.left, t = inBounds.top;
- var l = enyo.isString(l) ? l : l && (l + unit);
- var t = enyo.isString(t) ? t : t && (t + unit);
- enyo.dom.transform(inControl, {translateX: l || null, translateY: t || null});
- } else {
- inControl.setBounds(inBounds, inUnit);
- }
- }
- },
- opacifyControl: function(inControl, inOpacity) {
- var o = inOpacity;
- // FIXME: very high/low settings of opacity can cause a control to
- // blink so cap this here.
- o = o > .99 ? 1 : (o < .01 ? 0 : o);
- // note: we only care about ie8
- if (enyo.platform.ie < 9) {
- inControl.applyStyle("filter", "progid:DXImageTransform.Microsoft.Alpha(Opacity=" + (o * 100) + ")");
- } else {
- inControl.applyStyle("opacity", o);
- }
- }
- }
- });
|