Introducing YUI 3 AutoComplete

148

description

An all-new AutoComplete widget is landing in YUI 3.3.0. In this talk from YUIConf 2010, AutoComplete author Ryan Grove will take you on a whirlwind tour of some of the many autocomplete patterns it makes possible, as well as a deep dive into its powerful new YQL integration, filtering, and highlighting capabilities.

Transcript of Introducing YUI 3 AutoComplete

Page 1: Introducing YUI 3 AutoComplete
Page 2: Introducing YUI 3 AutoComplete

A brief history of YUI AutoComplete

Photo: http://www.flickr.com/photos/margolove/1204358675/

Page 3: Introducing YUI 3 AutoComplete

AutoComplete appeared in YUI 0.10.0, the first public release of YUI.

Page 4: Introducing YUI 3 AutoComplete

It was one of the first open source JavaScript autocomplete widgets.

Page 5: Introducing YUI 3 AutoComplete

Since then, it has been one of the most popular YUI widgets.

Page 6: Introducing YUI 3 AutoComplete

There are lots of different autocomplete patterns in use on

the web today.

Page 7: Introducing YUI 3 AutoComplete

In the YUI 2 world, this meant AutoComplete had to provide many

options within a single module.

Page 8: Introducing YUI 3 AutoComplete

Patterns that weren’t similar to a traditional list-based autocomplete

weren’t well-served by this model.

Page 9: Introducing YUI 3 AutoComplete

This isn’t a problem in the more granular YUI 3 world.

Page 10: Introducing YUI 3 AutoComplete

Say hello to YUI 3 AutoComplete

Photo: http://www.flickr.com/photos/christianschuit/4201189548/

Page 11: Introducing YUI 3 AutoComplete

Download video: http://j.mp/yui3ac1

Page 12: Introducing YUI 3 AutoComplete

New modular API provides more flexibility and easier extension to

allow for countless autocomplete patterns.

Photo: http://www.flickr.com/photos/grdloizaga/817443503/

Page 13: Introducing YUI 3 AutoComplete

autocomplete-base

event-valuechange

autocomplete-filters

autocomplete-highlighters

autocomplete-list

AutoComplete modules

Page 14: Introducing YUI 3 AutoComplete

Synthetic event; fires when an input field’s value changes.

AutoComplete modules

autocomplete-base

event-valuechange

autocomplete-filters

autocomplete-highlighters

autocomplete-list

Core logic and API. No UI, minimal dependencies.

Optional prepackaged result filters and highlighters.

Traditional list widget, just like Mom used to make.

Page 15: Introducing YUI 3 AutoComplete

1KB

2KB

3KB

4KB

5KB

6KB

7KB

8KB

2.8.2 3.3.0

AutoComplete module size(min + gzip)

Filters

Highlighters

List

Base

Page 16: Introducing YUI 3 AutoComplete

90% feature parity with YUI 2 AutoComplete.

*

* This is a highly scientific number. I swear.

Page 17: Introducing YUI 3 AutoComplete

autocomplete-base autocomplete-list

allowBrowserAutocomplete activateFirstItem

inputNode align

maxResults alwaysShowList

minQueryLength circular

queryDelay visible

queryDelimiter tabSelect

requestTemplate zIndex

resultFilters

resultFormatter

resultHighlighter

resultListLocator

resultTextLocator

source

yqlProtocol

Page 18: Introducing YUI 3 AutoComplete

autocomplete-base autocomplete-list

allowBrowserAutocomplete activateFirstItem

inputNode align

maxResults alwaysShowList

minQueryLength circular

queryDelay visible

queryDelimiter tabSelect

requestTemplate zIndex

resultFilters

resultFormatter

resultHighlighter

resultListLocator

resultTextLocator

source

yqlProtocol

Page 19: Introducing YUI 3 AutoComplete

Results can come from a DataSource, Array, or Object.

Page 20: Introducing YUI 3 AutoComplete

Results can also come from aJSONP URL or a YQL query.

This is awesome.

Page 21: Introducing YUI 3 AutoComplete

Use the prepackaged result filters and highlighters, or provide your own.

Page 22: Introducing YUI 3 AutoComplete

Built-in filters and highlighters support word breaking and accent folding.

Page 23: Introducing YUI 3 AutoComplete

Provide a custom result formatter to free yourself from boring text-only

results.

Page 24: Introducing YUI 3 AutoComplete

Fully accessible out of the box.

Page 25: Introducing YUI 3 AutoComplete

Mobile-ready out of the box.

Page 26: Introducing YUI 3 AutoComplete

Photo: http://www.flickr.com/photos/tonymadrid/4696501004/

Page 27: Introducing YUI 3 AutoComplete

Photo: http://www.flickr.com/photos/tonymadrid/4696501004/

No keyboard? No point loading keyboard code.

Page 28: Introducing YUI 3 AutoComplete

Speaking of code...SHOW ME IT.

Photo: http://www.flickr.com/photos/tambako/3535904860/

Page 29: Introducing YUI 3 AutoComplete

// Plugin-style.YUI().use('autocomplete', function (Y) { Y.one('#my-input').plug(Y.Plugin.AutoComplete, { source: 'select * from search.suggest where query="{query}"' });});

Basic usage (YQL result source)

Page 30: Introducing YUI 3 AutoComplete

// Plugin-style.YUI().use('autocomplete', function (Y) { Y.one('#my-input').plug(Y.Plugin.AutoComplete, { source: 'select * from search.suggest where query="{query}"' });});

Basic usage (YQL result source)

Page 31: Introducing YUI 3 AutoComplete

// Plugin-style.YUI().use('autocomplete', function (Y) { Y.one('#my-input').plug(Y.Plugin.AutoComplete, { source: 'select * from search.suggest where query="{query}"' });});

