dojo.provide("demos.skew.src.Image");
dojo.require("dojo.parser");
dojo.require("dijit._Widget");
dojo.require("dijit._Templated");
dojo.require("dojo.fx");
dojo.require("dojo.fx.easing");
dojo.declare("image.Skewed",
[dijit._Widget, dijit._Templated],{
// a node on the surface
imgUrl: "", // dojo.moduleUrl("dojo", "resources/blank.gif"),
// filterUrl: String
// Endpoint to get valid image data. This url is passed query params
// of 'src' (the original filename) and dir 1 || 0 (left of right skew)
// The default [supplied] implementation uses PHP-5 and required the GD
// library.
filterUrl:"imageReflect.php",
// Selected: Boolean
// Is image initially selected
selected:"",
// value: String
// Each Item has a value associated with it's image.
value:"",
reflectSpacing: 5,
angle: 25,
templateString:
'
',
postCreate: function(){
// summary: start the widget, and fetch the filtered images.
this.inherited(arguments);
this.imageNode.src = this.filterUrl + "?greyscale=1&src=" + this.imgUrl + "&spacing=" + this.reflectSpacing;
this.leftImage.src = this.filterUrl + "?greyscale=1&src=" + this.imgUrl + "&skew=left&angle=" + this.angle + "&spacing=" + this.reflectSpacing;
this.rightImage.src = this.filterUrl + "?greyscale=1&src=" + this.imgUrl + "&skew=right&angle=" + this.angle + "&spacing=" + this.reflectSpacing;
this.connect(this.domNode,"onfocus","center");
},
startup: function(){
if(!this._started){
this.inherited(arguments);
if(this.selected){
this.center();
}
}
},
center: function(e){
// summary: public function to center a particular image
var p = dijit.getEnclosingWidget(this.domNode.parentNode);
p._center(this.domNode);
}
});
dojo.declare("image.Container",
[dijit._Widget,dijit._Templated],
{
// loop: Boolean
// If true, Images will loop when continuing on beyond end or before beginning
loop:false,
// useWheel: Boolean
// Disable/enable mouse wheel listener
useWheel: true,
// useDrag: Boolean
// Experimental: NOT WORKING, toggles dragging a direction on the pane as
// a method of reordering
useDrag: false,
// spacing: Integer
// The relative offset of each image from it's immediate siblings
spacing: 50,
_spacing: 50, // an additional param for offset from center
// only use even numbers:
visibleItems: 15,
// offOpacity: Float
// An opacity value to set to the images that do not have focus
offOpacity: 0.75,
// easing: String|Function
// An easing function [name] to use
easing:"dojo.fx.easing.easeOut",
templateString:
'',
postCreate:function(){
this.inherited(arguments);
this.threshold = (this.visibleItems + (this.visibleItems % 2)) / 2;
var node = this.domNode;
dojo.style(this.containerWrapper,"position","relative");
this.easing = (dojo.isString(this.easing) ? dojo.getObject(this.easing) : this.easing);
if(dojo.isIE){
// FIXME: can move to css with .dj_ie prefix
dojo.style(this.containerNode,"overflow","hidden");
}
this.connect(node,"onclick","_click");
this.connect(node,"onkeypress","_handleKey");
if(this.useWheel){
this.connect(node, (!dojo.isMozilla ? "onmousewheel" : "DOMMouseScroll"), "_scroll");
}
},
startup:function(){
// sets this.nl
if(this._started) return;
this.inherited(arguments);
var sel = Math.floor(this._getChildren().length / 2);
// FIXME: if no children, this throws an error
this._center(this.nl[sel].firstChild);
},
_getChildren: function(){
this.nl = dojo.query(".anImage",this.domNode);
return this.nl;
},
_click: function(e){
if(!dojo.isIE){
dijit.focus(this.domNode);
}
var n = e.target;
if(n !== this.domNode && n !== this.containerNode){
this._center(n);
}
},
resize: function(){
this._size = {
w: this.domNode.clientWidth,
h: this.domNode.clientHeight
};
if(dojo.isIE){
dojo.marginBox(this.containerNode,dojo.mixin(this._size,{ t: 0, l:0 }));
}
if(this.selectedChild){
this._center(this.selectedChild.domNode);
}
},
_center: function(/* DomNode */node){
// summary: Main function used to arrage the images based on a selected node
var w = dijit.getEnclosingWidget(node);
if(this._centering){
this.selectedChild = w;
return;
}
this._centering = true;
var _anims = [];
var currentIdx = null;
if(this.selectedChild){
currentIdx = this.nl.indexOf(this.selectedChild.domNode);
}
this.selectedChild = w;
var x = this.nl.indexOf(w.domNode);
// fire our stub functions
this[(x === currentIdx ? "onSelected" : "onShow")](this.selectedChild);
if(!this._size){ this.resize(); }
var centerL = Math.floor(this._size.w / 2);
// FIXME: we can use just a slice around +/- x for long lists! (alex?)
var _delay = 10;
var _diff = this._spacing;
var thresh = this.threshold;
var some = this.nl.map(function(n,i){
var dist = Math.abs(i - x);
dojo.style(n, "display", (Math.abs(i - x) > thresh ? "none" : ""));
});
this.nl
.forEach(function(n,i){
var isNextRight = (i === x + 1);
var isNextLeft = (i === x - 1);
var _mix = {
opacity: this.offOpacity,
zIndex:69
};
var c;
if(i > x){
c = "alignRight";
// stagger z-index downward from center on
_mix.zIndex = isNextRight ? 45 : 40 - i;
}else if(i < x){
c = "alignLeft";
// left z-indexes are fine, they go in order of markup
_mix.zIndex = isNextLeft ? 45 : 40;
}else{
// center should be on top always
c = "alignCenter";
_mix.opacity = 1;
}
dojo.style(n, _mix);
dojo.forEach(["alignLeft","alignRight","alignCenter"],function(cl){
dojo.removeClass(n,cl);
});
dojo.addClass(n,c);
// need to make dynamic, this is "half the size of a single image"
var _half = 50;
if(currentIdx || currentIdx === 0){
// figure out where our left edge will be: magically,
// this centers and seems to subtly get further from
// center. need maff master here:
var d = i - x;
var _off = (d === 0 ? 0 : _diff) * (d < 0 ? -1 : 1);
var lef = centerL - _half + (d * this.spacing) + _off;
// create another animation for this node:
_anims.push(
dojo.animateProperty({
duration:150,
node:n,
properties: { left: lef },
delay: parseInt(_delay),
easing: this.easing
})
);
// oh so slightly, or less if going away from node:
_delay += (d < 0 ? 15 : -15);
}
}, this) // forEach
;
// don't use onEnd here, but might ought to stop()?
// seems like it handles the new animations okay?
this._anim && this._anim.stop && this._anim.stop();
this._anim = dojo.fx.combine(_anims);
this._anim.play();
this._centering = false;
},
onShow: function(widget){
// summary: stub fired when a user triggers a recenter
// this could happen very often!
},
onSelected: function(widget){
// summary: stub fired when a user explictly clicks the already displayed value
},
_handleKey: function(e){
// summary: keyboard handling code
var dk = dojo.keys,
cur = this.nl.indexOf(this.selectedChild.domNode || this.nl[0]),
ni
;
switch(e.charOrCode){
case dk.RIGHT_ARROW:
// goto next item or stop if loop='false' and at end
ni = cur + 1;
if(ni >= this.nl.length){ ni = (this.loop ? 0 : cur); }
if(ni !== cur){ this._center(this.nl[ni]); }
break;
case dk.LEFT_ARROW:
// ditto, but left.
ni = cur - 1;
if(ni < 0){ ni = (this.loop ? this.nl.length - 1 : cur); }
if(ni !== cur){ this._center(this.nl[ni]); }
break;
case dk.ENTER:
// just like clicking a selected image
this.onSelected(this.selectedChild);
break;
}
},
_scroll: function(e){
// summary: handle mouse wheel event, and duck type a fake event to pass
// along to _handleKey
dojo.stopEvent(e);
var scroll = e[(!dojo.isMozilla ? "wheelDelta" : "detail")] * (!dojo.isMozilla ? 1 : -1);
this._handleKey({
charOrCode: dojo.keys[(scroll > 0 ? "LEFT_ARROW" : "RIGHT_ARROW")]
});
}
});