/**
* @class Ext.ux.Cover
* @extend Ext.DataView
*
* A Cover represents elements in a Store as visual elements in a Coverflow-like widget.
* @author Maximiliano Fierro
* @notes Inspired on zflow: http://css-vfx.googlecode.com/ By Charles Ying
*/
Ext.define('Ext.ux.Cover',{
extend: 'Ext.DataView',
xtype: 'cover',
config:{
/**
* @cfg {Number} selectedIndex The idx from the Store that will be active first. Only one item can be active at a
* time
* @accessor
* @evented
*/
selectedIndex: 0,
/**
* @cfg {String} itemCls
* A css class name to be added to each item element.
*/
itemCls: '',
/**
* @cfg {Boolean} preventSelectionOnItemTap
* Prevent selection when item is tapped. This is false by default.
*/
preventSelectionOnItemTap: false,
/**
* @cfg {Number} angle for cover background items
* This is the angle that not selected items are moved in space.
*/
angle: 70,
/**
* @cfg {Boolean} set to true if you want a flat representation. Defaults to false so the
* coverflow remains 3d.
*/
flat: false,
/**
* @cfg {Boolean} preventOrientationChange
* Prevent attaching refresh method to orientation change event on Ext.Viewport
*/
preventOrientationChange: false,
//private
baseCls: 'ux-cover',
//private
itemBaseCls: 'ux-cover-item-inner',
//private
scrollable: false,
//private
orientation: undefined
},
offset: 0,
//override
initialize: function(){
//we need somehow to put the itemCls to the tpl wraper element
this.innerItemCls = this.getItemCls();
if(this.innerItemCls) {
this.setItemCls(this.innerItemCls+'-wrap');
}
this.callParent();
this.element.on({
drag: 'onDrag',
dragstart: 'onDragStart',
dragend: 'onDragEnd',
scope: this
});
this.on({
painted: 'onPainted',
itemtap: 'doItemTap',
scope: this
});
if(!this.getPreventOrientationChange()){
//subscribe to orientation change on viewport
Ext.Viewport.on('orientationchange', this.refresh, this);
}
this.setItemTransformation = (this.getFlat())?this.setItemTransformFlat:this.setItemTransform3d;
},
getElementConfig: function(){
return {
reference: 'element',
children:[{
reference: 'innerElement',
className: 'ux-cover-scroller'
}]
}
},
applyFlat: function(flat) {
return (Ext.os.is('Android')? true : flat);
},
updateOrientation: function(newOrientation, oldOrientation) {
var baseCls = this.getBaseCls();
if(this.element && newOrientation != oldOrientation) {
this.element.removeCls(baseCls+'-'+oldOrientation);
this.element.addCls(baseCls+'-'+newOrientation);
}
},
applyItemTpl: function(config){
if(Ext.isArray(config)){
config = config.join("");
}
return new Ext.XTemplate('
'+config+'
');
},
onPainted: function(){
this.refresh();
},
//private
getTargetEl: function(){
return this.innerElement;
},
onDragStart: function(){
this.getTargetEl().dom.style.webkitTransitionDuration = "0s";
},
onDrag: function(e){
var curr = this.getOffset(),
offset,
ln = this.getViewItems().length,
selectedIndex,
delta = e.previousDeltaX;
//slow down on border conditions
selectedIndex = this.getSelectedIndex();
if((selectedIndex === 0 && e.deltaX > 0) || (selectedIndex === ln - 1 && e.deltaX < 0)){
delta.x *= 0.5;
}
offset = delta + curr;
this.setOffset(offset, true);
},
onDragEnd: function(){
var idx = this.getSelectedIndex(),
x = - (idx * this.gap);
this.getTargetEl().dom.style.webkitTransitionDuration = "0.4s";
//this.setOffset(x);
this.applySelectedIndex(idx);
},
doItemTap: function(cover, index, item, evt){
if(!this.getPreventSelectionOnItemTap() && this.getSelectedIndex() !== index){
this.setSelectedIndex(index);
}
},
getSelectedIndex: function(){
var idx, ln;
if(this.isRendered()){
ln = this.getViewItems().length;
idx = - Math.round(this.getOffset() / this.gap);
this.selectedIndex = Math.min(Math.max(idx, 0), ln - 1);
}
return this.selectedIndex;
},
applySelectedIndex: function(idx){
if(this.isRendered()){
this.updateOffsetToIdx(idx);
this.selectWithEvent(this.getStore().getAt(idx));
}else{
this.selectedIndex = idx;
}
},
updateOffsetToIdx: function(idx){
var ln = this.getViewItems().length,
offset;
idx = Math.min(Math.max(idx, 0), ln - 1);
offset= -(idx * this.gap);
this.setOffset(offset);
},
setOffset: function(offset){
var items = this.getViewItems(),
idx = 0,
l = items.length,
item;
this.offset = offset;
this.getTargetEl().dom.style.webkitTransform = "translate3d(" + offset + "px, 0, 0)";
for(;idx cH) ? 0.68 : 0.52,
h, w;
h = w = Math.min(containerBox.width, containerBox.height) * sizeFactor;
return {
top: 40 ,
height: h * 1.5,
width: w,
left: (containerBox.width - w) / 2
};
},
setBoundaries: function(itemBox){
var w = itemBox.width;
if(this.getFlat()){
this.gap = w * 1.1;
this.threshold = this.gap / 3;
this.delta = w * 0.2;
} else {
this.gap = w / 3;
this.threshold = this.gap / 2;
this.delta = w * 0.4;
}
},
setItemTransformation: Ext.emptyFn,
setItemTransform3d: function(item, idx, offset){
var x = idx * this.gap,
ix = x + offset,
transf = "";
if(ix < this.threshold && ix >= - this.threshold){
transf = "translate3d("+x+"px, 0, 150px)"
this.selectedIndex = idx;
}else if(ix > 0){
transf = "translate3d("+(x+this.delta)+"px, 0, 0) rotateY(-"+this.getAngle()+"deg)"
}else{
transf = "translate3d("+(x-this.delta)+"px, 0, 0) rotateY("+this.getAngle()+"deg)"
}
item.dom.style.webkitTransform = transf;
},
setItemTransformFlat: function(item, idx, offset){
var x = idx * this.gap,
ix = x + offset,
transf = "";
if(ix < this.threshold && ix >= - this.threshold){
transf = "translate3d("+x+"px, 0, 150px)"
this.selectedIndex = idx;
}else if(ix > 0){
transf = "translate3d("+(x+this.delta)+"px, 0, 0)"
}else{
transf = "translate3d("+(x-this.delta)+"px, 0, 0)"
}
item.dom.style.webkitTransform = transf;
},
doRefresh: function(me){
var container = me.container,
items, idx = 0, l,
orientation = Ext.Viewport.getOrientation();
this.setOrientation(orientation);
this.callParent([me]);
items = container.getViewItems();
l = items.length;
this.itemBox = this.getBaseItemBox(this.element.getBox());
this.setBoundaries(this.itemBox);
for(;idx