Академический Документы
Профессиональный Документы
Культура Документы
#2 - MAY 2012
Pamela
Exclusi
ve inte rview
Fox
DEVELOPERS
TUTORIALS
appliness
(
FOCUS GROUP INTERVIEW SHOWCASE video tutorial VISUAl and juicy WTFJS BLEEDING EDGE TEAM
WHICHELEMENT.com
false advertising
by Toby Ho
NAVIGATE
GO BACK TO THE LIBRARY MOVE TO THE PREVIOUS ARTICLE DISPLAY THE TABLE OF CONTENTS VISUALLY BROWSE ALL THE ARTICLES
appliness
Along with the community, ADOBE ENGINEERS ARE developing new standards and advancing existing standards. IN THIS ARTICLE, they introduce CSS REGIONS AND CSS EXcLUSIONS which are two proposals for the w3c. thanks to these new additions, a designer or developer can create high-quality, magazine-style layouts for the web using HTML5 and CSS3.
CSS REGIONS
Lets first discuss CSS Regions. HTML and CSS today allow you to place text in a box, and has support for flowing text through identical column boxes contained in a single box. If you want to size and position
3/7
separate boxes for your text to flow through, you can only approximate your desired layout by breaking up your text and assigning which text goes in which box. This results in a fixed layout that breaks down at the slightest change of font or window size. With the introduction of CSS Regions, you can flow unbroken text fluidly from box to box without any restrictions on size or position. Designers & developers are free to use columns and gutters with different widths and flow text through whatever expressive layout they choose to create. CSS Regions makes achieving this easy. With this new feature, you can specify how text or images should flow across multiple regions with simple, declarative CSS. In the video below, three distinct regions are specified and as the browser resizes, notice how the text flows naturally from one region to the other.
VIDEO CSS Regions shows how browser resizing causes fluid reflowing of text
The code for this is quite simple. The text source is named using the new vendor prefixed -webkitflow-into CSS property on the element that contains the content. This naming causes the content to be removed from the normal CSS layout flow and allows it to be inserted into specially defined regions by setting the -webkit-flow-from property. The code for the video above looks like this: CSS: #source{ -webkit-flow-into: main-thread; } .region{ -webkit-flow-from: main-thread; } HTML: <div id=source> <p>Lorem ipsum dolor [...]</p> </div> <div id=region1 class=region></div> <div id=region2 class=region></div> <div id=region3 class=region></div>
4/7
In fact, regions can be positioned anywhere. Using this same syntax, you can have multiple threads of text or images flow into separate chains of regions. The video below shows two threads of text flowing into non-contiguous regions because the order in which text is flowed is explicitly controlled by the -webkit-flow-into property.
VIDEO Multiple text threads flow naturally into non-contiguous regions with simple CSS properties
Here is a video of a more complex example created by Adobe engineer, Christian Cantrell. In this sample, a short story is formatted using CSS Regions. Youll notice that the story is divided into two columns, which is more of a print-like layout and friendly to read. The power of CSS Regions becomes obvious when you see that the text is actually flowing from one column to the other. Notice that as the browser resizes, the text flows from column to column and the page concept is maintained. Without CSS Regions, you would have to write a fair amount of JavaScript to break the text into appropriately sized pieces (and re-run the script any time the font or window size changed). Now its just a matter of setting a few CSS properties!
VIDEO Multiple text threads flow naturally into non-contiguous regions with simple CSS properties
5/7
What is even better is that CSS Regions can be experimented with now! All of the above examples were shown in recent builds of Chrome. CSS Regions is also available in the Developer Preview of Internet Explorer 10 and nightly builds of WebKit. While there has been great progress, CSS Regions is still a cutting edge feature so in some cases it is protected by both vendor prefixes and runtime flags. To play with CSS Regions in Chrome you will need to enable the feature through the --enable-css-regions runtime flag. There are instructions on the web about how to easily do this in Chrome. We are thrilled with how CSS Regions is progressing and are working on some new features to add. These include making it even simpler to style regions, auto-setting the height for regions, and introducing a page template model to create boxes in CSS and better handle pagination. To stay informed of the evolution of CSS Regions and get access to sample code and new demos, keep an eye on the CSS Regions page on html.adobe.com.
CSS EXCLUSIONS
A complementary feature to CSS Regions is CSS Exclusions, which allows the creation of custom text exclusions to wrap text with shapes or images. Again, with simple CSS properties, you can define a custom shape as the container for text, like so:
6/7
This behavior is simple to achieve with just a few new properties CSS Exclusions introduces. The webkitwrap-shape property defines the boundary in which to flow text content and also defines the area to be avoided when laying out content. The -webkit-wrap-shape-mode property controls how the content responds to a shape and flows the content appropriately. In this video, using the webkit-wrap-shape and webkit-wrap-shape-mode CSS properties, you can see several things. Notice that as the browser resizes, text flows around the custom shape and if the shape size changes, the text continues to flow as one would expect of a responsive layout. Additionally, the custom shape can be dynamically swapped to any polygon and text layout and reflowing capabilities are maintained!
VIDEO Dynamic shapes can be used to cause text to flow naturally with CSS Exclusions
Adobe is actively working on CSS Exclusions and while it is not yet fully available in current browsers, it should be available in Chrome and WebKit nightly builds soon. The CSS Exclusions page on Adobe & HTML will be updated as the feature progresses but till then, it is there you can access a custom WebKit build to play with the feature now. We think the power that both CSS Regions and CSS Exclusions offer designers and developers is very exciting! Expressive, liquid layouts are achievable with just a few CSS properties and a clever eye. Were thrilled that the features are being used to create compelling digital experiences, like in the following example where both features are used to cause text to flow around the mountain and car images as the user scrolls the arrow to pan around. Keep an eye out for CSS Regions and Exclusions to land in your favorite browser and we hope you consider using them as you develop rich layouts on both desktop and mobile devices.
ONLINE RESOURCES The Adobe & HTML website http://html.adobe.com CSS Regions W3C Specification http://dev.w3.org/csswg/css3-regions/ CSS Exlusions W3C Sepcification http://dev.w3.org/csswg/css3-exclusions/
appliness
Drag and drop is a classic gesture in desktop applications. Learn how to code it on touch devices such as your tablet using jQuery UI and some hacks.
As a RIA (Rich Internet Application) developer, I try to introduce meaningful and efficient user interactions in my apps. A classic and natural way to associate items is to use drag and drop. Its a classic action in desktop applications. With the introduction of touch screens, its even more natural on mobile devices. When you need to order items, assign items to categories or to an action, drag-and-drop makes sense. In this tutorial, Ill play with a list of team members and a list of tasks. As you can guess, the enduser will be able to assign a specific member to a task member using drag-and-drop. Desktop frameworks have implemented Drag and Drop management based on mouse events. Thats why a lot of these libraries are not effective on touch devices. Well see in this tutorial how to hack these libraries and simulate touch events. On the next page, you can start playing with the final application. Drag users on tasks using your finger and read this tutorial to understand how to code it.
d n u o laygr
Difficulty
- rookie - intermediate - expert
- jQuery I U y r e u Q j - CSS
Todo list
- drag stuff - drop things - wash fingers
by Michal Chaize
8/14
Some cool features that you should notice: - If you dont drop a user on a task, then he will automatically move back to his original place. - Users snap to the edges of the task boxes while dragging them on the stage. - Once a user is assigned to a task, you cannot drag him anymore, and you cannot drop another user on this task.
9/14
// Detect touch support $.support.touch = ontouchend in document; // Ignore browsers without touch support if (!$.support.touch) { return; } Then he gets a reference to the mouse prototype: var mouseProto = $.ui.mouse.prototype; For every touch event, he will simulate the corresponding mouse event. He rewrites the touchMove handler: mouseProto._touchMove = function (event) { // Ignore event if not handled if (!touchHandled) { return; } // Interaction was not a click this._touchMoved = true; // Simulate the mousemove event simulateMouseEvent(event, mousemove);
};
The simulateMouseEvent contains the hack and the classic event.preventDefault() call. function simulateMouseEvent (event, simulatedType) { // Ignore multi-touch events if (event.originalEvent.touches.length > 1) { return; } event.preventDefault(); var touch = event.originalEvent.changedTouches[0], simulatedEvent = document.createEvent(MouseEvents); // Initialize the simulated mouse event using the touch events coordinates simulatedEvent.initMouseEvent( simulatedType, // type true, // bubbles true, // cancelable window, // view 1, // detail touch.screenX, // screenX touch.screenY, // screenY touch.clientX, // clientX touch.clientY, // clientY
10/14
);
// // // // //
This touch-punch library is on github. Just download it and include it in your web project in addition to jQueryUI and jQuery. <head> <script src=jquery-1.7.1.min.js/></script> <script src=jquery-ui-1.8.18.custom.min.js/></script> <script src=jquery.ui.touch-punch.min.js/></script> </head>
DRAG...
Now you can use the draggable() plugin on your elements and start dragging them on the stage. <html> <head> <title>Drag</title> <link rel=stylesheet type=text/css href=css/ui-lightness/jquery-ui-1.8.18.custom.css rel=stylesheet> <link rel=stylesheet type=text/css href=style.css> <script src=jquery-1.7.1.min.js/> </script> <script src=jquery-ui-1.8.18.custom.min.js></script> <script src=jquery.ui.touch-punch.min.js></script> <script> $(function() { $( #draggable1 ).draggable(); }); </script> </head> <body> <div class=titleStyle style=width:600px> DRAG ME </div> <div id=members style=width:600px; height:150px> <div id=draggable1 class=ui-widget-content displayBloc>
11/14
<img src=mchaize-sf-low.jpg width=100/>Michal C. </div> </div> <div class=titleStyle style=width:600px;margin-top:50px;>DROP HERE</div> <div id=tasks class= bigBox> <div id=droppable_1 class=ui-widget-header dropyBloc titleStyle> <p>Task 1</p> </div> </div> </div> </body> </html>
...AND DROP
Lets define a drop zone for our user. The jQuery UI Droppable plugin makes the elements of your choice droppable, which means that they accept being dropped on by draggables. In this application, the <DIV> element with the id droppable_1 will be our target. A drop event will be triggered when the draggable will be dropped over. In the callback, well find the paragraph <p> element and modify the text from Task 1 to Task assigned. <script> $(function() { $( #draggable1 ).draggable(); $(#droppable_1).droppable({ drop: function( event, ui ) { $( this ) .find( p ) .html( Task assigned) } }); }); </script> </head> <body> <div class=titleStyle style=width:600px> DRAG ME </div> <div id=members style=width:600px; height:150px> <div id=draggable1 class=ui-widget-content displayBloc> <img src=mchaize-sf-low.jpg width=100/>Michal C.
12/14
</div> </div> <div class=titleStyle style=width:600px;margin-top:50px;>DROP HERE</div> <div id=tasks class= bigBox> <div id=droppable_1 class=ui-widget-header dropyBloc titleStyle> <p>Task 1</p> </div> </div> </div> </body>
SNAP MODE
The method has some very cool built-in options. To guide the user, you can choose to snap a draggable to the edges of a specific element. In this case, I want the user to snap the inner edges of the task box while dragging it. In the draggable plugin options, I specify the selector as a snap target and I set the to (possible values are , and ). I also want to add a visual feedback if a user is not dropped on a task (on a valid droppable element). Thats why I set the option to . $( #draggable1 ).draggable({ snap: .ui-widget-header, snapMode: inner,revert:true }); By default, the draggable object will always return to its original position when dropped. I need to disable the behavior when the item is dropped on a correct place. To do so, I just need to extend the drop callback setting the option to . Im also setting the final coordinates of the draggable element once dropped using the options. $(#droppable_1).droppable({ drop: function( event, ui ) { $( this ) .find( p ) .html( Task assigned) ui.draggable.draggable(option,revert,false); ui.draggable.position({of: $( this ),my: left bottom, at: left bottom }); } });
13/14
MORE INFORMATION
>
>
appliness
In this article, Im going to discuss object creation in JavaScript using prototypal inheritance as an alternative to the new operator.
d n u o laygr
t - JavaScrip e p y t o t o r P - Canvas
Difficulty
- rookie - intermediate - expert
Todo list
forget class code reuse particles
by Keith Peters
15/27
Before going any further, I want to clarify the term prototype. First, there is the prototype property of a constructor function as shown in the last sections example. There is another hidden property that is the actual prototype of an object. This can be very confusing. The ECMAScript proposal refers to this hidden property as [[Prototype]]. This is exposed in some JavaScript environments as the __proto__ property, but this is not a standard part of the language and should not be counted on. When you create a new object using new with a constructor function, that new objects [[Prototype]] is set with a reference to the constructor functions prototype. In addition to this naming confusion, there were two design decisions made in the language that have added to the confusion ever since. First, due to the concern that some developers might not be comfortable with prototypal inheritance, constructor functions and the new operator were introduced. Second, there was no direct native way to create a new object with another object as its [[Prototype]], except through the new operator with a constructor function. Fortunately, most browsers now support the Object.create method. This method takes an existing object as a parameter. It returns a new object that has the existing object assigned as its [[Prototype]]. Even more fortunately, this method is quite easy to create for those environments that do not support it: if(typeof Object.create !== function) { Object.create = function (o) { function F() {} F.prototype = o; return new F(); }; } So, how would you rewrite the earlier example using Object.create? First you create a foo object that has a name property and a sayHello function: var foo = { name: foo, sayHello: function() { alert(hello from + this.name); } }; foo.sayHello(); Then, you use Object.create to make a bar object that has foo as its prototype, and add a sayGoodbye function to it: var bar = Object.create(foo); bar.sayGoodbye = function() { alert(goodbye from + this.name); } bar.sayHello(); bar.sayGoodbye(); Its also very common to create an extend function that simplifies the adding of methods and properties to the new object. The following method simply copies over any properties from props onto obj: function extend(obj, props) { for(prop in props) { if(props.hasOwnProperty(prop)) { obj[prop] = props[prop]; }}}
17/27
This enables you to create bar like so: var bar = Object.create(foo); extend(bar, { sayGoodbye: function() { alert(goodbye from + this.name); } }); Not such a big deal here, but it simplifies things greatly when you are adding several more properties or methods. OK, now that you have the basics down, you can start putting them together in a real world scenario.
18/27
var adc = adc || {}; adc.particle = { x: 0, y: 0, vx: 0, vy: 0, gravity: 0.0, bounce: -0.9, friction: 1.0, bounds: null, color: #000000, context: null, update: function() { this.vy += this.gravity; this.x += this.vx; this.y += this.vy; this.vx *= this.friction; this.vy *= this.friction; if(this.x < this.bounds.x1) { this.x = this.bounds.x1; this.vx *= this.bounce; } else if(this.x > this.bounds.x2) { this.x = this.bounds.x2; this.vx *= this.bounce; } if(this.y < this.bounds.y1) { this.y = this.bounds.y1; this.vy *= this.bounce; } else if(this.y > this.bounds.y2) { this.y = this.bounds.y2; this.vy *= this.bounce; }
},
} };
render: function() { if(this.context === null) { throw new Error(context needs to be set on particle); } this.context.fillStyle = this.color; this.context.fillRect(this.x - 1.5, this.y - 1.5, 3, 3);
Next, youll need a particle system to keep track of all the particles and handle updating and rendering them.
19/27
var adc = adc || {}; adc.particleSystem = { particles: [], addParticle: function(particle) { this.particles.push(particle); }, update: function() { var i, numParticles = this.particles.length; for(i = 0; i < numParticles; i += 1) { this.particles[i].update(); }
},
};
And finally, youll need a main file that creates the system, creates and adds all the particles, and sets up the animation loop. (function() { if (typeof Object.create !== function) { Object.create = function (o) { function F() {} F.prototype = o; return new F(); }; } var system, numParticles, canvas, context, bounds; function initSystem() { system = Object.create(adc.particleSystem); numParticles = 200; canvas = document.getElementById(canvas); context = canvas.getContext(2d); canvas.width = window.innerWidth; canvas.height = window.innerHeight; bounds = { x1: 0, y1: 0,
20/27
};
function initParticles() { var i, particle; for(i = 0; i < numParticles; i += 1) { particle = Object.create(adc.particle); particle.bounds = bounds; particle.context = context; particle.x = Math.random() * bounds.x2; particle.y = Math.random() * bounds.y2; particle.vx = Math.random() * 10 - 5; particle.vy = Math.random() * 10 - 5; system.addParticle(particle); } } function animate() { context.clearRect(bounds.x1, bounds.y1, bounds.x2, bounds.y2); system.update(); system.render(); } initSystem(); initParticles(); setInterval(animate, 1000 / 60); }()); The code in this file is contained in an immediately invoked function expression, again to avoid global namespace pollution. It includes the Object.create shim for browsers that might need it. This is all pulled together in the following HTML file: <!DOCTYPE html> <html> <head> <title>Particles v1</title> <style type=text/css> .html, body { margin: 0; padding: 0; } </style> </head> <body> <div> <canvas id=canvas/> </div> <script type=text/javascript src=v1/particle.js></script> <script type=text/javascript src=v1/particleSystem.js></script> <script type=text/javascript src=v1/main.js></script> </body></html>
21/27
The important lines, for the purposes of this article, are those that create the particle system: system = Object.create(adc.particleSystem); and that create the particles themselves: particle = Object.create(adc.particle); particle.bounds = bounds; particle.context = context; particle.x = Math.random() * bounds.x2; particle.y = Math.random() * bounds.y2; particle.vx = Math.random() * 10 - 5; particle.vy = Math.random() * 10 - 5; You havent implemented any kind of extend function yet, but you can see here where it would be useful calling extend a single time, rather than line after line of assigning properties. In the next iteration, youll add that and then some.
22/27
};
this.vy = Math.random() * 10 - 5;
The extend method takes care of creating a new object, passing this as a parameter to Object.create. Thus, it makes a copy of itself. It then takes any properties that were passed into extend, copies them onto the new object it created, and finally returns the new object. Now, rather than calling Object.create(adc.particle) and setting and tweaking property after property, you can call adc.particle.extend, passing in an object with the properties you want to set, and then call init on the newly created particle. When you add the extend method to the particle system, the main file becomes a bit simpler. In initSystem, you call adc.particleSystem.extend() to create the new system. You dont need to add any properties to the system, so extend is called with no parameters. Not much of a change there: function initSystem() { system = adc.particleSystem.extend(); numParticles = 200; canvas = document.getElementById(canvas); context = canvas.getContext(2d); canvas.width = window.innerWidth; canvas.height = window.innerHeight; bounds = { x1: 0, y1: 0, x2: canvas.width, y2: canvas.height }; } In the initParticles method, though, you see an improvement: function initParticles() { var i, particle; for(i = 0; i < numParticles; i += 1) { particle = adc.particle.extend({ bounds: bounds, context: context }); particle.init(); system.addParticle(particle); } } Now you can call adc.particle.extend to create each particle, passing in an object that contains the bounds and context, which are then copied to each particle. Finally, you just call init on the new particle, which takes care of randomly setting up its position and velocity. This version works exactly the same as the last, but the creation of individual particles has been greatly simplified.
23/27
Adding inheritance
The third version of the particle system supports inheritance. This is key to code reuse. You have one type of object and you want to make another type of object that is slightly different. You dont want to completely recreate the first object with just a couple of changes. Code reuse has two important benefits. First, there is less code to write. You certainly dont want to write the same code twice. You also dont want to copy and paste code, as this can lead to things getting out of sync, with a function implemented one way over here and the same function implemented a bit differently over there. The second benefit is better performance. When you have the same code duplicated in your live application, it takes longer to download, eats up more memory, and can cause your code to be slower, particularly in object instantiation (because it is instantiating the same code again and again). The particle system currently renders to an HTML5 canvas. Now, you may want to make a different particle type that renders itself as a DOM object. Ideally, almost all of the particle code would be reused, with only the render method differing. So, with great confidence, you can just take particle.js and remove the render method from it. Next, make two new files, canvasParticle.js and comParticle.js. The canvas version will be similar to what youve just done: var adc = adc || {}; adc.canvasParticle = adc.particle.extend({ render: function() { if(this.context === null) { throw new Error(context needs to be set on particle); } this.context.fillStyle = this.color; this.context.fillRect(this.x - 1.5, this.y - 1.5, 3, 3); } }); This code is quite simple. You just call adc.particle.extend, passing in an object that contains your old render method. This will create a new object that has particle as its [[Prototype]], and render as a new method directly on the object. Next youll have to change main.js a bit to allow for your new object types. Create a mainCanvas.js file for setting up the canvas-based particles. It will only differ in one line, where it uses the adc.canvasParticle type to instantiate particles, rather than just adc.particle: function initParticles() { var i, particle; for(i = 0; i < numParticles; i += 1) { particle = adc.canvasParticle.extend({ bounds: bounds, context: context }); particle.init(); system.addParticle(particle); } }
24/27
The particleSystem.js file can remain unchanged, but of course the HTML file will have to reflect new source files youve created. This example should function identically to the first two versions. Now youre ready to create the DOM version. The domParticle.js file will be almost as simple as canvasParticle.js. It assumes that there is an element it can position, and positions it using style properties: adc.domParticle = adc.particle.extend({ render: function() { if(this.element === null) { throw new Error(element needs to be set on particle); } this.element.style.left = this.x; this.element.style.top = this.y; } });
But in this example, the HTML file and main.js file will need to change significantly. In addition to referencing different source files, the HTML file can eliminate the canvas element and add a container div in which to put all the particle elements: <html> <head> <title>Particles v3</title> <style type=text/css> .html, body { margin: 0; padding: 0; overflow: hidden; } </style> </head> <body> <div id=container> </div> <script <script <script <script </body> </html> type=text/javascript type=text/javascript type=text/javascript type=text/javascript src=v3/particle.js></script> src=v3/domParticle.js></script> src=v3/particleSystem.js></script> src=v3/mainDom.js></script>
The main.js file will become mainDom.js and will obviously need to change a bit to create domParticles and give them individual elements instead of references to the canvass context.
25/27
(function() { var system, numParticles, container, bounds; function createElement() { var el = document.createElement(div); el.style.position = absolute; el.style.width = 3; el.style.height = 3; el.style.backgroundColor = #000000; container.appendChild(el); return el; } function initSystem() { system = adc.particleSystem.extend(); numParticles = 200; container = document.getElementById(container); bounds = { x1: 0, y1: 0, x2: window.innerWidth, y2: window.innerHeight }; } function initParticles() { var i, particle; for(i = 0; i < numParticles; i += 1) { particle = adc.domParticle.extend({ bounds: bounds, element: createElement() }); particle.init(); system.addParticle(particle);
function animate() { system.update(); system.render(); } initSystem(); initParticles(); setInterval(animate, 1000 / 60); }());
26/27
This makes use of a new function, createElement, that simply creates a div, styles it, and adds it to the container div. This is what the particle will position when its render method is called. This final example should be nearly identical to all the other versions. Of course, there are lots of optimization and enhancements that you can do to improve all of these examples. I purposely kept it simple to better illustrate the inheritance aspect.
ONLINE RESOURCES Prototypal Inheritance in JavaScript http://javascript.crockford.com/prototypal.html Classical Inheritance in JavaScript http://javascript.crockford.com/inheritance.html JavaScript Objects http://javascriptjabber.com/005-jsj-javascript-objects/
appliness
Ive been blogging a lot about Backbone.js recently. Backbone.js is a lightweight architectural framework that brings structure to your Web applications. Backbone is not, however, a user interface framework that helps you with the way your application looks.
Crafting Native LOOking IOS APPS WITH HTML, BACKBONE.JS AND PHONEGAP
So, where do you turn to for help when you need to make your application look good?
BACKGROUND
For traditional web apps (delivered through a browser), Twitter Bootstrap can help (read here). But what about Mobile apps? I explored Backbone.js + jQuery Mobile here. Depending on what you are looking for, it may or may not be the right solution: jQM provides mobile skins, but they dont look native. Its also more of a full stack framework than a lightweight UI toolkit that you can easily layer on top of your app. The alternative to using an existing UI toolkit is to roll your own styles to make your application look and behave like a native app. Sounds easy enough, but when you consider all the details and want to achieve pixel perfection, it becomes a daunting task.
d n u o laygr
p - Bootstra ile b o M y r e u - jQ p a G e n o h P -
Difficulty
- rookie - intermediate - expert
Todo list
- look native - perform - fire Jim
by Christophe Coenraets
28/29
As I was getting ready to tackle the challenge, and build a new native looking version of my Employee Directory app, I came across this great blog post by Chee Aun where he documents the process he went through to build his own Hacker News mobile app. His post is a real gem, and I ended up reusing a lot of the Hacker News app styles. Compared to the Hacker News app, the Employee Directory page flow is more random. Here are a few examples: 1. *-SearchPage -> EmployeePage -> ReportsPage -> EmployeePage -> 2. SearchPage -> EmployeePage -> EmployeePage (manager) -> Reports -> 3. SearchPage -> EmployeePage -> EmployeePage (manager) -> EmployeePage (managers manager) ->
As you can see, the page flow includes same page transitions, when the user navigates from one employee to his/her manager. To accommodate the Employee Directory page flow requirements, my Backbone.js infrastructure creates and destroys pages as needed with the appropriate slide-in/slide-out transitions. The implementation of these transitions was inspired by Wesley Hales article.
PhoneGap
Even though you can run this application in a browser (here), I built it with the intention of packaging it as a native app with PhoneGap so that you could start it like any other app from your iPhone home screen. If you are not familiar with PhoneGap, Ill provide more details on packaging this app as a native app in my next post.
Source Code
I updated the backbone-directory GitHub repository to include this version: It is available in the iphone directory.
ONLINE RESOURCES
JQuery Mobile official website http://jquerymobile.com/ Backbone.js official website http://documentcloud.github.com/backbone/ Backbone-JQuery mobile https://github.com/ccoenraets/backbone-jquerymobile
appliness
Backbones confined scope is a good thing: its lightweight, non-intrusive, not coupled to things you dont need, and it lets you use the UI toolkit of your choice or simply roll your own styles and widgets. In my previous post, I demonstrated how to use Twitter Bootstrap on top of Backbone.
d n u o laygr
- Backbone e l i b o M Q j M O D L M - HT
Difficulty
- rookie - intermediate - expert
Todo list
- catch event - use bootstrap - structure code
by Christophe Coenraets
30/33
SAMPLE APPLICATION
I ended up spending a decent amount of time trying different things to get the two frameworks to play well together without stepping on each other. To save you some headaches if you are trying to do the same, I put together a simple application with the basic setup to combine Backbone (for the application structure and routing) and jQuery Mobile (for its styles and widgets). NOTE: Another approach would be to use jQMs routing instead of Backbones. Ben Nolan has an example of this approach here. I prefer to use Backbones routing because I find it more flexible and less page-centric. Here is the app:
Click here to run the application in a separate window. The source code is available in this GitHub repository.
31/33
HOW IT WORKS
The key to this approach is to disable jQuery Mobiles routing: In other words, you need to tell jQuery Mobile not to handle links, hash tag changes, and so on. I isolated that code in jqm-config.js: $(document).bind(mobileinit, function () { $.mobile.ajaxEnabled = false; $.mobile.linkBindingEnabled = false; $.mobile.hashListeningEnabled = false; $.mobile.pushStateEnabled = false; }); If jQuery Mobile is not in charge of page navigation, you also have to manually remove the pages from the DOM when they are not used anymore. Here is one way to do it: $($(div[data-role=page]).live(pagehide, function (event, ui) { $(event.currentTarget).remove(); }); With this configuration in place, you use Backbones routing as usual: $.mobile.hashListeningEnabled = false; var AppRouter = Backbone.Router.extend({ $.mobile.pushStateEnabled = false; routes:{ :home, page1:page1, page2:page2 }, home:function () { this.changePage(new HomeView()); }, page1:function () { this.changePage(new Page1View()); }, page2:function () { this.changePage(new Page2View()); }, changePage:function (page) { $(page.el).attr(data-role, page); page.render(); $(body).append($(page.el)); $.mobile.changePage($(page.el), {changeHash:false}); } });
32/33
SOURCE CODE
The source code is available in this repository on GitHub.
John Bender
Ben Nolan
Sample App
MORE INFORMATION
>
ONLINE RESOURCES
JQuery Mobile official website http://jquerymobile.com/ Backbone.js official website http://documentcloud.github.com/backbone/ Backbone-JQuery mobile https://github.com/ccoenraets/backbone-jquerymobile
>
appliness
I had heard about Handlebars from various people. Its also the templating engine that Ember.js uses. Handlebars works by allowing you to define templates using simple script blocks
d n u o laygr
s - Handlebar s e t a l p m e T - Ember
Difficulty
- rookie - intermediate - expert
Todo list
- shave - MVC - use gravatar
by Raymond Camden
34/40
Im probably being overly dramatic, but to me, it feels a lot like ORM. Yeah, its simple to go into a database client, open a table, and add a new field. But when you can do all of that via code... it feels incredibly freeing. You feel yourself trying new and interesting things. In fact, the demo Im going to show has about twice the features I was planning just because it was so damn easy to add. Thats how I feel today - and any day where my computer makes me smile is a good day. Ok, enough rambling. I had heard about Handlebars from various people. Its also the templating engine that Ember.js uses. Handlebars works by allowing you to define templates using simple script blocks, so for example, you can write your template in your document like so: <script id=result-template type=text/x-handlebars-template> <div class=entry> <h1>{{title}}</h1> <div class=body> {{body}} </div> </div> </script> You then use the Handlerbars API to create a template out of the block, apply data to it, and then render it to screen. Its all relatively simple, but the docs dont necessarily do a great job I think of demonstrating simple examples in full pages so you can see things in context. Here is a trivial example: <html> <head> <title>Test 1</title> <script src=js/handlebars-1.0.0.beta.6.js></script> <script id=result-template type=text/x-handlebars-template> <h2>Your Bio</h2> <p> Your name is {{firstname}} {{lastname}} and you are {{age}} years old. </p> </script> <link rel=stylesheet href=style.css type=text/css /> </head> <body> <h2>Render Simple Bio</h2> <input type=text id=firstname placeholder=First Name><br/> <input type=text id=lastname placeholder=Last Name><br/> <input type=number id=age placeholder=Age><br/> <button id=demoButton>Demo</button>
<div id=resultDiv></div> <script> document.addEventListener(DOMContentLoaded, function() { //Get the contents from the script block var source = document.querySelector(#result-template).innerHTML;
35/40
//Compile that baby into a template template = Handlebars.compile(source); document.querySelector(#demoButton).addEventListener(click, function() { var fname = document.querySelector(#firstname).value; var lname = document.querySelector(#lastname).value; var age = document.querySelector(#age).value; var html = template({firstname:fname, lastname:lname,age:age}); document.querySelector(#resultDiv).innerHTML = html; }); }); </script> </body> </html> Notice how Ive got a simple template block on top. If youve never seen Handlebars before, or any JavaScript templating engine, you can probably guess which portions of the block represent dynamic portions and which represent static text. Ive got a simple form with a button bound to a simple click listener. Looking at the JavaScript, you can see that first I have to grab the HTML from the template block. I then compile this. This gives me a template that I can reuse to generate output. My form has a simple click handler. When you hit the button, I pass the values to my template and grab the HTML out of it. You can play with this demo here:
36/40
dynamic templates
Of course, not every template will be a simple set of keys and values. Your template may also need to be dynamic based on the values passed in. Lets look at another example that makes use of both lists and conditionals. <html> <head> <title>Test 2</title> <script src=js/handlebars-1.0.0.beta.6.js></script> <script id=result-template type=text/x-handlebars-template> <h2>Your Favorite Things</h2> {{#if things}} <ul> {{#each things}} <li>{{this}}</li> {{/each}} </ul> {{else}} <p> Apparently, you like nothing. Poor you. </p> {{/if}} </script> <link rel=stylesheet href=style.css type=text/css /> </head> <body> <h2>List of Things</h2> <p> Enter a comma-separated list of things you like. </p> <input type=text id=things placeholder=Things you like...><br/> <button id=demoButton>Demo</button> <div id=resultDiv></div> <script> document.addEventListener(DOMContentLoaded, function() { //Get the contents from the script block var source = document.querySelector(#result-template).innerHTML; //Compile that baby into a template template = Handlebars.compile(source); document.querySelector(#demoButton).addEventListener(click, function() { var things = document.querySelector(#things).value;
37/40
if(things.length) var arrThings = things.split(,); var html = template({things:arrThings}); document.querySelector(#resultDiv).innerHTML = html; }); }); </script> </body> </html> In our template, weve got two things going on here. First is a conditional that checks if things is a truthy value (truthy being one of the things that make JavaScript so fun). Within the true part of the conditional we use an each block to enumerate over a set of values. If you scroll down to the HTML/JavaScript, you can see Im just asking for you to enter a list of things you like. That value is split into an array and passed (if there were values) to the template. Demo is below:
38/40
custom functions
Lets look at one more example. One of the cooler aspects of Handlebars is that you can add custom functions to the engine. For example, you could write a cowbell function that wraps your results in the beautiful rocking sounds of the cowbell. Ok, maybe not that. But what about something a bit complex - like converting an email address into a MD5 hash that could be used for Gravatar? Yeah - no way that would work... <html> <head> <title>Test 3</title> <script src=js/handlebars-1.0.0.beta.6.js></script> <script src=js/webtoolkit.md5.js></script> <script id=result-template type=text/x-handlebars-template> <h2>You and Your Gravatar</h2> <p> Your email is {{email}} and your gravatar is:<br/> <img src={{gravatarurl email }}> </p> </script> <link rel=stylesheet href=style.css type=text/css /> </head> <body> <h2>Enter Email Address for Awesomeness</h2> <input type=email id=email placeholder=Email goes here...> <button id=demoButton>Demo</button> <div id=resultDiv></div> <script> document.addEventListener(DOMContentLoaded, function() { //Tip on using Gravar with JS: http://www.deluxeblogtips.com/2010/04/getgravatar-using-only-javascript.html Handlebars.registerHelper(gravatarurl, function(email) { return http://www.gravatar.com/avatar/ + MD5(email) + .jpg?s=250; }); //Get the contents from the script block var source = document.querySelector(#result-template).innerHTML; //Compile that baby into a template template = Handlebars.compile(source); document.querySelector(#demoButton).addEventListener(click, function() { var email = document.querySelector(#email).value; if(!email.length) return;
39/40
document.querySelector(#resultDiv).innerHTML = html; }); }); </script> </body> </html> Notice in the template we have one simple value, email, and then this: gravatar email. This isnt something built into Handlebars, but rather, injected via the registerHelper function you see in the main script block of the page. The demo is below:
ONLINE RESOURCES Full tutorial with code http://www.raymondcamden.com/index.cfm/2012/4/19/Demo-ofHandlebars-and-why-you-should-consider-a-templating-engine Handlebars http://handlebarsjs.com/ Ember http://emberjs.com/
appliness
the websocket api is one of the more powerful new features in the html5 specification because it opens the door to real-time communication and pushing messages. This article describes a basic chat program that shows the basics of websockets and how to implement them on the client side.
USING WEBSOCKETS
The WebSocket API has been somewhat volatile over the past year as the W3C specification has been solidified. It has finally been completed and the specification can now be implemented consistently across browsers. Why use WebSockets? Instead of using the HTTP protocol, WebSockets use their own protocol. There is a significant amount of overhead incurred whenever communication over HTTP happens. Because of the request/response mechanism and all of the information that HTTP stores in header information, exchanging even basic information can result in lots of data being sent back and forth. WebSockets, by contrast, are full duplex, which means they can communicate back and forth at the same time without the request/response overhead. The header information is also much smaller, so the bulk of the data being exchanged is the actual data from the application.
d n u o laygr
- real-time s e g a s s e m - sockets
Difficulty
- rookie - intermediate - expert
Todo list
- hike - build a chat - read the spec
by Ryan Stewart
41/47
Browser Support for WebSockets Most of the major browsers now support some version of WebSockets. Firefox, Chrome, and the latest version of Internet Explorer all have added support for the WebSocket API. Safari and Opera offer partial support for the API. One of the major issues is understanding which draft of the WebSocket spec is supported by the browsers. Wikipedia has a good entry that lists the specifications by version number and which browser versions support them; for details, visit http://en.wikipedia.org/wiki/WebSocket#Browser_support. Going forward, the final version of the specification, RFC 6455, is the one that will be implemented. Setting Up a Server When working with WebSockets, you need to have a server that supports them. Complete instructions for configuring a server that adheres to the WebSockets specification are beyond the scope of this article, but its an important enough topic to address at least briefly. There are a few different ways to potentially implement WebSockets. PHP ships with built-in support for WebSockets, so you could write your own PHP socket server that handles the requests and responses from the client code. There are also Java and Ruby projects that provide WebSocket support for those languages. One of the more interesting ways to get up and running is a project called Socket.io that runs on Node. js. It has server-side and client-side libraries that make using WebSockets very easy. Node.js lets you use JavaScript on the server so the client- and server-side languages can be the same. For basic socket testing, websocket.org hosts a test server at http://websocket.org/echo.html that will simply send the transmitted data as a response back to the client. The server I use comes from Kevin Hoyt who wrote a socket server using Adobe AIR. For details, see the AIRWebSocket project on Github.
The first line of code above defines the connection object that will be used by the rest of the application. When you make it a global variable, the connection object can be used in other functions. After checking to make sure that the browser supports WebSockets, the code checks to make sure there isnt already a connection active. The WebSocket object provides a readyState property that indicates the connections ready status. The values are as follows: const const const const unsigned unsigned unsigned unsigned short short short short CONNECTING = 0; OPEN = 1; CLOSING = 2; CLOSED = 3;
As long as the readyState is greater than 1, the connection isnt open so the application can connect to the socket server. Connecting to the server is just a matter of instantiating the WebSocket class and passing in the URL and port number of the socket server. The browser then makes a connection with the server. Handling the WebSocket object in Firefox The WebKit browsers and Opera handle WebSockets in the same way, but in Firefox the WebSocket object has a prefix; it is referred to as MozWebSocket. Beyond that, the APIs are the same, so an easy way to keep everything simple is to check for the existence of window.MozWebSocket and then set it to the regular WebSocket object. if (window.MozWebSocket) { window.WebSocket = window.MozWebSocket; } The open event If the connection is successful, the browser will fire an open event. To make sure this gets caught, the WebSocket API includes an onopen property, which is assigned to a function that will run code for every open event. The code below sets the onopen property to a corresponding onopen() function that sets a couple of variables so that the UI is updated to indicate that the user is logged in. window.WebSocket Here is the onopen() function: function onopen (event) { document.getElementById(connected).innerHTML = Connected; document.getElementById(chat).innerHTML = You have joined the chat<br />; } Note that most people dont actually assign those methods to named functions but rather include them in anonymous functions right where they are first defined. I have implemented it this way because I like having the separation, but it may seem a bit redundant to you as you dig into more WebSocket examples.
43/47
Managing Data
Now that your client is connected you can start dealing with actual chat messages. The server I have set up for the moment just cycles through all of the currently connected users whenever it gets a message and then sends that message out to all of those users. Though it is a pretty basic chat server, it illustrates many key WebSocket concepts. Sending messages With WebSockets you can send text, or UTF-8 data, as well as binary data such as pictures or videos. They both use the same API on the client side, but it will largely depend on the server to actually handle the data types correctly. To send a message to the socket server the chat application simply invokes the send() method of the connection object. It takes a single parameter, the message being sent, which it passes to the socket server. When the user clicks on the Send Message button in the chat application, the sendmessage() method sends the message typed by the user along with the username. The socket server will then loop through all the clients, including the sender, and deliver the message to them. function sendmessage() { var messagetext = document.getElementById(chatmessage).value; messagetext = username + : + messagetext; connection.send(messagetext); }
Receiving messages To handle incoming messages, the WebSocket API uses the onmessage property of the connection event. Just like the onopen property covered earlier, this property takes a function that will be called whenever a new message arrives. So the first step is to set up the event handler in the original connect() method right before the onopen definition: connection.onmessage = onmessage; Once that is set up, define the onmessage() function: function onmessage (event) { var chatdiv = document.getElementById(chat); chatdiv.innerHTML = chatdiv.innerHTML + event.data + <br />; } The event that is received by onmessage is of type MessageEvent . It includes a data property that has the value of the message being received. In this case, that is used to display the chat text. This data property includes the username of the chat participant along with the message they sent. This value is appended to the chat div window.
44/47
Handling errors Error handling is an important topic to cover, even if only quickly. Along with onopen and onmessage, the WebSocket API also includes an onerror property, which takes a function that runs any time an error occurs. The error event includes a data property that provides some information about the error. Here is the basic error handler used in the chat application: function onerror(event) { console.log(event); document.getElementById(chat).innerHTML = There was an error: + event. data; }
Going binary
By enabling the exchange of real-time data, the WebSocket API opens some interesting possibilities when combined with the rest of the host of new HTML5, JavaScript, and CSS3 features. One of the cooler demos Ive seen is a collaborative whiteboard using the canvas element. Every time someone connected to the socket draws on it, a message gets sent out to the connected clients so everyone can see what is being drawn. Its a neat idea, but all thats really happening under the hood is that the socket server and application are exchanging a set of x and y coordinates in text. To illustrate the binary capabilities of the WebSocket API, I implemented a similar application that uses binary data. Specifically, I implemented a quick canvas painting feature that the user can use to draw something on a small canvas area. When the user clicks a button, the application does not send a set of coordinates to the socket server, but rather takes a snapshot of the image and sends it as binary data to the socket server. The socket server sends the data back as an image, which will appear in the chat window of all connected clients. This demo will only work in the latest version of Chrome because binary WebSocket support is still somewhat on the cutting edge. Creating binary data To send and receive binary data correctly you need to set up a binaryType for the WebSocket API. The binaryType can be either arraybuffer or blob , which are the two basic binary types that JavaScript supports. You can use either one depending on what youre sending and how you want to access it. I found arraybuffer to be ideal for this example because its easy to iterate through an array, and I found that I had to copy a lot of data back and forth between arrays. So the WebSocket setup code becomes this: connection = new WebSocket(ws://localhost:1740); connection.binaryType = arraybuffer; connection.onopen = onopen; connection.onmessage = onmessage; connection.onclose = onclose; connection.onerror = onerror;
45/47
Now you need to get binary data out of the canvas. I wrote a sendphoto() method that does the work of pulling the binary data out of the canvas element on the page. It uses the getImageData() method to get the actual binary array data and then it loops through the data and inserts it into a Uint8Array. The code accesses the buffer property of this array and sends it using the WebSocket API. function sendphoto() { imagedata = context.getImageData(0, 0, imagewidth,imageheight); var canvaspixelarray = imagedata.data; var canvaspixellen = canvaspixelarray.length; var bytearray = new Uint8Array(canvaspixellen); for (var i=0;i<canvaspixellen;++i) { bytearray[i] = canvaspixelarray[i]; } connection.send(bytearray.buffer); context.fillStyle = #ffffff; context.fillRect(0, 0, imagewidth,imageheight);
That data goes to the socket server and the socket server sends the binary data back out to all of the connected clients. If youre interested in seeing how the server does that, you can take a look at the Github project for the code. Receiving a binary message To handle incoming binary messages, youll need to modify the onmessage() function. Because youll have to handle two types of data, the ArrayBuffer and the String data, youll want to check the instanceof property of event.data and route the data accordingly. Once you do that, the process will be to translate the ArrayBuffer data into a typed JavaScript array. Then, create a temporary Canvas element that is used to insert the ArrayBuffer data by manipulating the image data of the canvas. Finally, with the image stored in the temporary canvas, use the toDataURL() method to get a URL string that you can set as the source of an img element, which then gets displayed on the screen. if(event.data instanceof ArrayBuffer) { var bytearray = new Uint8Array(event.data); var tempcanvas = document.createElement(canvas); tempcanvas.height = imageheight; tempcanvas.width = imagewidth; var tempcontext = tempcanvas.getContext(2d);
46/47
var imgdata = tempcontext.getImageData(0,0,imagewidth,imageheight); var imgdatalen = imgdata.data.length; for(var i=8;i<imgdatalen;i++) { imgdata.data[i] = bytearray[i]; } tempcontext.putImageData(imgdata,0,0); var img = document.createElement(img); img.height = imageheight; img.width = imagewidth; img.src = tempcanvas.toDataURL(); chatdiv.appendChild(img); chatdiv.innerHTML = chatdiv.innerHTML + <br />;
And with that, youre sending and receiving text and binary messages with the WebSocket API.
+ This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. Permissions beyond the scope of this license, pertaining to the examples of code included within this work are available at Adobe.
MORE INFORMATION
>
>
appliness
The swipe gesture has been broadly used on list to remove items, especially in native ios applications. lets code this behavior with jquery mobile.
Hybrid applications raise a lot of UI and technical challenges. Using web standards, developers are working hard to reproduce native UI behaviors without impacting the global performance of their application. The swipe gesture is one of them. Today, jQuery Mobile handle swipe events which are triggered when a horizontal drag of 30px or more occurs within 1 second duration. But these thresholds can be configured. To play with this event, well use a simple jQuery Mobile list and manage a two-step deletion task. First, the user will swipe on an item. Then, an active delete button appears to confirm the deletion. The swipe gesture is ideal for actions that requires an user confirmation.
d n u o laygr
e l i b o m y r - jQue s s a l C e l g g - To - Events
Difficulty
- rookie - intermediate - expert
Todo list
- swipe left - buy milk - try on iOS
by Michal Chaize
48/52
try
i
me
49/52
<html> <head> <meta http-equiv=Content-Type content=text/html; charset=UTF-8 /> <title>swipe</title> <link type=text/css rel=stylesheet href=http://code.jquery.com/mobile/1.1.0-rc.1/jquery.mobile-1.1.0-rc.1.min.css/> <script src=http://code.jquery.com/jquery-1.7.1.min.js/></script> <script src=http://code.jquery.com/mobile/1.1.0-rc.1/jquery.mobile-1.1.0-rc.1.min.js></script> <script type=text/javascript src=myScript.js> </script> <style> div.menu{ height: 0px; overflow:hidden; position:absolute; top:0; right:0; -webkit-transition: all 0.2s ease-in-out; } div.menu.active { position:absolute; top:0; right:0; width:160px; height:50px; } .myItem{ height:40px; vertical-align:middle; } .ui-btn{ width:140px; } .myItem.active{ color:#CC0000; } </style> <meta name=viewport content=width=device-width; initial-scale=1.0; maximum-scale=1.0; userscalable=0; /> </head>
<body> <div data-role=page id=page1> <div data-role=header data-position=fixed> <h1>Swipe events</h1> </div> <div data-role=content> <div class=list-questions> <ul data-role=listview id=listQuestions> </ul> </div> </div> </div></body></html>
i
50/52
$( document ).delegate(#page1, pageinit, function() { $.ajax({ type: GET, url: questions.xml, dataType: xml, success: function(xml){ var i=0; var myItems = ; $(xml).find(question).each(function() { var titleQuestion = $(this).find(title).text(); myItems += <li id=listItem+i+><div class=myItem>+titleQ uestion+<div class=menu><a id=myButton+i+ data-role=button dataicon=delete data-inline=false>Delete</a></div></div></li>; i = i+ 1; }); $(#listQuestions).html(myItems); $(#listQuestions).listview(refresh); $(#listQuestions).trigger(create); addBinding(); } }); });
function addBinding(){ for(var j=0; j< $(#listQuestions li).size();j++){ $(#listItem+j).bind(swipe,function(event) { $(div.menu, this).toggleClass(active); $(div.myItem, this).toggleClass(active); }); $(#myButton+j).attr(index,j); $(#myButton+j).bind(tap,function(event) { theIndex = $(# + event.currentTarget.id).attr(index);
51/52
ONLINE RESOURCES JQuery Mobile official website http://jquerymobile.com/ PhoneGap official website http://www.phonegap.com Using JQuery mobile themes http://www.adobe.com/fr/devnet/dreamweaver/articles/themecontrol-jquery-mobile.html
appliness
http://appliness.com/code/02.zip
appliness
app-UI is a collection of reusable application container user interface components that may be helpful to web and mobile developers for creating interactive applications using HTML and JavaScript, especially those targeting mobile devices.
app-UI is a continual work in progress it was born out of the necessity to have rich & native-feeling interfaces in HTML/JS experiences, and it works great with PhoneGap applications (http://www.phonegap.com). app-UI can easily be styled/customized using CSS. All of app-UI was created using HTML, CSS, & JavaScript. All animations are rendered using CSS3 translate3d, so that they are hardware accelerated (where supported). app-UI works well on iOS, Android and BlackBerry browsers (others not tested), and works well on the latest releases of most desktop browsers (I know it does not work on old versions of IE).
54/58
Application Containers
app-UI currently has three application containers, and at this time it is not intended to be a complete UI widget framework.
ViewNavigator
The ViewNavigator component allows you to create mobile experiences with an easily recognizable mobile UI paradigm. You use this to push & pop views from the stack.
55/58
The ViewNavigator component allows you to create mobile experiences with an easily recognizable mobile UI paradigm. You use this to push & pop views from the stack. Some code used in the sample: $(document).ready( function() { //Setup the default view var defaultView = getView(); defaultView.backLabel = null; //Setup the ViewNavigator window.viewNavigator = new ViewNavigator( body ); window.viewNavigator.pushView( defaultView ); } ); function pushView() { //create a view and push it onto the view navigator var view = getView(); window.viewNavigator.pushView( view ); } function popView() { //pop a view from the view navigator window.viewNavigator.popView(); } function getView() { //create a view descriptor with random content var bodyView = $(<div> + Math.random().toString() + <hr><li href=# onclick=pushView() class=viewNavigator_backButton>push view</li> <li href=# onclick=popView() class=viewNavigator_backButton>pop view</li><hr> + getMeat() + </div>); var links = bodyView.find(a); return { title: Default View + parseInt(Math.random()*1000), backLabel: Back, view: bodyView }; }
56/58
SplitViewNavigator
The SplitViewNavigator component allows you to create tablet experiences with an easily recognizable mobile UI paradigm. The SplitViewNavigator allows you to have side-by-side content in the landscape orientation, and the sidebar is hidden in portrait orientation.
57/58
function getSidebarView() { var viewHTML = <ul> + <li onclick=pushSidebarView() class=viewNavigator_ backButton>Push Sidebar View</li> + <li onclick=window.splitViewNavigator.popSidebarView() class=viewNavigator_backButton>Pop Sidebar View</li> + <li onclick=pushBodyView() class=viewNavigator_backButton>Push Body View</li> + <li onclick=window.splitViewNavigator.popBodyView() class=viewNavigator_backButton>Pop Body View</li> + </ul>; return { title: Sidebar + parseInt( Math.random() * 100 ).toString(), backLabel: Back, view: $(viewHTML) }; } function pushSidebarView() { window.splitViewNavigator.pushSidebarView( getSidebarView() ); }
SlidingView
The SlidingView allows content to slide to the side using a horizontal swipe gesture, revealing a navigation container underneath. This is very similar to the behavior in Facebooks iPad application. Just swipe horizontally with a finger:
MORE INFORMATION
>
>
appliness
IAN DEVLIN, THE AUTHOR OF HTML5 Multimedia: Develop and Design explains how to use the HTML5 VIDEO AND AUDIO ELEMENTS, AND HOW TO CREate custom playback components.
enough to write a book on HTML5 Multimedia with Peachpit. What are you currently working on? Nothing special est. Ive re c e n t moved Germaso Ive b e e n concentrating on settling in here and trying to improve my German. That said, I did find the time to redesign my to be hono n l y l y t o ny
website, including a custom built Wordpress theme (based on HTML5 Starkers though which sped up the process!). In addition my job requires learning some new technologies such as TYPO3 which is used a lot in Germany so I have that to do too. I am trying to find some personal project to work on though, so if anyone needs a co-conspirator... Youre a recognized HTML5 expert, especially when it deals with Multimedia elements such as video and audio. Why did you focus on this topic? It happened by accident! I curate for HTML5 Gallery and Peachpit, now my publisher, who were looking for someone to write a book on HTML5 multimedia and they approached us. Writing a book was something I had never thought about doing before but I thought that this would be a good opportunity so I went for it. I knew the basics of using HTML5 multimedia already of course, but there were other related topics that I had to learn in order to be able to write about them. This was ideal though as I would read about something, test it, and then write about it in an orderly fashion while it was still fresh in my mind. So it wasnt planned and I focused on it as I had a book to write! Apple encouraged the use of the HTML5 video tag when they launched devices without Flash. What has evolved since this positioning that happened 2 years ago? Do you feel that HTML5 is rapidly growing and evolving to broadcast multimedia content? I think a lot of developers were already aware of HTML5 multimedia and the <audio> and <video> elements, but Apples announcement probably increased this number (of developers) but also brought it to the attention of nondevelopers who suddenly had to find another method of delivering video and audio to Apple devices. A number of related JavaScript APIs which utilise HTML5 multimedia are currently being developed that allow more advanced audio manipulation and also the ability to access a devices web cam (e.g. Opera have re-
leased a demo of this). Eventually it will probably be possible to have video conferencing in the browser using HTML5 alone. In your opinion, what should be improved in the current HTML5 specifications for multimedia content? The issue of DRM is a big one for some companies who have a business requirement for protected content. Not everyone agrees with this requirement, but I feel thats a moot point as you wont change that mindset for a long time. This has restricted these big companies from using HTML5 multimedia and I think that something to facilitate these companies requirements should be added. That said, there is currently a proposal to explore this topic and potentially either add it to the HTML5 specification or create a separate but related specification that supports it. Whether you agree with DRM or not, its addition would increase take up. Do you have in mind an amazing HTML5 multimedia experience that we could share with the readers? I dont know about amazing, but I think there will come a time when the afformentioned video conferencing with configurable sound and automatic subtitles (if required) will be possible and quite useful. HTML5 already helps with subtitles via WebVTT and I think itll be possible to either have someone translating on the fly (in the same way subtitles are added to live TV programmes) and entering values that way. With some of the sound APIs being worked on, browser games and videos in general should hopefully be able to take advantage of all the capabilities of advanced sound systems (e.g., surround sound) through the browser. You blog, you also wrote a book... Would you say that sharing your knowledge is essential for you and for developers in general? Sharing knowledge is not essential, but definitely very useful. I cant count the number
of times Ive come across a problem, gone to Google and found that others have had the exact same issue and solved it. Even if the solution isnt presented, blog and forum posts can lead to discussions that will set you on the right track, or even off on a tangent to creating something else. As web develoeprs were constantly learning, especially from each other. Im a big fan of the music band called Justice. Now that we get the Audio and the Video elements in HTML5, should we get the Disco tag pretty soon? My first thought on reading that was that it would be similar to the <blink> tag that was deprecated in HTML5! Id envision it taking a number of images and flashing them to the screen with various filters...and that cant be a good thing! Interview by Michal Chaize
Topics include: - Using Audio: How to add audio to web documents using the HTML5 audio element. - Using Video: How to add video to web documents using the HTML5 video element. - JavaScript API and Custom Controls: How to use the HTML5 Media JavaScript API to create custom controls for HTML5 audio and video. - Styling Media Elements with CSS: Shows how HTML5 media elements can be styled with CSS2.1 and CSS3. - Using Video with SVG: Shows how SVG and HTML5 video can work together. - Using Video with Canvas: Introduces the HTML5 canvas element and shows how HTML5 video and canvas can work together.
appliness
This new ability for browsers to provide native video has made it easier for web developers to add video content to their websites without having to rely on the availability of external technology.
d n u o laygr
Difficulty
- rookie - intermediate - expert
Todo list
- encode - play - fallback
by Ian Devlin
62/68
VIDEO CODECS
Video codecs are software that encode or decode video for a specific file format. Although the HTML5 specification initially mandated support for the Theora Ogg video codec, this requirement was dropped from the specification after it was challenged by Apple and Nokia. Sadly, this means that different browsers support different codecs, which sounds like a bit of a pain and it is. Recently, however, the situation has improved so that you actually only need to provide your video content in two different formats: MP4/H.264 for Safari and Internet Explorer 9, and WebM for Firefox, Chrome, and Opera. Firefox also supports Theora Ogg, but it has supported WebM since version 4. There is, of course, a way to define more than one video file for your video content, but Ill cover that a bit later.
VIDEO ELEMENT
The video element, which you use to embed the video into your web page, can include several different attributes, some of which are outlined in this table. Attribute src autoplay controls muted loop Description Provides the URL of the video file. Indicates that the video should be started automatically, where possible. Tells the browser to display its default video control set. Sets the videos initial audio state to muted. (This attribute is currently not supported by any browser.) Indicates that the video should be played continuously in a loop. (Firefox currently doesnt support this attribute.)
63/68
Description Sets a default image to display instead of the videos first frame. Specifies the width of the video element in pixels. Specifies the height of the video element in pixels. Suggests to the browser how it should attempt to preload the video in question. It can have three possible values: - none: dont perform any preloading - metadata: only load the videos metadata, for example, duration - auto: lets the browser decide for itself (this is the default)
For example, if you want a video to play automatically and for the browser to provide the controls, you simply use: <video src=myVideo.mp4 autoplay controls></video>
To specify both an MP4 and WebM source for the same video, you could use the following code: <video autoplay controls> <source src=myVideo.mp4 type=video/mp4> <source src=myVideo.webm type=video/webm> </video> When a browser attempts to play the video, it will check the list of sources until it finds one that it can play. So Firefox will skip the MP4 source as it is unable to play it, but it will happily play the WebM source file. Note that in the previous example Ive removed the src attribute from the video element itself since the src attributes in the source element are being used instead. If you did specify the src attribute in the video element, it would override any src attributes in the source elements. If you wish, you can specify the exact codec that was used to encode the video file. This helps the brows64/68
er decide whether it can play the video or not. Its generally a better idea to simply provide the type and let the browser decide for itself, as often youre not sure of what codec was actually used. Should you wish to include the codec, you can do so as follows: <video autoplay controls> <source src=myVideo.mp4 type=video/mp4; codec=mp4a.40.2> <source src=myVideo.webm type=video/webm; codec=vp8> </video> Note how the codec is added to the type attribute, specifically the quotes used and the separation of the type and codec by a semicolon. When adding the codec to the type definition, its relatively easy to misplace the quotes, which will make the video unplayable because the browser will be unable to parse the source element. So, if you decide to specify the codecs explicitly, be careful.
LEGACY FALLBACK
Of course, youll also need to provide a solution for those users who continue to use a browser that doesnt support HTML5, such as Internet Explorer 8 and below. Since browsers ignore what they dont understand, legacy browsers such as Internet Explorer 8 will ignore the video and source elements and simply act as if they dont exist. You can take advantage of this behavior to provide an alternative method of displaying your video, either via a simple download link, or a third-party plug-in such as Flash Player. Building on the earlier example, you might provide a link to the same video as follows: <video autoplay controls> <source src=myVideo.mp4 type=video/mp4> <source src=myVideo.webm type=video/webm> <a href=myVideo.mp4>Download the video</a> </video> The legacy browser will only display the link to the video file download. Adding support for Flash Player is just as easy: <video autoplay controls> <source src=myVideo.mp4 type=video/mp4> <source src=myVideo.webm type=video/webm> <object type=application/x-shockwave-flash data=player. swf?videoUrl=myVideo.mp4&autoPlay=true> <param name=movie value=player.swf?videoUrl=mVideo mp4&autoPlay=true> </object> <a href=myVideo.mp4>Download the video</a> </video>
65/68
With this example, an older browser such as Internet Explorer 8 will display the video in Flash Player (if Flash Player is installed on the system) and also the download link. By providing a download link as well as a Flash Player fallback, youre giving users who dont have Flash Player installed a way access the video by downloading it and viewing it from their desktop.
Video subtitling
The provision of subtitling for HTML5 video was initially part of the HTML5 specification. A file format called WebSRT was defined, and this format could be used to specify video subtitles using the popular SRT file format. Later renamed to WebVTT (Web Video Text Tracks), the subtitling specification was taken out of the HTML5 specification and given a specification of its own. A WebVTT file is a specially formatted text file with a .vtt file extension. The file itself must be UTF-8 encoded and labeled with the type/vtt MIME type. The file must begin with a WebVTT string at the top. Lines within the file are terminated by a carriage return (\r), a new line (\n), or a carriage return followed by a new line (\r\n). The file consists of a number of cues, which are used to specify the text and timing location within the video file of the subtitle in question. The basic format is as follows: WEBVTT [unique-cue-identifier] [hh]mm:ss.msmsms --> [hh]mm:ss.msmsms [cue settings] Subtitle text 1 [Subtitle text 2] ... The unique-cue-identifier is optional. It is a simple string that helps identify the cue within the file. The cue timing is given in a straightforward format, with the hour portion optional. Each cue can also have a number of cue settings, which are used to align and position the text. These are described in more detail below. Next follows the actual text of the subtitle, on one or more lines.
66/68
The individual cues for different time locations within the video file are set up in this way, with each cue block separated by a new line. Here is a short example: WEBVTT 1 00:00:10.500 --> 00:00:13.000 Elephants Dream 2 00:00:15.000 --> 00:00:18.000 At the left we can see... You can use the cue settings to specify the location and alignment of the subtitle text that is overlaid on the video. There are five such settings, as shown in this table. Cue setting D:vertical | vertical-lr L:value A:start | middle | end T:value S:value Description The text direction: vertical right-to-left or vertical left-toright. The line position, either in percentage values or a specific line number. The alignment of the text relative to the line. The text position, in percentage, relative to the video frame. The text size, in percentage.
For example, to position text at the end of the line, 10% from the top of the video frame, you would use the following cue settings: 2 00:00:15.000 --> 00:00:18.000 A:end L:10% At the left we can see... You can see how the WebVTT file can be built up in this way to add subtitles to an entire video. You may be wondering how you link your WebVTT file to your video. The answer is the track element. This element, which was also introduced in HTML5, lets you specify external text tracks for media elements such as video. Its attributes are shown in the following table. Attribute kind src srclang Description The type of content for the track definition. Can be one of: subtitles, captions, descriptions, chapters, metadata. The URL to the text track, in this case the WebVTT file. The language of the text track data.
67/68
label default
A user-readable label for the text track. If present, indicates that this text track is the default.
For example, consider a WebVTT file named english-subtitles.vtt that you want to attach to the video example used above. You could do this using the following code: <video autoplay controls> <source src=myVideo.mp4 type=video/mp4> <source src=myVideo.webm type=video/webm> <track src=english-subtitles.vtt kind=subtitles srclang=en label=English subtitles> </video> This ties the WebVTT file with English subtitles to your video. You can, of course, have multiple track elements within the video element. With the srclang attribute you can specify multiple WebVTT files that are in different languages to add subtitle support in multiple languages. (The default attribute can then be used to identify the track to use if the users preferences to not indicate a more appropriate track.) Unfortunately, no browsers currently support WebVTT directly, but there are a number of JavaScript libraries available that enable you to use the WebVTT file format and provide subtitles for your videos, including: - Playr - Captionator (CaptionCrunch version) - LeanBack Player - MediaElement.js All of these solutions support video subtitles, and some offer additional features. Browsers are beginning to add support with both Safari and Firefox making advancements towards support, and Microsoft have recently posted a demo on WebVTT which shows how serious vendors are about supporting WebVTT in the near future. You have seen how easy it is to add HTML5 video to your web pages and provide a fallback method using Flash Player to serve video content to legacy browser users. As powerful as it is, HTML5 video is not currently advisable for those wishing to protect their video content, as it provides no DRM capability. You also saw, briefly, how you will be able to add subtitles to your videos in the future, and how you can do it now via JavaScript libraries.
appliness
In this ARTICLE I cover the audio element, its attributes, and the different types of audio files that can be used with HTML5. Many of the concepts and techniques covered in the previous article for video apply to audio as well.
d n u o laygr
Difficulty
- rookie - intermediate - expert
Todo list
encode listen protect
by Ian Devlin
69/72
AUDIO CODECS
I covered video codecs in Part 1 of this series, and it will come as no surprise to learn that many of the ideas carry over to audio codecs. The HTML5 specification initially had made support for the Ogg Vorbis codec mandatory, but Apple and Nokias challenge put an end to this. Browsers today support more audio codecs than video codecs, so you have more choices when deciding what to use: - Firefox supports Ogg Vorbis and WAV. - Safari supports MP3, AAC, WAV, and MP4. - Internet Explorer 9 supports MP3, AAC, and MP4. - Opera supports Ogg Vorbis and WAV. - Chrome supports all of the above. To cover all browsers that support HTML5 audio, you need to serve your audio in only two different formats: Ogg Vorbis and MP3. Its not advised to use the WAV file format as it doesnt compress very well if at all and therefore the file size can be quite large.
70/72
Description Tells the browser to display its default audio control set. Sets the initial audio state to muted. (This attribute is currently not supported by any browser.) Indicates that the audio should be played continuously in a loop. (Firefox currently doesnt support this attribute.) Suggests to the browser how it should attempt to preload the audio in question. It can have three possible values: - none: dont perform any preloading - metadata: only load the audios metadata, for example, duration - auto: lets the browser decide for itself (this is the default)
For example, with the audio element and its attributes, you can use the following code to embed an MP3 audio file that starts playing on load, has a default set of controls, and loops repeatedly: <audio src=myAudio.mp3 autoplay controls loop></audio> I must point out that this example would likely be quite annoying to your users. Automatically playing a looping audio file is generally considered to be bad Internet etiquette.
Note how the codec is added to the type attribute, specifically the quotes used and the separation of the type and codec by a semicolon. As with specifying the video codec, its not difficult to make a formatting mistake here that will render the audio unplayable. So, if youre specifying the codecs explicitly, be careful with the syntax.
LEGACY FALLBACK
Not everyone uses a browser that supports HTML5. Older versions of Internet Explorer (version 8 and below), for example, are still quite popular. To support users who are using these browsers, you can use a third-party plug-in such as Flash Player to embed audio files, just as you would have before the arrival of HTML5 and native multimedia. Browsers disregard what they dont understand, so your HTML5 audio and source elements will be completely ignored by older browsers such as Internet Explorer 8. For example, you might use the following code to add a link to the audio file: <audio autoplay controls> <source src=myAudio.ogg type=audio/ogg> <source src=myAudio.mp3 type=audio/mp3> <a href=myAudio.mp3>Download the audio file</a> </audio> Older browsers will simply display the Download the audio file link and ignore the rest. To add fallback support via Flash Player (as well as the download link) you can use the following code: <audio autoplay controls> <source src=myAudio.ogg type=audio/ogg> <source src=myAudio.mp3 type=audio/mp3> <object type=application/x-shockwave-flash data=player. swf?audioUrl=myAudio.mp3&autoPlay=true> <param name=movie value=player.swf?audioUrl=myAudio. mp3&autoPlay=true> </object> <a href=myAudio.mp3>Download the audio file</a> </audio> Older browsers will display Flash Player and the download link, so users can choose how they want to access the audio. If a user doesnt have Flash Player installed they can still access your audio file via the download link. Note that you can use the same MP3 audio file with Flash Player, since it is fully capable of playing MP3 files.
appliness
If you want to achieve a uniform look across browsers for your media controls, you can use the handy HTML5 media element API. You can create and style your own media control set using standard HTML and CSS and then use the media element API to hook it up to the audio and video elements you want to control.
d n u o laygr
Difficulty
- rookie - intermediate - expert
- HTML5 s t n e n o p m - co t p i r c S a v a J -
Todo list
- play - pause - rewind
by Ian Devlin
73/79
Getting started
To begin with, youll need to define a video element to use with the yet to be created media player: <video id=video controls> <source src=grass-in-the-wind-sma.mp4 type=video/mp4> <source src=grass-in-the-wind-sma.webm type=video/webm> </video> Youll notice that the controls attribute has been defined for the video, even though youre going to create your own. Since your custom controls will be built in JavaScript, youre going to turn the default controls off via JavaScript. That way, if a user has JavaScript turned off, theyll still be served with the browsers default control set. To turn the default controls off, you simply set the video elements controls attribute to false: <script> // Grab a handle to the video var video = document.getElementById(video); // Turn off the default controls video.controls = false; </script> And with that, youre ready to move on!
To have this function invoked every time the play/pause button is clicked, you add it to the onclick event of the button: <button id=playpause title=play onclick=togglePlayPause()>Play</button> The first line of the togglePlayPause() function obtains a handle to the play/pause button itself, and assigns it to the variable playpause: var playpause = document.getElementById(playpause); Next, it checks the status of the video to see if its paused or ended, via the two attributes paused and ended. If the video is in either of these states, it then sets the buttons title and innerHTML attributes to pause and calls video.play() to start playing the video. If the video is not currently paused or ended, then you can assume it is already playing. In this case, the function sets the buttons title and innerHTML to play and calls video.pause() to pause the video. The buttons default text is play. When the button is clicked for the first time, the video will start playing and the buttons text will be changed to pause. Subsequently, when the pause button is clicked, the video will pause and the buttons text will be changed back to play. As youll see, the remaining functionality that youll add in this tutorial follows the same basic format: listen for an event from the video element, check the elements status, and then act on it via API methods.
Note: Firefox 7 doesnt support the range input type and displays a text field instead. Typing a new value in this text field (between 0 and 1) and moving the focus away from the text field will alter the volume in this browser. Adding a mute button is just as easy. Again, you start by defining a new button, this time with an onclick handler: <button id=mute onclick=toggleMute()>Mute</button> Next, create a function named toggleMute(): function toggleMute() { video.muted = !video.muted; } This function simply sets the video elements (Boolean) muted attribute to be the opposite of its current value. This toggles the mute status of the button. Easy!
The first line of this function obtains a handle to the progress span element itself. It checks the value of the video elements currentTime attribute, which defines the current playback position, in seconds. If currentTime is greater than 0, and therefore the video has advanced, it calculates the current progress as a percentage using the video elements duration attribute, which contains the videos total length in seconds. Finally, it sets the CSS width of the progress span to this calculated value. With the play, pause, mute, and volume controls you used events such as onclick and onchange to invoke the appropriate functions. You cant use this approach with a progress bar, because it updates in response to video progress, not user interaction. The HTML5 media element API, however, raises a number of events that you can listen for and act upon instead. One of these is the timeupdate event, which fires every time the medias currentTime attribute is changed. (This attribute changes as the media is played.) In the JavaScript initialization code of your web page, add an event listener that invokes the updateProgress function when the timeupdate event fires: video.addEventListener(timeupdate, updateProgress, false); Now your progress bar will be updated as the video plays.
When youre adding custom controls, its good practice to listen for some of the available events to make sure your controls are always synchronized with the state of the video. How might the controls lose synchronization? Recall that you removed the default control set via JavaScript. It is possible, however, for a user to reenable these controls and use them to interact with the video. For example, in Firefox, a user can right-click the video, select Show Controls, and click Play or Pause. If a user did this and started a video playing, then the text on the play/pause button that you created would no longer accurately reflect the medias current state. Regardless of what mechanism is used to control the video, the appropriate events will still be raised. So you can listen for the pause and play events and act on them accordingly to keep your buttons in synch; for example:
video.addEventListener(play, function() { var playpause = document.getElementById(playpause); playpause.title = pause; playpause.innerHTML = pause; }, false); video.addEventListener(pause, function() { var playpause = document.getElementById(playpause); playpause.title = play; playpause.innerHTML = play; }, false); You should also listen for the ended event, so that when the video ends, the play/pause button is also kept up to date. You can do this by calling the pause() method on the video when the ended event is raised: video.addEventListener(ended, function() { this.pause(); }, false); Note: The reason you call the pause() method here is that it automatically causes the pause event to be raised which will in turn cause the code weve written above for the pause event handler to be called. You could indeed duplicate the code in the ended event handler, or, if you wanted to do something different or extra, you would define it here.
Adding a playlist
The final feature to add is a media playlist, which the user can use to change the video played in the media player. This is actually quite simple. First of all you define your playlist; for example: <ul id=playlist> <li><a href=# onclick=playlistClick(grass-in-the-wind-sma);>Grass blowing in the wind</a></li> <li><a href=# onclick=playlistClick(tree-in-the-wind-sma);>Trees blowing in the wind</a></li> </ul> There are two items in this playlist, and each calls a function named playlistClick() when clicked. This function takes a single argument: the stem of the video file it is to play (that is, the file name without the file extension). This function is defined as follows: function playlistClick(file) { var v = document.createElement(video); if (v.canPlayType(video/mp4) != ) { changeSource(file + .mp4); } else if (v.canPlayType(video/webm) != ) { changeSource(file + .webm); } return false; } This function first creates a temporary video element and then calls the canPlayType() method for each of the supported video types, which in this case are MP4 and WebM. After determining which file type the browser is capable of playing, it calls changeSource() with one argument, the file stem that
was passed into the function concatenated with the appropriate file extension. This function also returns false to prevent the element from following the link to the value of its href attribute. The changeSource() function is defined as follows: function changeSource(src) { resetPlayer(); video.src = src; video.load(); } This function calls resetPlayer(), which youll look at next, and then sets the video elements src attribute to the new video file that has been passed as an attribute. Finally, it calls load() to load the new video source into the video element. Note: Not all browsers require the load() method to be called, but Safari does. Therefore its a good idea to call it. The resetPlayer() function resets a few of the players components in preparation for loading a new video: function resetPlayer() { var playpause = document.getElementById(playpause); playpause.title = play; playpause.innerHTML = play; if (video.currentTime > 0) video.currentTime = 0; updateProgress(); } First, it sets the play/pause button text to play. Next it resets the video elements currentTime variable to 0 if its not already at 0. Finally it calls the updateProgress() function, which will reset the progress bar back to the start. (The progress bar uses the video elements currentTime attribute, which was just set to 0.)
PAMELA FOX
To me, programming wasnt about math, it was about making apps that people could interact with, and thats what was so cool about it.
80/83
ee why this twenty-something-year old shy girl is asked to speak at conferences and user groups around the world...that is, when shes not reading, writing, coding or just generally horsing around.
Hi Pamela, its a great honor that you have agreed to an interview for the second issue of Appliness magazine (BTW, our first, of hopefully many, women interviewees). Can you introduce yourself to our readers? I'm a twenty-something-year-old living in San Francisco. I suppose I would be best described as a web developer, though I've never identified as one. I just like making stuff, and coding is my means to that end.
What do you think are some roadblocks in the way of developers effectively deciding on a mobile strategy? In preparing a talk on mobile app strategies a few months ago, I researched the different mobile app platforms out there and discovered that there are a huge number of them, with a variety of input languages, optimal use cases, and pricing models. But, the fact that there are so many of them and that theyre so new makes it hard for developers to pick one. A platform might look promising from the landing page, but it may play out very differently. Does it breakdown when you try to customize it? Does it perform horribly? Does with their support suck?
I graduated from USC in 2007 with a bachelors and masters in Computer Science, with minors in Linguistics and 3-D animation. After that, I spent 5 years in Google Developer Relations working on the widely successful Maps API, and the went ill-fated Wave API. (Hey, you win some, I you lose some). I recently left Google to PhoneGap and I When Im thinking of using a new platpursue my own projects and see what form, I take to Twitter and ask my followthey might turn into. I've been working achieve my goal of ers what they think of it, and Ill usually on a nutrition-tracking service (eatdifre-usability... get a handful of responses reporting on ferent.com) for almost a year now, and the good and the bad of it. But Im in since I offer both web (Python/AppEnthe fortunate situation of having a sizable number gine) and mobile (PhoneGap/HTML5) interfaces for of followers to ask, and most developers arent. it, it's been a great learning experience. On my blog a few months ago, I proposed what I called a yelp for developers - a review site for developer platforms, so you could see, at a glance, It sounds like you got an early start in the world of what other developers think about the platform beprogramming. How old were you when you really got fore you start developing with it. Id argue its more interested in computers and programming? important to have a yelp for developers than a yelp for restaurants, because hey, a meal only lasts a few On one fateful Mothers Day, I realised I did not hours, but an app can last months. Maybe Yelp will have a gift for my mum, and since we lived approxipivot. :) mately in the middle of nowhere, I didnt have an easy way to obtain a physical gift. We did have a What are some of the hidden gotchas when develT1 line in our house though (my dads a computer oping in the wide world of HTML5 and how have you scientist), and I was very aware of the internet - so learned to work around some of those issues? I decided Id make her a webpage. I Yahood for webpage making instructions and promptly preOne of the tricky parts of HTML5 is how varied its sented my mum with her digital gift. As soon as my support is. Its not like with a usual API, where you dad saw that I was interested in programming, he can say all features from version X onwards are spurred me on to learn more (real) languages like supported instead, you have this situation where Perl and Java. From then on, I was hooked, and the each browser supports a different subset of fearest is history. tures. Even the oft-maligned IE supports some features that other browsers dont - its not behind on How did you come to select PhoneGap for your everything. Worse, even when a browser technically supports an HTML5 feature, it may still perform mobile app strategy? How many other mobile app quite badly with it, like in the case of the Android platforms did you review in the process? Webkit browser and CSS3 gradients. In deciding how to build the mobile apps for EatDifferent, my goal was re-usability. I wanted to reuse as much of my app logic and assets as possible, and I wanted to re-use as much of my existing web development knowledge as possible. I didnt want to start from scratch on either front, and didnt feel like I had the time or motivation to become an expert Android Java and Apple iOS developer. So, I went with PhoneGap and I achieved my goal of reusability - about 90% of my code is shared across the web and mobile apps, and that means its easier for me to add new features to all the platforms at once. So, if youre a developer trying to use HTML5, you need to use something like Modernizr to check whether a feature exists, you need to use libraries that abstract on top of the feature across the different browsers, and you need to actually test your app in all the browsers and see both if it works and if it works fast enough. Two invaluable resources for HTML5 developers are the Modernizr wiki on HTML5 polyfills (https:// github.com/Modernizr/Modernizr/wiki/HTML5Cross-browser-Polyfills) and caniuse.com with upto-date browser support tables.
81/83
Do you think that cross-platform development makes sense? When should you go native instead of using web standards? It depends. Are you building an app that a user would only want to access on a mobile device? Or is it an app that users would want to access everywhere? Does the app need to be usable by everyone to be useful, or can you use it by yourself or with strangers? An app like Draw Something is very mobile-specific - someone is bored, they have their phone, they start a game with some random other person, and they draw with their touch screen. It makes sense for them to go the native route, as they dont have to target every platform, and they can then take advantage of native touch capabilities. But an app like Twitter needs to be cross-platform - people want to tweet from everywhere, and they want to tweet with everyone. It makes sense for them to go the route of web standards, since they can then serve apps on any platform that has a web browser and a way of entering text, and they dont need to worry about excluding users. I personally prefer apps that are accessible everywhere (I would totally Draw Something on my laptop), but each developer needs to decide for themselves how much to prioritize cross-platform development given their limited resources. Youve had a number of different roles in the developer/IT world, what are some of the highlights that were most beneficial to giving you the perspective for where you are today?
Now that Ive left that role and Im a free-range developer, I can appreciate the perspective that developer relations has given me, and when Im interacting with 3rd party APIs, I can put myself in their shoes. When I run into a bug, I try to actually post in their forum instead of simply ranting on Twitter, because I realize that they are busy too and they can get it fixed faster if its reported properly. Before I make a feature request, I try to think to myself whether that request is actually in line with their core mission and will be sustainable for them, and not just a niche request that would only satsify me. Basically, by being able to balance both perspectives in my head, I can be a more productive and useful developer of a 3rd party API. Weve been hearing a lot lately about User Experience. Can you share your thoughts on Developer Experience? How important is it, really, for companies, such as Facebook and others enjoying their view from the top, to provide a good developer experience with their APIs? Were now in a time when there are many companies out there that are purely dedicated to developer products - hosting platforms like Heroku and App-Forge, functional APIs like SendGrid and Twilio, services like Loggly and Pingdom. For those companies, their success depends solely on the success of their developer products, so they need to provide the best developer experience possible... and they generally do. But there are also many companies that provide both user-facing products and developer-facing products. Sometimes, the success of the user product is directly dependent on the success of the developer product. For example, Twitter might not be as popular as it is today if there werent so many alternative, 3rd-party clients built for it.
Actually, Ive technically only had one job in my life: Google Developer Relations. But, that job was probably the best possible job that I could get in terms of how much I learnt across so many different aspects. There was the technical knowledge: JavaScript, Maps/GIS, Flex, Python, App Engine, NonBut othertimes, its not obvious how much the user Relational Datastores, and even a bit of Java. But product depends on the developer product. Would even more valuable was the not so tangible Facebook still be the worlds biggest soknowledge: how to deal with developers in cial network today if they didnt provide a community (the good, the bad, the ugly), My first applet an API? Quite possibly, yes. And unforhow to prioritize feature requests, how to tunately, when a company is in the posiwas a virtual handle a bug that breaks thousands of tion of owning the social graph on the sites, how to organize events, how to write dress-up doll... web and theyre the only ones that can the most universally useful documentation, provide a reasonable API to that social how to give entertaining yet educational graph, then social app developers dont really have talks, the list goes on. a choice but to use the Facebook API, regardless Developer Relations is a mix of many jobs in one - something like 10% software engineer, 30% support engineer, 30% community manager, 20% evangelist, 10% product manager. Its a great role for someone starting out because it exposes you to everything at once, and it can help you figure out what aspects you like the most. And hey, if you like it all, you can work in developer relations for life. of the developer experience. Facebook has a monopoly, and they know it.
But, hey, if a company comes along that has a reasonable slice of the social pie and provides an amazing developer experience for their social graph API, they may be able to compete with Facebook. The web moves fast, well see!
82/83
How do you perceive Adobe and the work it has done in creating tools for developers now and throughout the years?
Okay, so Im going to steal the next 2 questions from your interview with your mum, What was the first line of code you ever wrote? That depends if were counting HTML as code... Asssuming not, my first script was a Mad Libs game written in Perl. My dad and I celebrated one New Years eve by writing the script, and running it just as the clock struck midnight. Yes, I come from a geeky family.
Now that I think about it, Ive been using Adobe or Adobe-acquired products since I was a kid, though not always for programming. When I was in middle school, I used to draw advertisements for my parents college classes using Aldus Freehand, the vector drawing program. In high school, I used AdoSo, in that case, my first line was probably: be Pagemaker and InDesign to layout the school #!/usr/local/bin/perl newspaper. At computer camp one summer, I discovered Adobe Flash and started making animations and Flash websites (and yes, they had aweHow do you think the fundamental differences in men and women play out in the IT industry? some intros). In college, I minored in 3-D animation and continued using Flash for animations and fun Well, I think its good to clarify that there are aclittle web toys, plus spent a year using PhotoShop tually fundamental differences between men and as a graphic designer for our on-campus events. women. It seems like people try to pretend that At Google, I was working on the Maps API team were the same in all regards, but were not. We when they came out with the Maps API for Flash, evolved to be optimized for different tasks, both which was significantly more powerful than the Jaour minds and bodies. vaScript API in many ways at that time, and I spent a year Men are generally better at math, seeing what I could do in Flex/ women are generally better with Pams Pams Eat AS4. And now, Im using the people - so in the IT industry, youll Blog Projects often find men playing the part of Different recently acquired PhoneGap for building mobile web apps. the engineer and women playing the part of the community managSo, wow, I think Adobe has er. If we want to see more women in the engineer been with me more than any other company, and role, then perhaps one way is to show women that curiously, the Adobe line of products has evolved engineering isnt *just* math. at the same rate as my personal interests. But now the web is moving faster and faster while Adobe is For example, I first learnt programming via Java getting bigger, so... applets, and my first applet was a virtual dress-up doll that I uploaded and shared with my friends. To me, programming wasnt about math, it was about In what ways is there still work to be done to make making apps that people could interact with, and HTML5 a valid solution for developing applications? thats what was so cool about it. When it comes to using HTML5 for making mobile web applications, were in need of better, faster debugging tools. We now have really amazing developer tools for desktop debugging, particularly in Chrome and Firefox, but when it comes to mobile, it sometimes feel like debugging in IE6. There are a few tools for remote debugging, like weinre and iOS remote inspector, and theres talk of better Webkit remote debugging in the future (http:// www.webkit.org/blog/1875/announcing-remotedebugging-protocol-v1-0/), but theyre still not on par with desktop tools - and there are times when all you can do is console.log or even alert. We also need a better testing solution for mobile web apps. We have great ways of running integration tests in the browser on our desktop, using tools like Selenium, but were not quite there when it comes to mobile (particularly mobile apps with embedded browser views, like PhoneGap). Once again, there are developers working on this, so theres hope for the (near?) future. So, when I teach people how to program, I try to show them the many ways that it can be used, because you never know what their mind will be most excited by. And I think thats how we can increase the diversity of the IT industry. Or one way, at least. What would you like to shout out to the developer world for a successful 2012? We all want to make the world a better place somehow, whether that means making an app that lets people play games with their friends or making an app that improves government efficiency. The faster we can make those apps, the faster we can reach our own idea of what a better world looks like. We can all make it easier for each other to build what we want if we share our knowledge and our code with eachother. So, please, when you learn something: share it, and when you write a bit of useful, reusable code: opensource it. Sharing is caring. :)
appliness
IS A WARM GUN
e want to showcase in this section the best mobile applications built with web standards. If you want to showcase your application, contact us by email - contact@appliness.net. This month, find clothes that match your tastes, discover cuuuuuute animals and build muscle thanks to PhoneGap.
Colour Match
The colour picker works very well. Good usage of jQuery Mobile.
84/85
Michal
Christophe
Piotr
Cutest Paw
by Ho Man Cheung
Cutest Paw iPhone App is designed for those who love to see new cute animal pictures everyday. You will love the seamless way we display the pictures on your iPhone. User can search the cute animal pictures by keywords or categories. User can register a new account, and login to upload their cute animal pictures. You can take a picture or choose any pictures from your photo library. You can also track your uploaded pictures. Oh my god! Its so CUUUUUTE. The main screen is incredibly beautiful. A dynamic compisiting that really make a difference. The developer used jQuery Mobile and PhoneGap.
I was surprised at how much of a distraction this turned out to be. Great job!
Holly Greg Alan
Bit Timer
by Peiter Buick
This app is designed for the no-frills, hard-core workout. This is the first interval timer youll see with a set up that is this fast and easy. Your workout should be intense, not your workout set up. The clean design and simplicity of Bit Timer make it the perfect app for exercise enthusiasts. One of the best feature is that music automatically fades, allowing you to hear interval tones. The app uses smart drag and drop gestures to define the Work, Rest and Repeat parameters. The developers used PhoneGap to control the sound of the device.
Greg
Andy
Michal
WHICH ELEMENT ?
One of the main challenges we see in building semantic content is picking what tag to use when. WhichElement.com seeks to help with that. Now, lest we seem all judgy and preachy let me get a few beliefs out there: - A perfectly semantic site does not exist. - Even if it did, someone would disagree with its semantics. - Therefore semantics for semantics sake is pointless.
However, semantics are about more than just semantics for semantics sake. Semantics can be about accessibility, SEO, or just good developer to developer communication of intent. They can be used to create better hooks for CSS and DOM manipulation. Therefore we approach this site with the following in mind:
- Semantics exist along a continuum, something can be more or less semantic. - We encourage semantics, but not at the cost of reasonableless.
Our goal is to suggest things to help you make a good decision about what you should do to be semantic. We certainly dont think we have any authority to command you to do things to be absolutely semantic. by Terry Rian and Ray Camden Visit WhichElement.com
? . . . . . . .
<aside> or <blockquote> ?
Pull Quote
A pull quote is a fluffed up copy of a bit of the content on the current page. Its usually bigger and more visually distinctive than the rest of the body copy. A pull quote in most cases is used to emphasize a theme or point of a piece. The idea is that by presenting this block quote, readers can determine more quickly if they want to read the piece. Its a stylistic addition to a page that emphasizes content without actually adding concrete content.
Candidates
- <aside> - <blockquote> - Highlighted with CSS and HTML5, no semantic reference. The first issue to clear is, Is this a quote or a pull quote? An easy rule of thumb here is If you are repeating something that is on this exact page, its pull quote. Since it is not a quote, <blockquote> is inappropriate. The W3C specifically points out in their definition of <aside> that is intended for pull quotes: The element can be used for typographical effects like pull quotes or sidebars, for advertising, for groups of nav elements, and for other content that is considered separate from the main content of the page.
86/87
However Maykel Loomans makes a great case in his article Pull Quotes with HTML5 and CSS that pull quotes are a display issue and not a content issue. If you buy into it, it means adding extra markup, and repeating content just to show a pull quote is semantically wrong. He makes a compelling case for it, and has an awesome solution. Just using HTML5 and CSS to style a pull quote. The article is great reading.
Verdict
The semantic nitpicker in me loves to point to Highlighted with CSS and HTML5. It might be a little kludgy on the CSS side but from a semantic and content point of view, its very elegant. That being said, the W3C says you can use <aside> which might be a bit more flexible in terms of styling.
Further Reading
Wikipedia > Pull Quote
Smashing Magazine > Block Quotes and Pull Quotes W3C > The aside element
Maykel Loomans on design, the web and other stuff nerds like > Pull Quotes with HTML5 and CSS
? . . . . . . .
MORE INFORMATION
Comments
Candidates
<div> <dl> <ol> <section> <ul>
At first glace, one of the lists makes a good candidate. This is a big honkin list of comments. Semantically, the <ol> makes a strong showing as comments are usually listed in chronological order. You can choose to have the numbers part of the display of the items or style them away. Note, however, that it is hard to style the <ol> numbers independent of the text. It can be done, but involves adding more elements to the content. The <ul> is also a reasonable choice here. The <dl> might be semantically correct, but seems like youre just showing off your use of obscure elements. Not that there is anything wrong with that. You could go with a <div>. The w3c discourages using a <div> when there is a more specific element to use, and in this case you have several. A <section> refers to a group of related bits of content. A list of comments in a blog definately fit the bill.
Verdict
We recomend the <section>, containing either <ul> or <ol>.
Further Reading
Macrofolio > Style your lists
>
>
appliness
VIDEO TUTORIAL
raymond camden demonstrates how to use the html5 file API with phonegap to start working with the file systems of mobile devices.
d n u o laygr
- PhoneGap m e t s y S e l i F - Storage
Difficulty
- rookie - intermediate - expert
Todo list
- store stuff - read & write - shave
by Raymond Camden
appliness
in this article, i wont explain what is phonegap. Ill focus on where this technology fits in the mobile solutions landscape and when phonegap is relevant.
MOBILE
GROWING
WEB
IS
2013
2012
First, you need to choose the userexperience for your app. A classic page by page navigation or an application UX with tabs, footers...
x
Which mobile user-experience do you need?
The mobile Web is growing eight times the speed of the Internet
Classic Web UX
Links, Pages, navigation, text & images
ANSWERS
Application UX
Menu, Header, buttons, footer, tabs
ANSWERS
There are three ways to code a mobile app user experience, inside or outside the browser.
Web-app
DESCRIPTION
Hybrid
Hybrid apps are executed in the web view component of a native app (think of a headless browser). The app is coded with webStandard (HTML5, JS...). Hybrid apps are distributed as native apps on market places.
Native
A native application is coded with the native language of the mobile operating system (ObjectiveC for iOS, Java for Android...)
A Wep-app is executed in the browser of the mobile device. Its coded with web standards (HTML5, JS...)
ACCESS
To access a web-app, the user launches the web browser and types a URL.
Native apps are distributed on market places (app store, google play, appWorld...).
LIMITATION
Very limited access to HW features and APIs. You cant take a picture, store persistant data...
Full access to HW fea- Full access to HW and tures and APIs thanks native APIs. to native extensions (or plug-ins). The developer calls the native APIs with JavaScript commands. Developers need couple a mobile HTML framework (jQuery Mobile) and a mobile container framework such as PhoneGap to access native APIs with JS. Each platform provides specific SDK and IDE: ObjectiveC and Xcode for iOS, Java and Eclipse for Android...
SOLUTIONS
?
GAME
inspired by Emmanuel le Valensi
In my opinion, the biggest challenge is to find a HTML framework that will simulate the user-experience of a native app. jQuery Mobile is a good candidate. Then, PhoneGap will expose native APIs in JavaScript (take a picture, accelerometer, File API...) and run your HTML code in a web-view (a kind of headless browser).
PATH
same?
These 3 mobile apps have very similar user-experiences. They are all using application UI patters: menu, header, icons, tabs... But just one of them is native and written with ObjectiveC. Its Path, one of the most beautiful social application. Facebook is Hybrid, it has been written with HTML and JS. They used a distribution of PhoneGap to run it as a mobile application outside the browser and distribute it on app stores. LinkedIn is a pure web application. A wonderful HTML development that you can try on mobile. linkedin.com. That said, they just released an Hybrid app too. They just had to reuse their existing HTML code and package it as an mobile app with a technology such as PhoneGap.
What is PhoneGap?
a platform that allows you to author native applications with web standards
= Hybrid
Workflow
Build your app once with web-standards
Based on HTML5, PhoneGap leverages web technologies developers already know best... HTML and JavaScript. Pick the HTML framework of your choice (jQuery Mobile, Sencha Touch...) and build your application. At the end, your HTML app must look like a native one.
d n u o laygr
s p p a d i r b y - H p a G e n o h P - Browser
Difficulty
- rookie - intermediate - expert
Todo list
- user XP - Xcode - Xplatform
by Michal Chaize
appliness
WTFJS?!*%
JavaScript is a language we love despite it giving us so much to hate. wtfjs.com by brian leroux is a collection of those very special irregularities, inconsistencies and just plain painfully unintuitive moments for the language of the web.
Answer: do you think this constructor returns for new Dude(Bob)? Doug or Bob? function Dude(name){ this.name = name; return {name: Doug}; } Answer: var bob = new Dude(Bob); // { name: Doug } bob instanceof Dude // false Huh!? So you can just slip in anything? What about arrays? function Dude(name){ this.name = name; return [1, 2, 3]; } new Dude(Bob); // [1, 2, 3] That cant be! What about... function Dude(name){ this.name = name; return 3; } new Dude(Bob); // { name: Bob } Wah? No way! So, if you try to return a primitive type from a constructor(number, string, date), it will ignore the return value and return the originally initialized object, but otherwise, the returned value overrides.
d n u o laygr
Difficulty
- rookie - intermediate - expert
Todo list
- laugh - have fun - sleep
by Toby Ho
appliness
BLEEDING EDGE
One of the more interesting aspects of PhoneGap development is that the features it provides open up interesting possibilities when combined with other products. So for example, you can combine PhoneGaps camera support with existing JavaScript libraries that manipulate images. HTML5 is much the same way. By broadening what the browser can do, all of a sudden you see multiple new opportunities for mashups and unique new creations. Today Im going to demonstrate one simple example of this. I mentioned PhoneGap earlier because these particular demos are based on an earlier application I built that utilized an excellent JavaScript library called Color Thief. Color Thief gives you the ability to examine images and determine either the dominant color or get a palette of prominent colors. For my PhoneGap application, I made use of the Camera API to allow you to take pictures and generate a color palette from the result. I thought it might be interesting to apply similar logic to a desktop application making use of live video streams. In order to test this you will have to use Chrome 19 (still in beta) or higher and you must enabled WebRTC. WebRTC is a project aimed at giving browsers a way to perform real time communication with other clients. It involves quite a bit of moving parts and is very much a work in progress, but you can begin experimenting with it now. Note that before you do so, you must enable the feature. Details on how this is done may be found here: Testing WebRTC on Chrome. The first demo makes use of the web cam and combines it with the ColorThief library to provide a live view of the colors from the camera. You have a screenshot of my demo on the left.
91/95
This code is based on a simple demo by Greg Miernicki. Lets look at the code, and then Ill explain whats happening.
<!DOCTYPE html> <html> <head> <script src=js/jquery-1.6.2.min.js></script> <script src=js/quantize.js></script> <script src=js/color-thief.js></script> <script> $(document).ready(function() { if(!navigator.webkitGetUserMedia) return; navigator.webkitGetUserMedia(video, gotStream, noStream); var video = $(#monitor)[0]; var canvas = $(#tempCanvas)[0]; var img = $(#tempImage); img.load(function() { console.log(load); try { var p = createPalette(img,5); for(var i=0; i<p.length; i++) { $(#p+i).css(background-color,rgb(+p[i][0]+,+p[i][1]+,+p[i] [2]+)); } var dom = getDominantColor(img); $(#domColor).css(background-color,rgb(+dom[0]+,+dom[1]+,+d om[2]+)) } catch(e) {}; setTimeout(doSnapShot,1500); }); function gotStream(stream) { video.src = webkitURL.createObjectURL(stream); setTimeout(doSnapShot, 1500); video.onerror = function () { stream.stop(); streamError(); }; } function noStream() { document.getElementById(errorMessage).textContent = No camera available.; } function streamError() { document.getElementById(errorMessage).textContent = Camera error.; }
more on next page
92/95
function doSnapShot() { canvas.width = video.videoWidth; canvas.height = video.videoHeight; canvas.getContext(2d).drawImage(video, 0, 0); img.attr(src,canvas.toDataURL()); } }) </script> <style> #monitor { width:640px; height:480px; } #tempCanvas, #tempImage { width: 640px; height: 480px; position:absolute; left:-1000px; top:-1000px; } div#domColor { width: 640px; height:50px; } div#palette { width: 640px; } div#palette div { width:20%; height:50px; float:left; } </style> </head> <body> <div id=errorMessage></div> <video id=monitor autoplay></video> <div id=domColor></div> <div id=palette> <div id=p0></div><div id=p1></div><div id=p2></div><div id=p3></div><div id=p4></div> </div> <canvas id=tempCanvas></canvas> <img id=tempImage></img> </body> </html>
93/95
Theres quite a bit here, so lets tackle it in pieces. First - notice our jQuery $(document).ready block checks to see if the feature, webkitGetUserMedia, exists, and if not, immediately leaves. Normally Id present some form of message to the user. Being a proof of concept though we can be mean like that. The magic begins with a request for the web cam. This is as simple as: navigator.webkitGetUserMedia(video, gotStream, noStream); noStream is a simple error handler, so lets focus on gotStream. gotStream handles two distinct things. First, it hands off the video data from the media stream to the actual video tag we have in the DOM. Secondly, it automatically runs a function, doSnapShot. That function then handles getting a still from the video source and drawing it to a canvas. (And again, I want to credit Greg Miernicki. All of this logic comes from his demo.) Heres where things get interesting. Once we have an image, we can use ColorThief on it. But ColorThief only works on fully loaded images. Youll notice we write to an image addressed by the JavaScript variable img. This was set earlier in a jQuery selector. Because Ive got a handle to the image object in the DOM, I can attach an event handler specifically for the load event of the image. Once a load event occurs, I then turn to ColorThief. I mentioned earlier that it supports getting both a dominant color as well as a palette of used colors. I call both of those and draw them out to some divs below the video. Note the use of try/catch. I encountered errors with ColorThief when it first started hitting the video so I simply try/catch to avoid the initial problem. By the way - why the use of setTimeout - and why 1500 milliseconds? Because ColorThief has quite a bit of work to do, I thought it best to go for slightly slower than real time updating. Obviously this could be tweaked a bit. Another issue is the use of the image passed to ColorThief. I use CSS to hide this image offscreen. If you look at the source of ColorThief though you will see it actually creates a canvas out of the image. So Ive actually got a canvas item sourcing an image sourcing a canvas. That could be optimized. So while running this demo and noticing the colors seemed pleasant (entirely due to my snazzy clothing selections), I wondered what could be done with this on a bigger scale. Remember how we hid the image used to source the color operations? What if we hid everything! Why? Imagine a web site that changes its main theme based on what you wore. Thats a bit over the top - but possible. Consider the following simple Bootstrap based site on the next page:
94/95
>
By grabbing the webcam again and selecting the dominant color, you can end up with something like the screenshot on the right. Of course, this assumes a user wearing a bright red shit - I used a handy Imperial Guard action figure I had nearby . The code for this version is much like the previous one - but simply uses jQuery to update Bootstrap CSS: img.load(function() { try { var dom = getDominantColor(img); $(.navbar-inner).css({background-image:none,backgroundcolor:rgb(+dom[0]+,+dom[1]+,+dom[2]+)}); om[2]+)}); $(h1,h2,p).css({color:rgb(+dom[0]+,+dom[1]+,+d
Obviously this is a bit of a contrived example, but the idea is that once you have access to the web cam, theres the possibility of doing much more than chat or taking silly pictures.
ONLINE RESOURCES Color Thief http://lokeshdhakar.com/projects/color-thief/ Rays blog http://raymondcamden.com/ WebRTC http://webrtc.org/
appliness
BLEEDING EDGE
Thanks to Molly Holzschlags tweet, I learned there was an Editors Draft of CSS Variables.
Let me first say that I think its awesome that the W3C is taking this on. I think that variables in CSS will ultimately be a good thing. It will make it easy to reuse colors and other CSS properties. It will make large amounts of redundancy go away. It will make CSS files smaller, and therefore give less toehold to bugs. That being said, I have a major complaint with the implementation of--in a word data. See, here is how CSS variables are supposed to work according to the draft. I create a property in the root named data-header-color. :root { data-header-color: #06c; }
This Gist brought to you by Github variableset.css view raw
Then to refer to that color elsewhere, I use a construct that looks like a function named data() to retrieve it as so: h1 { background-color: data(header-color); }
This Gist brought to you by Github variableget.css view raw
96/98
As far as I can tell, the only explanation in the draft for why this is, is that it is trying to match the HTML specification for data: The naming here is loosely based on the form of custom data attributes in HTML5. However, as defined here, the syntax for variable usage is different from the syntax for variable definition (i.e. data-foo for definition, data(foo) for usage). Some have suggested that the syntaxes should should match, using functional syntax in both cases. Others have suggested using a prefixed symbol instead of functional syntax (e.g. $foo) for both the property and usage. Well at least they are aware that some might object to this format. So let me add my voice. I object. Variables are a pretty standard construct, people know how they work. Make them work like variables in other languages. I have a bunch of reasons here: Two different syntaxes for creation and consumption seems confusing. It looks like youre calling a function, but youre not. Youre referring to a variable. Thats confusing. CSS and HTML dont have a lot of overlap in syntax, why is adding some a good thing? My preference here is that I can just use plain old words as a variable, then consume them as plain old words. That being said, I would be okay with a prefixed symbol, like a $ if it comes down to some sort of parsing issue. Thats my major problem with the draft, but I have one other issue with the behavior on invalid variables. Like if you set the margin to #FFFFFF. Basically if you have this code:
Then the p comes out as red, but if you have this code:
:root { data-not-a-color: Behold I am not a valid color at ALL!!!! } p { background-color: red; } p { background-color: data(not-a-color); }
This Gist brought to you by Github errorwithvariables.css view raw
The p comes out transparent. This sort of change in behavior might be pretty confusing. The explanation makes some sense: The invalid at computed-value time concept exists because variables cant fail early like other syntax errors can, so by the time the user agent realizes a property value is invalid, its already thrown away the other cascaded values. I think attr() needs to rely on it as well, as its behavior is almost identical to variables.
97/98
But I imagine this is something that browser manufacturers can handle as they control the behavior of throw[ing] away the other cascaded values. They could hold on to cascaded values until they are done computing variables. But maybe Im missing something here. But its also worth considering if this will make invalid CSS easier to track down. I doubt it, but until a browser implements these, it will be hard to determine if that is true. Anyway. The good news here is that this is the editors draft, not the recommendation. This means that now is the time to start analyzing this spec and commenting on it. So what do you think?
Aside on W3C Drafts Its important to note that a Working Draft is a pretty early stage of the W3C recommendation process. W3C follows these steps when advancing a technical report to Recommendation. 1. Publication of the First Public Working Draft. 2. Last Call announcement. 3. Call for Implementations. 4. Call for Review of a Proposed Recommendation. 5. Publication as a Recommendation.
I believe we are between steps 1 and 2 at the moment. Also relevant: Purpose: The publication of the First Public Working Draft is a signal to the community to begin reviewing the document. So to be clear, were supposed to be commenting at this stage.
ONLINE RESOURCES
Editors Draft of CSS Variables http://dev.w3.org/csswg/css-variables/ HTML Specification for data http://www.whatwg.org/specs/web-apps/... CSS Variables Draft Comments https://gist.github.com/2136922 98/98
appliness
Fresh news about HTML and Javascript collected by Brian Rinaldi - remotesynthesis.com
WebStorage: Persistent client side data storage. via John Allsopp Experimenting with CSS Exclusions. via Ryan Stewart How to do content folding for your responsive web design using CSS Regions. via Chris Coyier
What is the meaning of this? via Douglas Crockford Device-agnostic and content-centric approach to responsive web design. via Thierry Koblentz How to create the popular infinite scroll pagination effect using jQuery via Mohd Hadihaizil Din
How to make Dreamweaver add code coloring and hinting with the Sass and Less CSS preprocessors via Greg Rewis
appliness
Toying With the HTML5 File System API via Ivaylo Gerchev Build animated CSS3 content tabs. via Ring Wing Understanding MVVM - A Guide For JavaScript Developers via Addy Osmani
Stop Nesting Functions! (But Not All of Them) via Jeremy McPeak Extending JavaScript The Right Way. via websanova
DIRECTION-AWARE HOVER EFFECT WITH CSS3 AND JQUERY via MARY LOU
Persisting Backbone Collections via Eric Feminella Object types in JavaScript by Keith Peters
appliness
THE TEAM
Contribute and join Appliness
Appliness is a free digital magazine edited by passionate web developers. We are looking for contributors. Contact us and join the adventure. Youll find on our website appliness.com a feedback form. You can also follow us on twitter, facebook and Google+.
MICHAEL
Michal Chaize is a Developer Evangelist at Adobe where he focuses on Rich Internet Application and Mobile applications. Based in Paris, he works with large accounts that need to understand the benefits of rich user interfaces, leverage the existing back-ends to add a rich presentation layer and measure the impact on the existing IT teams. He believes that intuitive user experiences in the Enterprise are key to successful developments of effective, efficient, engaging, easy to learn and error free applications. Before joining Adobe, Michael founded a software company and taught RIA languages such as Flex and PHP in IT engineering schools. Hes the editor in chief of Appliness.
CHAIZE
R AY M O N D
Meet Raymond Camden. He is a 38 year old married father of three living in beautiful Lafayette, Louisiana. Ray is a developer evangelist for Adobe where his primary technical focus is ColdFusion, jQuery, Flex, AIR and the mobile space. Hes been invited to speak at many conferences over the years, including CFUNITED and Adobe MAX .
CAMDEN
IAN CHRISTOPHE
Christophe is a Developer Evangelist for Adobe where he focuses on Web Standards, Mobile, and Rich HTML Applications with a special focus on Enterprise Integration. In this role, Christophe has helped some of the largest financial services companies design, architect and implement some of their most mission critical applications. He was one of the initial members of the Flex Product Team in 2003. In his previous role at Macromedia, Christophe worked on JRun, the companys J2EE application server. Before joining Macromedia, Christophe was managing Java and Internet Applications Evangelism at Sybase and Powersoft. Christophe has been a regular speaker at conferences worldwide for the last 15 years.
COENRAETS
Ian Devlin is an Irish web developer, blogger, and author who enjoys coding and writing about emerging web technologies such as HTML5 and CSS3. In addition to front-end development, Ian also builds solutions with back-end technologies such as .NET and PHP. He has recently written a book titled HTML5 Multimedia: Develop and Design.
DEVLIN
Keith has been programming professionally for over a decade and as a hobby for a while longer. He has written or contributed to a dozen books on programming and maintains his personal site at www. bit-101.com.
PETERS
B R I A N
Brian Rinaldi is as a Content and Community Manager for the Adobe Developer Center team, where he helps drive content strategy for HTML5 and JavaScript developer content. Brian blogs regularly at http://remotesynthesis.comand and is a unreformed twitter addict.
RINALDI
He lives near Boston, MA in the USA, and is the Engineering Guru at Infrared5.
T E R R E NC E
Terrence Ryan is a Worldwide Developer Evangelist for Adobe. His job basically entails traveling the world and talking about the developer tools and technologies that Adobe has to offer or that evangelists support.
R Y A N
Ryan Stewart is a Web Developer Evangelist for Adobe Systems. After graduating from the University of Pennsylvania with a degree in Economics he started on the Flash Platform by building eLearning rich Internet applications in Flex 1.5 and ColdFusion 7 for the Wharton School of Business. He is a long time blogger and had a prominent blog on ZDNet where he covered all sides of rich Internet applications. He has spoken at a number of industry conferences including Web 2.0 Expo, Adobe MAX, 360|Flex, SXSW, PHP Tek, and Web Design World. When not working with the latest Adobe technology you can find him in Seattle where he enjoys making beer, mountaineering, and spending as much time as possible in the outdoors.
STEWART
A N D R E W
Andrew Trice is a Technical Evangelist with Adobe Systems. Andrew brings to the table more than a decade of experience designing, implementing, and delivering rich applications for the web, desktop, and mobile devices. He is an experienced architect, team leader, accomplished speaker, and published author, specializing in object oriented principles, mobile development, realtime data systems, GIS, and data visualization.
T R I C E
M A I L E
Maile is the assistant editor for Appliness magazine and has worked with Adobe both as an employee and consultant for 8 years now. Mailestarted with Adobe on the Technical Marketing team as a technical trainer for the Adobe LiveCycle Enterprise Suite (most recently Adobe Digital Enterprise Platform). She then went on to work with the Adobe Enterprise Evangelist team to support great Flex developer resources such as Tour de Flex and Flex.org. Maile is excited to jump into the world of digital publishing and dig deeper into leading edge HTML and related technologies.
VALENTINE
Greg is a Developer Evangelist at Adobe Systems focusing on the use of Adobe technologies in enterprise applications. Technologies include HTML, JavaScript and related technologies, Flex, AIR, data services, digital publishing, and anything mobile, tablet and desktop app development related. Prior to joining Adobe, Greg architected and developed many largescale applications at Verizon, Motorola, NASA/Boeing and others.
W I LS O N
Appliness is a digital magazine written by passionate web developers. You can follow our activity on Facebook, Twitter or Google+.
O W FO LL
o t t n a w ? u e Yo ribut t n co
U S
If you want to contribute writing articles or showcasing your app, feel free to contact us. We are permanently looking for new contributions and content to cover all the aspect of application development with web standards. We are also opened to suggestions. The Give us feedback form on our website is the best way to contact the team.
GIVE US FEEDBACK
CO
TR I
BU
TE