Basic usage (YQL result source)

Page 32: Introducing YUI 3 AutoComplete

// Plugin-style.YUI().use('autocomplete', function (Y) { Y.one('#my-input').plug(Y.Plugin.AutoComplete, { source: 'select * from search.suggest where query="{query}"' });});

Basic usage (YQL result source)

Page 33: Introducing YUI 3 AutoComplete

// Plugin-style.YUI().use('autocomplete', function (Y) { Y.one('#my-input').plug(Y.Plugin.AutoComplete, { source: 'select * from search.suggest where query="{query}"' });});

Basic usage (YQL result source)

Page 34: Introducing YUI 3 AutoComplete

// Plugin-style.YUI().use('autocomplete', function (Y) { Y.one('#my-input').plug(Y.Plugin.AutoComplete, { source: 'select * from search.suggest where query="{query}"' });});

Basic usage (YQL result source)

Page 35: Introducing YUI 3 AutoComplete

// Plugin-style.YUI().use('autocomplete', function (Y) { Y.one('#my-input').plug(Y.Plugin.AutoComplete, { source: 'select * from search.suggest where query="{query}"' });});

Basic usage (YQL result source)

// Widget-style.YUI().use('autocomplete', function (Y) { var ac = new Y.AutoComplete({ inputNode: '#my-input', render : true, source : 'select * from search.suggest where query="{query}"' });});

Page 36: Introducing YUI 3 AutoComplete

// Plugin-style.YUI().use('autocomplete', function (Y) { Y.one('#my-input').plug(Y.Plugin.AutoComplete, { source: 'select * from search.suggest where query="{query}"' });});

Basic usage (YQL result source)

// Widget-style.YUI().use('autocomplete', function (Y) { var ac = new Y.AutoComplete({ inputNode: '#my-input', render : true, source : 'select * from search.suggest where query="{query}"' });});

Page 37: Introducing YUI 3 AutoComplete

// Plugin-style.YUI().use('autocomplete', function (Y) { Y.one('#my-input').plug(Y.Plugin.AutoComplete, { source: 'select * from search.suggest where query="{query}"' });});

Basic usage (YQL result source)

// Widget-style.YUI().use('autocomplete', function (Y) { var ac = new Y.AutoComplete({ inputNode: '#my-input', render : true, source : 'select * from search.suggest where query="{query}"' });});

Page 38: Introducing YUI 3 AutoComplete

// Plugin-style.YUI().use('autocomplete', function (Y) { Y.one('#my-input').plug(Y.Plugin.AutoComplete, { source: 'select * from search.suggest where query="{query}"' });});

Basic usage (YQL result source)

// Widget-style.YUI().use('autocomplete', function (Y) { var ac = new Y.AutoComplete({ inputNode: '#my-input', render : true, source : 'select * from search.suggest where query="{query}"' });});

Page 39: Introducing YUI 3 AutoComplete

Y.one('#my-input').plug(Y.Plugin.AutoComplete, { source: 'http://example.com/search?q={query}&callback={callback}'});

JSONP result source

Page 40: Introducing YUI 3 AutoComplete

Y.one('#my-input').plug(Y.Plugin.AutoComplete, { source: 'http://example.com/search?q={query}&callback={callback}'});

JSONP result source

Page 41: Introducing YUI 3 AutoComplete

Y.one('#my-input').plug(Y.Plugin.AutoComplete, { source: 'http://example.com/search?q={query}&callback={callback}'});

JSONP result source

Page 42: Introducing YUI 3 AutoComplete

Y.one('#my-input').plug(Y.Plugin.AutoComplete, { source: ['apple pie', 'peach pie', 'pecan pie', 'pumpkin pie']});

Array and object result sources

Page 43: Introducing YUI 3 AutoComplete

Y.one('#my-input').plug(Y.Plugin.AutoComplete, { source: ['apple pie', 'peach pie', 'pecan pie', 'pumpkin pie']});

Array and object result sources

Page 44: Introducing YUI 3 AutoComplete

Y.one('#my-input').plug(Y.Plugin.AutoComplete, { source: ['apple pie', 'peach pie', 'pecan pie', 'pumpkin pie']});

Array and object result sources

Y.one('#my-input').plug(Y.Plugin.AutoComplete, { source: { pies : ['apple', 'peach', 'pecan', 'pumpkin'], cookies: ['chocolate chip', 'molasses', 'peanut butter'] }});

Page 45: Introducing YUI 3 AutoComplete

Y.one('#my-input').plug(Y.Plugin.AutoComplete, { source: ['apple pie', 'peach pie', 'pecan pie', 'pumpkin pie']});

Array and object result sources

Y.one('#my-input').plug(Y.Plugin.AutoComplete, { source: { pies : ['apple', 'peach', 'pecan', 'pumpkin'], cookies: ['chocolate chip', 'molasses', 'peanut butter'] }});

Page 46: Introducing YUI 3 AutoComplete

Y.one('#my-input').plug(Y.Plugin.AutoComplete, { source: ['apple pie', 'peach pie', 'pecan pie', 'pumpkin pie']});

Array and object result sources

Y.one('#my-input').plug(Y.Plugin.AutoComplete, { source: { pies : ['apple', 'peach', 'pecan', 'pumpkin'], cookies: ['chocolate chip', 'molasses', 'peanut butter'] }});

Page 47: Introducing YUI 3 AutoComplete

var ds = new Y.DataSource.IO({ source: 'http://example.com/search'});

Y.one('#my-input').plug(Y.Plugin.AutoComplete, { requestTemplate: '?q={query}', source: ds});

DataSource result source

Page 48: Introducing YUI 3 AutoComplete

