custom yui widgets

Post on 06-Dec-2014

11.698 Views

Category:

Technology

0 Downloads

Preview:

Click to see full reader

DESCRIPTION

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

TRANSCRIPT

Building interactive widgets with YUI

Cyril DoussinYahoo! EU Front-End Summit, Dec 2007

WarningsLots of code

/** * Returns the namespace specified and creates it if it doesn't exist * <pre> * YAHOO.namespace("property.package"); * YAHOO.namespace("YAHOO.property.package"); * </pre> * Either of the above would create YAHOO.property, then * YAHOO.property.package * * Be careful when naming packages. Reserved words may work in some browsers * and not others. For instance, the following will fail in Safari: * <pre> * YAHOO.namespace("really.long.nested.namespace"); * </pre> * This fails because "long" is a future reserved word in ECMAScript * * @method namespace * @static * @param {String*} arguments 1-n namespaces to create * @return {Object} A reference to the last namespace object created */YAHOO.namespace = function() { var a=arguments, o=null, i, j, d; for (i=0; i<a.length; i=i+1) { d=a[i].split("."); o=YAHOO;

// YAHOO is implied, so it is ignored if it is included for (j=(d[0] == "YAHOO") ? 1 : 0; j<d.length; j=j+1) { o[d[j]]=o[d[j]] || {};

YAHOO.env.ua = function() { var o={

/** * Internet Explorer version number or 0. Example: 6 * @property ie * @type float */ ie:0,

/** * Opera version number or 0. Example: 9.2 * @property opera * @type float */ opera:0,

/** * Gecko engine revision number. Will evaluate to 1 if Gecko * is detected but the revision could not be found. Other browsers * will be 0. Example: 1.8 * <pre> * Firefox 1.0.0.4: 1.7.8 <-- Reports 1.7 * Firefox 1.5.0.9: 1.8.0.9 <-- Reports 1.8 * Firefox 2.0.0.3: 1.8.1.3 <-- Reports 1.8 * Firefox 3 alpha: 1.9a4 <-- Reports 1.9

YAHOO.env.ua = function() { var o={

/** * Internet Explorer version number or 0. Example: 6 * @property ie * @type float */ ie:0,

/** * Opera version number or 0. Example: 9.2 * @property opera * @type float */ opera:0,

/** * Gecko engine revision number. Will evaluate to 1 if Gecko * is detected but the revision could not be found. Other browsers * will be 0. Example: 1.8 * <pre> * Firefox 1.0.0.4: 1.7.8 <-- Reports 1.7 * Firefox 1.5.0.9: 1.8.0.9 <-- Reports 1.8

Warnings(probably) Norm incompatible

Warningssoz

(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

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

YUI widgets

• Autocomplete

• Button

• Calendar

• Color Picker

• Container

• DataTable

• Logger

• Menu

• Rich Text Editor

• Slider

• TabView

• TreeView

YUI widgets

• Autocomplete

• Button

• Calendar

• Color Picker

• Container

• DataTable

• Logger

• Menu

• Rich Text Editor

• Slider

• TabView

• TreeView

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.”

YUI ContainerModule

Overlay

SimpleDialog

Dialog

Tooltip Panel

YUI ContainerModule

Overlay

SimpleDialog

Dialog

Tooltip Panel

Your Control

YAHOO.widget.Module

• Common markup structure

• Customisation through Configuration

• Custom Events

• Utility functions

Our example:Contact List with pagination

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="http://www.ejeliot.com/">ejeliot.com</a></dd> </dl> </li> <li> <dl> <dt>Name</dt> <dd>Stuart Colville</dd> <dt>Web site</dt> <dd><a href="http://muffinresearch.co.uk/">Muffin Research Labs</a></dd> </dl> </li> <li> <dl> <dt>Name</dt> <dd>Ben Ward</dd> <dt>Web site</dt> <dd><a href="http://ben-ward.co.uk/">ben-ward.co.uk</a></dd> </dl> </li></ol>

Setting things up:Structured Markup

<div id="contact-list"> <div class="hd"> <h2>Contacts</h2> </div> <div class="bd"> <ol> <li> <dl> <dt>Name</dt> <dd>Ed Eliot</dd> <dt>Web site</dt> <dd><a href="http://www.ejeliot.com/">ejeliot.com</a></dd> </dl> </li> <li> <dl> <dt>Name</dt> <dd>Stuart Colville</dd> <dt>Web site</dt> <dd><a href="http://muffinresearch.co.uk/">Muffin Research Labs</a></dd> </dl> </li> <li> <!-- ... --> </li> </ol> </div> <div class="ft"></div></div>

Setting things up:

<div id="contact-list"> <div class="hd"> <h2>Contacts</h2> </div> <div class="bd"> <ol> <li> <dl> <dt>Name</dt> <dd>Ed Eliot</dd> <dt>Web site</dt> <dd><a href="http://www.ejeliot.com/">ejeliot.com</a></dd> </dl> </li> <li> <dl> <dt>Name</dt> <dd>Stuart Colville</dd> <dt>Web site</dt> <dd><a href="http://muffinresearch.co.uk/">Muffin Research Labs</a></dd> </dl> </li> <li> <!-- ... --> </li> </ol> </div> <div class="ft"></div></div>

Structured Markup

Setting things up:

<script type="text/javascript" src="http://yui.yahooapis.com/2.4.0/build/yahoo-dom-event/yahoo-dom-event.js"></script>

dependencies• YAHOO

• YAHOO.util.Dom

• YAHOO.util.Event

• YAHOO.widget

• YAHOO.widget.Module<script type="text/javascript" src="http://yui.yahooapis.com/2.4.0/build/container/container-min.js"></script>

Setting things up:

YAHOO.Cyril.ContactList = function(el, userConfig) { YAHOO.Cyril.ContactList.superclass.constructor.call(this, el, userConfig);};YAHOO.extend(YAHOO.Cyril.ContactList, YAHOO.widget.Module);

extending Module

YAHOO.namespace(YAHOO.Cyril);

Done :)

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'; } );});

YAHOO.util.Event.onDOMReady(function() { var contact_list = new YAHOO.Cyril.ContactList('contact-list');});

Done :)

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 });}

Configuration

YAHOO.Cyril.ContactList.prototype.validateNumContacts = function(value) {

value = parseInt(value);

return !(isNan(value) || (value < 1) || (value > 3));

};

Configuration

contact_list.config.setProperty('num_contacts', 1);

alert(contact_list.getProperty('num_contacts));

Custom Events

Custom Events

Custom Events

• with other Controls

• with itself

A structured way to make your Control play well:

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("beforeShowContact", 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("showContact", this);};

Custom Events

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);

giving control to third-party code

contact_list.updateContactsEvent.subscribe(function(type, args) { alert(args[0].current_index);});

Init function

• called upon instantiation

• some “mandatory” things to do

• gets your widget up and running

Init function

Call YAHOO.widget.Module.prototype.init

YAHOO.Cyril.ContactList.superclass.init.call(this, el/*, userConfig*/);

Init function

Fire "beforeInit" and "init" 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

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.

Init function

Do DOM manipulations

// create/modify DOM elements (ie. previous/next links)

this.initDOMManipulations();

Init function

set up Event listeners

// initialise event delegation

this.initEventListeners();

Init function

Default behaviour

// show/hide contact elements

this.updateDisplay();

Init functionYAHOO.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); };

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); }); }

});

Teh End

• 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/

Cyril Doussin (http://cyril.doussin.name)

YUI: http://developer.yahoo.com/yui/

YUI blog: http://yuiblog.com

top related