Is html5-ready-workshop-110727181512-phpapp02

151
Is HTML5 ready for production?

Transcript of Is html5-ready-workshop-110727181512-phpapp02

Page 1: Is html5-ready-workshop-110727181512-phpapp02

Is HTML5 ready for

production?

Page 2: Is html5-ready-workshop-110727181512-phpapp02

Hi, I’m Remy

@[email protected]

I <3 JavaScript

Questions: interrupt & ask!

Page 3: Is html5-ready-workshop-110727181512-phpapp02
Page 4: Is html5-ready-workshop-110727181512-phpapp02
Page 5: Is html5-ready-workshop-110727181512-phpapp02

There's a lot more down here.

Page 6: Is html5-ready-workshop-110727181512-phpapp02

HTML5 is a spec

Page 7: Is html5-ready-workshop-110727181512-phpapp02

"HTML5" is a brandsort of

^

Page 8: Is html5-ready-workshop-110727181512-phpapp02

HTML5

Offline applications

Offline events

Canvas

Video

Web Form

s

"HTML5"

Web Storage

Web SQ

L Databases

Web Sockets

Web W

orkersG

eolocationM

OA

R!!!

Page 9: Is html5-ready-workshop-110727181512-phpapp02

NOT HTML5

NOT HTML5

Page 10: Is html5-ready-workshop-110727181512-phpapp02

CSS != HTMLBut maybe we should have been more careful

Page 11: Is html5-ready-workshop-110727181512-phpapp02

caniuse.com

Page 12: Is html5-ready-workshop-110727181512-phpapp02

When can I use "HTML5"?

Page 13: Is html5-ready-workshop-110727181512-phpapp02
Page 14: Is html5-ready-workshop-110727181512-phpapp02
Page 15: Is html5-ready-workshop-110727181512-phpapp02
Page 16: Is html5-ready-workshop-110727181512-phpapp02

Making it work in the "other" browser

Page 17: Is html5-ready-workshop-110727181512-phpapp02

PolyfillA shim that mimics a futureAPI providing a fallback to

older browsershttp://goo.gl/0Z9eI

Page 18: Is html5-ready-workshop-110727181512-phpapp02

ToolsModernizr to detect support

yepnode.js to conditionally load(available as part of Modernizr)

Page 19: Is html5-ready-workshop-110727181512-phpapp02

ToolsModernizr.load({ test: Modernizr.geolocation, nope: 'geo-polyfill.js', complete: initMyGeoApp});

Page 20: Is html5-ready-workshop-110727181512-phpapp02

Oh, and learn JavaScript

Page 21: Is html5-ready-workshop-110727181512-phpapp02

Web Storage

Page 22: Is html5-ready-workshop-110727181512-phpapp02

Cookies suck.

Page 23: Is html5-ready-workshop-110727181512-phpapp02

Cookies suck.

Not the edible ones, duh.

Page 24: Is html5-ready-workshop-110727181512-phpapp02

The code for cookies is a pain - I always

google it.

Page 25: Is html5-ready-workshop-110727181512-phpapp02

"Session" cookies leak across sessions.

Page 26: Is html5-ready-workshop-110727181512-phpapp02

Persistent cookies require special date

format

Page 27: Is html5-ready-workshop-110727181512-phpapp02

Deleting a cookie, isn't really deleting, but setting in the past.

Page 28: Is html5-ready-workshop-110727181512-phpapp02

Varying degrees of limitations on size and

number.

Page 29: Is html5-ready-workshop-110727181512-phpapp02

Fuck cookies.

Page 30: Is html5-ready-workshop-110727181512-phpapp02

Sexy Web Storage FTW

Page 31: Is html5-ready-workshop-110727181512-phpapp02

One Interface

localStoragesessionStorage

http://dev.w3.org/html5/webstorage/

Page 32: Is html5-ready-workshop-110727181512-phpapp02

localStorage

• Persists

• Applied to document origin, i.e. scheme/host/port tuple

• No expiry

Page 33: Is html5-ready-workshop-110727181512-phpapp02

sessionStorage

• Lasts whilst on the document origin

• Doesn't leak

• Exactly the same API as localStorage

Page 34: Is html5-ready-workshop-110727181512-phpapp02

How much space do you want?

5mb?Done! \o/However: utf-16 ∴ 2½Mb

Page 35: Is html5-ready-workshop-110727181512-phpapp02

