dojo.provide("demos.skew.src"); dojo.require("demos.skew.src.Image"); dojo.require("dojo.NodeList-fx"); dojo.require("dojo.fx.easing"); dojo.require("dojox.widget.Dialog"); dojo.require("dojox.layout.RadioGroup"); dojo.require("dojox.analytics.Urchin"); (function($){ var _stuffMoving = false, _started = false, _stalltime = 650, // ms _doneAnim = null, _needed = null, _loaded = [], _connects = [], profileWidget = null, stack = null, timer = null, _profiletimer = null ; var _doneAnim = function(){ $.fadeOut({ // fade out the overlay node: "overlay", duration: 300, onEnd: function(){ // then make our image surface 240px, and fade it in $.animateProperty({ node:"imageContainer", properties: { height: 240, opacity:1 }, // with teh sexy easing: $.fx.easing.backOut, duration:420, // wait for the fadeout above to finish delay:600, onEnd: function(){ // hide the actual overlay so you can click underneath it $.style("overlay","display","none"); _started = true; // take all the elements with "startsHidden" class, and // set them up, fade them in, and remove hidden class $.query(".startsHidden") .style("opacity", "0") .removeClass("startsHidden") .fadeIn().play(500); } }).play(); } }).play(); }; // onShow result, it no timer was running (see later) var updateProfile = function(datawidget){ //if(!_started){ return; } _stuffMoving = true; // conveniently, later, we stored a reference to our avatar (RadioGroupSlide child) // in the Image widget. stack.selectChild(datawidget._avatar); profileWidget.setData(datawidget._userInfo); } var _oneBroke = function(n,e){ _gotOne(n,e); } // the handler for our image onloader. // FIXME: if we get a 404, we'll never finish ... var _gotOne = function(n,e){ _loaded.push(n); if(_loaded.length >= $._neededImages){ $.forEach(_connects, $.disconnect); _doneAnim(); } } // the onLoad function var init = function(){ // tracking demo: var u = new dojox.analytics.Urchin({ acct: "UA-3572741-1", GAonLoad: function(){ this.trackPageView("/demos/skew"); } }); $.style("whoNode","opacity", 0); // see, the page "degrades" ;) . This contributor listing page is only a link to // http://dojo.jot.com/ContrbutorListing $.query("a[href^=http://dojo.jot]").forEach(function(n){ n.parentNode.innerHTML = n.innerHTML; }); // create a "help" dialog out of the node in the page. var dialog = new dojox.widget.Dialog({ dimensions:[640,420] },"dialog"); dialog.startup(); // setup a way to show it $.connect($.byId("helper"), "onclick", dialog, "show"); // set it all off: grab some data from a remote file, and create // the interface $.xhrGet({ url:"../resources/users.json", handleAs:"json", load:function(data){ var labelNode = $.byId("whoNode"); var _lastNode = null; profileWidget = new profile.Data({},"profileData"); // create the region where the avatars will live. stack = new dojox.layout.RadioGroupSlide({ style:"width:180px; height:200px", // FIXME: when did StackContainer start setting relative explicitly? _setupChild: function(/*Widget*/ page){ $.style(page.domNode,{ display:"none", position:"absolute", overflow:"hidden" }) return page; // dijit._Widget } },"stack"); // iterate over each of the returned committers, setting up the canvas $.forEach(data.committers,function(user, i){ // create an Image in the container, and store the user profile data // in it's instance. var im = new image.Skewed({ // use a default square.png if no imgUrl found. imgUrl: user.imgUrl || "images/square.png", value: user.name }); $.mixin(im,{ _userInfo: user }); // create a reflection-less scale thumbnail (color) in a div var node = $.doc.createElement('div'); stack.containerNode.appendChild(node); node.innerHTML = ""; // and make it a child of our RadioGroupSlide var avatar = new dijit.layout.ContentPane({ id: im.id + "avatar", slideFrom:"top" }, node); // mix a reference to the child of the stackContianer in the image widget $.mixin(im, { _avatar: avatar }); // store a ref to our "center" image if(i === 0){ _lastNode = im; } // either add this image to the beginning or append to the end. alternate. if(i % 2 == 0){ $.byId("imageContainer").appendChild(im.domNode); }else{ $.place(im.domNode, "imageContainer", "first"); } }); // this will setup all the children we _just_ added stack.startup(); // turn the container holding all the image widgets into the interface var ic = new image.Container({ // for performance (it's a big list/lot of images) offOpacity:1, onShow: function(widget){ // onShow fires _every_ time an image is "centered" visually (no skew) // so for UX, we'll defer the "updateProfile()" call until some delay, if(timer){ clearTimeout(timer); } timer = setTimeout($.partial(updateProfile, widget), _stalltime); // but still update one label from our widget data labelNode.innerHTML = widget.value + ""; $.anim("profileArea",{ opacity:0 }, 175); }, // should be lower, but i want to stage opacity on the edges rather // than display:none, so for now this looks better. visibleItems: 42, // tweak as needed spacing:25, angle:10 },"imageContainer"); // find every image in this container, and connect an onload connect to it // when each image fires it's onload, the _gotOne function above is alerted var _needed = $.query("img", "imageContainer"); $._neededImages = Number(_needed.length); _needed.forEach(function(n,i){ _connects.push($.connect(n, "onload", $.partial(_gotOne, n))); _connects.push($.connect(n, "onerror", $.partial(_oneBroke, n))); // if you don't touch the .src attribute _after_ connecting to onload, it // won't fire in weird conditions. if($.isIE){ n.src = n.src; } }); ic.startup(); _lastNode.center(); // center the first node (from above creating image widgets) // resize the image container when the window does, it's fluid $.connect(window, "onresize", ic, "resize"); // make it small, so we can wipe it in $.style("imageContainer",{ height:"1px", opacity:0 }); } }) }; $.declare("profile.Stalker", dijit._Widget, { }); $.declare("profile.Data", dijit._Widget, { // summary: A simple widget we probably don't even need. constructor: function(){ var $$ = $.byId; this.nodeReferences = { "location" : $$("proLocation"), "website" : $$("proWebsite"), "employer" : $$("proEmployer"), "title" : $$("proRole") } }, setData: function(data){ var node = this.nodeReferences; for(var i in node){ if(i in data){ $.style(node[i],"display",""); var txt = ( i == "website" ? "" + data[i] + "
" : data[i] ); node[i].innerHTML = txt; }else{ $.style(node[i],"display","none"); } } // this is really a list of potential aliases, so start clean: var nick = ""; if("handle" in data){ // add the "handle" attribute nick += '"' + data["handle"] + '"'; } if("irc" in data && data["irc"] !== data["handle"]){ // add the "irc" attribute, if it is different from the "handle" attribute nick += ' "' + data["irc"] + '"'; } $.byId("proAliases").innerHTML = nick; // fade and swipe in the content. // FIXME: weirdness w/ IE7 and no respecting -42 marginLegf $.anim("profileArea",{ opacity:{ start:0, end: 0.99 }, paddingLeft:{ start:72, end:0 } }, 520, $.fx.easing.bounceOut); } }); var newp = function(){ // IE6 branch of this demo window.location.href = "http://" + (confirm("Hi IE6 user! Is it 2008?") ? "webkit.org" : "mozilla.org") + "/"; } // setup our branch launch: ;) $.addOnLoad(($.isIE < 7 ? newp : init)); })(dojo);