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