Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

A brief history of YUI AutoComplete Photo: http://www.flickr.com/photos/margolove/1204358675/

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

There are lots of different autocomplete patterns in use on the web today.

Slide 7

Slide 7 text

In the YUI 2 world, this meant AutoComplete had to provide many options within a single module.

Slide 8

Slide 8 text

Patterns that weren’t similar to a traditional list-based autocomplete weren’t well-served by this model.

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

Say hello to YUI 3 AutoComplete Photo: http://www.flickr.com/photos/christianschuit/4201189548/

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

New modular API provides more flexibility and easier extension to allow for countless autocomplete patterns. Photo: http://www.flickr.com/photos/grdloizaga/817443503/

Slide 13

Slide 13 text

autocomplete-base event-valuechange autocomplete- filters autocomplete- highlighters autocomplete-list AutoComplete modules

Slide 14

Slide 14 text

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.

Slide 15

Slide 15 text

1KB 2KB 3KB 4KB 5KB 6KB 7KB 8KB 2.8.2 3.3.0 AutoComplete module size (min + gzip) Filters Highlighters List Base

Slide 16

Slide 16 text

90% feature parity with YUI 2 AutoComplete. * * This is a highly scientific number. I swear.

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

Results can also come from a JSONP URL or a YQL query. This is awesome.

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

Fully accessible out of the box.

Slide 25

Slide 25 text

Mobile-ready out of the box.

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

Photo: http://www.flickr.com/photos/tonymadrid/4696501004/ No keyboard? No point loading keyboard code.

Slide 28

Slide 28 text

Speaking of code... SHOW ME IT. Photo: http://www.flickr.com/photos/tambako/3535904860/

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