var ds = new Y.DataSource.IO({ source: 'http://example.com/search'});

Y.one('#my-input').plug(Y.Plugin.AutoComplete, { requestTemplate: '?q={query}', source: ds});

DataSource result source

Page 49: Introducing YUI 3 AutoComplete

Deep Dive

Photo: http://www.flickr.com/photos/steelcityhobbies/1084984228/

Page 50: Introducing YUI 3 AutoComplete

Locating Results

Photo: http://www.flickr.com/photos/st3f4n/3951143570/

Page 51: Introducing YUI 3 AutoComplete

[ "apple pie", "peach pie", "pecan pie", "pumpkin pie"]

Y.one('#my-input').plug(Y.Plugin.AutoComplete, { source: 'http://example.com/search?q={query}&callback={callback}'});

✓ No problem.

Page 52: Introducing YUI 3 AutoComplete

{ "status": "success",

"search": { "results": [ "apple pie", "peach pie", "pecan pie", "pumpkin pie" ] }}

Y.one('#my-input').plug(Y.Plugin.AutoComplete, { source: 'http://example.com/search?q={query}&callback={callback}'});

✗ Bit of a problem.

Page 53: Introducing YUI 3 AutoComplete

{ "status": "success",

"search": { "results": [ "apple pie", "peach pie", "pecan pie", "pumpkin pie" ] }}

Y.one('#my-input').plug(Y.Plugin.AutoComplete, { resultListLocator: 'search.results', source: 'http://example.com/search?q={query}&callback={callback}'});

✓ Awesome.

Page 54: Introducing YUI 3 AutoComplete

Y.one('#my-input').plug(Y.Plugin.AutoComplete, { resultListLocator: function (response) { return response && response.search && response.search.results; },

source: 'http://example.com/search?q={query}&callback={callback}'});

The list locator can also be a function.

Page 55: Introducing YUI 3 AutoComplete

Y.one('#my-input').plug(Y.Plugin.AutoComplete, { resultListLocator: 'results', source: 'http://search.twitter.com/search.json?q={query}&' + 'callback={callback}'});

Page 56: Introducing YUI 3 AutoComplete

Y.one('#my-input').plug(Y.Plugin.AutoComplete, { resultListLocator: 'results', source: 'http://search.twitter.com/search.json?q={query}&' + 'callback={callback}'});

Page 57: Introducing YUI 3 AutoComplete

{ "results": [ { "created_at": "Fri, 29 Oct 2010 07:00:58 +0000", "from_user": "EricF", "to_user_id": null, "text": "YUIConf is looking like it's gonna be crazy good!", "id": 29064356310, "from_user_id": 2469883, "iso_language_code": "en" },

... ]}

Y.one('#my-input').plug(Y.Plugin.AutoComplete, { resultListLocator: 'results', source: 'http://search.twitter.com/search.json?q={query}&' + 'callback={callback}'});

Page 58: Introducing YUI 3 AutoComplete

{ "results": [ { "created_at": "Fri, 29 Oct 2010 07:00:58 +0000", "from_user": "EricF", "to_user_id": null, "text": "YUIConf is looking like it's gonna be crazy good!", "id": 29064356310, "from_user_id": 2469883, "iso_language_code": "en" },

... ]}

Y.one('#my-input').plug(Y.Plugin.AutoComplete, { resultListLocator: 'results', resultTextLocator: 'text', source: 'http://search.twitter.com/search.json?q={query}&' + 'callback={callback}'});

Page 59: Introducing YUI 3 AutoComplete

Y.one('#my-input').plug(Y.Plugin.AutoComplete, { resultListLocator: 'results',

resultTextLocator: function (result) { return result.text; },

source: 'http://search.twitter.com/search.json?q={query}&' + 'callback={callback}'});

Like the list locator, the text locator can be a function.

Page 60: Introducing YUI 3 AutoComplete

Filtering & Highlighting Results

Photo: http://www.flickr.com/photos/27953349@N06/4465442322/

Page 61: Introducing YUI 3 AutoComplete

Prepackaged Filters & Highlighters

• All are case-insensitive by default, but case-sensitive versions are available (charMatchCase, phraseMatchCase, etc.).

• Accent-folding versions are available as well (charMatchFold, phraseMatchFold, etc.).

charMatchphraseMatchstartsWithwordMatch

Page 62: Introducing YUI 3 AutoComplete

YUIConf  is  super  awesome,  and  so  is  YUI.

charMatch: 'yui'

Page 63: Introducing YUI 3 AutoComplete

YUIConf  is  super  awesome,  and  so  is  YUI.

phraseMatch: 'yui'

Page 64: Introducing YUI 3 AutoComplete

YUIConf  is  super  awesome,  and  so  is  YUI.

startsWith: 'yui'

Page 65: Introducing YUI 3 AutoComplete

YUIConf  is  super  awesome,  and  so  is  YUI.

wordMatch: 'yui'

Page 66: Introducing YUI 3 AutoComplete