APIvoid setItem(key, value)

any* getItem(key)

void removeItem(key)

string key(index)

void clear()

readonly number length

Page 36: Is html5-ready-workshop-110727181512-phpapp02

var store = sessionStorage;

store.setItem('name','rem');

store.getItem('name');

store.removeItem('name');

Play

Do it in the console!

Page 37: Is html5-ready-workshop-110727181512-phpapp02

APIsetter setItem

getter getItem

deleter removeItem

Page 38: Is html5-ready-workshop-110727181512-phpapp02

var store = sessionStorage;

store.name = 'rem';

store.name;

delete store.name;

Play

Do it in the console!

Page 39: Is html5-ready-workshop-110727181512-phpapp02

// Safari debugger broken:

ss.setItem('key', 12);

tipThere's no security protecting the API

Page 40: Is html5-ready-workshop-110727181512-phpapp02

Values are strings

Work around: JSON(and http://www.json.org/json2.js)

Page 41: Is html5-ready-workshop-110727181512-phpapp02

var store = sessionStorage,

user = { screen_name : ‘rem’,

rating : 11 };

store.user = JSON.stringify(user));

var gotUser = JSON.parse(store.user);

alert(gotUser.screen_name);

Play

Page 42: Is html5-ready-workshop-110727181512-phpapp02
Page 43: Is html5-ready-workshop-110727181512-phpapp02

Events too

window.addEventListener('storage', function (event) {

console.log(event);

}, false);

http://jsbin.com/ahafa3

Page 44: Is html5-ready-workshop-110727181512-phpapp02
Page 45: Is html5-ready-workshop-110727181512-phpapp02

Storage in all browsers

Page 46: Is html5-ready-workshop-110727181512-phpapp02

window.name

Page 47: Is html5-ready-workshop-110727181512-phpapp02

sessionStorage = (function () { var data = window.name ? JSON.parse(window.name) : {};

return { clear: function () { data = {}; window.top.name = ''; }, getItem: function (key) { return data[key] || null; }, removeItem: function (key) { delete data[key]; window.top.name = JSON.stringify(data); }, setItem: function (key, value) { data[key] = value; window.top.name = JSON.stringify(data); } };})(); http://gist.github.com/350433

Page 48: Is html5-ready-workshop-110727181512-phpapp02