[ "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.

Slide 52

Slide 52 text

{ "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.

Slide 53

Slide 53 text

{ "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.

Slide 54

Slide 54 text

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.

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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.

Slide 60

Slide 60 text

Filtering & Highlighting Results Photo: http://www.flickr.com/photos/27953349@N06/4465442322/

Slide 61

Slide 61 text

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.). charMatch phraseMatch startsWith wordMatch

Slide 62

Slide 62 text

YUIConf  is  super  awesome,  and  so  is  YUI. charMatch: 'yui'

Slide 63

Slide 63 text

YUIConf  is  super  awesome,  and  so  is  YUI. phraseMatch: 'yui'

Slide 64

Slide 64 text

YUIConf  is  super  awesome,  and  so  is  YUI. startsWith: 'yui'

Slide 65

Slide 65 text

YUIConf  is  super  awesome,  and  so  is  YUI. wordMatch: 'yui'

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

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

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

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

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

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

Slide 78

Slide 78 text

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

Slide 79

Slide 79 text

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

Slide 80

Slide 80 text

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

Slide 81

Slide 81 text

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

Slide 82

Slide 82 text

function twitterFormatter(query, raw, highlighted) { return Y.Array.map(raw, function (result, i) { return Y.Lang.sub( '
' + '
' + '' + '
' + '
' + '{user}' + '{text}' + '
' + '
{time}
' + '
', { id : result.id, img : result.profile_image_url, text: highlighted[i], time: result.created_at, user: result.from_user } ); }); }

Slide 83

Slide 83 text

function twitterFormatter(query, raw, highlighted) { return Y.Array.map(raw, function (result, i) { return Y.Lang.sub( '
' + '
' + '' + '
' + '
' + '{user}' + '{text}' + '
' + '
{time}
' + '
', { id : result.id, img : result.profile_image_url, text: highlighted[i], time: result.created_at, user: result.from_user } ); }); }

Slide 84

Slide 84 text

function twitterFormatter(query, raw, highlighted) { return Y.Array.map(raw, function (result, i) { return Y.Lang.sub( '
' + '
' + '' + '
' + '
' + '{user}' + '{text}' + '
' + '
{time}
' + '
', { id : result.id, img : result.profile_image_url, text: highlighted[i], time: result.created_at, user: result.from_user } ); }); }

Slide 85

Slide 85 text

{ "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" }, ... ] } user: result.from_user } ); }); }

Slide 86

Slide 86 text

function twitterFormatter(query, raw, highlighted) { return Y.Array.map(raw, function (result, i) { return Y.Lang.sub( '
' + '
' + '' + '
' + '
' + '{user}' + '{text}' + '
' + '
{time}
' + '
', { id : result.id, img : result.profile_image_url, text: highlighted[i], time: result.created_at, user: result.from_user } ); }); }

Slide 87

Slide 87 text

function twitterFormatter(query, raw, highlighted) { return Y.Array.map(raw, function (result, i) { return Y.Lang.sub( '
' + '
' + '' + '
' + '
' + '{user}' + '{text}' + '
' + '
{time}
' + '
', { id : result.id, img : result.profile_image_url, text: highlighted[i], time: result.created_at, user: result.from_user } ); }); }

Slide 88

Slide 88 text

[ "YUIConf is looking like it's gonna be crazy good!", ... ] user: result.from_user } ); }); }

Slide 89

Slide 89 text

function twitterFormatter(query, raw, highlighted) { return Y.Array.map(raw, function (result, i) { return Y.Lang.sub( '
' + '
' + '' + '
' + '
' + '{user}' + '{text}' + '
' + '
{time}
' + '
', { id : result.id, img : result.profile_image_url, text: highlighted[i], time: result.created_at, user: result.from_user } ); }); }

Slide 90

Slide 90 text

function twitterFormatter(query, raw, highlighted) { return Y.Array.map(raw, function (result, i) { return Y.Lang.sub( '
' + '
' + '' + '
' + '
' + '{user}' + '{text}' + '
' + '
{time}
' + '
', { id : result.id, img : result.profile_image_url, text: highlighted[i], time: result.created_at, user: result.from_user } ); }); }

Slide 91

Slide 91 text

function twitterFormatter(query, raw, highlighted) { return Y.Array.map(raw, function (result, i) { return Y.Lang.sub( '
' + '
' + '' + '
' + '
' + '{user}' + '{text}' + '
' + '
{time}
' + '
', { id : result.id, img : result.profile_image_url, text: highlighted[i], time: result.created_at, user: result.from_user } ); }); }

Slide 92

Slide 92 text

function twitterFormatter(query, raw, highlighted) { return Y.Array.map(raw, function (result, i) { return Y.Lang.sub( '
' + '
' + '' + '
' + '
' + '{user}' + '{text}' + '
' + '
{time}
' + '
', { id : result.id, img : result.profile_image_url, text: highlighted[i], time: result.created_at, user: result.from_user } ); }); }

Slide 93

Slide 93 text

function twitterFormatter(query, raw, highlighted) { return Y.Array.map(raw, function (result, i) { return Y.Lang.sub( '
' + '
' + '' + '
' + '
' + '{user}' + '{text}' + '
' + '
{time}
' + '
', { id : result.id, img : result.profile_image_url, text: highlighted[i], time: result.created_at, user: result.from_user } ); }); }

Slide 94

Slide 94 text

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

Slide 95

Slide 95 text

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

Slide 96

Slide 96 text

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

Slide 97

Slide 97 text

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

Slide 98

Slide 98 text

Other new modules Photo: http://www.flickr.com/photos/thomashawk/55519741/

Slide 99

Slide 99 text

• 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

Slide 100

Slide 100 text

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

Slide 101

Slide 101 text

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

Slide 102

Slide 102 text

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

Slide 103

Slide 103 text

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

Slide 104

Slide 104 text

Y.Escape.html('alert("pwned!")'); // => '<script>alert("pwned!")</script>' Y.Escape.regex('$3.14 (plus tax)'); // => '\$3\.14\ \(plus\ tax\)' escape

Slide 105

Slide 105 text

Y.Escape.html('alert("pwned!")'); // => '<script>alert("pwned!")</script>' Y.Escape.regex('$3.14 (plus tax)'); // => '\$3\.14\ \(plus\ tax\)' escape

Slide 106

Slide 106 text

Y.Escape.html('alert("pwned!")'); // => '<script>alert("pwned!")</script>' Y.Escape.regex('$3.14 (plus tax)'); // => '\$3\.14\ \(plus\ tax\)' escape

Slide 107

Slide 107 text

Y.Escape.html('alert("pwned!")'); // => '<script>alert("pwned!")</script>' Y.Escape.regex('$3.14 (plus tax)'); // => '\$3\.14\ \(plus\ tax\)' escape

Slide 108

Slide 108 text

Y.Escape.html('alert("pwned!")'); // => '<script>alert("pwned!")</script>' Y.Escape.regex('$3.14 (plus tax)'); // => '\$3\.14\ \(plus\ tax\)' escape

Slide 109

Slide 109 text

Y.Escape.html('alert("pwned!")'); // => '<script>alert("pwned!")</script>' Y.Escape.regex('$3.14 (plus tax)'); // => '\$3\.14\ \(plus\ tax\)' escape

Slide 110

Slide 110 text

Y.Escape.html('alert("pwned!")'); // => '<script>alert("pwned!")</script>' Y.Escape.regex('$3.14 (plus tax)'); // => '\$3\.14\ \(plus\ tax\)' escape

Slide 111

Slide 111 text

And now, a brief interlude wherein I whine about having discovered, yesterday afternoon, that “Unicode” is a registered trademark of the Unicode® Consortium.

Slide 112

Slide 112 text

®?

Slide 113

Slide 113 text

®?

Slide 114

Slide 114 text

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

Slide 115

Slide 115 text

I apologize for the inconvenience.

Slide 116

Slide 116 text

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

Slide 117

Slide 117 text

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

Slide 118

Slide 118 text

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

Slide 119

Slide 119 text

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

Slide 120

Slide 120 text

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

Slide 121

Slide 121 text

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

Slide 122

Slide 122 text

Y.☃.WordBreak.getWords("A kilobyte's just 1,024 bytes."); // => ["A", "kilobyte's", "just", "1,024", "bytes"] Y.☃.WordBreak.getWords('ύΠ͕޷͖Ͱ͢'); // => ["ύΠ", "͕", "޷", "͖", "Ͱ", "͢"] ‚-wordbreak

Slide 123

Slide 123 text

Y.☃.WordBreak.getWords("A kilobyte's just 1,024 bytes."); // => ["A", "kilobyte's", "just", "1,024", "bytes"] Y.☃.WordBreak.getWords('ύΠ͕޷͖Ͱ͢'); // => ["ύΠ", "͕", "޷", "͖", "Ͱ", "͢"] ‚-wordbreak

Slide 124

Slide 124 text

Y.☃.WordBreak.getWords("A kilobyte's just 1,024 bytes."); // => ["A", "kilobyte's", "just", "1,024", "bytes"] Y.☃.WordBreak.getWords('ύΠ͕޷͖Ͱ͢'); // => ["ύΠ", "͕", "޷", "͖", "Ͱ", "͢"] ‚-wordbreak

Slide 125

Slide 125 text

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 ". • Doesn’t infringe any trademarks.

Slide 126

Slide 126 text

Y.Highlight.all('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.start('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.words('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.allFold('YÜIConf 2010: YUI rocks!', 'yui'); // => 'YÜIConf 2010: YUI rocks!' highlight

Slide 127

Slide 127 text

Y.Highlight.all('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.start('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.words('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.allFold('YÜIConf 2010: YUI rocks!', 'yui'); // => 'YÜIConf 2010: YUI rocks!' highlight

Slide 128

Slide 128 text

Y.Highlight.all('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.start('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.words('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.allFold('YÜIConf 2010: YUI rocks!', 'yui'); // => 'YÜIConf 2010: YUI rocks!' highlight

Slide 129

Slide 129 text

Y.Highlight.all('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.start('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.words('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.allFold('YÜIConf 2010: YUI rocks!', 'yui'); // => 'YÜIConf 2010: YUI rocks!' highlight

Slide 130

Slide 130 text

Y.Highlight.all('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.start('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.words('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.allFold('YÜIConf 2010: YUI rocks!', 'yui'); // => 'YÜIConf 2010: YUI rocks!' highlight

Slide 131

Slide 131 text

Y.Highlight.all('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.start('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.words('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.allFold('YÜIConf 2010: YUI rocks!', 'yui'); // => 'YÜIConf 2010: YUI rocks!' highlight

Slide 132

Slide 132 text

Y.Highlight.all('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.start('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.words('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.allFold('YÜIConf 2010: YUI rocks!', 'yui'); // => 'YÜIConf 2010: YUI rocks!' highlight

Slide 133

Slide 133 text

Y.Highlight.all('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.start('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.words('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.allFold('YÜIConf 2010: YUI rocks!', 'yui'); // => 'YÜIConf 2010: YUI rocks!' highlight

Slide 134

Slide 134 text

Y.Highlight.all('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.start('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.words('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.allFold('YÜIConf 2010: YUI rocks!', 'yui'); // => 'YÜIConf 2010: YUI rocks!' highlight

Slide 135

Slide 135 text

Y.Highlight.all('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.start('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.words('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.allFold('YÜIConf 2010: YUI rocks!', 'yui'); // => 'YÜIConf 2010: YUI rocks!' highlight

Slide 136

Slide 136 text

Y.Highlight.all('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.start('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.words('YUIConf 2010: YUI rocks!', 'yui'); // => 'YUIConf 2010: YUI rocks!' Y.Highlight.allFold('YÜIConf 2010: YUI rocks!', 'yui'); // => 'YÜIConf 2010: YUI rocks!' highlight

Slide 137

Slide 137 text

Why ? • HTML5 defines a new element for denoting the relevance (as opposed to the importance) of a span of text. • It recommends using “to highlight a part of quoted text that was not originally emphasized”. • But, since isn’t yet supported in all browsers, we use , 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

Slide 138

Slide 138 text

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

Slide 139

Slide 139 text

What I just said but 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/

Slide 140

Slide 140 text

One more thing... Photo: http://www.flickr.com/photos/jabb/3502160522/

Slide 141

Slide 141 text

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

Slide 142

Slide 142 text

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

Slide 143

Slide 143 text

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

Slide 144

Slide 144 text

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

Slide 145

Slide 145 text

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

Slide 146

Slide 146 text

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

Slide 147

Slide 147 text

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

Slide 148

Slide 148 text

Ryan Grove, YUI Team @yaypie on Twitter https://github.com/rgrove/ Slides: http://lanyrd.com/smym Photo: http://www.flickr.com/photos/damaradeaella/2822846819/