function customFilter(query, results) { return Y.Array.filter(results, function (result) { result = result.toLowerCase();

// Only include results that start with an "a" and contain // the query string. return result.charAt(0) === 'a' && result.indexOf(query) !== -1; });}

Custom Filter

Page 67: Introducing YUI 3 AutoComplete

function customFilter(query, results) { return Y.Array.filter(results, function (result) { result = result.toLowerCase();

// Only include results that start with an "a" and contain // the query string. return result.charAt(0) === 'a' && result.indexOf(query) !== -1; });}

Custom Filter

Page 68: Introducing YUI 3 AutoComplete

function customFilter(query, results) { return Y.Array.filter(results, function (result) { result = result.toLowerCase();

// Only include results that start with an "a" and contain // the query string. return result.charAt(0) === 'a' && result.indexOf(query) !== -1; });}

Custom Filter

Page 69: Introducing YUI 3 AutoComplete

function customFilter(query, results) { return Y.Array.filter(results, function (result) { result = result.toLowerCase();

// Only include results that start with an "a" and contain // the query string. return result.charAt(0) === 'a' && result.indexOf(query) !== -1; });}

Custom Filter

Page 70: Introducing YUI 3 AutoComplete

function customFilter(query, results) { return Y.Array.filter(results, function (result) { result = result.toLowerCase();

// Only include results that start with an "a" and contain // the query string. return result.charAt(0) === 'a' && result.indexOf(query) !== -1; });}

Custom Filter

Page 71: Introducing YUI 3 AutoComplete

Y.one('#my-input').plug(Y.Plugin.AutoComplete, { resultFilters: customFilter, source: 'select * from search.suggest where query="{query}"'});

Custom Filter

Page 72: Introducing YUI 3 AutoComplete

Y.one('#my-input').plug(Y.Plugin.AutoComplete, { resultFilters: customFilter, source: 'select * from search.suggest where query="{query}"'});

Custom Filter

Page 73: Introducing YUI 3 AutoComplete

Y.one('#my-input').plug(Y.Plugin.AutoComplete, { resultFilters: [customFilter, 'wordMatch', otherFilter, ...], source: 'select * from search.suggest where query="{query}"'});

Custom Filter

Page 74: Introducing YUI 3 AutoComplete

function customHighlighter(query, results) { return Y.Array.map(results, function (result) { return Y.Highlight.all(result, query); });}

Custom Highlighter

Page 75: Introducing YUI 3 AutoComplete

function customHighlighter(query, results) { return Y.Array.map(results, function (result) { return Y.Highlight.all(result, query); });}

Custom Highlighter

Page 76: Introducing YUI 3 AutoComplete

function customHighlighter(query, results) { return Y.Array.map(results, function (result) { return Y.Highlight.all(result, query); });}

Custom Highlighter

Page 77: Introducing YUI 3 AutoComplete

function customHighlighter(query, results) { return Y.Array.map(results, function (result) { return Y.Highlight.all(result, query); });}

Custom Highlighter

Page 78: Introducing YUI 3 AutoComplete

function customHighlighter(query, results) { return Y.Array.map(results, function (result) { return Y.Highlight.all(result, query); });}

Custom Highlighter

Page 79: Introducing YUI 3 AutoComplete

Y.one('#my-input').plug(Y.Plugin.AutoComplete, { resultHighlighter: customHighlighter, source: 'select * from search.suggest where query="{query}"'});

Custom Highlighter

Page 80: Introducing YUI 3 AutoComplete

Y.one('#my-input').plug(Y.Plugin.AutoComplete, { resultHighlighter: customHighlighter, source: 'select * from search.suggest where query="{query}"'});

Custom Highlighter

Page 81: Introducing YUI 3 AutoComplete

Formatting Results

Photo: http://www.flickr.com/photos/doug88888/4544745031/

Page 82: Introducing YUI 3 AutoComplete

function twitterFormatter(query, raw, highlighted) { return Y.Array.map(raw, function (result, i) { return Y.Lang.sub( '<div class="tweet">' + '<div class="hd">' + '<img src="{img}" class="photo" ' + 'alt="Profile photo for {user}">' + '</div>' + '<div class="bd">' + '<strong class="user">{user}</strong>' + '<span class="tweet-text">{text}</span>' + '</div>' + '<div class="ft">{time}</div>' + '</div>', { id : result.id, img : result.profile_image_url, text: highlighted[i], time: result.created_at, user: result.from_user } ); });}

Page 83: Introducing YUI 3 AutoComplete

function twitterFormatter(query, raw, highlighted) { return Y.Array.map(raw, function (result, i) { return Y.Lang.sub( '<div class="tweet">' + '<div class="hd">' + '<img src="{img}" class="photo" ' + 'alt="Profile photo for {user}">' + '</div>' + '<div class="bd">' + '<strong class="user">{user}</strong>' + '<span class="tweet-text">{text}</span>' + '</div>' + '<div class="ft">{time}</div>' + '</div>', { id : result.id, img : result.profile_image_url, text: highlighted[i], time: result.created_at, user: result.from_user } ); });}

Page 84: Introducing YUI 3 AutoComplete

function twitterFormatter(query, raw, highlighted) { return Y.Array.map(raw, function (result, i) { return Y.Lang.sub( '<div class="tweet">' + '<div class="hd">' + '<img src="{img}" class="photo" ' + 'alt="Profile photo for {user}">' + '</div>' + '<div class="bd">' + '<strong class="user">{user}</strong>' + '<span class="tweet-text">{text}</span>' + '</div>' + '<div class="ft">{time}</div>' + '</div>', { id : result.id, img : result.profile_image_url, text: highlighted[i], time: result.created_at, user: result.from_user } ); });}

Page 85: Introducing YUI 3 AutoComplete

{ "results": [ { "created_at": "Fri, 29 Oct 2010 07:00:58 +0000", "from_user": "EricF", "to_user_id": null, "text": "YUIConf is looking like it's gonna be crazy good!", "id": 29064356310, "from_user_id": 2469883, "iso_language_code": "en" },

... ]}

time: result.created_at, user: result.from_user } ); });}

Page 86: Introducing YUI 3 AutoComplete

function twitterFormatter(query, raw, highlighted) { return Y.Array.map(raw, function (result, i) { return Y.Lang.sub( '<div class="tweet">' + '<div class="hd">' + '<img src="{img}" class="photo" ' + 'alt="Profile photo for {user}">' + '</div>' + '<div class="bd">' + '<strong class="user">{user}</strong>' + '<span class="tweet-text">{text}</span>' + '</div>' + '<div class="ft">{time}</div>' + '</div>', { id : result.id, img : result.profile_image_url, text: highlighted[i], time: result.created_at, user: result.from_user } ); });}

Page 87: Introducing YUI 3 AutoComplete

function twitterFormatter(query, raw, highlighted) { return Y.Array.map(raw, function (result, i) { return Y.Lang.sub( '<div class="tweet">' + '<div class="hd">' + '<img src="{img}" class="photo" ' + 'alt="Profile photo for {user}">' + '</div>' + '<div class="bd">' + '<strong class="user">{user}</strong>' + '<span class="tweet-text">{text}</span>' + '</div>' + '<div class="ft">{time}</div>' + '</div>', { id : result.id, img : result.profile_image_url, text: highlighted[i], time: result.created_at, user: result.from_user } ); });}

Page 88: Introducing YUI 3 AutoComplete

[ "<b class=\"yui3-highlight\">YUIConf</b> is looking like it's gonna be crazy good!", ...]

time: result.created_at, user: result.from_user } ); });}

Page 89: Introducing YUI 3 AutoComplete

function twitterFormatter(query, raw, highlighted) { return Y.Array.map(raw, function (result, i) { return Y.Lang.sub( '<div class="tweet">' + '<div class="hd">' + '<img src="{img}" class="photo" ' + 'alt="Profile photo for {user}">' + '</div>' + '<div class="bd">' + '<strong class="user">{user}</strong>' + '<span class="tweet-text">{text}</span>' + '</div>' + '<div class="ft">{time}</div>' + '</div>', { id : result.id, img : result.profile_image_url, text: highlighted[i], time: result.created_at, user: result.from_user } ); });}

Page 90: Introducing YUI 3 AutoComplete

function twitterFormatter(query, raw, highlighted) { return Y.Array.map(raw, function (result, i) { return Y.Lang.sub( '<div class="tweet">' + '<div class="hd">' + '<img src="{img}" class="photo" ' + 'alt="Profile photo for {user}">' + '</div>' + '<div class="bd">' + '<strong class="user">{user}</strong>' + '<span class="tweet-text">{text}</span>' + '</div>' + '<div class="ft">{time}</div>' + '</div>', { id : result.id, img : result.profile_image_url, text: highlighted[i], time: result.created_at, user: result.from_user } ); });}

Page 91: Introducing YUI 3 AutoComplete

function twitterFormatter(query, raw, highlighted) { return Y.Array.map(raw, function (result, i) { return Y.Lang.sub( '<div class="tweet">' + '<div class="hd">' + '<img src="{img}" class="photo" ' + 'alt="Profile photo for {user}">' + '</div>' + '<div class="bd">' + '<strong class="user">{user}</strong>' + '<span class="tweet-text">{text}</span>' + '</div>' + '<div class="ft">{time}</div>' + '</div>', { id : result.id, img : result.profile_image_url, text: highlighted[i], time: result.created_at, user: result.from_user } ); });}

Page 92: Introducing YUI 3 AutoComplete

function twitterFormatter(query, raw, highlighted) { return Y.Array.map(raw, function (result, i) { return Y.Lang.sub( '<div class="tweet">' + '<div class="hd">' + '<img src="{img}" class="photo" ' + 'alt="Profile photo for {user}">' + '</div>' + '<div class="bd">' + '<strong class="user">{user}</strong>' + '<span class="tweet-text">{text}</span>' + '</div>' + '<div class="ft">{time}</div>' + '</div>', { id : result.id, img : result.profile_image_url, text: highlighted[i], time: result.created_at, user: result.from_user } ); });}

Page 93: Introducing YUI 3 AutoComplete

function twitterFormatter(query, raw, highlighted) { return Y.Array.map(raw, function (result, i) { return Y.Lang.sub( '<div class="tweet">' + '<div class="hd">' + '<img src="{img}" class="photo" ' + 'alt="Profile photo for {user}">' + '</div>' + '<div class="bd">' + '<strong class="user">{user}</strong>' + '<span class="tweet-text">{text}</span>' + '</div>' + '<div class="ft">{time}</div>' + '</div>', { id : result.id, img : result.profile_image_url, text: highlighted[i], time: result.created_at, user: result.from_user } ); });}

Page 94: Introducing YUI 3 AutoComplete

Y.one('#ac-input').plug(Y.Plugin.AutoComplete, { resultFormatter: twitterFormatter, resultHighlighter: 'phraseMatch', resultListLocator: 'results', resultTextLocator: 'text', source: 'http://search.twitter.com/search.json?q={query}&' + 'callback={callback}'});

Page 95: Introducing YUI 3 AutoComplete

Y.one('#ac-input').plug(Y.Plugin.AutoComplete, { resultFormatter: twitterFormatter, resultHighlighter: 'phraseMatch', resultListLocator: 'results', resultTextLocator: 'text', source: 'http://search.twitter.com/search.json?q={query}&' + 'callback={callback}'});

Page 96: Introducing YUI 3 AutoComplete

.tweet { clear: both; margin: 6px 0; padding: 2px 0;}

.tweet .hd { float: left; }

.tweet .bd,

.tweet .ft { margin-left: 52px; }

.tweet .ft { color: #cfcfcf; font-size: 11px;}

.tweet .photo { height: 48px; margin: 2px 0; width: 48px;}

.tweet .user { margin-right: 6px; }

Page 97: Introducing YUI 3 AutoComplete

Download video: http://j.mp/yui3ac2

Page 98: Introducing YUI 3 AutoComplete

Other new modules

Photo: http://www.flickr.com/photos/thomashawk/55519741/

Page 99: Introducing YUI 3 AutoComplete

• Synthetic event. Fires when an input node’s value changes due to user input.

• Handles keystrokes, pastes, and IME input.

• Creates a level playing field across browsers, particularly with languages that have multi-stroke characters.

event-valuechange

Page 100: Introducing YUI 3 AutoComplete

Y.one('#my-input').on('valueChange', function (e) { Y.log('Old value: ' + e.prevVal); Y.log('New value: ' + e.newVal);});

event-valuechange

Page 101: Introducing YUI 3 AutoComplete

Y.one('#my-input').on('valueChange', function (e) { Y.log('Old value: ' + e.prevVal); Y.log('New value: ' + e.newVal);});

event-valuechange

Page 102: Introducing YUI 3 AutoComplete

Y.one('#my-input').on('valueChange', function (e) { Y.log('Old value: ' + e.prevVal); Y.log('New value: ' + e.newVal);});

event-valuechange

Page 103: Introducing YUI 3 AutoComplete

escape

• Static utility methods for escaping strings.

• Currently has methods for escaping HTML and regex strings. More to come in future releases.

• Feel free to add your own escaping methods to the Y.Escape namespace (and share on the Gallery).

Page 104: Introducing YUI 3 AutoComplete

Y.Escape.html('<script>alert("pwned!")</script>');// => '&lt;script&gt;alert(&quot;pwned!&quot;)&lt;&#x2F;script&gt;'

Y.Escape.regex('$3.14 (plus tax)');// => '\$3\.14\ \(plus\ tax\)'

escape

Page 105: Introducing YUI 3 AutoComplete

Y.Escape.html('<script>alert("pwned!")</script>');// => '&lt;script&gt;alert(&quot;pwned!&quot;)&lt;&#x2F;script&gt;'

Y.Escape.regex('$3.14 (plus tax)');// => '\$3\.14\ \(plus\ tax\)'

escape

Page 106: Introducing YUI 3 AutoComplete

Y.Escape.html('<script>alert("pwned!")</script>');// => '&lt;script&gt;alert(&quot;pwned!&quot;)&lt;&#x2F;script&gt;'

Y.Escape.regex('$3.14 (plus tax)');// => '\$3\.14\ \(plus\ tax\)'

escape

Page 107: Introducing YUI 3 AutoComplete

Y.Escape.html('<script>alert("pwned!")</script>');// => '&lt;script&gt;alert(&quot;pwned!&quot;)&lt;&#x2F;script&gt;'

Y.Escape.regex('$3.14 (plus tax)');// => '\$3\.14\ \(plus\ tax\)'

escape

Page 108: Introducing YUI 3 AutoComplete

Y.Escape.html('<script>alert("pwned!")</script>');// => '&lt;script&gt;alert(&quot;pwned!&quot;)&lt;&#x2F;script&gt;'

Y.Escape.regex('$3.14 (plus tax)');// => '\$3\.14\ \(plus\ tax\)'

escape

Page 109: Introducing YUI 3 AutoComplete

Y.Escape.html('<script>alert("pwned!")</script>');// => '&lt;script&gt;alert(&quot;pwned!&quot;)&lt;&#x2F;script&gt;'

Y.Escape.regex('$3.14 (plus tax)');// => '\$3\.14\ \(plus\ tax\)'

escape

Page 110: Introducing YUI 3 AutoComplete

Y.Escape.html('<script>alert("pwned!")</script>');// => '&lt;script&gt;alert(&quot;pwned!&quot;)&lt;&#x2F;script&gt;'

Y.Escape.regex('$3.14 (plus tax)');// => '\$3\.14\ \(plus\ tax\)'

escape

Page 111: Introducing YUI 3 AutoComplete

And now, a brief interlude wherein I whine about having discovered, yesterday

afternoon, that “Unicode” is a registered trademark of the

Unicode® Consortium.

Page 112: Introducing YUI 3 AutoComplete

®?

Page 113: Introducing YUI 3 AutoComplete

®?

Page 114: Introducing YUI 3 AutoComplete

As a result, the word “Unicode” has been replaced with ☃ in the following slides.

Page 115: Introducing YUI 3 AutoComplete

I apologize for the inconvenience.

Page 116: Introducing YUI 3 AutoComplete

☃-accentfold

• Helpers for creating and working with accent-folded strings.

• Accent folding converts “résumé” to “resume” (etc.) for easier comparison.

• Should be a last resort. Only use it when better tools aren’t available on the server. Don’t fold strings you will display to the user.

• Will have an actual name before 3.3.0 final.

Page 117: Introducing YUI 3 AutoComplete

Y.☃.AccentFold.fold('résumé');// => 'resume'

Y.☃.AccentFold.compare('résumé', 'resume');// => true

Y.☃.AccentFold.filter(['föö', 'bår', 'móó'], function (str) { return str.indexOf('o') !== -1;});// => ['föö', 'móó']

☃-accentfold

Page 118: Introducing YUI 3 AutoComplete

Y.☃.AccentFold.fold('résumé');// => 'resume'

Y.☃.AccentFold.compare('résumé', 'resume');// => true

Y.☃.AccentFold.filter(['föö', 'bår', 'móó'], function (str) { return str.indexOf('o') !== -1;});// => ['föö', 'móó']

☃-accentfold

Page 119: Introducing YUI 3 AutoComplete

Y.☃.AccentFold.fold('résumé');// => 'resume'

Y.☃.AccentFold.compare('résumé', 'resume');// => true

Y.☃.AccentFold.filter(['föö', 'bår', 'móó'], function (str) { return str.indexOf('o') !== -1;});// => ['föö', 'móó']

☃-accentfold

Page 120: Introducing YUI 3 AutoComplete

Y.☃.AccentFold.fold('résumé');// => 'resume'

Y.☃.AccentFold.compare('résumé', 'resume');// => true

Y.☃.AccentFold.filter(['föö', 'bår', 'móó'], function (str) { return str.indexOf('o') !== -1;});// => ['föö', 'móó']

☃-accentfold

Page 121: Introducing YUI 3 AutoComplete

☃-wordbreak

• Implements ☃ text segmentation guidelines for word breaking.

• Handles edge cases like contractions, decimals, thousands separators, Katakana, non-Latin punctuation, etc.

• Not perfect, but much smarter than /\b/.

• Will have an actual name before 3.3.0 final.

Page 122: Introducing YUI 3 AutoComplete

Y.☃.WordBreak.getWords("A kilobyte's just 1,024 bytes.");// => ["A", "kilobyte's", "just", "1,024", "bytes"]

Y.☃.WordBreak.getWords('パイが好きです');// => ["パイ", "が", "好", "き", "で", "す"]

☃-wordbreak

Page 123: Introducing YUI 3 AutoComplete

Y.☃.WordBreak.getWords("A kilobyte's just 1,024 bytes.");// => ["A", "kilobyte's", "just", "1,024", "bytes"]

Y.☃.WordBreak.getWords('パイが好きです');// => ["パイ", "が", "好", "き", "で", "す"]

☃-wordbreak

Page 124: Introducing YUI 3 AutoComplete

Y.☃.WordBreak.getWords("A kilobyte's just 1,024 bytes.");// => ["A", "kilobyte's", "just", "1,024", "bytes"]

Y.☃.WordBreak.getWords('パイが好きです');// => ["パイ", "が", "好", "き", "で", "す"]

☃-wordbreak

Page 125: Introducing YUI 3 AutoComplete

highlight

• Static utility methods for highlighting strings using HTML.

• Supports phrase highlighting, start-of-string highlighting, and word highlighting.

• Can use accent folded strings for comparisons while highlighting the original, non-folded string.

• Smart enough not to highlight inside HTML entities like &quot;.

• Doesn’t infringe any trademarks.

Page 126: Introducing YUI 3 AutoComplete

Y.Highlight.all('YUIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YUI</b>Conf 2010: <b class="yui3-highlight">YUI</b> rocks!'

Y.Highlight.start('YUIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YUI</b>Conf 2010: YUI rocks!'

Y.Highlight.words('YUIConf 2010: YUI rocks!', 'yui');// => 'YUIConf 2010: <b class="yui3-highlight">YUI</b> rocks!'

Y.Highlight.allFold('YÜIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YÜI</b>Conf 2010: <b class="yui3-highlight">YUI</b> rocks!'

highlight

Page 127: Introducing YUI 3 AutoComplete

Y.Highlight.all('YUIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YUI</b>Conf 2010: <b class="yui3-highlight">YUI</b> rocks!'

Y.Highlight.start('YUIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YUI</b>Conf 2010: YUI rocks!'

Y.Highlight.words('YUIConf 2010: YUI rocks!', 'yui');// => 'YUIConf 2010: <b class="yui3-highlight">YUI</b> rocks!'

Y.Highlight.allFold('YÜIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YÜI</b>Conf 2010: <b class="yui3-highlight">YUI</b> rocks!'

highlight

Page 128: Introducing YUI 3 AutoComplete

Y.Highlight.all('YUIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YUI</b>Conf 2010: <b class="yui3-highlight">YUI</b> rocks!'

Y.Highlight.start('YUIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YUI</b>Conf 2010: YUI rocks!'

Y.Highlight.words('YUIConf 2010: YUI rocks!', 'yui');// => 'YUIConf 2010: <b class="yui3-highlight">YUI</b> rocks!'

Y.Highlight.allFold('YÜIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YÜI</b>Conf 2010: <b class="yui3-highlight">YUI</b> rocks!'

highlight

Page 129: Introducing YUI 3 AutoComplete

Y.Highlight.all('YUIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YUI</b>Conf 2010: <b class="yui3-highlight">YUI</b> rocks!'

Y.Highlight.start('YUIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YUI</b>Conf 2010: YUI rocks!'

Y.Highlight.words('YUIConf 2010: YUI rocks!', 'yui');// => 'YUIConf 2010: <b class="yui3-highlight">YUI</b> rocks!'

Y.Highlight.allFold('YÜIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YÜI</b>Conf 2010: <b class="yui3-highlight">YUI</b> rocks!'

highlight

Page 130: Introducing YUI 3 AutoComplete

Y.Highlight.all('YUIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YUI</b>Conf 2010: <b class="yui3-highlight">YUI</b> rocks!'

Y.Highlight.start('YUIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YUI</b>Conf 2010: YUI rocks!'

Y.Highlight.words('YUIConf 2010: YUI rocks!', 'yui');// => 'YUIConf 2010: <b class="yui3-highlight">YUI</b> rocks!'

Y.Highlight.allFold('YÜIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YÜI</b>Conf 2010: <b class="yui3-highlight">YUI</b> rocks!'

highlight

Page 131: Introducing YUI 3 AutoComplete

Y.Highlight.all('YUIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YUI</b>Conf 2010: <b class="yui3-highlight">YUI</b> rocks!'

Y.Highlight.start('YUIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YUI</b>Conf 2010: YUI rocks!'

Y.Highlight.words('YUIConf 2010: YUI rocks!', 'yui');// => 'YUIConf 2010: <b class="yui3-highlight">YUI</b> rocks!'

Y.Highlight.allFold('YÜIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YÜI</b>Conf 2010: <b class="yui3-highlight">YUI</b> rocks!'

highlight

Page 132: Introducing YUI 3 AutoComplete

Y.Highlight.all('YUIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YUI</b>Conf 2010: <b class="yui3-highlight">YUI</b> rocks!'

Y.Highlight.start('YUIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YUI</b>Conf 2010: YUI rocks!'

Y.Highlight.words('YUIConf 2010: YUI rocks!', 'yui');// => 'YUIConf 2010: <b class="yui3-highlight">YUI</b> rocks!'

Y.Highlight.allFold('YÜIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YÜI</b>Conf 2010: <b class="yui3-highlight">YUI</b> rocks!'

highlight

Page 133: Introducing YUI 3 AutoComplete

Y.Highlight.all('YUIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YUI</b>Conf 2010: <b class="yui3-highlight">YUI</b> rocks!'

Y.Highlight.start('YUIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YUI</b>Conf 2010: YUI rocks!'

Y.Highlight.words('YUIConf 2010: YUI rocks!', 'yui');// => 'YUIConf 2010: <b class="yui3-highlight">YUI</b> rocks!'

Y.Highlight.allFold('YÜIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YÜI</b>Conf 2010: <b class="yui3-highlight">YUI</b> rocks!'

highlight

Page 134: Introducing YUI 3 AutoComplete

Y.Highlight.all('YUIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YUI</b>Conf 2010: <b class="yui3-highlight">YUI</b> rocks!'

Y.Highlight.start('YUIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YUI</b>Conf 2010: YUI rocks!'

Y.Highlight.words('YUIConf 2010: YUI rocks!', 'yui');// => 'YUIConf 2010: <b class="yui3-highlight">YUI</b> rocks!'

Y.Highlight.allFold('YÜIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YÜI</b>Conf 2010: <b class="yui3-highlight">YUI</b> rocks!'

highlight

Page 135: Introducing YUI 3 AutoComplete

Y.Highlight.all('YUIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YUI</b>Conf 2010: <b class="yui3-highlight">YUI</b> rocks!'

Y.Highlight.start('YUIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YUI</b>Conf 2010: YUI rocks!'

Y.Highlight.words('YUIConf 2010: YUI rocks!', 'yui');// => 'YUIConf 2010: <b class="yui3-highlight">YUI</b> rocks!'

Y.Highlight.allFold('YÜIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YÜI</b>Conf 2010: <b class="yui3-highlight">YUI</b> rocks!'

highlight

Page 136: Introducing YUI 3 AutoComplete

Y.Highlight.all('YUIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YUI</b>Conf 2010: <b class="yui3-highlight">YUI</b> rocks!'

Y.Highlight.start('YUIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YUI</b>Conf 2010: YUI rocks!'

Y.Highlight.words('YUIConf 2010: YUI rocks!', 'yui');// => 'YUIConf 2010: <b class="yui3-highlight">YUI</b> rocks!'

Y.Highlight.allFold('YÜIConf 2010: YUI rocks!', 'yui');// => '<b class="yui3-highlight">YÜI</b>Conf 2010: <b class="yui3-highlight">YUI</b> rocks!'

highlight

Page 137: Introducing YUI 3 AutoComplete

Why <b>?

• HTML5 defines a new <mark> element for denoting the relevance (as opposed to the importance) of a span of text.

• It recommends using <mark> “to highlight a part of quoted text that was not originally emphasized”.

• But, since <mark> isn’t yet supported in all browsers, we use <b>, which HTML5 defines as a last resort for highlighting text without implying importance.

• You can customize the highlighting markup by changing Y.Highlight._TEMPLATE.

More details: http://www.whatwg.org/specs/web-apps/current-work/multipage/text-level-semantics.html#the-mark-element

Page 138: Introducing YUI 3 AutoComplete

Photo: http://www.flickr.com/photos/tim_norris/2789759648/

Page 139: Introducing YUI 3 AutoComplete

What I just saidbut with bullets

• Modular architecture makes it easy to implement a range of autocomplete patterns.

• Dead simple JSONP and YQL support.

• Use prepackaged filters and highlighters with word breaking and accent folding, or roll your own.

• Create custom result formatters with just a few lines of code.

• AutoComplete and friends are available now in YUI 3.3.0pr1.

Photo: http://www.flickr.com/photos/tim_norris/2789759648/

Page 140: Introducing YUI 3 AutoComplete

One more thing...

Photo: http://www.flickr.com/photos/jabb/3502160522/

Page 141: Introducing YUI 3 AutoComplete

Download video: http://j.mp/yui3ac3

Page 142: Introducing YUI 3 AutoComplete

YUI().use('gallery-node-tokeninput', function (Y) { Y.one('#my-input').plug(Y.Plugin.TokenInput);});

node-tokeninput

Page 143: Introducing YUI 3 AutoComplete

YUI().use('gallery-node-tokeninput', function (Y) { Y.one('#my-input').plug(Y.Plugin.TokenInput);});

node-tokeninput

Page 144: Introducing YUI 3 AutoComplete

YUI().use('gallery-node-tokeninput', function (Y) { Y.one('#my-input').plug(Y.Plugin.TokenInput);});

node-tokeninput

Page 145: Introducing YUI 3 AutoComplete

YUI().use('gallery-node-tokeninput', function (Y) { Y.one('#my-input').plug(Y.Plugin.TokenInput);});

node-tokeninput

Page 146: Introducing YUI 3 AutoComplete

...but beware, there are some rough edges at the moment.

Page 147: Introducing YUI 3 AutoComplete

Photo: http://www.flickr.com/photos/damaradeaella/2822846819/

Page 148: Introducing YUI 3 AutoComplete

Ryan Grove, YUI Team@yaypie on Twitter

https://github.com/rgrove/

Slides: http://lanyrd.com/smym

Photo: http://www.flickr.com/photos/damaradeaella/2822846819/