This example demonstrates how to insert content when working with NodeList
instances.
Click buttons to build your burger.
Setting up the NodeList
First we need some HTML to work with.
<ul class="demo"> <li class="bun-top"><img src="assets/images/bun_top.png"/></li> <li class="bun-bottom"><img src="assets/images/bun_bottom.png"/></li> </ul>
Next we'll add some buttons to be clicked.
<ul class="buttons-list"> <li><button class='yui3-button patty'> Patty · Before Last Bun</button></li> <li><button class='yui3-button lettuce'> Lettuce · Before Last Bun</button></li> <li><button class='yui3-button cheese' disabled="disabled"> Cheese · Before First Patty</button></li> <li><button class='yui3-button tomato'> Tomato · After First Bun</button></li> <li><button class='yui3-button onions'> Onions · After First Bun</button></li> <li><button class='yui3-button pickles'> Pickles · After First Bun</button></li> <li><button class='yui3-button ketchup'> Ketchup · After First Bun</button></li> <li><button class='yui3-button done'> Done</button></li> <li><button class='yui3-button another'> Another Please</button></li> </ul>
Adding Content
After defining some var
s, we'll
add a buttonClicks
handler to run when an event is fired.
It will add content to the demo
node.
Note that the this
in the handler is the object that was clicked.
var demo = Y.one('.demo'), btnList = Y.all('.buttons-list .yui3-button'), ...; // This inserts burger parts and manages the display of buttons var buttonClicks = function (e) { var obj; if (this.hasClass('patty')) { // Create a node with an image of the burger part obj = Y.Node.create('<li class="patty"><img src="' + imgPath + 'burg_patty.png"/></li>'); // Insert it before the bottom bun demo.insert(obj, Y.one('.bun-bottom')); // ... } else if // other buttons follow...
The handler inserts different objects into the demo
container object
in different places based on these methods:
prepend
- as firstChildappend
- as lastChildinsert
- before a specified node or childNode index
Attaching Events
We assign our handler to all of the yui3-button
objects through
event subscription to the matching selector.
Y.on('click', buttonClicks, '.example .buttons-list .yui3-button');
Transitions
When an event handler simply inserts an object, it appears instantly, and other DOM objects are rendered in their new locations, which can be a visually jarring experience.
In this example, we've added a transitionObject
function to smooth things out.
Inserted burger elements have an initial CSS height
of 0.
After each insertion, we call the transitionObject
function,
passing the inserted object. It begins growing to a height equal to the image
it contains (the images are different heights). This gradually pushes open a space
for itself, while it moves in from offscreen left, and fades in.
var transitionObject = function (obj) { obj.transition({ duration: 0.8, // height grows from initial 0, to height of contained image height: obj.one('img').getStyle('height'), marginLeft: '0px', // transition into place from offscreen left. opacity: { delay: 0.2, duration: 0.5, value: 1 } }); }
Here's more code in the buttonClicks
handler where we call transitionObject
,
and do some special handling for the cheese button state.
// This inserts burger parts and manages the display of buttons var buttonClicks = function (e) { var obj; if (this.hasClass('patty')) { // Create a node with an image of the burger part obj = Y.Node.create('<li class="patty"><img src="' + imgPath + 'burg_patty.png"/></li>'); // Insert it before the bottom bun demo.insert(obj, Y.one('.bun-bottom')); // Smooth out insert with transition transitionObject(obj); // Cheese button becomes available // only when there's a patty to insert before Y.one('.buttons-list .cheese')._node.disabled = false; } else if // other buttons follow...
Complete Example Source
In the complete source you'll see we also added handling for:
- Removing elements from the burger
- Clicking the Done button to vertically compress the burger
- Requesting another
<style> .example .demo, .example .buttons-list{ width: 302px; display: inline-block; zoom: 1; *display: inline; margin: 0; padding: 0; vertical-align: top; text-align: center; } .example .buttons-list{ list-style: none; text-align: left; margin-left: 100px; width: auto; height: 21em; } .example .buttons-list .yui3-button { margin-bottom: 0.5em; } .example .buttons-list .ketchup{ margin-bottom: 1em; } .example .buttons-list .another{ display: none; } .example .demo li { position: relative; list-style: none; height: 0; width: 302px; opacity: 0; margin: 0 0 0 -800px; cursor: no-drop; font-size: 1px; } .example .demo li img { position: absolute; top: 0; left: 0; } .example .demo .bun-top, .example .demo .bun-bottom{ opacity: 1; height: 106px; margin: 0; } </style> <ul class="demo"> <li class="bun-top"><img src="../assets/node/images/burg_bun_top.png" width="271" height="106" alt="Burger bun top"/></li> <li class="bun-bottom"><img src="../assets/node/images/burg_bun_bottom.png" width="291" height="115" alt="Burger bun bottom"/></li> </ul> <ul class="buttons-list"> <li><button class='yui3-button patty'> Patty · Before Last Bun</button></li> <li><button class='yui3-button lettuce'> Lettuce · Before Last Bun</button></li> <li><button class='yui3-button cheese' disabled="disabled"> Cheese · Before First Patty</button></li> <li><button class='yui3-button tomato'> Tomato · After First Bun</button></li> <li><button class='yui3-button onions'> Onions · After First Bun</button></li> <li><button class='yui3-button pickles'> Pickles · After First Bun</button></li> <li><button class='yui3-button ketchup'> Ketchup · After First Bun</button></li> <li><button class='yui3-button done'> Done</button></li> <li><button class='yui3-button another'> Another Please</button></li> </ul> <script> YUI().use('node', 'cssbutton', 'transition', 'UA', function (Y) { var demo = Y.one('.demo'), btnList = Y.all('.buttons-list .yui3-button'), i = 0, objList, myZIndex, imgPath = '../assets/node/images/'; if (Y.UA.ie && Y.UA.ie < 7) { // Add a prefix to the image file name in the imgPath. // This is needed to work around IE6 non-support of alpha pngs imgPath = imgPath + '8bit_'; Y.one('.example .demo .bun-top img').setAttribute('src', imgPath + 'burg_bun_top.png'); Y.one('.example .demo .bun-bottom img').setAttribute('src', imgPath + 'burg_bun_bottom.png'); } // This smoothes out the visual experience of adding // an element to the burger var transitionObject = function (obj) { obj.transition({ duration: 0.8, // height grows from initial 0, to height of contained image height: obj.one('img').getStyle('height'), marginLeft: '0px', // transition into place from offscreen left. opacity: { delay: 0.2, duration: 0.5, value: 1 } }); } // This removes an element of the burger // the height transitions to 0, it moves left, and fades out var removeObject = function(e) { e.currentTarget.transition({ duration: 0.8, height: 0, marginLeft: '-400px', opacity: { delay: 0.2, duration: 0.5, value: 0 } }, // after the transition finishes... function(){ e.currentTarget.remove(); // remove the clicked item from the DOM // If there's no patty in the burger if (Y.one('.example .demo').getHTML().indexOf('patty') === -1) { // Disable the cheese button // Cheese is inserted before first patty. // The cheese button will be enabled when there's a patty Y.one('.buttons-list .cheese')._node.disabled = true; } }); } // This inserts burger parts and manages the display of buttons var buttonClicks = function (e) { var obj; if (this.hasClass('patty')) { // Create a node with an image of the burger part obj = Y.Node.create('<li class="patty"><img src="' + imgPath + 'burg_patty.png" width="268" height="75" alt="Burger patty"/></li>'); // Insert it before the bottom bun demo.insert(obj, Y.one('.bun-bottom')); // Smooth out insert with transition transitionObject(obj); // Cheese button becomes available // only when there's a patty to insert before Y.one('.buttons-list .cheese')._node.disabled = false; } else if (this.hasClass('lettuce')) { obj = Y.Node.create('<li class="lettuce"><img src="' + imgPath + 'burg_lettuce.png" width="302" height="87" alt="Lettuce"/></li>'); demo.insert(obj, Y.one('.bun-bottom')); transitionObject(obj); } else if (this.hasClass('cheese')) { obj = Y.Node.create('<li class="cheese"><img src="' + imgPath + 'burg_cheese.png" width="274" height="89" alt="Cheese"/></li>'); demo.insert(obj, Y.one('.patty')); transitionObject(obj); } else if (this.hasClass('ketchup')) { obj = Y.Node.create('<li class="ketchup"><img src="' + imgPath + 'burg_ketchup.png" width="208" height="66" alt="Ketchup"/></li>'); Y.one('.bun-top').insert(obj, 'after'); transitionObject(obj); } else if (this.hasClass('pickles')) { obj = Y.Node.create('<li class="pickles"><img src="' + imgPath + 'burg_pickles.png" width="236" height="61" alt="Pickles"/></li>'); Y.one('.bun-top').insert(obj, 'after'); transitionObject(obj); } else if (this.hasClass('onions')) { obj = Y.Node.create('<li class="onions"><img src="' + imgPath + 'burg_onions.png" width="248" height="77" alt="Onions"/></li>'); Y.one('.bun-top').insert(obj, 'after'); transitionObject(obj); } else if (this.hasClass('tomato')) { obj = Y.Node.create('<li class="tomato"><img src="' + imgPath + 'burg_tomato.png" width="225" height="68" alt="Tomato slice"/></li>'); Y.one('.bun-top').insert(obj, 'after'); transitionObject(obj); } else if (this.hasClass('done')) { objList = Y.all('.demo li'); myZIndex = objList.size(); // for resetting z-index of burger parts // Hide all the buttons when done btnList.setStyle('display', 'none'); // Show the "Another Please" button Y.one('.buttons-list .another').setStyle('display', 'block'); // The normal z-index of <li>s in a <ul> results in the // bottom of the bun picture being on top // The z-index of the burger elements must be reversed. for (i = 0; i < objList.size(); i += 1) { objList.item(i).setStyle('zIndex', myZIndex); myZIndex -= 1; objList.item(i).setStyle('position', 'relative'); // transition the height of the elements proportionally smaller // so you could get your mouth around it objList.item(i).transition({ duration: 0.5, height: parseInt(objList.item(i).one('img').getStyle('height'), 10) * 0.15 + 'px' }); } } else if (this.hasClass('another')) { // Empty out the content of the burger image demo.setContent(''); // Insert just the buns demo.append('<li class="bun-top"><img src="' + imgPath + 'burg_bun_top.png" width="271" height="106" alt="Burger bun top"/></li>'); demo.append('<li class="bun-bottom"><img src="' + imgPath + 'burg_bun_bottom.png" width="291" height="115" alt="Burger bun bottom"/></li>'); // Disable the cheese button // Cheese is inserted before first patty. // The cheese button will be enabled when there's a patty Y.one('.buttons-list .cheese')._node.disabled = true; // Display all the buttons except the "Another Please" btnList.setStyle('display', 'block'); Y.one('.buttons-list .another').setStyle('display', 'none'); } } Y.on('click', buttonClicks, '.example .buttons-list .yui3-button'); Y.one('.example .demo').delegate('click', removeObject, 'li'); }); </script>