Firefox cookie security applies to Storage too :(

tip

Page 49: Is html5-ready-workshop-110727181512-phpapp02

tipvar cookiesEnabled = (function () { // the id is our test value var id = +new Date();

// generate a cookie to probe cookie access document.cookie = '__cookieprobe=' + id + ';path=/';

// if the cookie has been set, then we're good return (document.cookie.indexOf(id) !== -1);})();

Page 50: Is html5-ready-workshop-110727181512-phpapp02

Web SQL Databases

http://flic.kr/p/drmCJ

Page 51: Is html5-ready-workshop-110727181512-phpapp02

IndexedDB

http://flic.kr/p/5KXFwB

Page 52: Is html5-ready-workshop-110727181512-phpapp02

Questions?

Page 53: Is html5-ready-workshop-110727181512-phpapp02

Ca

nv

as

Cooler than this guy.

Page 54: Is html5-ready-workshop-110727181512-phpapp02

Canvas SVG

Page 55: Is html5-ready-workshop-110727181512-phpapp02

http://vimeo.com/6691519

Page 56: Is html5-ready-workshop-110727181512-phpapp02

• It's not one is better than the other, they do different things

• Select canvas when it makes sense

• Don't assume interactive means canvas

• Check out raphaeljs.com

Page 57: Is html5-ready-workshop-110727181512-phpapp02
Page 58: Is html5-ready-workshop-110727181512-phpapp02

http://mrdoob.com

Page 59: Is html5-ready-workshop-110727181512-phpapp02

<!DOCTYPE html><html lang="en"><head><meta charset="utf-8" /><title>Canvas</title></head><body> <canvas></canvas></body></html>

Play

canvas-1.html

http://dev.w3.org/html5/canvas-api/canvas-2d-api.html

Page 60: Is html5-ready-workshop-110727181512-phpapp02

2D API

ctx = canvas.getContext('2d')

Page 61: Is html5-ready-workshop-110727181512-phpapp02

Start Simple

Page 62: Is html5-ready-workshop-110727181512-phpapp02

fillRect, strokeRect & colours

Page 63: Is html5-ready-workshop-110727181512-phpapp02

ctx.fillRect(10, 10, 100, 100);

Page 64: Is html5-ready-workshop-110727181512-phpapp02

ctx.fillRect(10, 10, 100, 100);

ctx.fillStyle = '#c00';

Page 65: Is html5-ready-workshop-110727181512-phpapp02

ctx.fillRect(10, 10, 100, 100);

ctx.fillStyle = '#c00';

ctx.fillRect(100, 75, 50, 50);

Page 66: Is html5-ready-workshop-110727181512-phpapp02

ctx.fillRect(10, 10, 100, 100);

ctx.fillStyle = '#c00';

ctx.fillRect(100, 75, 50, 50);

ctx.strokeStyle = '#0c0';

Page 67: Is html5-ready-workshop-110727181512-phpapp02

ctx.fillRect(10, 10, 100, 100);

ctx.fillStyle = '#c00';

ctx.fillRect(100, 75, 50, 50);

ctx.strokeStyle = '#0c0';

ctx.lineWidth = 5;

Page 68: Is html5-ready-workshop-110727181512-phpapp02

ctx.fillRect(10, 10, 100, 100);

ctx.fillStyle = '#c00';

ctx.fillRect(100, 75, 50, 50);

ctx.strokeStyle = '#0c0';

ctx.lineWidth = 5;

ctx.arc(100,50,25,0,Math.PI*2,true);

Page 69: Is html5-ready-workshop-110727181512-phpapp02

ctx.fillRect(10, 10, 100, 100);

ctx.fillStyle = '#c00';

ctx.fillRect(100, 75, 50, 50);

ctx.strokeStyle = '#0c0';

ctx.lineWidth = 5;

ctx.arc(100,50,25,0,Math.PI*2,true);

ctx.stroke();

Page 70: Is html5-ready-workshop-110727181512-phpapp02

Math.PI == 180°

tip

Page 71: Is html5-ready-workshop-110727181512-phpapp02

Math.PI *2 == 360°

tip

Page 72: Is html5-ready-workshop-110727181512-phpapp02

d * Math.PI / 180 == radian

tip

Page 73: Is html5-ready-workshop-110727181512-phpapp02

tip CSS stretches

Page 74: Is html5-ready-workshop-110727181512-phpapp02

Gradient fills

Page 75: Is html5-ready-workshop-110727181512-phpapp02

1. Create a gradient object

2.Add colour stops

3.Set the gradient to the fillStyle

4.Draw

Page 76: Is html5-ready-workshop-110727181512-phpapp02

var w = canvas.width, h = canvas.height;

var gradient = ctx.createLinearGradient(0, 0, w, h);

Page 77: Is html5-ready-workshop-110727181512-phpapp02

var w = canvas.width, h = canvas.height;

var gradient = ctx.createLinearGradient(0, 0, w, h);gradient.addColorStop(0, '#fff');gradient.addColorStop(0.5, '#f00');gradient.addColorStop(1, '#000');

Page 78: Is html5-ready-workshop-110727181512-phpapp02

var w = canvas.width, h = canvas.height;

var gradient = ctx.createLinearGradient(0, 0, w, h);gradient.addColorStop(0, '#fff');gradient.addColorStop(0.5, '#f00');gradient.addColorStop(1, '#000');

ctx.fillStyle = gradient;

Page 79: Is html5-ready-workshop-110727181512-phpapp02

var w = canvas.width, h = canvas.height;

var gradient = ctx.createLinearGradient(0, 0, w, h);gradient.addColorStop(0, '#fff');gradient.addColorStop(0.5, '#f00');gradient.addColorStop(1, '#000');

ctx.fillStyle = gradient;ctx.fillRect(0, 0, w, h);

Page 80: Is html5-ready-workshop-110727181512-phpapp02

Play

createRadialGradient(x0,y0,r0,x1,y1,r1)

Page 81: Is html5-ready-workshop-110727181512-phpapp02

Pattern Fills

Page 82: Is html5-ready-workshop-110727181512-phpapp02

var img = new Image();

img.src = url;

var pattern = ctx.createPattern(img,'repeat');

ctx.fillStyle = pattern;

ctx.fillRect(0, 0, w, h);

Page 83: Is html5-ready-workshop-110727181512-phpapp02

tip invalid_state

img.onload = function () { // now use image for canvas};

Page 84: Is html5-ready-workshop-110727181512-phpapp02

Playing with paths

Page 85: Is html5-ready-workshop-110727181512-phpapp02

• For drawing irregular shapes

• Can be filled

• ...or stroked.

Page 86: Is html5-ready-workshop-110727181512-phpapp02

lineWidth

lineTo(x,y)

moveTo(x,y)

beginPath()

closePath()

rect(x,y,h,w)

arc(x,y,r,s,e, anticw)

fill()

stroke()

Page 87: Is html5-ready-workshop-110727181512-phpapp02

drawImage

Page 88: Is html5-ready-workshop-110727181512-phpapp02

<canvas>

<img> <video><canvas>

Page 89: Is html5-ready-workshop-110727181512-phpapp02

drawImage(src, dx, dy)

drawImage(src, dx, dy, dw, dh)

drawImage(src, sx, sy, sw, sh, dx, dy, dw, dh)

Page 90: Is html5-ready-workshop-110727181512-phpapp02
Page 91: Is html5-ready-workshop-110727181512-phpapp02

Play

canvas-10.html

img.onload = function () { // this == img canvas.width = this.width; canvas.height = this.height; ctx.drawImage(this, 0, 0);};

Page 92: Is html5-ready-workshop-110727181512-phpapp02

pixelpushing

Page 93: Is html5-ready-workshop-110727181512-phpapp02

ctx.getImageData(0,0,w,h)

Page 94: Is html5-ready-workshop-110727181512-phpapp02

ctx.getImageData(0, 0, w, h);

0 1 2 3

i = 0 r g b a

i = 1 r g b a

i... r g b a

Page 95: Is html5-ready-workshop-110727181512-phpapp02

pixels.data[i * 4 + 0];

0 1 2 3

i = 0 r g b a

i = 1 r g b a

i... r g b a

Page 96: Is html5-ready-workshop-110727181512-phpapp02

pixels.data[i * 4 + 1];

0 1 2 3

i = 0 r g b a

i = 1 r g b a

i... r g b a

Page 97: Is html5-ready-workshop-110727181512-phpapp02

pixels.data[i * 4 + 2];

0 1 2 3

i = 0 r g b a

i = 1 r g b a

i... r g b a

Page 98: Is html5-ready-workshop-110727181512-phpapp02

pixels.data[i * 4 + 3];

0 1 2 3

i = 0 r g b a

i = 1 r g b a

i... r g b a

Page 99: Is html5-ready-workshop-110727181512-phpapp02

var pixels = ctx.getImageData(0, 0, w, h), l = pixels.data.length, i;

for (i = 0; i < l; i += 4) {

}

Page 100: Is html5-ready-workshop-110727181512-phpapp02

var pixels = ctx.getImageData(0, 0, w, h), l = pixels.data.length, i;

for (i = 0; i < l; i += 4) {

}

This says loop over each pixel

Page 101: Is html5-ready-workshop-110727181512-phpapp02

var pixels = ctx.getImageData(0, 0, w, h), l = pixels.data.length, i;

for (i = 0; i < l; i += 4) { // red: pixels.data[i+0]

}

Page 102: Is html5-ready-workshop-110727181512-phpapp02

var pixels = ctx.getImageData(0, 0, w, h), l = pixels.data.length, i;

for (i = 0; i < l; i += 4) { // red: pixels.data[i+0] // green: pixels.data[i+1]

}

Page 103: Is html5-ready-workshop-110727181512-phpapp02

var pixels = ctx.getImageData(0, 0, w, h), l = pixels.data.length, i;

for (i = 0; i < l; i += 4) { // red: pixels.data[i+0] // green: pixels.data[i+1] // blue: pixels.data[i+2]

}

Page 104: Is html5-ready-workshop-110727181512-phpapp02

var pixels = ctx.getImageData(0, 0, w, h), l = pixels.data.length, i;

for (i = 0; i < l; i += 4) { // red: pixels.data[i+0] // green: pixels.data[i+1] // blue: pixels.data[i+2] // alpha: pixels.data[i+3]}

Page 105: Is html5-ready-workshop-110727181512-phpapp02

ctx.putImageData(pixels, 0, 0)

Page 106: Is html5-ready-workshop-110727181512-phpapp02

ctx.putImageData(pixels, 0, 0)

Needs to be a CanvasPixelArray

object

Page 107: Is html5-ready-workshop-110727181512-phpapp02

tip security_err

To use getImageData, your document

must be served over http (or https) -

i.e. it doesn't work offline.

Page 108: Is html5-ready-workshop-110727181512-phpapp02

Play

http://jsbin.com/aguho3/2/edit

greyscale = r*.3 + g*.59 + b*.11;

r = g = b = greyscale;

saturation = (Math.max(r,g,b) + Math.min(r,g,b))/2;

r = g = b = saturation;

/workshop/authors-large.jpg

Page 109: Is html5-ready-workshop-110727181512-phpapp02

canvas.toDataURL('image/png');

Page 110: Is html5-ready-workshop-110727181512-phpapp02

save.onclick = function () { window.open( canvas.toDataURL('image/png') );};

Play

canvas-13.html

Page 111: Is html5-ready-workshop-110727181512-phpapp02

Questions?

Page 112: Is html5-ready-workshop-110727181512-phpapp02

Offline Applications

Page 113: Is html5-ready-workshop-110727181512-phpapp02

Offline Apps

• Application cache / manifest

• Events: offline, online

• navigator.onLine property

Page 114: Is html5-ready-workshop-110727181512-phpapp02

http://icanhaz.com/rubiks

Page 115: Is html5-ready-workshop-110727181512-phpapp02

Using a Manifest<!DOCTYPE html>

<html manifest="my.appcache">

<body>

<!-- my page -->

</body>

</html>

Page 116: Is html5-ready-workshop-110727181512-phpapp02

CACHE MANIFEST

app.html

css/style.css

js/app.js

#version 13

my.appcache

Page 117: Is html5-ready-workshop-110727181512-phpapp02

The Manifest

1. Serve as text/manifest, by adding to mime.types:

text/cache-manifest appcache

Page 118: Is html5-ready-workshop-110727181512-phpapp02

<IfModule mod_expires.c>

ExpiresActive on

ExpiresByType text/cache-manifest

↪ “access plus 0 seconds”

</IfModule>

tip Firefox caching

Page 119: Is html5-ready-workshop-110727181512-phpapp02

The Manifest

2. First line must be:

CACHE MANIFEST

Page 120: Is html5-ready-workshop-110727181512-phpapp02

The Manifest

3. Including page is implicitly included in the cache.

Page 121: Is html5-ready-workshop-110727181512-phpapp02

The Manifest

4. Two futher namespaces: NETWORK & FALLBACK

FALLBACK:/ offline.html

Page 122: Is html5-ready-workshop-110727181512-phpapp02

CACHE MANIFEST

/index.htmlrange.jsdatastore.js

FALLBACK:# force everything through # the index url/ /

# this won't match # anything unless it's on # another domainNETWORK:*

# v4

Page 123: Is html5-ready-workshop-110727181512-phpapp02

CACHE MANIFEST

/index.htmlrange.jsdatastore.js

FALLBACK:# force everything through # the index url/ /

# this won't match # anything unless it's on # another domainNETWORK:*

# v4

Served from cache

Page 124: Is html5-ready-workshop-110727181512-phpapp02

CACHE MANIFEST

/index.htmlrange.jsdatastore.js

FALLBACK:# force everything through # the index url/ /

# this won't match # anything unless it's on # another domainNETWORK:*

# v4

Requests for files not

found in the cache, are

directed to /

i.e. index.html

(when offline).

Page 125: Is html5-ready-workshop-110727181512-phpapp02

CACHE MANIFEST

/index.htmlrange.jsdatastore.js

FALLBACK:# force everything through # the index url/ /

# this won't match # anything unless it's on # another domainNETWORK:*

# v4

Any requests to urls

that don't match / -

i.e. on another

domain, will be

served through the

web.

Page 126: Is html5-ready-workshop-110727181512-phpapp02

CACHE MANIFEST

/index.htmlrange.jsdatastore.js

FALLBACK:# force everything through # the index url/ /

# this won't match # anything unless it's on # another domainNETWORK:*

# v4

Also ensures

browser even

attempts to load the

asset

Page 127: Is html5-ready-workshop-110727181512-phpapp02

CACHE MANIFEST

/index.htmlrange.jsdatastore.js

FALLBACK:# force everything through # the index url/ /

# this won't match # anything unless it's on # another domainNETWORK:*

# v4

The contents of the

manifest must

change to trigger an

update

Page 128: Is html5-ready-workshop-110727181512-phpapp02

The Manifest

5. Include some versioning to cache bust your manifest

# version 16

Page 129: Is html5-ready-workshop-110727181512-phpapp02

The process

Page 130: Is html5-ready-workshop-110727181512-phpapp02

Browser: request Server: serve allBrowser: I have a manifest, cache

assets

Server: serve manifest assets

Browser: applicationCache

updatedBrowser: reload

Browser: serve locally

Browser: only request manifest

file

Server: 304 Not Modified

Page 131: Is html5-ready-workshop-110727181512-phpapp02

Browser: request Server: serve allBrowser: I have a manifest, cache

assets

Server: serve manifest assets

Browser: applicationCache

updatedBrowser: reload

Browser: serve locally

Browser: only request manifest

file

Server: 304 Not Modified

Problem:Change of contentrequires 2 refreshes

Page 132: Is html5-ready-workshop-110727181512-phpapp02

document.body.onOnline = function () { // fire an update to the cache applicationCache.update();};

Page 133: Is html5-ready-workshop-110727181512-phpapp02

applicationCache.onUpdateReady = function () { if (confirm("New version ready. Refresh?")) { // reload window.location.refresh(); }};

Page 134: Is html5-ready-workshop-110727181512-phpapp02

tip

Do offline last

Page 135: Is html5-ready-workshop-110727181512-phpapp02

Questions?

Page 136: Is html5-ready-workshop-110727181512-phpapp02

Web Sockets

Page 137: Is html5-ready-workshop-110727181512-phpapp02

Native or polyfilled

Page 139: Is html5-ready-workshop-110727181512-phpapp02

new WebSocket(url)

http://dev.w3.org/html5/websockets/

Page 140: Is html5-ready-workshop-110727181512-phpapp02

ws://node.remysharp.com:8000

http://github.com/miksago/node-websocket-server

Page 141: Is html5-ready-workshop-110727181512-phpapp02

onopen

onmessage

onclose

onerror

Page 142: Is html5-ready-workshop-110727181512-phpapp02

var data = JSON.parse(event.data);

Page 143: Is html5-ready-workshop-110727181512-phpapp02

.send

Page 144: Is html5-ready-workshop-110727181512-phpapp02

var url = 'ws://node.remysharp.com:8000',

conn = new WebSocket(url);

conn.onopen = function () {

conn.send('hello world');

};

conn.onmessage = function (event) {

console.log(event.data);

};

Page 145: Is html5-ready-workshop-110727181512-phpapp02

var url = 'ws://node.remysharp.com:8000',

conn = new WebSocket(url);

conn.onopen = function () {

conn.send('hello world');

};

conn.onmessage = function (event) {

console.log(event.data);

};

Page 146: Is html5-ready-workshop-110727181512-phpapp02

var url = 'ws://node.remysharp.com:8000',

conn = new WebSocket(url);

conn.onopen = function () {

conn.send('hello world');

};

conn.onmessage = function (event) {

console.log(event.data);

};

Page 147: Is html5-ready-workshop-110727181512-phpapp02

var url = 'ws://node.remysharp.com:8000',

conn = new WebSocket(url);

conn.onopen = function () {

conn.send('hello world');

};

conn.onmessage = function (event) {

console.log(event.data);

};

Page 148: Is html5-ready-workshop-110727181512-phpapp02

var url = 'ws://node.remysharp.com:8000',

conn = new WebSocket(url);

conn.onopen = function () {

conn.send('hello world');

};

conn.onmessage = function (event) {

console.log(event.data);

};

Page 149: Is html5-ready-workshop-110727181512-phpapp02

var url = 'ws://node.remysharp.com:8000',

conn = new WebSocket(url);

conn.onopen = function () {

conn.send('hello world');

};

conn.onmessage = function (event) {

console.log(event.data);

};

Page 150: Is html5-ready-workshop-110727181512-phpapp02

var url = 'ws://node.remysharp.com:8000',

conn = new WebSocket(url);

conn.onopen = function () {

conn.send('hello world');

};

conn.onmessage = function (event) {

console.log(event.data);

};

Play

Page 151: Is html5-ready-workshop-110727181512-phpapp02

Questions?To contact me after my presentation – text NHT to INTRO (46876)

Or [email protected]@rem