Custom YUI Widgets

8,367 views

Published on

My presentation for the YAHOO! Europe Front-End Engineering Summit in December 2007.

Published in: Technology
0 Comments
5 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
8,367
On SlideShare
0
From Embeds
0
Number of Embeds
91
Actions
Shares
0
Downloads
149
Comments
0
Likes
5
Embeds 0
No embeds

No notes for slide

Custom YUI Widgets

  1. 1. Building interactive widgets with YUI Cyril Doussin Yahoo! EU Front-End Summit, Dec 2007
  2. 2. Warnings Lots of code /** YAHOO.env.ua = function() { * Returns the namespace specified and creates it if it doesn't exist var o={ * <pre> * YAHOO.namespace(quot;property.packagequot;); /** * YAHOO.namespace(quot;YAHOO.property.packagequot;); * Internet Explorer version number or 0. Example: 6 * </pre> YAHOO.env.ua = function() { * @property ie * Either of the above would create YAHOO.property, then var o={ * @type float * YAHOO.property.package */ * /** ie:0, * Be careful when naming packages. Reserved words may work in some browsers * Internet Explorer version number or 0. Example: 6 * and not others. For instance, the following will fail in Safari: * @property ie /** * <pre> * @type float * Opera version number or 0. Example: 9.2 * YAHOO.namespace(quot;really.long.nested.namespacequot;); */ * @property opera * </pre> ie:0, * This fails because quot;longquot; is a future reserved word in ECMAScript * @type float */ * /** opera:0, * @method namespace * Opera version number or 0. Example: 9.2 * @static * @property opera /** * @param {String*} arguments 1-n namespaces to create * @type float * @return {Object} A reference to the last namespace object created * Gecko engine revision number. Will evaluate to 1 if */ Gecko */ opera:0, * is detected but the revision could not be found. YAHOO.namespace = function() { Other browsers var a=arguments, o=null, i, j, d; /** * will be 0. Example: 1.8 for (i=0; i<a.length; i=i+1) { * Gecko engine revision number. * Will evaluate to 1 if Gecko <pre> d=a[i].split(quot;.quot;); * is detected but the revision could not be found. 1.7.8 browsers * Firefox 1.0.0.4: Other <-- Reports 1.7 o=YAHOO; * will be 0. Example: 1.8 * Firefox 1.5.0.9: 1.8.0.9 <-- Reports 1.8 * <pre> // YAHOO is implied, so it is ignored if it is included for (j=(d[0] == quot;YAHOOquot;) ? 1 :*0; j<d.length; j=j+1) { Firefox 1.0.0.4: 1.7.8 <-- Reports 1.7 * Firefox 1.5.0.9: 1.8.0.9 <-- Reports 1.8 o[d[j]]=o[d[j]] || {}; * Firefox 2.0.0.3: 1.8.1.3 <-- Reports 1.8 * Firefox 3 alpha: 1.9a4 <-- Reports 1.9
  3. 3. Warnings (probably) Norm incompatible
  4. 4. Warnings soz
  5. 5. (some) YUI Goals • Provide solid foundations: • Patch up DOM API • Do the hard work for you (CSS layouts, browser testing etc.) • Avoid repeating yourself (reusable components) • Make it simple: consistent design, good documentation
  6. 6. Javascript widgets • Common need: enhance page functionality in an unobtrusive, accessible way • ActiveX Flash Javascript is (most often) the appropriate way to do this • nice to make this reusable on many pages/ sites
  7. 7. YUI widgets • Autocomplete • Logger • Button • Menu • Calendar • Rich Text Editor • Color Picker • Slider • Container • TabView • DataTable • TreeView
  8. 8. YUI widgets • Autocomplete • Logger • Button • Menu • Calendar • Rich Text Editor • Color Picker • Slider • Container • TabView • DataTable • TreeView
  9. 9. YUI Container “The Container family of components is designed to enable developers to create different kinds of content-containing modules on the web.” “Module and Overlay are the most basic containers, and they can be used directly or extended to build custom containers.”
  10. 10. YUI Container Module Overlay Tooltip Panel Dialog SimpleDialog
  11. 11. YUI Container Module Overlay Your Control Tooltip Panel Dialog SimpleDialog
  12. 12. YAHOO.widget.Module • Common markup structure • Customisation through Configuration • Custom Events • Utility functions
  13. 13. Our example: Contact List with pagination
  14. 14. Setting things up: Basic Markup <h2>Contacts</h2> <ol> <li> <dl> <dt>Name</dt> <dd>Ed Eliot</dd> <dt>Web site</dt> <dd><a href=quot;http://www.ejeliot.com/quot;>ejeliot.com</a></dd> </dl> </li> <li> <dl> <dt>Name</dt> <dd>Stuart Colville</dd> <dt>Web site</dt> <dd><a href=quot;http://muffinresearch.co.uk/quot;>Muffin Research Labs</a></dd> </dl> </li> <li> <dl> <dt>Name</dt> <dd>Ben Ward</dd> <dt>Web site</dt> <dd><a href=quot;http://ben-ward.co.uk/quot;>ben-ward.co.uk</a></dd> </dl> </li> </ol>
  15. 15. Setting things up: Structured Markup <div id=quot;contact-listquot;> <div class=quot;hdquot;> <h2>Contacts</h2> </div> <div class=quot;bdquot;> <ol> <li> <dl> <dt>Name</dt> <dd>Ed Eliot</dd> <dt>Web site</dt> <dd><a href=quot;http://www.ejeliot.com/quot;>ejeliot.com</a></dd> </dl> </li> <li> <dl> <dt>Name</dt> <dd>Stuart Colville</dd> <dt>Web site</dt> <dd><a href=quot;http://muffinresearch.co.uk/quot;>Muffin Research Labs</a></dd> </dl> </li> <li> <!-- ... --> </li> </ol> </div> <div class=quot;ftquot;></div> </div>
  16. 16. Setting things up: Structured Markup <div id=quot;contact-listquot;> <div class=quot;hdquot;> <h2>Contacts</h2> </div> <div class=quot;bdquot;> <ol> <li> <dl> <dt>Name</dt> <dd>Ed Eliot</dd> <dt>Web site</dt> <dd><a href=quot;http://www.ejeliot.com/quot;>ejeliot.com</a></dd> </dl> </li> <li> <dl> <dt>Name</dt> <dd>Stuart Colville</dd> <dt>Web site</dt> <dd><a href=quot;http://muffinresearch.co.uk/quot;>Muffin Research Labs</a></dd> </dl> </li> <li> <!-- ... --> </li> </ol> </div> <div class=quot;ftquot;></div> </div>
  17. 17. Setting things up: dependencies • YAHOO • YAHOO.util.Dom • YAHOO.util.Event <script type=quot;text/javascriptquot; src=quot;http://yui.yahooapis.com/2.4.0/build/yahoo-dom-event/yahoo-dom-event.jsquot;></ script> • YAHOO.widget • YAHOO.widget.Module <script type=quot;text/javascriptquot; src=quot;http://yui.yahooapis.com/2.4.0/build/container/container-min.jsquot;></script>
  18. 18. Setting things up: extending Module YAHOO.namespace(YAHOO.Cyril); YAHOO.Cyril.ContactList = function(el, userConfig) { YAHOO.Cyril.ContactList.superclass.constructor.call(this, el, userConfig); }; YAHOO.extend(YAHOO.Cyril.ContactList, YAHOO.widget.Module);
  19. 19. Done :) YAHOO.util.Event.onDOMReady(function() { var contact_list = new YAHOO.Cyril.ContactList('contact-list'); }); YAHOO.util.Event.onDOMReady(function() { var contact_list = new YAHOO.Cyril.ContactList('contact-list'); YAHOO.util.Dom.batch( [ contact_list.element, contact_list.header, contact_list.body, contact_list.footer], function(el) { el.style.border = '1px solid red'; } ); });
  20. 20. Done :)
  21. 21. Configuration YAHOO.Cyril.ContactList.prototype.initDefaultConfig = function () { YAHOO.Cyril.ContactList.superclass.initDefaultConfig.call(this); /** * Maximum number of contacts to show * @config * @type Number * @default 2 */ this.cfg.addProperty('num_contacts', { handler: this.configNumContacts, validator: this.validateNumContacts, suppressEvent: true, supercedes: false, value: 2 }); }
  22. 22. Configuration YAHOO.Cyril.ContactList.prototype.validateNumContacts = function(value) { value = parseInt(value); return !(isNan(value) || (value < 1) || (value > 3)); };
  23. 23. Configuration contact_list.config.setProperty('num_contacts', 1); alert(contact_list.getProperty('num_contacts));
  24. 24. Custom Events
  25. 25. Custom Events
  26. 26. Custom Events A structured way to make your Control play well: • with other Controls • with itself
  27. 27. Custom Events /** * Initializes the custom events for YAHOO.Cyril.ContactList. * This method gets called by YAHOO.widget.Module.prototype.init * @method initEvents */ YAHOO.Cyril.ContactList.prototype.initEvents = function() { // call the base class method to make sure inherited custom events get set up YAHOO.Cyril.ContactList.superclass.initEvents.call(this); /** * CustomEvent fired before showing a different contact * @event beforeUpdateContactsEvent * @param {HTMLElement} contactElement LI HTMLElement for the contact to show */ this.beforeUpdateContactsEvent = new YAHOO.util.CustomEvent(quot;beforeShowContactquot;, this); /** * CustomEvent fired after showing a different contact * @event updateContactsEvent * @param {HTMLElement} contactElement LI HTMLElement for the contact now displayed */ this.updateContactsEvent = new YAHOO.util.CustomEvent(quot;showContactquot;, this); };
  28. 28. Custom Events giving control to third-party code contact_list.updateContactsEvent.subscribe(function(type, args) { alert(args[0].current_index); }); var contactElement = get a reference to the new contact element here; if (this.beforeUpdateContactsEvent.fire(contactElement)) { // ... change the contact displayed to contactElement here } this.updateContactsEvent.fire(contactElement);
  29. 29. Init function • called upon instantiation • some “mandatory” things to do • gets your widget up and running
  30. 30. Init function Call YAHOO.widget.Module.prototype.init YAHOO.Cyril.ContactList.superclass.init.call(this, el/*, userConfig*/);
  31. 31. Init function Fire quot;beforeInitquot; and quot;initquot; events when appropriate this.beforeInitEvent.fire(YAHOO.Cyril.ContactList); // .. rest of the init function this.initEvent.fire(YAHOO.Cyril.ContactList); Note there is no need to call this.initEvents(...) to initialise Custom Events
  32. 32. Init function Cache DOM references // cache element reference this.some_element = document.getElementById('some_element_id'); No need for the main widget’s element + header, body, and footer child elements.
  33. 33. Init function Do DOM manipulations // create/modify DOM elements (ie. previous/next links) this.initDOMManipulations();
  34. 34. Init function set up Event listeners // initialise event delegation this.initEventListeners();
  35. 35. Init function Default behaviour // show/hide contact elements this.updateDisplay();
  36. 36. Init function YAHOO.Cyril.ContactList.prototype.init = function(el, userConfig) { // Note that we don't pass the user config in here yet because we only want it processed once, at the lowest subclass level (by calling this.cfg.applyConfig later on) // this also calls this.initEvents YAHOO.Cyril.ContactList.superclass.init.call(this, el/*, userConfig*/); // fire event saying we are about to start the initialisation this.beforeInitEvent.fire(YAHOO.Cyril.ContactList); if (userConfig) { this.cfg.applyConfig(userConfig, true); } this.contact_elements = this.body.getElementsByTagName('li'); if (this.contact_elements.length == 0) { return; } this.current_index = 0; // create/modify DOM elements (ie. previous/next links) this.initDOMManipulations(); // show/hide contact elements this.updateDisplay(); // initialise event delegation this.initEventListeners(); // fire event saying initialisation of the Control is done this.initEvent.fire(YAHOO.Cyril.ContactList); };
  37. 37. Multiple instances • store instance in an Array • Custom Events don’t get in the way YAHOO.util.Event.onDOMReady(function() { // grab all contact lists by their classes and instanciate them. var contact_lists = YAHOO.util.Dom.getElementsByClassName('contact-list'); for (var i = 0, contact_list; contact_list = contact_lists[i]; i ++) { var control = new YAHOO.Cyril.ContactList(contact_list); // store a reference to the instance YAHOO.Cyril.contactLists = [ control ] control.updateContactsEvent.subscribe(function(type, args) { alert('Current index: ' + args[0].current_index); }); } });
  38. 38. Teh End Cyril Doussin (http://cyril.doussin.name) YUI: http://developer.yahoo.com/yui/ YUI blog: http://yuiblog.com • http://www.wat.tv/playlist/689334 • http://www.jaunted.com/files/3873/French_baguette.jpg • http://flickr.com/photos/plasticbag/971055811/ • http://flickr.com/photos/intranation/1113203816/ • http://flickr.com/photos/intranation/1870271315/

×