c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass<div class="intro">
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass<p>This example uses DD and <a href="http://developer.yahoo.com/yql/">YQL</a> to build a Photo Browser application. This example was part of the YUI 3 presentation by <a href="http://twiiter.com/davglass">@davglass</a> at <a href="http://openhacklondon.pbworks.com/">Open Hack : London</a></p>
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass<div class="example newwindow">
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass <a href="photo-browser-example.html" target="_blank" class="button">
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass View Example in New Window
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass<h3>Drag and Drop</h3>
aed0a1e5e3f44c4b7d2afd9e1c7dc78203e11251Dav Glass<p>In this example, Drag and Drop is heavily customized by using "event bubbling" and "custom proxies".</p>
aed0a1e5e3f44c4b7d2afd9e1c7dc78203e11251Dav Glass<p>When you see `Y.DD.DDM.on` in the code, you are seeing the built-in "event bubbling".</p>
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass<p>The DD `dragNode` is the proxy node, we add some styles to it allowing it to look the way we want.</p>
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass<p>Here is the Flickr YQL query used in this example.</p>
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav GlassSELECT * FROM flickr.photos.search(100) WHERE
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass (text="yuiconf")
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav GlassAND (safe_search = 1)
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav GlassAND (media = "photos")
8e13d74e6b6797ec62039f6f0cab4d9b9e2d70aeDav GlassAND (api_key = "1895311ec0d2e23431a6407f3e8dffcc")
8e13d74e6b6797ec62039f6f0cab4d9b9e2d70aeDav Glass<p><em>Note: You need to get your own API key, please do not use ours.</em></p>
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass<h3>Slider and StyleSheet</h3>
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass<p>In this example, we will use the Slider control to dynamically manipulate a CSS Style Rule.</p>
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass<p>First, we need to create the slider and render it.</p>
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass//Create and render the slider
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glassvar sl = new Y.Slider({
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass length: '200px', value: 40, max: 70, min: 5
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass}).render('.horiz_slider');
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass<p>Now, we listen for the Slider's `valueChange` event. This event is fired when the value of the Slider has changed.</p>
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass<p>Next we use the StyleSheet utility to dynamically change a style rule to resize the images.
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav GlassThe style rule that we want to change is `#yui-main .yui-g ul li`. When the Slider's value changes, we will take the value and divide it by 2, then use that as the percentage width of the li.
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav GlassThis will give us the effect we want (resizing images) without touching all the images via the DOM.
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass//Listen for the change
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glasssl.after('valueChange',function (e) {
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass //Insert a dynamic stylesheet rule:
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass var sheet = new Y.StyleSheet('image_slider');
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass sheet.set('#yui-main .yui-g ul li', {
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass width: (e.newVal / 2) + '%'
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass<h3>Event Delegation</h3>
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass<p>This listener listens for all `mouseup` events on the `document` and it will only fire when the target element matches the `*` selector (which should be all elements).</p>
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass<p>This way we can remove all the `selected` CSS classes from all the images in the browser when a `mouseup` occurs, only if the shift key was not pressed. We can then check to determine if the mouseup came from one of the images. If it has, add the selected class back to it.</p>
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass//Listen for all mouseups on the document (selecting/deselecting images)
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav GlassY.delegate('mouseup' , function(e) {
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass //No shift key - remove all selected images
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass wrapper.all('img.selected').removeClass('selected');
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass //Check if the target is an image and select it.
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass if (e.target.test('#yui-main .yui-g ul li img')) {
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass}, document, '*');
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass<p>This listener, listens for all `click` events on the album list `#photoList li`.
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav GlassFirst, it stops the click, so the href is not followed. Next, it removes all the `selected` classes from the list. Then, it adds the `selected` class to the item that was clicked on.</p>
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass<p>After that UI setup, it uses Selectors to change the view of the images in the browser.
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav GlassFirst, it checks if we are viewing "all" or a "sub album". If all is selected, it removes the `hidden` class from all the images.
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav GlassIf it was an album, it adds the `hidden` class to all the images, then selects all the images with the class of its `id`, then it removes the hidden class from them.
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass<p>Basically, it hides all the images, then determines the ones it needs to show and removes the `hidden` class from them.</p>
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass//Listen for all clicks on the '#photoList li' selector
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav GlassY.delegate('click', function(e) {
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass //Prevent the click
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass //Remove all the selected items
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass e.currentTarget.get('parentNode').all('li.selected').removeClass('selected');
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass //Add the selected class to the one that one clicked
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass //The "All Photos" link was clicked
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass //Remove all the hidden classes
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass wrapper.all('li').removeClass('hidden');
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass //Another "album" was clicked, get its id
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass var c = e.target.get('id');
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass //Hide all items by adding the hidden class
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass wrapper.all('li').addClass('hidden');
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass //Now, find all the items with the class name the same as the album id
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass //and remove the hidden class
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass wrapper.all('li.' + c).removeClass('hidden');
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass}, document, '#photoList li');
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass<h3>Full Source</h3>
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass<p>Here is the full commented JavaScript source for this example.</p>
c3573884ddb87405d819f8c70cb7fed1ff8f471eDav Glass{{> photo-browser-source-js}}