photo-browser.mustache revision aed0a1e5e3f44c4b7d2afd9e1c7dc78203e11251
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein<div class="intro">
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein<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>
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein<div class="example newwindow">
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein <a href="photo-browser-example.html" target="_blank" class="button">
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein View Example in New Window
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein<h3>Drag and Drop</h3>
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein<p>In this example, Drag and Drop is heavily customized by using "event bubbling" and "custom proxies".</p>
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein<p>When you see `Y.DD.DDM.on` in the code, you are seeing the built-in "event bubbling".</p>
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein<p>The DD `dragNode` is the proxy node, we add some styles to it allowing it to look the way we want.</p>
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein<p>Here is the Flickr YQL query used in this example.</p>
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob AusteinSELECT * FROM flickr.photos.search(100) WHERE
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein (text="yuiconf")
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob AusteinAND (safe_search = 1)
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob AusteinAND (media = "photos")
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein<h3>Slider and StyleSheet</h3>
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein<p>In this example, we will use the Slider control to dynamically manipulate a CSS Style Rule.</p>
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein<p>First, we need to create the slider and render it.</p>
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein//Create and render the slider
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austeinvar sl = new Y.Slider({
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein length: '200px', value: 40, max: 70, min: 5
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein}).render('.horiz_slider');
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein<p>Now, we listen for the Slider's `valueChange` event. This event is fired when the value of the Slider has changed.</p>
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein<p>Next we use the StyleSheet utility to dynamically change a style rule to resize the images.
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob AusteinThe 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.
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob AusteinThis will give us the effect we want (resizing images) without touching all the images via the DOM.
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein//Listen for the change
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austeinsl.after('valueChange',function (e) {
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein //Insert a dynamic stylesheet rule:
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein var sheet = new Y.StyleSheet('image_slider');
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein sheet.set('#yui-main .yui-g ul li', {
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein width: (e.newVal / 2) + '%'
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein<h3>Event Delegation</h3>
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein<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>
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein<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>
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein//Listen for all mouseups on the document (selecting/deselecting images)
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob AusteinY.delegate('mouseup' , function(e) {
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein //No shift key - remove all selected images
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein wrapper.all('img.selected').removeClass('selected');
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein //Check if the target is an image and select it.
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein if (e.target.test('#yui-main .yui-g ul li img')) {
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein}, document, '*');
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein<p>This listener, listens for all `click` events on the album list `#photoList li`.
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob AusteinFirst, 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>
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein<p>After that UI setup, it uses Selectors to change the view of the images in the browser.
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob AusteinFirst, it checks if we are viewing "all" or a "sub album". If all is selected, it removes the `hidden` class from all the images.
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob AusteinIf 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.
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein<p>Basically, it hides all the images, then determines the ones it needs to show and removes the `hidden` class from them.</p>
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein//Listen for all clicks on the '#photoList li' selector
f293a69bcd1c1dd7bdac8f4102fc2398b9e475c8Eric LuceY.delegate('click', function(e) {
f293a69bcd1c1dd7bdac8f4102fc2398b9e475c8Eric Luce //Prevent the click
f293a69bcd1c1dd7bdac8f4102fc2398b9e475c8Eric Luce //Remove all the selected items
f293a69bcd1c1dd7bdac8f4102fc2398b9e475c8Eric Luce e.currentTarget.get('parentNode').all('li.selected').removeClass('selected');
f293a69bcd1c1dd7bdac8f4102fc2398b9e475c8Eric Luce //Add the selected class to the one that one clicked
f293a69bcd1c1dd7bdac8f4102fc2398b9e475c8Eric Luce //The "All Photos" link was clicked
f293a69bcd1c1dd7bdac8f4102fc2398b9e475c8Eric Luce //Remove all the hidden classes
f293a69bcd1c1dd7bdac8f4102fc2398b9e475c8Eric Luce wrapper.all('li').removeClass('hidden');
f293a69bcd1c1dd7bdac8f4102fc2398b9e475c8Eric Luce //Another "album" was clicked, get its id
f293a69bcd1c1dd7bdac8f4102fc2398b9e475c8Eric Luce var c = e.target.get('id');
f293a69bcd1c1dd7bdac8f4102fc2398b9e475c8Eric Luce //Hide all items by adding the hidden class
f293a69bcd1c1dd7bdac8f4102fc2398b9e475c8Eric Luce wrapper.all('li').addClass('hidden');
f293a69bcd1c1dd7bdac8f4102fc2398b9e475c8Eric Luce //Now, find all the items with the class name the same as the album id
f293a69bcd1c1dd7bdac8f4102fc2398b9e475c8Eric Luce //and remove the hidden class
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein wrapper.all('li.' + c).removeClass('hidden');
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein}, document, '#photoList li');
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein<h3>Full Source</h3>
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein<p>Here is the full commented JavaScript source for this example.</p>
60e5e10f8d2e2b0c41e8abad38cacd867caa6ab2Rob Austein{{> photo-browser-source-js}}