Escolar Documentos
Profissional Documentos
Cultura Documentos
#3 - JUNE 2012
Chris H
Exclusi
ve inte rview
eilmann
DEVELOPERS
TUTORIALS
HTML5, EMBER.JS, jQUERY, PHONEGAP, SVG, REQUIRE.JS...
INNOVATION
BUILD YOUR MOBILE APPS IN THE CLOUD
appliness
(
VISUAl and juicy INTERVIEW CHEAT SHEET FEEDBACK SHOWCASE video tutorial BLEEDING EDGE TEAM
TABLE OF CONTENTS
Getting started with HTML mobile app development using jQmobile, RequireJS and BackboneJS
by Mark Dong
Simple Offline Data Synchronization for Mobile Web and PhoneGap Apps
by Christophe Coenraets
ADOBE SHADOW
by Holly Schinsky
CSS SELECTORS
by Ben Howdle
phonegap BUILD
by Piotr Walczyszyn
WHICHELEMENT.com
NAVIGATE
GO BACK TO THE LIBRARY MOVE TO THE PREVIOUS ARTICLE DISPLAY THE TABLE OF CONTENTS VISUALLY BROWSE ALL THE ARTICLES
appliness
CoffeeScript has a number of other nice features, and its always evolving. Its less verbose and improves readability. here are my top 10 features. My name is Karl Seguin, Im a software developer and amateur writer. I contribute to various open source projects, run a few side projects and enjoy learning new technologies.
#1
Its pretty common that youll want to build a string based on one or more variables. With CoffeeScript, variables can cleanly be placed inside of as string:
level greater than #{maxPowerLevel} level greater than + maxPowerLevel +
With well-named variables, string interpolation is easier to read and maintain. Of the three main ways to do this (the third being via some type of formatting function like sprintf), string interpolation is by far, the best, for both simple and complex cases.
d n u o laygr
String interpolation
Difficulty
- rookie - intermediate - expert
- Coffee t p i r c S a v a J - Templates
Todo list
- dring tea
by Karl Seguin
#2
Statement Modifiers
Ill admit that statement modifiers are a pretty minor thing, but as trivial as they are, Ive always found them useful for simple statements:
applyChanges = (elements) -> return if elements.length == 0 ... applyChanges = function(elements) { if (elements.length === 0) { return; } ...
#3
Callback Handling
Whether you are doing client-side development or server-side development, callbacks and JavaScript go hand-in-hand. And, although I dont mind braces, Ive always found JavaScripts syntax to be far too verbose. CoffeeScript helps in two ways. First, optional parenthesis, which I generally dislike, except when dealing with callbacks. Second, blocks via indentation. Compare:
$(#data).on click, tr, (e) -> id = $(this).data(id) ... $(#data).on(click, tr, function(e) { id = $(this).data(id) ... });
I find this particularly useful to help minimize the clutter caused by node.js callback soup. On the downside, it isnt great when you have a parameter after the callback, such as with setInterval or $.get and $.post.
#4
Comprehensions
Looping over arrays and hashes is pretty fundamental, and the more we can enhance the experience, the better. Even if you dont leverage comprehensions as-is, simply having a for loop that exposes the value+index of an array, or the key+value of a hash, is a nice addition.
books = [ {name: Dune, rating: 5} {name: Old Mans War, rating: 4} {name: Foundation, rating: 3} ] good = (b.name for b in books when b.rating > 3) books = [ {name: Dune, rating: 5}, {name: Old Mans War, rating: 4}, {name: Foundation, rating: 3} ]; good = []; for(var i = 0; i < books.length; ++i) { if (books[i].rating > 3) { good.push(books[i].name); } }
4/7
#5
In JavaScript, the meaning of this isnt always intuitive. Consider this CoffeeScript code:
class DataTable constructor: (element) -> this.element = $(element).on click, tr, this.clicked clicked: (e) -> this.highlight() highlight: -> ....
One might expect that this in the clicked method to be our DataTable instance, but instead, itll be the row which is clicked. This means that the call to highlight will fail, since the html row element doesnt have a highlight method. That clicked exists as a method of DataTable doesnt mean much.
To solve this, CoffeeScript lets you define a method with a fat arrow =>. Using => binds the function to the expected scope:
class DataTable constructor: (element) -> this.element = $(element).on click, tr, this.clicked clicked: (e) => this.highlight() highlight: => .... __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; function DataTable(element) { this.highlight = __bind(this.highlight, this); this.clicked = __bind(this.clicked, this); this.element = $(element).click(this. clicked); } DataTable.prototype.clicked = function(e) { this.highlight(); ... }; DataTable.prototype.highlight = function() { ... };
Sometimes youll want the normal JavaScript behavior (via a slim arrow), and sometimes youll want to fat arrow behavior. In general, I find myself using slim arrows more often in client-side code, and fat arrows more often on server-side code.
#6
@ Alias
Speaking of this, CoffeeScript has a shortcut for it, the @ symbol. Its easy to write this off as meaningless syntactical sugar, but it is useful. First, constructor parameters prefixed with @ are converted into properties:
5/7
Neither @ nor the fat arrow mean that you dont have to worry about the current meaning of this (or its alias @). They arent silver bullets, which isnt to say that they dont add value.
#7 #8 #9
SCOPING
CoffeeScript takes care of properly scoping your variables. This means that you dont use the var keyword and dont have to worry about having an inner variable shadow an outer one. One top of that, all CoffeeScript output is wrapped inside an anonymous functions, which means you wont leak any global objects. If you do want to expose something globally, say like our User class above, you need to attach it to a global object, like window. Of course, on the node.js side, you can simply export it.
One of the nicest things about CoffeeScript is that it generates clean and readable JavaScript. This makes it both easy to learn and debug. In fact, one of the best ways to learn CoffeeScript is to go to the official website, click the Try CoffeeScript button at the top, and type away. Seeing the instant translation to JavaScript is pretty useful.
CLASSES
Weve seen examples of it as a side effect of other features, but CoffeeScript classes are cleaner and more intuitive than their JavaScript counterparts. And the only reason Im not showing how to inherit via extend is because I dont want to include all the necessary JavaScript...
6/7
class User constructor: (@id) -> @findById: (id) -> @findByEmail: (email) -> save: =>
function User(id) { this.id = id; this.save = __bind(this.save, this); } User.findById = function(id) {}; User.findByEmail = function(email) {}; User.prototype.save = function() {};
#10
OPERATORS
In CoffeeScript, == and != translate to === and !==, which you probably always want to be using. This alone removes a common pain point. In addition to that, theres the existential operator. In its simplest form, it checks for undefined and null:
if (typeof name === undefined || name === null) { return null; }
CoffeeScript has a number of other nice features, and its always evolving. I understand that some people simply dont like it, which is fine, since a lot of what it offers is subjective. However, Im baffled that people dismiss as being nothing but syntactical sugar. Almost anything in the programming world can be described as syntactical sugar which sits on top of a more fundamental concept. Its less verbose and improves readability. Thats a win in my books. Of course, as someone who believes that knowing C is critical, I agree that new developers should first learn JavaScript and then spend a day learning CoffeeScript. But thats pretty much as much of a debate as I plan on having about it.
ONLINE RESOURCES Understanding CoffeeScript Comprehensions http://openmymind.net/2012/1/15/Understanding-CoffeeScriptComprehensions/ CoffeeScript http://coffeescript.org/ Karls blog http://openmymind.net/
appliness
hammer.js is a very simple but very powerful library to enable multitouch experiences on touch devices.
d n u o laygr
Difficulty
- rookie - intermediate - expert
Todo list
- pinch - rotate - wash fingers
by Michal Chaize
My sample application
Im just playing with three pictures. You can drag, rescale and rotate them. The Polaroid look and feel is produced by a CSS. This is pure HTML and JavaScript powered by Hammer.js:
Getting started
Ok it looks cool and its pretty responsive. Now lets see how to play with Hammer. First, you need to download the library from GitHub: https://github.com/eightmedia/hammer.js If you plan to use jQuery in your project (yes, in some cases, there is a JavaScript life without jQuery), then dont forget to download and import the dedicated jquery.hammer.js also available in the GitHub repository. In my sample, Im using jQuery, Ive put the JavaScript logic in a separate file and Ive created a CSS. My imports look like this: <head> <meta name=viewport content=width=device-width, initial-scale=1.0, user-scalable=no> <script src=jquery-1.7.2.min.js></script> <script src=hammer.js></script> <script src=jquery.hammer.js></script> <script src=myLogic.js></script> <link href=http://fonts.googleapis.com/css?family=Bree+Serif rel=stylesheet type=text/css> <link href=style.css rel=stylesheet type=text/css> </head>
9/13
Then Ive declared three DIV to display the pictures. The pictures are contained in a zoomwrapper DIV element. <body> <div class=welcome> <p>This sample is using Hammer.js.<br/> Drag and drop the pictures, zoom with pinch and rotate them.</p> </div> <div id=zoomwrapper> <div id=zoom class=zoomProps > <div class=polaroid> <img src=pic1.jpg alt= width=200 height=200 /> <span>Coco</span> </div> </div> <div id=zoom2class=zoomProps > <div class=polaroid> <img src=pic2.jpg alt= width=200 height=200 /> <span>Axo</span> </div> </div> <div id=zoom3 class=zoomProps> <div class=polaroid> <img src=pic3.jpg alt= width=200 height=200 /> <span>Gwo</span> </div> </div> </div> </body> There is nothing particular to notice in the CSS. The zoomwrapper DIV has an overflow property set to hidden. And here is the code to imitate the Polaroid effect: #zoomwrapper { height: 377px; width: 600px; overflow: hidden; } .polaroid{ text-align: center; padding: 10px 10px 25px 10px; background: #eee; border: 1px solid #fff; -moz-box-shadow: 0px 2px 15px #333; -webkit-box-shadow: 0px 2px 15px #333; border: 1px solid #dfdfdf; border: 1px solid rgba(96,96,96,0.2); font-family:Imitation; font-size:24px; color:#000; padding-bottom:10px; text-shadow:#333; }
10/13
drag pictures
The DragView function contains the logic to handle drag events. For each picture, you must associate a DragView call and bind the drag events: var dragview = new DragView($(container)); container.bind(dragstart, $.proxy(dragview.OnDragStart, dragview)); container.bind(drag, $.proxy(dragview.OnDrag, dragview)); container.bind(dragend, $.proxy(dragview.OnDragEnd, dragview)); setInterval($.proxy(dragview.WatchDrag, dragview), 10); Lets look at the OnDragStart method declared in DragView. this.OnDragStart = function(event) { var touches = event.originalEvent.touches || [event.originalEvent]; for(var t=0; t<touches.length; t++) { var el = touches[t].target.parentNode; if(el.className.search(polaroid) > -1){ el = touches[t].target.parentNode.parentNode; } el.style.zIndex = zIndexBackup + 1; zIndexBackup = zIndexBackup +1; if(el && el == this.target) { $(el).children().toggleClass(upSky); this.lastDrag = { el: el, pos: event.touches[t] }; return; } } } It stores the touch events in an array and make sure that were dealing with the DIV element with a polaroid class attached. If not, then we need to play with its parent node. Its due to the structure of my HTML elements. If you tap the title of the picture, then you also want the picture to move. Im also playing with the zIndex property to put the picture at the top when you drag it. Then, thanks to the toggleClass method (jQuery), I assign the upSky class to the element: its just setting an intense white background.
tch1 = [e.touches[0].x, e.touches[0].y], tch2 = [e.touches[1].x, e.touches[1].y] tcX = (tch1[0]+tch2[0])/2, tcY = (tch1[1]+tch2[1])/2 toX = tcX toY = tcY var left = $(element).offset().left; var top = $(element).offset().top; cssOrigin = (-(left) + toX)/scaleFactor +px + (-(top) + toY)/ scaleFactor +px; }) The transform state fires the transform method, passing the transform event and setting the scaleFactor. You can specify the minimum and maximum zoom thanks to the MIN_ZOOM and MAX_ZOOM constants. container.bind(transform, function(event) { scaleFactor = previousScaleFactor * event.scale; scaleFactor = Math.max(MIN_ZOOM, Math.min(scaleFactor, MAX_ZOOM)); transform(event); }); The transform() method uses simple CSS transformations that are hardware accelerated on mobile devices to get the best performance on touch devices. As the transform event powered by Hammer also contains information about the angle of rotation of your element, you can use the rotateZ property to enable rotation. function transform(e) { //Were going to scale the X and Y coordinates by the same amount var cssScale = scaleX(+ scaleFactor +) scaleY(+ scaleFactor +) rotateZ(+ e.rotation +deg); element.css({ webkitTransform: cssScale, webkitTransformOrigin: cssOrigin, transform: cssScale, transformOrigin: cssOrigin,
}); }
Thats very efficient and easy to implement. Now go to the next page to discover the full code of this sample.
12/13
<<< YOU CAN SCROLL DOWN THE CONTENT OF THIS FRAME >>> <<< YOU CAN SCROLL DOWN THE CONTENT OF THIS FRAME >>>
appliness
In this tutorial youll become more familiar with the basics of Ember.js as you build a working Twitter timeline viewer.
d n u o laygr
- MVC - Ember.js t p i r c S a v a - J
Difficulty
- rookie - intermediate - expert
Todo list
by Andy Matthews
Knockout.js, Spine.js, Batman.js, and Angular.js have emerged. Written in JavaScript and designed for JavaScript development, these libraries have filled the void between beginner and intermediate developers on one side, and hardcore programmers on the other. They offer various features and functionality that will suit different developers of varying skill levels based on their needs.
introducting ember.js
Ember.js (under that name) is one of the newest members of the JavaScript framework pack. It evolved out of a project called SproutCore, created originally in 2007 and used heavily by Apple for various web applications including MobileMe. At emberjs.com, Ember is described as a JavaScript framework for creating ambitious web applications that eliminates boilerplate and provide a standard application architecture. It comes tightly integrated with a templating engine known as Handlebars, which gives Ember one of its most powerful features: two-way data-binding. Ember also offers other features such as state management (is a user logged out or logged in), auto-updating templates (when the underlying data changes so does your UI), and computed properties (firstName + lastName = fullName). Ember is already a powerful player after a solid years worth of development. Ember has only one dependencyjQuery. The boilerplate HTML setup for an Ember application should look something like the code below. Note that both jQuery and Ember are being pulled from a CDN (content delivery network). This speeds up your users page load if they have already downloaded these files as a result of earlier visits to other websites that require them. <html> <head> <script src=http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery. min.js></script> <script src=http://cloud.github.com/downloads/emberjs/ember.js/ember0.9.6.min.js></script> <script src=js/app.js></script> </head> <body> </body> </html>
Defining mvc
Before you proceed with this tutorial it would probably be a good idea to more clearly define MVC. The concept has been around since 1979 and since that time a number of different variations on the pattern have emerged. The most common flow usually goes something like this: 1. A user performs an action such as typing on the keyboard or clicking a mouse button. 2. The Controller receives that input and fires off a message to the Model. 3. The Model changes its content based on the message (deletes a row or updates shopping cart quantities). 4. The View watches for a change in the Model and updates the user interface accordingly. Understanding how the MVC pattern works can make your application flow more easily. And, because code is split into distinct pieces, its easier for teams of developers to work together without interfering with each other.
15/25
When creating your Model you can provide default values for each property. The title , artist , and genre properties will obviously be filled in later, and so are marked null (or nothing). The listens property defaults to 0 and its value will increase as you listen to your music collection. Now that the Song model is in place, you can add your first song. You used extend to initialize the Song model, but youll use create to add an instance of it. Heres what that looks like: mySong = Song.create({ title: Son of the Morning, artist: Oh, Sleeper, genre: Screamo }); Notice that the variable doesnt begin with an upper case letter, thats because its an instance of the Song model. The new song also isnt within the Songs namespace. Youll almost never create an instance of a Model within your application. Youre certainly welcome to do so, but generally youd place each instance of a Model within a larger collection of similar objects such as an ArrayController (more on that later). Views In an Ember application or any MVC style application a View is something the user can see and interact with. You define an inline template by adding raw HTML directly to the page. This template will be contained within script tags. You add it to the page wherever you want your content to appear. <script type=text/x-handlebars> Hello <b>{{Songs.mixmaster}}</b> </script> Notice that the script tag has a type of text/x-handlebars. This gives Ember something to grab on to when it loads up the page. Any HTML contained within this script tag is automatically prepared by Ember for use in your application. Placing these lines of code within your application will display the following text: Hello <b>Andy</b> Before moving on, take a peek under the hood. In your browser, right-click the bold text and inspect it using the browsers dev tools. You might notice some extra elements. In order to know which part of your HTML to update when an underlying property changes, Handlebars will insert marker elements with a unique ID; for example: <b> <script id=metamorph-0-start type=text/x-placeholder></script> Andy <script id=metamorph-0-end type=text/x-placeholder></script>
</b>
You can also define a View directly in JavaScript, and then display it to the page by using a view helper. Ember has generic views that create simple div tags in your application, but it also comes prepackaged with a set of views for building basic controls such as text inputs, check boxes, and select lists. You start by defining a simple TextArea View within your JavaScript file. Songs.ReviewTextArea = Ember.TextArea.extend({ placeholder: Enter your review });
17/25
Then display it to the page by referencing the path to the variable containing the view, prefaced by the word view . Running the following code in your browser displays a TextArea field with placeholder text of Enter your review. You can also specify rows and cols as additional properties in your definition. <script type=text/x-handlebars> {{view Songs.ReviewTextArea}} </script> Handlebars By now youre probably wondering what the {{ and }} in the code stand for, so this is a perfect time to talk about Handlebars, also known as mustaches. Turn your head sideways and youll see why theyre called Handlebars pardner. Handlebars is a templating engine that lets developers mix vanilla HTML and Handlebars expressions resulting in rendered HTML. An expression begins with {{ and ends with }}. As discussed previously, all templates must be placed within script tags with a type of text/x-handlebars. By default, any value contained within handlebars is said to be bound to its value. That means that if the value changes because of some other action within the application, the value displayed to the user will update as well. Consider the following code: <script type=text/x-handlebars> My songs have {{Songs.totalReviews}} reviews. </script> When your application first initializes the user would see the following text. My songs have 0 reviews. But through the magic of data bindings, that value would change in real time as additional reviews were added by updating Songs.totalReviews. Handlebars also supports flow control through the use of {{#if}} and {{else}}. These elements let you conditionalize your templates based on values in your application. You could change the previous example to display an alternate message to the user when there are no reviews: <script type=text/x-handlebars> {{#if Songs.totalReviews}} Read all my reviews! {{else}} There are no reviews right now. {{/if}} </script> If at any point in the life of the application, the Songs.totalReviews value changes, the view will update and display the other part of the message. Its also worth noting that the # and / symbols are merely there to tell Handlebars that this particular view helper has a closing part. Controllers Earlier, the Model was defined as a way to enable developers to manage data. Thats true, but only in a very narrow way. A Model only contains data about a single thing; for example, a song (but not songs) or a person (but not people). When you want to manage multiple pieces of the same type of data you need a Controller. With Ember you can use an ArrayController to manage sets of songs, people, widgets, or whatever. Each ArrayController has a built-in content property that is used to store data. This data can be simple strings or complex values such as arrays or objects. Additionally, ArrayControllers can contain functions that are used to interact with the data contained within them. What might an ArrayController for your Song collection might look like?
18/25
Songs.songsController = Ember.ArrayController.create({ content: [], init: function(){ // create an instance of the Song model var song = Songs.Song.create({ title: Son of the Morning, artist: Oh, Sleeper, genre: Screamo }); this.pushObject(song); } }); The init function isnt required, but comes in handy as it will be triggered as soon as songsController is ready. It could be used to populate the controller with existing data, and in this case youll use it to add a single song to the Controller to illustrate Embers data-binding. Add the previous ArrayController definition and the following inline template and run the code in your browser: <script type=text/x-handlebars> {{#each Songs.songsController}} <h3>{{title}}</h3> <p>{{artist}} - {{genre}}</p> {{/each}} </script> The Handlebars each helper receives a path to a set of data, and then loops over it. Everything inside the matching each blocks will be displayed on the page for every item in the controller. Notice that youre not providing a path directly to the content array, because as far as Ember is concerned the controller is the array. The resulting HTML output looks like this: <h3>Son of the Morning</h3> <p>Oh, Sleeper - Screamo</p>
19/25
<link rel=stylesheet href=styles.css> <script src=http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery. min.js></script> <script src=http://cloud.github.com/downloads/emberjs/ember.js/ember0.9.6.min.js></script> <script src=app.js></script> </head> <body> <script type=text/x-handlebars> <div id=frm> <b>Load Tweets for: </b> </div> <div id=content> <div id=recent> <h3>Recent Users</h3> </div> <div id=tweets> <h3>Tweets</h3> </div> </div> </script> </body> </html> You can see there are three parts to this application: an input field, which allows users to input a Twitter username, the timeline viewer, which displays the selected Twitter users tweets, and a recent users list, which will store previous searches. The search box will appear at the top of the page, the recent users in a column to the left, and the tweets themselves will have the majority of the page on the right side. Next, create another file named app.js and add the following content. These comments helps you keep your code organized. Load this page up in your browser and make sure there are no errors. /************************** * Application **************************/ /************************** * Models **************************/ /************************** * Views **************************/ /************************** * Controllers **************************/ Application initialization The first thing youll need to do is to initialize your application. Directly under the comment block labeled Application, place the following code: App = Em.Application.create(); Notice that instead of saying Ember.Application, this line says Em.Application. The Ember team added this handy shortcut to reduce typing by allowing you to use Em in any place where you might use Em-
20/25
ber. Next youll add the TextInput view and the submit button. Directly under the comment block labeled Views add the following code: App.SearchTextField = Em.TextField.extend({ insertNewline: function(){ App.tweetsController.loadTweets(); } }); This block starts by using the App namespace, then extends one of Embers prepackaged Views, the TextField. In addition to allowing arbitrary properties and functions within Views, Ember also has built-in helper functions available for use. Thats what the insertNewLine() function is; it executes whenever the user presses the Enter/Return key on their keyboard while the cursor is within the input box. Creating template blocks Now that the TextField View is defined, youll add the corresponding view helper code to the HTML file. Switch to index.html and add the following code directly after the line that reads Load Tweets for. Remember that anything within {{ and }} is a template and will be used by Ember to output data. Additionally any template beginning with the word view refers to a View that has been defined within your JavaScript code. {{view App.SearchTextField placeholder=Twitter username valueBinding=App.tweetsController.username}} <button {{action loadTweets target=App.tweetsController}}>Go!</button> This portion of the template contains a view helper, and a button tag with an {{action}} helper. The TextField View, SearchTextField, begins with an attribute that is built into HTML5 text input fields, placeholder text. If the field is empty, the text within the placeholder attribute will be placed into the input field. When someone begins typing, the value goes away. Ember enables developers to use any HTML 5 standard attributes within its built-in views. The second attribute highlights the magic of Embers data-bindings. Ember uses a set of conventions to help it determine what youre trying to accomplish. Any attribute in a view (either within a template, or in a JavaScript file) that ends with the word Binding (note the capital letter) automatically sets up a binding for the attribute that precedes it. In this case Ember is binding the value of App.tweetsController.username to the input fields value attribute. Anytime the contents of the variable changes, the value contained within the input field will update automatically, and vice versa. The {{action}} makes it easier to add functionality to input driven elements. It has two options: the action name and the target. Taken together they form a path to a function contained within an Ember object. In the case of the above button the path would be App.tweetsController.loadTweets(), the same function called when a user presses the Enter key within the text field. Load index.html in your browser and click the submit button, or press the Enter key within the input field. If youre viewing the browser console youll see an error. This is because App.tweetsController is not yet defined. Preparing the Tweet storage object Now would be a good time to define App.tweetsController. Add the following code after the Controllers comment block in app.js. The code below should be familiar to you. Namespace, ArrayController, content arrayits all there. This time though youll be adding an arbitrary property (username), and a function ( loadTweets ). After adding the ArrayController, reload your browser. Type a word in the input box and then click the button. Youll get an alert box that echoes the word you typed. Feel free to remove the alert line at any time. Youll also see an error indicating that the addUser method is not defined.
21/25
App.tweetsController = Em.ArrayController.create({ content: [], username: , loadTweets: function() { var me = this; var username = me.get(username); alert(username); if ( username ) { var url = http://api.twitter.com/1/statuses/user_timeline.json url += ?screen_name=%@&callback=?.fmt(me.get(username)); // push username to recent user array App.recentUsersController.addUser(username); } } }); Take a closer look at the loadTweets function definition; it has some unfamiliar bits. The first line sets a scope for the rest of the function. By definition, the scope or this for all Ember objects is the current function, in this case App.tweetsController. However, youll be adding more functionality to the loadTweets function later in this tutorial. Setting the current scope now helps Ember understand the context youre using. As I noted previously, Ember offers a number of helper functions to make writing applications easier, and these include get() and set(). These two functions are built into every Ember object and provide quick access to any property or function. The next line uses the scope of the current object, App.tweetsController, and then calls the get() function, passing in the name of the property that you wish to get a value for. You might be curious about where the value of username is coming from to begin with. Remember that Embers data bindings are bidirectional. This means that as soon as you type a value into the input field the valueBinding attribute of the input field view updates the App.tweetsController object with a value. After the username has been retrieved, a test is run to make sure its not empty. At the moment there are only two statements within the if block, but that will change later. The first statement sets the URL to Twitters JSON file for a user. You might not immediately notice anything special about this until you look closer and see %@, and the .fmt() at the end. The .fmt() function performs a handy string replacement with the %@ as the marker. Since the design of the application calls for storing a running list of searches, youll have to somehow store your search term. The final line performs that function, pushing the username value into the App.recentUsersController ArrayController. Since this object doesnt exist yet, running the code will result in an error. Storing previous searches In this next section youll create the object used to store recent searches. Take the following code and add it after the App.tweetsController object. App.recentUsersController = Em.ArrayController.create({ content: [], addUser: function(name) { if ( this.contains(name) ) this.removeObject(name); this.pushObject(name); }, removeUser: function(view){ this.removeObject(view.context); }, searchAgain: function(view){ App.tweetsController.set(username, view.context); App.tweetsController.loadTweets();
22/25
});
Youre already familiar with creating an ArrayController and adding an empty content array, but this object has a few new elements starting with the addUser function. This will check the existing array ( this ) using a built-in Ember function named contains(). If it finds a result it removes it by using the ArrayControllers function removeObject(). This function has an opposite named pushObject(), which is used to add individual objects to the content array. Both functions also have pluralized versions that handle multiple objects: pushObjects() and removeObjects(). This code first removes an existing term before adding it so that the same search term isnt displayed more than once. Since you already know how to remove an object from the content array, the only new element in the removeUser() function is the argument. When a function is called using the {{action}} helper, Ember implicitly passes in a reference to the current view. In the case of App.tweetsController, the view has a context that is essentially the item that is currently being iterated over. This context is used to remove the selected item from the array. The searchAgain() function also receives the current view as an argument. When a user clicks a previously searched term, this function populates App.tweetsController.username with the selected username, then triggers the loadTweets() function, offering a single-click view for previous searches. By default, Ember displays contents to the page in ascending order. Array index 1 is first, array index 2 is second, and so on. The design of this application calls for displaying recent searches in descending order. This means that the array must be reversed. While this isnt built-in functionality you can see how easy it is to add. Reverse() first converts the Ember content array into a plain vanilla array using the Ember toArray() function, reverses it, and then returns it. What makes it possible to use this function as a data source is the property() function tacked on at the end. The property() function takes a comma-delimited list of properties required by the specified function. In this case the property() function is implicitly using the content array itself, addressing each element within that array using the @each dependant key. Youll see how to implement the reverse() function in the next section. Displaying previous searches Now that youre storing your previous searches, its time to display them on the page. Copy the following template and add it after the h3 tag labeled Recent Users. {{#each App.recentUsersController.reverse}} <li> <a href=# title=view again {{action searchAgain target=App.recentUsersController}}>{{this}}</a> <a href=# title=remove {{action removeUser target=App.recentUsersController}}>X</a> </li> {{/each}} </ol> You should be familiar with all of this code at this point. The each block points at the content array and the HTML contained within it will be applied for every item within the App.recentUsersController variable. Its not necessary to explicitly point to the content array, but in this case this code points to the reverse function, which provides the data in reverse order. The {{action}} helper lets users click on each anchor tag and trigger the indicated function. The only element that might not be familiar is {{this}}. When iterating over a content array, Ember keeps a reference to the current index in the {{this}} variable. Because the value of each item is only a string, you can directly output the value of the current item using {{this}}. Clicking on a Twitter username will load that users tweets again, while clicking on their name will remove them from the recentUsersController. <ol>
23/25
Loading tweets Saving search terms is good, but how about actually performing the search? Next youll be adding the pieces that will retrieve the JSON packet from Twitter and display it to the page. Take the following Ember Model and add it directly after the comment block labeled Model. Remember that Ember Models are a blueprint for the data they will contain. App.Tweet = Em.Object.extend({ avatar: null, screen_name: null, text: null, date: null }); In app.js locate the line that reads App.recentUsersController.addUser(username); and add the following code directly after it: $.getJSON(url,function(data){ me.set(content, []); $(data).each(function(index,value){ var t = App.Tweet.create({ avatar: value.user.profile_image_url, screen_name: value.user.screen_name, text: value.text, date: value.created_at }); me.pushObject(t); }) }); If youve used jQuery before you might have used the .get() function to retrieve data. The .getJSON() function does the same thing except it expects a JSON packet as a result. In addition it takes the returned JSON string and converts it into executable JavaScript code for you. Once the data has been retrieved, the content array is emptied removing all existing tweets. The next line takes the packet of data and wraps it in a jQuery object so that the .each() method can loop over the resulting Tweets. Within the each block a copy of the Tweet Model is populated with data, and then pushed into the ArrayController. Finally, youll need to add the following display code to index.html. Copy and paste it directly after the h3 tag labeled Tweets. <ul> {{#each App.tweetsController}} <li> <img {{bindAttr src=avatar}} /> <span>{{date}}</span> <h3>{{screen_name}}</h3> <p>{{text}}</p> </li> {{/each}} </ul>
24/25
Ember makes it easy to output data to the page using plain {{Handlebars}} but theres a catch. Remember how Ember wraps outputted values in script tags? Thats not an option when youre working with HTML attributes. So Ember provides the {{bindAttr}} helper. Any attribute placed within this helper will output as normal, but still retain bindings. Go ahead and run your application now. Input a username
MORE INFORMATION
>
ONLINE RESOURCES Ember.js official website http://emberjs.com/ Ember.js Documentation http://docs.emberjs.com/ Emberist http://www.emberist.com/
>
appliness
This article provides an introduction to RequireJS and how you can use it to help manage JavaScript projects.
introduction
In most software development languages, applications are built using dozens, hundreds, or even thousands of files. In JavaScript, however, developing inside only a small handful of fileseach containing hundreds or thousands of lines of codehas traditionally been more commonplace. Expert or beginner, comprehending the scope and intricacies of such files can be a daunting task. Making sure your code stays clean and modular is an even taller order. Then why are large, complex JavaScript files so common? The most commonly cited reasons are:
Thats the way JavaScript development has been done in the past. Loading many JavaScript files requires many HTTP requests resulting in longer load times. Dependency management is hard in JavaScript. While the first excuse is true, relying solely on whats been done in the past is the death of progression. The second point is a legitimate concern, and the third point used to be much more of a problem than it is today. Fortu-
d n u o laygr
Difficulty
- rookie - intermediate - expert
- Require S J n o m m o C - AMD
Todo list
- maintain
by Aaron Hardy
nately, there are fantastic libraries and standards that can help developers overcome both these problems. In fact, overcoming them is imperative. The scalability of JavaScript applications and the sanity of the engineers who develop them depend on it. This article provides an introduction to RequireJS and how you can use it to help manage JavaScript projects.
You can assume there are some dependencies here, but what are they? How do you find out? If Im new to the team, I wouldnt want to touch the order of these with a ten-foot pole. What if there was a better way? What if each file could declare its own dependencies so you didnt have to maintain this brittle master list? What if the relationships declared by each file could be understood by a loader of some sort that could load dependencies on demand, and the dependencies of those dependencies, and so on?
27/32
in which they must be loaded. AMD The module concept was great for server-side development as it addressed how to load modules based on dependency definitions, but the browser-side JavaScript developers got a bit jealous. Why should such a useful mechanism be confined to the server? Sure, browsers would need to load modules asynchronously rather than synchronously, but that didnt mean the concept of modules and dependency definitions couldnt apply. The Asynchronous Module Definition, or AMD, was born for this purpose. It takes the module and dependency definition API from the server side and applies it to the asynchronous paradigm of the browser. RequireJS So what does RequireJS have to do with this? Well, even though you can define your modules and their dependencies with AMD, you need something smart that can take this dependency map, load the modules, and execute the modules in order. Thats the role RequireJS plays. Both RequireJS and AMD are open source, popular, and well-curated by James Burke.
28/32
Once book.js is loaded and the book module is registered, RequireJS will execute the callback function and pass the module (the book object defined previously) in as a parameter. The argument name isnt technically significant. You could have just as easily used function(a1337Book) or whatever name you wanted. In this case, it makes sense to have the argument name match the module name since its consistent and easy to understand. Finally, whatever object is returned from this callback function will be registered with RequireJS as the bookshelf module. In this case, its an object with a listBook() method that just invokes alert() on the books title. RequireJS tries to be as efficient as possible when loading multiple modules. For example, if multiple dependencies are listed, RequireJS will load all the dependencies in parallel.
29/32
tered, it will then load book.js. Once thats done and book and then bookshelf have registered their respective objects as modules with RequireJS, the callback in main.js will be executed and bookshelf will be passed through. At that point you can do whatever you want with bookshelf. If needed, you can list multiple module dependencies and they will all be passed into the callback as soon as theyre all loaded and registered with RequireJS.
30/32
Constructor modules
So far, the modules youve seen have all been object instances; bookshelf was an object and book was an object. In reality, modules are often constructors (similar to classes in classical languages). In this example, you may want to make the book module a constructor. Library could then create and store multiple book objects. The book module would now look something like this: define(function() { var Book = function(title, publisher) { this.title = title; this.publisher = publisher; }; return Book; }); Notice here that youre passing a function into define() instead of an object. When you pass a function instead of a regular object, the function will get executed by RequireJS and whatever is returned from the function then becomes the module. Here the book constructor is returned. The bookshelf module would now look like this: define([ book ], function(Book) { var books = [ new Book(A Tale of Two Cities, Chapman & Hall), new Book(The Good Earth, John Day) ]; return { // Notice Ive changed listBook() to listBooks() now that // I am dealing with multiple books. listBooks: function() { for (var i = 0, ii = books.length; i < ii; i++) { alert(books[i].title); } } }; });
31/32
When a user loads index.html, it will in turn load RequireJS, which will then load the main.js file. The main. js file, this time, will not only contain your usual main.js bootstrap code but also all the minified, concatenated code of the rest of your app. All the modules in the file will register themselves with RequireJS at that time. When main starts asking for dependencies and those dependencies start asking for dependencies, RequireJS will recognize that all the required modules have already been loaded and forego loading them from the server again. Of course, the optimizer has its own set of options. You can optimize your app down to a few different files representing sections of your app instead of a single large file. You can also use different minifier libraries, exclude files from concatenation, or even minify CSS. This article has covered a great deal of ground, but theres plenty more to learn about dependency management. The RequireJS website is a great place to start.
ONLINE RESOURCES His blog about JavaScript http://aaronhardy.com/ RequireJS http://requirejs.org/ Documentation http://requirejs.org/docs/api.html
appliness
Getting started with HTML mobile application development using jQuery mobile, RequireJS and BackboneJS
In this introductory tutorial, I will cover BackboneJS, jQuery Mobile and RequireJS, to help web developers to build a modular mobile application. With using PhoneGap , it will be very easy for you to package and deploy the application to multiple platforms.
We will build a simple sample application step by step. With this progressive enhanced demo application, we will introduce: How to modularize application using BackboneJS,jQuery Mobile and RequireJS; How to use Backbone View, Collection/Model and Routers. How to decouple mobile view and model/collection using Backbone events.
SAMPLE APPLICATION
The demo application has 2 views:Home View and List View. The Home view features a list of categories for IT books, when the List View actually lists the books available in the store.
d n u o laygr
Difficulty
Todo list
- modules - MVC
- mobile dev
by Mark Dong
34/45
Project structure
IDEA
In a jQuery Mobile application, each view on the mobile device is a page and is declared with an element using data-role=page attribute. So in this tutorial, when we say view, it means page of jQuery Mobile. Multiple pages could be organized inside the body of html page and jQuery Mobile will manage them automatically, just like multi-page template structure described in jQuery Mobile doc. But we all know, loos coupled architecture is better. Using Require.js and Backbone.js, we can divide the pages into separate files as View modules with templates. It allows modular development and testing. It is also easier to extract the model and logic of view into behavior objects. Lets start building this modular application step by step.
index.html
index.html is just a shell page. <!DOCTYPE html> <html> <head> <title>DEMO APPLICATION</title> <meta name=viewport content=width=device-width, initial-scale=1/> <meta http-equiv=Access-Control-Allow-Origin content=*/> <link rel=stylesheet href=css/jquery.mobile-1.1.0.css /> <link rel=stylesheet href=css/style.css /> <!-- we will use cordova to package the mobile application--> <script src=js/vendor/phoneGap/cordova-1.6.0.js></script>
35/45
<!-- require.js: data-main attribute tells require.js to load js/main.js after require.js loads. --> <script data-main=js/main src=js/vendor/require/require.js></script> </head> <body> </body> </html>
Once require.js is loaded, it will take the value of data-main attribute and make a require call. In main.js, we usually configure path settings for require.js.
36/45
Mobile:http://coenraets.org/blog/2012/03/using-backbone-js-with-jQuery-mobile/) . In jqm-config.js, we disable the default jQuery Ajax navigation system. Then, use Backbone router to control application and manually call changePage() function to switch between the views. We also remove the hide page from DOM so there is only one view in the DOM every time. define([jquery], function($){ use strict; $(document).bind(mobileinit, function () { $.mobile.ajaxEnabled = false; $.mobile.linkBindingEnabled = false; $.mobile.hashListeningEnabled = false; $.mobile.pushStateEnabled = false; // Remove page from DOM when its being replaced $(div[data-role=page]).live(pagehide, function (event, ui) { $(event.currentTarget).remove(); }); }); });
});
Home View
Now, we are ready to render the first view : home view. 1. Define a module for home view: home.js To render homeView using template, we create a object by extending Backbone.View. Here are homeView codes: js/modules/home/home.js : define([jquery, underscore, backbone, text!modules/home/homeViewTemplate.html], function($, _, Backbone, homeViewTemplate){ var HomeView = Backbone.View.extend({ //initialize template template:_.template(homeViewTemplate), //render the content into div of view render: function(){ //this.el is the root element of Backbone.View. By default, it is a div. //$el is cached jQuery object for the views element. //append the compiled template into view div container this.$el.append(this.template()); //return to enable chained calls return this;
38/45
});
text.js, a RequireJS plugin, can help us load text-based template file through text! prefix so we can separate the template from script file. modules/home/homeViewTemplate.html will be loaded automatically and then passed to the module function as the argument homeViewTemplate. Inside the module function, we use the template engine of Underscore.js to compile the template, and then append the result html segment into views container: this.el, which is a div by default. So we have rendered the view but have not inserted it into DOM. 2. Define the template for home view: homeViewTemplate.html The template for homeView is a static page: modules/home/homeViewTemplate.html <div data-role=content > <div class=content-primary> <p class=intro> <strong>Welcome.</strong> It is a simple demo to show how to build mobile application using JQuery Mobile, Backbone.js and Require.js . </p> <ul data-role=listview data-inset=true > <li data-role=list-divider class=listTitle>IT BOOKSTORE</li> <li data-theme=a><a href=#list/1>JavaScript</a></li> <li data-theme=a><a href=#list/2>NodeJS</a></li> <li data-theme=a><a href=#list/3>IOS</a></li> </ul> </div><!-- /content --> </div> As we can see, in our example application, the template of HomeView has no Header and Footer. All contents are place into content div with data-role=content specified. jQuery Mobile uses HTML5 data- attributes to allow for markup-based initialization and configuration of widgets. Inside content container, we add a listview with using data-role=listview . Each item has a hardcoded link which will change the hash segment of the url. For example, #list/1 , 1 is categoryId, so we will use it to fetch book data from matching json file later. We will add the mapping in the routes of router.js later to allow Backbone to invoke mapping functions to response users interaction. 3. ShowHome in router.js We use showHome() to insert the view into DOM and present HomeView.The updated router.js is as below: define([jquery, underscore, backbone,modules/home/home, model/book/bookCollection, modules/list/books, jqm], function($, _, Backbone,HomeView,BookCollection,BookListView) { use strict; var Router = Backbone.Router.extend({ //define routes and mapping route to the function routes: { : showHome, //home view home: showHome, //home view as well list/:categoryId : showBooks,
39/45
*actions: defaultAction //default action defaultAction: function(actions){ this.showHome(); }, showHome:function(actions){ // will render home view and navigate to homeView var homeView=new HomeView(); homeView.render(); this.changePage(homeView); }, init:true, showBooks:function(categoryId){ //create a collection var bookList=new BookCollection(); //create book list view and pass bookList as the collection var bookListView=new BookListView({collection:bookList}); //need to pass this as context bookListView.bind(renderCompleted:Books,this.changePage,this); //update view bookListView.update(categoryId); }, changePage:function (view) { //add the attribute data-role=page for each views div view.$el.attr(data-role, page); //append to dom $(body).append(view.$el); if(!this.init){ $.mobile.changePage($(view.el), {changeHash:false}); }else{ this.init = false; }
} }); });
return Router;
First, add one more dependency for router.js: modules/home/home, which is a module defined in home. js; and then pass it to router module function as argument HomeView. In showHome function, we create homeView object and render the view content, then pass homeView to changePage function. The changePage(view) is responsible for setting jQuery Mobile data-role attribute of views root element (view.$el) and appending it into DOM. Now, we have a html document containing one jQuery mobile page div. This is the first page of our demo application. jQuery mobile will find and enhance the pages in the DOM and transition to the first page automatically once the DOM is ready. So it is not necessary to call jQuery mobile $.mobile.changePage() manually for initial page.
40/45
4. Run Open the browser and run the application by http://localhost/ (assuming you deploy your application on the root of your web server) , you will see the first view of the application:
LIST VIEW
When user clicks any item in the list, the application will navigate to the second view:book list view, to show the books of the selected category. 1. Prepare json data To make this demo application as simple as possible, we emulate backend service using local json data. For the list view, we need 3 local json data files mapping to the category item: JavaScript, NodeJS and IOS. The name of json file should follow the format of category + id + .json, like data/category1.json, data/category2.json and data/category3.json. For example , category1.json looks like as following : [ { id: 1001, name: JavaScript & jQuery: The Missing Manual }, { id: 1002, name: JavaScript: The Definitive Guide }, { id: 1003, name: JavaScript: the best parts }, { id: 1004, name: JavaScript: The Good Parts }, { id: 1005, name: JavaScript Patterns }, { id: 1006, name: Head First JavaScript } ]
2. Define a module for model (bookModel.js) and collection (bookCollection.js) Before we get into the list view, we need to define the model of book and the collection.
41/45
Book model is very simple. We just extend Backbone.Model and define the default value for the attributes.
define(function(){ var Book=Backbone.Model.extend({ //default attributes defaults:{ id:, name:, category: } }); return Book; });
Using Book model, we define the collection of book: bookCollection.js define([jquery, underscore, backbone,model/book/bookModel], function ($, _, Backbone,Book){ var Books=Backbone.Collection.extend( // Book is the model of the collection model:Book, //fetch data from books.json using Ajax //and then dispatch customized event fetchCompleted:Books fetch:function(categoryId){ var self=this; var tmpItem; //fetch the data using ajax var jqxhr = $.getJSON(data/category + categoryId+.json) .success(function(data, status, xhr) { $.each(data, function(i,item){ //create book for each item and then insert into the collection tmpItem=new Book({id:item.id,category:categoryId,name:item.name}); self.add(tmpItem); }); //dispatch customized event self.trigger(fetchCompleted:Books); }) .error(function() { alert(error); }) .complete(function() { console.log(fetch complete + + this); }); }
});
42/45
Add dependency for BookCollection. BookModel is passed to the module function as the argument Book.The item of collection is Book. So we set collections attribute model as Book.
For bookColllection, we will add a function fetch to read the json file and fill into the collection. Once we get the book list successfully, we will trigger a customized event : fetchCompleted:Books. Later, we will bind the event listener on this event in the book list view. 3. Create dynamic template for list view: bookViewTemplate.html Book list view is also rendered with the template. However, it is a dynamic template and is different with homeViews template. We use <%...%> to add script and then Underscore template can execute arbitrary JavaScript code inside <% ... %>. In the following template, the variable data will be passed from template function. Of course, you can use any variable name you prefer. <div data-role=header data-position=fixed> <h1>Books</h1> <a href=#home data-icon=home data-iconpos=notext data-direction=reverse>Home</a> </div> <div data-role=content> <ul data-role=listview data-inset=true > <!-- data is passed from template engine, and templat engine will execute the scripts inside <% %> --> <% for (var i = 0; i < data.length; i++) { %> <% var item = data[i]; %> <li> <a href=#detail/<%=item.name%>/<%= item.id%>> <%= item.name %></a> </li> <% } %> </ul> </div> 4. Define a module for list view: book.js We have already prepared model, collection and template. Now its time to make a view: book.js define([jquery, underscore, backbone, text!modules/list/bookViewTemplate.html], function ($, _, Backbone, bookViewTemplate) { use strict; var BookListView = Backbone.View.extend({ template: _.template(bookViewTemplate), update:function(categoryId){ //set callback of the event fetchCompleted:Books this.collection.bind(fetchCompleted:Books,this.render,this); this.collection.fetch(categoryId); }, render: function(){ this.$el.empty();
43/45
} });
//compile template using the data fetched by collection this.$el.append(this.template({data:this.collection.toJSON()})); this.trigger(renderCompleted:Books,this); return this;
return BookListView; }); First, add text dependency bookViewTemplate . BookListView has two functions: update(categoryId) and render() . The update(categoryId) will call collections fetch function to get book list of selected category by categoryId. Before that, we need to bind the render() function as eventListener for the event fetchCompleted:Books. Once we get the data successfully, we will render the view with using template. In the render function, we use Underscore template engine to compile the template and the data to produce the html segments and then insert into views div container. We also trigger the event renderCompleted:Books to notify router that the view is ready and please change page. In the real case, it is better to cache the template and the view to improve performance. 5. Add routes mapping in router.js Now back to router.js. We will tell router.js how to route application once user clicks category item of HomeView. The same with other modules, we need to add dependencies first. routes: { : showHome, //home view home: showHome, //home view as well list/:categoryId : showBooks, *actions: defaultAction //default action },
Now, once user clicks the item and changes hash segment of url, Backbone will call showBooks() and pass the category id. The following codes are what we will add in router.js. init:true, showBooks:function(categoryId){ //create a collection var bookList=new BookCollection(); //create book list view and pass bookList as the collection var bookListView=new BookListView({collection:bookList}); //need to pass this as context bookListView.bind(renderCompleted:Books,this.changePage,this); //update view bookListView.update(categoryId); },
44/45
changePage:function (view) { //add the attribute data-role=page for each views div view.$el.attr(data-role, page); //append to dom $(body).append(view.$el); if(!this.init){ $.mobile.changePage($(view.el), {changeHash:false}); }else{ this.init = false; }
As the codes shows, we add an attribute init, which is a flag attribute. Like we mentioned before, for the initial page of jQuery Mobile application, jQuery mobile will enhance and present it automatically. So we should not call $.mobile.changePage() manually. In the function showBooks() , we create BookCollection and bind it with BookListView. Before updating the view (which will call bookCollections fetch function) , we bind the changePage() function with the event renderCompleted:Books. So when the view is rendered , we will call changePage() to insert it into DOM and then enhance page and transit to the new page. In the function changePage(), if it is not the initial page, we manually call jQuery mobile function $.mobile.changePage() to load new page and apply transition effect.
CONCLUSION
It is just a very beginning application and far away from a real one. Actually, there are lots of things we can improve, like caching template and view, or even separating the control logic from router. RequireJS+BackboneJS+jQuery Mobile is a powerful combination and an easy to use technology. Especially, with requireJS and BackboneJS, we can modularize the application development and make the application clean and clear. In this introductory tutorial, weve only scratched the surface of jQuery mobile, BackboneJS and requireJS. If you want to learn more, you can go to the official sites of these libraries and frameworks. Thank you for taking your time to read this tutorial!
MORE INFORMATION
>
ONLINE RESOURCES JQuery Mobile official website http://jquerymobile.com/ JQuery UI http://jqueryui.com/ Touch Punch https://github.com/furf/jquery-ui-touch-punch
>
appliness
Simple Offline Data Synchronization for Mobile Web and PhoneGap Applications
Being able to work offline is an expected feature of mobile applications. For data-driven applications, it means that you the developer will have to store (a subset of) your application data locally, and implement a data synchronization mechanism that keeps your local and server data in sync.
In this article, I describe a simple data synchronization strategy that uses the devices (or browsers) SQLite database. The implementation currently leverages the Web SQL API (even though the W3C is no longer actively maintaining the spec) because both iOS and Android support it, but they dont support IndexedDB, the official alternative. However, the API described below getLastSync(), getChanges(), applyChanges() defines a generic synchronization contract, and the solution can be expanded and made pluggable: You could create different synchronization objects, each providing a different implementation of these methods. You could then choose which object to plug in based on the context and the platform your application is running on.
d n u o laygr
Difficulty
- rookie - intermediate - expert
Todo list
by Christophe Coenraets
Before looking at the code, you can try some offline syncing in this a hosted playground: 1. Open the Offline Client Playground in Chrome or Safari (they both support Web SQL). 2. Click the Synchronize button. 3. Look at the log (the textarea in the middle of the screen): Because its the first time you use the application, all the employees have been downloaded from the server and inserted in your local SQLite database. 4. Clear the log, click the Synchronize button, and look at the log again: because you now have an upto-date local version of the data, the server didnt return any change and your local database remains unchanged. 5. In another tab, open the Server Admin PlayGround. 6. Modify an existing employee and click Save. (Dont worry, its using your own session-based data set). 7. Go back to the Offline Client tab, click Synchronize, and notice that the server returned one change, and that it was applied to your local database. 8. Go back to the Server Admin tab and modify (create, update, delete) other employees. Switch back to the Offline Client tab, click Synchronize, and see how these changes are applied to your local database.
47/50
9. You can also use the Resources Tab in the Chrome Developer Tools to inspect your local database.
Server API
The only piece of infrastructure you need at the server side is an API that returns the items that have changed (created, updated, or deleted) since a specific moment in time expressed as a timestamp. Here is the RESTful API call used in my application: http://coenraets.org/offline-sync/api/employees?modifiedSince=2012-03-01 10:20:56 The format of the data returned by the server is up to you and is part of the contract between the client and the server. In this application, the server returns the changes as an array of JSON objects. The serverside technology (RoR, PHP, Java, .NET, ) and database system (SQL, NoSQL, ) you use to generate the list of changes is also totally up to you. I provide a simple PHP implementation as part of the source code. That implementation manages a session-based data set that provides an isolated and transient playground. In a real-life application, youd obviously get the data from some sort of database.
Client API
At the client side, our synchronization API consists of three methods. getLastSync() A method that returns a timestamp to be used as the query parameter for the next synchronization request. A common practice is to persist a timestamp after each synchronization request. But things can go wrong and the timestamp itself can get out-of-sync. I prefer to recalculate the lastSync timestamp before each synchronization request. getLastSync: function(callback) { this.db.transaction( function(tx) { var sql = SELECT MAX(lastModified) as lastSync FROM employee; tx.executeSql(sql, this.txErrorHandler, function(tx, results) { var lastSync = results.rows.item(0).lastSync; callback(lastSync); } ); } ); } getChanges() This is a wrapper around an Ajax call to the server-side API that returns the items that have changed (created, updated, or deleted) since a specific moment in time defined in the modifiedSince parameter. getChanges: function(syncURL, modifiedSince, callback) { $.ajax({ url: syncURL, data: {modifiedSince: modifiedSince}, dataType:json, success:function (changes) { callback(changes); }, error: function(model, response) {
48/50
});
alert(response.responseText);
applyChanges() A method that persists the changes in your local data store. Notice that SQLite supports a convenient INSERT OR REPLACE statement so that you dont have to determine if you are dealing with a new or existing employee before persisting it. applyChanges: function(employees, callback) { this.db.transaction( function(tx) { var l = employees.length; var sql = INSERT OR REPLACE INTO employee (id, firstName, lastName, title, officePhone, deleted, lastModified) + VALUES (?, ?, ?, ?, ?, ?, ?); var e; for (var i = 0; i < l; i++) { e = employees[i]; var params = [e.id, e.firstName, e.lastName, e.title, e.officePhone, e.deleted, e.lastModified]; tx.executeSql(sql, params); } }, this.txErrorHandler, function(tx) { callback(); } ); }
Synchronization Logic
With these server and client APIs in place, you can choreograph a data synchronization process as follows: sync: function(syncURL, callback) { var self = this; this.getLastSync(function(lastSync){ self.getChanges(syncURL, lastSync, function (changes) { self.applyChanges(changes, callback); } ); });
49/50
Final Notes
This solution currently supports unidirectional (server to client) data synchronization. It could easily be expanded to support bidirectional synchronization. This solution currently implements logical deletes: items are not physically deleted from the table, but the value of their deleted column is set to true. As mentioned above, you could replace the Web SQL implementation with another data access strategy. For example, take a look at Brian Leroux Lawnchair for another local persistence solution.
Source Code
The source code is available in this GitHub repository.
MORE INFORMATION
>
ONLINE RESOURCES PhoneGap official website http://phonegap.com/ Client Playground http://coenraets.org/offline-sync/client-app/ Sample Source https://github.com/ccoenraets/offline-sync
>
appliness
There are a lot of great blog posts, articles, and videos about HTML5 Application Cache, but because its fairly new and the spec is still evolving, its hard to get your head around all of the intricate details.
What is it?
The Application Cache is a new HTML5 capability that is different from the normal browser cache that weve had for years. The normal browser cache maintains copies of recent files that you have accessed and keeps copies of those files on your computer so that when you need the same file again, it wont have to re-download it. Other than some simple browser settings to control the overall cache size and a few meta tags to turn it on and off, you really dont have any useful control over how its used. The application cache is a web-application-specific cache, the content and behavior of which is controlled by the application itself. The application cache is persistent and provides full off-line capabilities. It is currently supported in Chrome (v4.0+), Safari (v4.0+), Firefox (v3.5+), and Opera (v10.6+). Its not currently supported in any shipping version of Internet Explorer, but it is coming in IE10.
d n u o laygr
Difficulty
- rookie - intermediate - expert
Todo list
by Greg Wilson
52/58
You can also see the files being downloaded from Chromes JavaScript console:
The console after hitting the same site for a second time:
53/58
54/58
iOS Making the web app run full-screen without Safari controls:
After the above changes, I can use mobile Safari on my iPhone and iPad to access the page. After accessing it once, its saved for offline use. I wanted it to be more app-like, so I added the following meta tag to the index.html: <meta name=apple-mobile-web-app-capable content=yes/> This will make the cached app run in full-screen mode so the user doesnt see the Safari controls.
55/58
56/58
57/58
Resources I used
Here are the resources I found while researching this: A Beginners Guide to using the Application Cache - HTML5Rocks.com tutorial Building and Offline Mobile Web Application by Christian Cantrell Offline Web Application Dive info HTML5 Take this Offline Appcache Facts - Good reference for the cache manifest file contents. This page claims that Firefox doesnt allow a simple * in the FALLBACK section, but my current version seems to work fine, so I suspect that it needs a minor edit. Storing Data on the Client (Apple) Configuring Web Applications (Apple covers Apple-specific meta tags, icons, splash screens, & more.) Building an Offline Mobile Web Application Configuring the Viewport (Apple important information on controlling the viewport) Application Cache is a Douchebag a colorful rant about some of the limitations of app caching. DOMApplicationCache Class Reference (Apple)
MORE INFORMATION
>
>
appliness
I am the author of the charting and mapping tools, amCharts.com and amMap.com. I am currently working on an SVG version of amMap - an interactive mapping tool I made with flash some years ago. Until this product is released, you can follow this tutorial and do a lot of things yourself.
In this article I will try to explain how you can quickly create an interactive and zoomable map from a simple SVG map downloaded from Wikipedia (or anywhere else). I dont use any 3rd party libraries in this tutorial and will try to keep it very simple, so even if you are not JavaScript guru, it will be easy to follow.
d n u o laygr
Difficulty
- rookie - intermediate - expert
Todo list
- zoom in
by Antanas Marcelionis
If you view the source of this SVG file with a text editor, you will see that its XML which you can modify: 1 <?xml version=1.0 encoding=UTF-8 standalone=no?> 2 <svg 3 xmlns:dc=http://purl.org/dc/elements/1.1/ 4 xmlns:cc=http://creativecommons.org/ns# 5 xmlns:rdf=http://www.w3.org/1999/02/22-rdf-syntax-ns# 6 xmlns:svg=http://www.w3.org/2000/svg 7 xmlns=http://www.w3.org/2000/svg 8 xmlns:sodipodi=http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd 9 xmlns:inkscape=http://www.inkscape.org/namespaces/inkscape 10 xml:space=preserve 11 width=680 12 height=520 13 viewBox=1754 161 9938 7945 14 version=1.0 15 id=svg2 16 sodipodi:version=0.32 17 inkscape:version=0.46 18 sodipodi:docname=Blank_map_europe2.svg 19 sodipodi:docbase=C:\Documents and Settings\Botek\Desktop 20 inkscape:output_extension=org.inkscape.output.svg.inkscape><metadata 21 id=metadata78><rdf:RDF><cc:Work 22 rdf:about=><dc:format>image/svg+xml</dc:format><dc:type 23 rdf:resource=http://purl.org/dc/dcmitype/StillImage /></ cc:Work></rdf:RDF></metadata><sodipodi:namedview 24 inkscape:window-height=691 25 inkscape:window-width=1014 26 inkscape:pageshadow=2 ...
60/68
So lets try it - lets make Lithuania (because I live there :)) green. Without looking into the structure of the document, I searched for Lithuania keyword first, but didnt find anything. So I searched for lt (iso country code of Lithuania), including quotes (otherwise I would find a lot of matches), and bingo - found the match on line 364: 362 style=fill: rgb(192, 192, 192); stroke: rgb(255, 255, 255); strokewidth: 8; fill-opacity: 1; 363 transform=translate(0.0005875, 7.53846e-05) /><path 364 id=lt 365 class=eu europe 366 d=M 7581.781,4394.3979 C 7584.6474,4391.5317 7584.6474,4385.799 I assumed that the XML node starting with <path whose attribute is my match (id=lt) referenced Lithuanias area on the map. I checked other attributes of path and found this one: style=fill: rgb(192, 192, 192); stroke: rgb(255, 255, 255); stroke-width: 8; fill-opacity: 1; And changed it to: style=fill: #00DD00; stroke: rgb(255, 255, 255); stroke-width: 8; fill-opacity: 1; (I like HEX color codes more, and guessed that SVG should understand it too). I then saved the file and opened it in browser:
As you see, you can easily modify SVG yourself. Sometimes coloring countries in different colors is all you need. In next part well dynamically change colors.
61/68
62/68
63/68
64/68
OK, so now I have pixels but I obviously need something else, as these numbers dont look like the ones from viewBox attribute. My guess is that I need to calculate ratio of original viewBox width and width of the map, same with the height and then use ratio to convert my pixels to new viewBox values. Lets create a method called getViewBox: function getViewBox(x1, y1, x2, y2) { // viewBox data (from SVG file) var svgMinX = 1754; var svgMinY = 161; var svgWidth = 9938; var svgHeight = 7945; // actual size (from SVG, but can also be set in HTML) var width = 680; var height = 520; // width and height ratio var wRatio = svgWidth / width; var hRatio = svgHeight / height; // desired width in pixels var desiredWidth = x2 - x1; // desired height in pixels var desiredHeight = y2 - y1; // new viewBox values var newWidth = Math.round(desiredWidth * wRatio); var newHeight = Math.round(desiredHeight * hRatio); // initial minX and minY must be added var newMinX = svgMinX + Math.round(x1 * wRatio); var newMinY = svgMinY + Math.round(y1 * hRatio); wHeight; return newMinX + + newMinY + + newWidth + + ne}
To be sure its correct I simply called this method with values I measured using Photoshop: getViewBox(365, 236, 430, 296); and entered the values Ive got directly in my SVG file: viewBox=7088 3767 950 917
65/68
Lets make the same map using JavaScript (do not forget to bring old values back before proceeding). function lithuaniaClicked() { var viewBox = getViewBox(365, 236, 430, 296); svgDoc.getElementById(svg2).setAttribute(viewBox, view}
Box);
svgDoc.getElementById(svg2) gets the first node of the SVG document and sets new viewBox value (svg2 is the id of this first node in this example, so it might be different in your code). I did the same for other two countries with slightly different values and here is final code: <?xml version=1.0 encoding=UTF-8?> <!DOCTYPE html> <html xmlns=http://www.w3.org/1999/xhtml> <head> <title>SVG map tutorial</title> <script type=text/javascript> var svgDoc; function colorizeCountries() { svgDoc = document.getElementById(map).contentDocument; var lithuania = svgDoc.getElementById(lt); lithuania.addEventListener(click, lithuaniaClicked, false) lithuania.style.fill = #00CC00;
66/68
latvia.addEventListener(click, latviaClicked, false) latvia.style.fill = #CC0000; var estonia = svgDoc.getElementById(ee); estonia.addEventListener(click, estoniaClicked, false) estonia.style.fill = #0000CC;
Box);
function lithuaniaClicked() { var viewBox = getViewBox(365, 236, 430, 296); svgDoc.getElementById(svg2).setAttribute(viewBox, view} function latviaClicked() { var viewBox = getViewBox(366, 213, 445, 273); svgDoc.getElementById(svg2).setAttribute(viewBox, view} function estoniaClicked() { var viewBox = getViewBox(368, 191, 447, 250); svgDoc.getElementById(svg2).setAttribute(viewBox, view} function getViewBox(x1, y1, x2, y2) { // viewBox data (from SVG file) var svgMinX = 1754; var svgMinY = 161; var svgWidth = 9938; var svgHeight = 7945; // actual size (from SVG, but can also be set in HTML) var width = 680; var height = 520; // width and height ratio var wRatio = svgWidth / width; var hRatio = svgHeight / height; // desired width in pixels var desiredWidth = x2 - x1; // desired height in pixels var desiredHeight = y2 - y1; // new viewBox values var newWidth = Math.round(desiredWidth * wRatio); var newHeight = Math.round(desiredHeight * hRatio);
Box);
Box);
67/68
// initial minX and minY must be added var newMinX = svgMinX + Math.round(x1 * wRatio); var newMinY = svgMinY + Math.round(y1 * hRatio); wHeight; return newMinX + + newMinY + + newWidth + + ne}
</script> </head> <body> <object data=europe.svg onload=colorizeCountries() id=map type=image/svg+xml></object> </body> </html> Open the page and click on one of the three countries - the map should zoom in. Now try to extend this example and do the zoom with animation :) And this is it for this tutorial. I hope you enjoyed it and you will get some use from it.
MORE INFORMATION
>
ONLINE RESOURCES amCharts official website http://www.amcharts.com/ amCharts blog http://blog.amcharts.com/ SVG official website http://www.w3.org/Graphics/SVG/
>
appliness
The standard language for control the layout and graphic styles in this new version comes with a new powerful control over animations. Now in html5 we can include animations or transitions over properties and transformations with techniques like web keyframes and transitions
animations
There will be certain cases where you need to publish a web animation, sure you know Flash is an easy tool for create and deliver interactive content over the web. In the new mobile revolution, the content must be written in standard way. Tools like Flash are not the best choice for simple animations. With new plugins or third part tools, you can export a complex animation created in Flash, and publish in HTML5 with a canvas element container. But what can you do for a simple menu button? what about my share button or a simple logo moved around the header zone? the answer to that is CSS3 animation property. The CSS3 animation property - a different approach from css transitions - can make a great impact with just a few lines of code . The standard for animations being in W3Cs working Draft: - http://www.w3.org/2005/10/Process-20051014/tr#RecsWD - http:// www.w3.org/Style/CSS/current-work but we can start using it safety, in modern web browsers and mobile devices.
d n u o laygr
- CSS - W3C - animation
Difficulty
- rookie - intermediate - expert
Todo list
by Francisco Granados
In this article we introduce you to the world of web animation with CSS3 and their new concepts about keyframes. Well see how can define keyframes and their potential with others new effects part of CSS3.
Syntax
The new elements we need for doing an animation in CSS3 are: // animation name // animation points // properties to change in each point // configuration and call for animation To start with the animation lets we write our block of @keyframes with a name /** example for syntax */ @keyframes name{ ... } Each time we need to start an animation we can look for its name, defined in the first line. Its important to notice we should name it without spaces.
time matters
Points of an animation are properly the keyframes. Each keyframe is a relative part of the whole animation. In this implementation of animations with keyframes we have the capacity to assign a variable time of reproduction each time we start the animation. We can set an animation for 4 seconds or 20 seconds and then play it. For example, if we have an animation of 4 seconds or 30 seconds the points of the animation are divided in relative parts expressed as percentages.
delay
from 0% 50%
to 100%
We move an element <div id=box></div> in vertical until 100px and come back. We can change the properties of style as we need in each block of the keyframes. In this example see how the property top is changed 3 times, from start the animation until the finish.
70/74
/** example for animation */ @keyframes my_animation { 0% { top: 0px; } 50% { top: 100px; } 100% { top: 0px; } } In the W3Cs working draft, we can use an alias for 0% & 100% /** example for animation with aliases */ @keyframes my_animation { /** works like 0%*/ from { top: 0px; } 50% { top: 100px; } /** works like 100%*/ to { top: 0px; } }
#box { animation-name: my_animation; animation-duration: 5s; animation-timing-function: ease-in; animation-iteration-count: 2; animation-direction: normal; animation-delay: 1s; } We just need to set this and the animation would start. Also, we can assign a class or a pseudo class like :hover #box:hover { animation-name: my_animation; animation-duration: 5s; animation-timing-function: ease-in; animation-iteration-count: 2; animation-direction: normal; animation-delay: 1s; }
72/74
from { top: 0px; } 50% { top: 100px; } to { top: 0px; } } /** the standard way */ @keyframes my_animation { from { top: 0px; } 50% { top: 100px; } to { top: 0px; } }
publish moment
CSS3 animations will establish a new way for doing movements and simple sequences, at this moment the W3C is completely aware for our needs in the web development. With features like this we can improve the experience of our visits and make the content better. Nowadays the web browsers which implements this way to do animations are: Chrome, Safari and Firefox and in mobile scene the Android Chrome and Safari mobile. Its very important to not put css animations in core functionality because the experience in our sites could be affected. If needed, I recommend Modernizr (http://modernizr.com/) for evaluate the browser support of this feature. /** in javascript */ if(Modernizr.cssanimations){ // have animations }else{ // do not, oh no... } A simple example I made for, is in the magazine source code bundle, I recommend to view the source code and take a look how I take just one definition for keyframes and set in several elements in HTML setting different durations or delays for each one.
73/74
go beyond
This are the basics for CSS3 animation properties an their use. I recommend this post to go deeper about this topic. // Taking Advantage of HTML5 and CSS3 with Modernizr // W3C Working draft // Keyframes and transforms I also recommend to learn about animations API in Javascript to control the play, stop or pause the animation, so you can start an animation with a behavior after a call in AJAX or after an event for jQuery or another one. I hope you enjoy this post and your next projects include this powerful feature of CSS3 web keyframes with web standards.
SAMPLE
HTML CODE
ONLINE RESOURCES W3C working draft http://www.w3.org/TR/css3-animations/ Keyframes and transform http://www.impressivewebs.com/mixing-css3-keyframe-animations/ Modernizr http://modernizr.com/
appliness
andrew explains how to use html, css and javascript to deliver first class data viz components to your users
Almost every enterprise application requires some form of data visualization. Whether it is a business dashboard, sales chart, performance comparison, or hierarchy viewer, there is always data, and there always needs to be an easy way to consume that data. Using web standards technologies (HTML, CSS, & JavaScript) there are 5 general techniques for visualizing data here is a brief overview:
<img>
You can embed images using the html <img> that have server-rendered data visualizations. This is nothing new They are very basic, but will certainly work.
Not interactive Requires online & round-trip to server No WOW factor lets face it, they are boring Example: Google Image Charts
d n u o laygr
- SVG - WebGL - Canvas
Difficulty
- rookie - intermediate - expert
Todo list
- build map
by Andrew Trice
HTML5 <canvas>
You can use the HTML5 <canvas> element to programmatically render content based upon data inmemory using JavaScript. The HTML5 Canvas provides you with an API for rendering graphical content via moveTo or lineTo instructions, or by setting individual pixel values manually. Learn more about the HTML5 canvas from the MDN tutorials.
Can be interactive Dynamic client side rendering with JavaScript Hardware accelerated on some platforms Can work offline Works in newer browsers: http://caniuse.com/#search=canvas Rgraph Open source charting library using HTML5 <canvas> One Million Points Scatter Plot Let the page load, then use the mouse to click and drag regions to drill into. This is a live visualization that shows a scatter plot with a histogram for massive data sets by manipulating individual pixels. This sample is rendering 50.000 points !
76/78
<script> var data = [ 1,2,4,6,7,4,2,3,6,7,8,9,3,2,7,4,1,2,1,1,2 ]; function draw() { var canvas = document.getElementById( myCanvas ); var context = canvas.getContext( 2d ); //draw background grid; context.strokeStyle = #DDDDDD; context.lineWidth = 1; var xIncrement = canvas.width / data.length; var yIncrement = canvas.height / 10;
var padding = 2; context.strokeRect( 0,0, canvas.width, canvas.height ); for ( var yPosition = 0; yPosition < canvas.height; yPosition += yIncrement ) { context.moveTo( 0, yPosition ); context.lineTo( canvas.width, yPosition ); } context.stroke(); //now we can draw the data context.strokeStyle = #000000; context.lineWidth = 1; context.fillStyle = rgba(0,0,255,0.25); for ( var i = 0; i < data.length; i++ ) { var xPosition = (xIncrement * i) + padding; var dataHeight = canvas.height * (data[i]/10); var yPosition = canvas.height - (dataHeight-1); context.fillRect( xPosition, yPosition, xIncrement-2*padding, dataHeight ); context.strokeRect( xPosition, yPosition, xIncrement-2*padding, dataHeight ); } } </script>
WebGL
WebGL is on the bleeding edge of interactive graphics & data visualization across the web. WebGL enables hardware-accelerated 3D graphics inside the browser experience. Technically, it is not a standard, and there is varied and/or incomplete support across different browsers (http://caniuse.com/#search=webgl). There is also considerable debate whether it ever will be a standard; however there are some incredible samples out on the web worth mentioning: WebGL Globe Global Temperature Anomalies Realtime Color Histogram
ONLINE RESOURCES Blog post about data viz http://www.tricedesigns.com/2012/05/02/data-visualization-withweb-standards/ Andys Census app http://tricedesigns.com/census Andys blog http://www.tricedesigns.com
appliness
Adobe Shadow
Adobe Shadow is a great new tool from Adobe that allows developers to design and develop their mobile web content quickly by providing a way to inspect and debug from their desktops wirelessly and synchronously across multiple devices.
about shadow
Shadow essentially allows a developer to browse web content on their desktops and see that same content displayed at the same time on multiple devices. At which point, the layout can be tweaked on-the-fly so results can be seen immediately. If you are a developer doing mobile development with HTML/JS or PhoneGap, you should definitely check it out. If you are wondering how it works, the Adobe Shadow desktop application listens for changes in a URL location in the browser, and when a change occurs, it pushes the new URL out to all wirelessly connected devices immediately so the changed content is seen on the devices immediately. Adobe Shadow consists of the following components and takes just a couple of minutes to get set up and running: Adobe Shadow Desktop Application Adobe Shadow Google Chrome plugin Adobe Shadow Mobile Clients (for iOS/Android devices) Take a look at this short video showing how it works followed by an explanation of the setup and how to use it.
d n u o laygr
Difficulty
- rookie - intermediate - expert
Todo list
by Holly Schinsky
Setup
Desktop 1. Install the Adobe Shadow desktop application from Adobe Labs. 2. Ensure you have the Google Chrome Browser installed (its free). 3. Open the Google Chrome browser and add the Adobe Shadow Google Chrome Extension from the Google Chrome Store. Mobile Devices Go to the AppStore on your iOS devices or Google Play (Android Market) on your Android devices and download the Adobe Shadow mobile device client apps Refer to Adobe Labs for further information on setup. IMPORTANT NOTE: Adobe Shadow runs wirelessly so you must ensure that all devices and computers have access to the Internet and run on the same network.
Mobile Inspection
Start-up the Adobe Shadow Desktop application. You should see the following upon execution:
80/86
Next, open the website or app to be inspected. In this case Ill use Google to keep things simple, but you could open any web content that you are currently working on.
Click on the blue Adobe Shadow icon in the top right corner of the Google Chrome browser toolbar. You will see a drop-down black box displayed that looks like the following:
81/86
If you forget to start your desktop Shadow application, you will get a reminder at this point that looks like the following, and the Shadow icon in the toolbar will be grey (rather than blue):
Now go to your devices and click on the Settings icon in the top left corner. You should now see any computer connections currently running Shadow. In my case I have my MacBook-AIR connection started and waiting, so I click on that to establish the connection back to the latop. I will be notified on my device when the connection is established, such as in the following, as well as any previous connections you may have made to other computers, as shown below:
82/86
Once the connection is established, you can go back into your Google Chrome Shadow icon on your desktop and see all the devices that have made a connection, such as in the following:
Next, you can either change the URL location on your desktops Chrome browser to see the synchronous browsing occur on your devices (or trigger the URL change with clicks within your app), or you can start doing remote inspection on a specific device and make other changes to your application (e.g., update CSS, etc.) to see the immediate effects. To start remote inspection on your device, click the double arrows on the black box next to the device you want to inspect:
83/86
You will be presented with a weinre screen. Adobe Shadow includes the open source weinre project as its core engine for remote inspection. (See below for more information about weinre).
From here, you can click on HTML elements and actually modify the CSS inline and see the results on the device immediately. For instance, in the next few screenshots you can see how I updated the background color of the main element on the Google web page on the fly and viewed the results directly on the iPad: This is Google before being viewed in an iPad Adobe Shadow application.
84/86
85/86
You can also view things like storage resources, network activity and console messages from device interaction. For instance, below is the Resources tab for Google:
Here are some other things to note when using Adobe Shadow: Shadow will continue trying to reconnect on the device while open, and keep the device from sleeping, so you need to specifically shut it down when you are not using it or it will run your battery down more quickly due to the reconnection attempts. weinre Adobe Shadow is based on Weinre (Web Inspector Remote), which is technology that allows you to debug between devices. Weinre is composed of 3 programs or web pages running simultaneously: 1. target - the web page being debugged 2. client - the Web Inspector code running as a web page 3. agent - an HTTP server which allows the target and client to communicate. For more in-depth information of how this technology works, I highly recommend checking out this page by Patrick Mueller.
Resources
Here are some links to check out: Adobe Shadow FAQ Adobe Shadow video by Sr Product Manager Bruce Bowman
MORE INFORMATION
>
>
CHRISTIAN HEILMANN
PRINCIPAL EVANGELIST FOR MOZILLA
The mission of a web browser is to allow users to take part in the web.
87/100
E E IV W S E U I V L R C X TE IN
WE ARE VERY HAPPY TO INTERVIEw christian whos one of the most active evangelists on the web. his mission is to promote standards, the open web and innovation at mozilla. he received us at the new mozilla space in london.
Hi Chris, were very happy and excited to interview you. Can you introduce yourself to our readers?
I am Chris Heilmann, @codepo8 on Twitter and I am the principal evangelist for Mozilla with focus on the Open Web and HTML5. My business card says online mythbuster which describes it a bit better. My job is to cut through sales talk and unearth the things people can use now to make the web better. Ive been working as a web developer for over 16 years and I use my experience to make sure we dont repeat mistakes of the past.
Mozilla is so unique. Can you explain to us the mission of Mozilla and whos behind it?
Mozilla is the only independent, non-profit organisation advocating for and creating an interoperable, standards-based Web that creates opportunity for all, regardless of how or where they access the Web. Thats the tagline. It means mostly that from day one of our inception Mozilla made sure that people are at the centre of innovation. We gave people a choice with Firefox. Without Mozilla and Firefox (and the history is well-documented on our Wiki) wed have been locked into Windows and Internet Explorer and I am certain the web would not be what it is now. Seeing how Microsoft was back then I am sure the web would still be a corporate thing and very expensive. And lots of grey boxes. We showed in 2003 that innovation on the web can be done by and for people by being open source and open in our documentation and communication. There are no secrets, there are no stakeholder meetings and the hierarchy in Mozilla is defined by how much you are responsible for. The larger part of our code is not written inside the organisation but by volunteers working with us. We localise Firefox to over 90 languages using volunteers. The trick is simple - we give and respect people who participate and we get back that way. It would be impossible to pay the time and effort put into our products. We pay our volunteers in partnering with them, supporting education and documentation and giving access to a vast amount of knowledge stored in the heads of our community.
88/100
I came from a large corporation when I started here and I found an incredible amount of passion, people working because they want to and an avalanche of innovative ideas and discussions. Where I had to ask for information in the past and got hindered by red tape in a lot of cases, I learned triaging information in Mozilla. It is quite a ride, but you are allowed to be yourself and speak your mind here much more than anywhere I have been before.
Youve had a pretty eclectic career path including working with people with disabilities for the Red Cross and as a radio producer. How did you get interested in web development?
Working at a radio station I was frustrated that I wasnt able to report on a lot of interesting issues when they didnt fit the financial goals of the station. I found it annoying that interesting and intelligent people werent allowed to be on the air. Obviously boring people reading soundbites from a sheet of paper their PR team had written for them were as they paid for the right to publish. Thats not right and not the job of the media. Having worked with a day group of people with learning disabilities in the Red Cross (instead of my national army service) I knew that everybody has an interesting story to tell. It is wonderful to see when people start being able to speak for themselves and gain independence and self-assurance from that. I always dabbled with computers since I was a kid (writing things on Commodore 64, later on creating games). When I realised that there is a new media emerging that has an incredibly low barrier to entry that allows anyone to publish world-wide, I was immediately sold. I built my own web site, quit my job and went on to become a web developer. As this was the right time and I was one of a very few people in my area doing that I got some contracts to build company web sites and got head-hunted to work on the intranet of BMW in 1997 or so. The rest is history.
In addition to evangelizing, youre a web developer and still coding a lot. What is a web developer in 2012? What has changed in the last few years?
The web is moving, both from being structured documents that link to each other towards apps and from desktops to mobiles and tablets. The internet connected fridge is almost clich by now but I can see it being a normal sight before long - except our phones will know what is in our fridge and not a computer built into it. This brings quite a few new challenges. As web developers we were always pitied by real developers who build in C++ and build huge systems in Java. Now we are not pitied any longer but these developers also want a slice of the pie that is web apps. As a web developer now you need to know your web standards and how to build sites but you should also be knowledgable about using APIs, talking to servers and architecting solutions. The web is under attack by native apps on mobile platforms. In order to keep it the biggest distribution platform and the main channel to reach millions of people we need to step up and stand our ground in an app world. We should build web apps, native to the web and wonderfully connected to battle the silo-ed world of native apps instead of trying to simulate their look and feel on the web.
89/100
The web has rapidly extended its scope to new playgrounds: server-side, mobile web apps, gaming, hybrid apps Do you feel that web developers should embrace everything, or focus on specific areas?
You should have an understanding of everything and partner with the right people who have a passion for the other pieces of the puzzle but it is very much fine to be an expert in a specific area. We move away from building everything by hand and from scratch to using frameworks, libraries and building blocks. This is hard to swallow for a lot of people but there is no glory in reinventing the wheel over and over again. Whilst the web world smugly points out that it is OK to omit semicolons in JavaScript native apps get rolled out in dozens on a weekly basis. We need to be more nimble and build on what works rather than being in our ivory tower of web developer awesomeness. I dont think being a jack of all trades works out, you should have one pet subject that you cherish and know by heart. But you should also be ready to not use that technology when another is easier to understand for everybody involved.
These days, a new JS library is launched every 6 seconds. It features the excitement around web technologies, but at the same time, developers can feel a little bit lost among all of the possibilities. In your opinion, what should be the top priorities of a web developer?
Get the job done, using reliable tools and leave code behind that is understandable and nimble. Ive spoken quite a lot about how sick I am of quick, small and clever solutions that fall by the wayside a few months down the line and grow into the bloated monsters they originally replaced. As a good web developer you write for the next person to inherit your code. Not for machines. Optimisation can be done with build and conversion scripts, it should not be the start of your work when it results in hard to grasp code.
What excites you the most when you start developing a web application?
The end goal - what do people get out of this app? How does it change their life? If the app doesnt do anything for the user, I have a hard time caring about it. We should write software to make the life of people easier. This can be frivolous things like blowing up pigs by flinging birds at them - it does not have to though. The same addictive and playful interaction could be used to learn things or to organise your life. Apps are different to web sites. With apps you should start thinking about the use case and the environment. The more natural it seems to use your app, the better. I am very excited that we can use touch, device orientation and soon cameras in our web apps. This allows us to create things that are more human to use than things you click with a mouse.
What is your development process and whats the role of design in this process?
There are quite a few different things in here: design as in visual design, design as in interaction design and designing your code solutions before you start writing them. All are equally important. I am not a designer, so I tend to partner with those who are. You can not create an amazing product if you are not engaged in the task. I found the best solutions are found when developers and UX people work together and brainstorm the heck out of an idea before we start developing it. There is a wonderful dynamic in that. The time of making mockups and designs in Photoshop and chucking them over the wall for the developer to implement is over - and good riddance.
90/100
What will it take to turn the possibilities of responsive and scalable mobile applications into a reality with web technologies?
Full access to the hardware from the browser. Right now web apps are treated by mobile platforms and hardware as second class citizens - simulated apps if you will. This is not fair and is very wrong and mostly based on mobile platforms making more money with native apps. The building blocks are there - local storage, offline storage, Drag and Drop, Canvas and WebGL for gaming, native video and audio are supported and WebRTC, Filereader, Web intents, Webcomponents and other innovations are in the making and incredibly exciting. Where it falls down is support from the native browsers on mobile platforms. A lot is incredibly broken which is especially annoying on platforms where the browser is not open source and things are not created in public. Open source doesnt mean releasing a product and making the code available two weeks later. It means building it in the open and taking on advice from those who use your products whilst building the next iteration. A big misconception is also that apps built with web technologies should feel the same and have the same functionality as native apps. To me this actually makes them less interesting. You can never get the same fidelity in a web app that you can get in a native app as you are not that close to the metal and the engine. You can however build a much smaller, easier to update and more connected app as you are not locked into the incredibly outdated world of fullsize downloads, installs and uninstalls. If anything, I think native apps should learn from the web - not the other way around.
91/100
open you can create a web enabled smart phone for the price of a feature phone in a year from scratch. Boot to Gecko allows a JavaScript developer to get to make calls, send text messages, take photos and access the photo data, read the battery status and the network state. This is what we should have had from the very start on HTML5 enabled phones but we didnt. Now we have a stake in the ground and I want a lot more barriers to be broken down.
Do you feel that web standards are evolving faster and in the right direction to answer todays users needs?
They are certainly moving faster and much more in the open than they did in the past. When HTML5 started this was the breath of fresh air we needed. Nowadays they do still move fast but there is a weird undercurrent of things getting in faster when they benefit a platform rather than developers. A great example right now is the responsive image proposal using srcset. The developer community had a different proposal but this one got into the WHATWG specs. I can see quite some discontent or disillusion coming our way if we dont start demanding more discussion from the WHATWG in these matters. In terms of what the users need, yes, we do great work. The issue is that we lose a lot of users to native apps. I can see this turning around soon though. Native apps are getting bigger and sluggish and people are getting sick of having to upgrade to a new phone just to play a game.
How does Mozilla contribute to web standards? Can you detail its role in the process?
We propose a lot of new standards and have people in all the working groups of the W3C. We sponsor research into standards and implementations and with a browser that ships every 6 weeks and Nightly builds and Aurora preview builds we have a great platform to show that the proposals can work. A lot of the standards that made it in and get promoted a lot by other players were actually defined by Mozilla. Great examples of that are the requestAnimationFrame API or the fullscreen API.
92/100
How could developers get involved in the evolution of the web with Mozilla?
Test out beta browsers, Nightly builds, give feedback and take part in the discussions in the WHATWG and on the W3C mailing lists. Mozilla is you, there is no big barrier to entry. If you read the Mozilla Developer Network documentation and you find something that needs fixing, hit the edit button and fix it. If you have a great example that shows how to use the API we talk about hit edit and attach the example. Everything in Mozilla is open - even our conference calls and meeting notes. If you have something useful to contribute, your voice is as important as the one of the person paid by Mozilla. You can sign up at Mozillians.org to get direct access to a lot more people and if you work a lot with us even sponsorship to attend events for Mozilla. Above all - use what we publish. A lot of broken mobile web promises happen right now because developers follow documentation and examples that are build to target one browser and not the standards or all of them. This has to stop. The CSS that only works in webkit right now and renders an unreadable button on other browsers is no better than the best viewed in IE6 of the past. Another big wish of mine is to stay up-to-date before you complain. Almost daily I get people spouting truisms on Twitter that Firefox is slow or doesnt do things other browsers do just to find out that the complaint is based on a one year old article and applies to a Firefox that is 6 numbers behind the currently official one. It is easy to try something before calling it broken - lets do that more.
Are there special specifications youd like to promote or that youd like to see in all browsers as soon as possible?
The Web API spec (Battery status, Camera access, IndexDB, Vibration, Sending SMS) and the Web Runtime (installing HTML5 apps as full-screen, chromeless apps) is things we really, really need. There is no point in trying to build a mobile web app if you can not access the hardware. For example I can read the orientation of an Android device in all three axes as radians in Firefox, it doesnt work with the current Android browser. That is not right. Another thing Firefox does is animating and transition content generated in CSS with ::after and ::before. Other browsers dont do that and it allows you to do so many great visual things without soiling your markup. WebRTC and getUserMedia is something we need, too. I am sick of buggy video chat clients using plugins.
What is your feeling about JavaScript? Do you think that the language should evolve into a more advanced one, closer to Java for instance?
I like JavaScript as it is simple to learn but hard to master. I am getting excited by the things I can build with JavaScript. Hypothetical discussions on where the language should go are not high on my list of must haves. There are things that are very, very broken in JS - especially the security model - but I dont see it as a good use of my time to try to change a language that is probably the most used one on the web. I leave that to the experts that get very excited about that kind of research. Ive seen a lot of people trying to shoe-horn best practices of other languages into JS come and go whilst I happily used what is supported. I think, with the move of JS to the server side, we have to come up with new rules and extensions. Bring them on. Then we try them out and see just how much more we get.
93/100
Whats the mission of a web browser? Whats the positioning of Firefox within that mission?
The mission of a web browser is to allow users to take part in the web. This means that they should get the best experience of the web without being locked in to a certain environment or having to sign up. It also means that their privacy and security should be the most important asset to protect. The ability to surf the web in a quick, secure and safe way should not come at the cost of giving up your identity or all your movements being monitored and sold to advertisers. Firefox very much is a browser that follows these principles. The Do Not Track feature invented by Mozilla allows you to say that you dont want to be tracked when you surf the web. Moreover, Firefox is available across your devices - there is no need to have an Android profile and a Desktop one. Your history, your passwords and your tabs get synced across the tablet, mobile and desktop. All of this backed up by a not-for-profit organisation that only answers to you and not stakeholders of the parent company. I think people can use whatever they want, but I found Firefox to be the most portable and consistent of browsers over the years. I wished that Chrome for Android be the standard in Android and not the browser it has now. There is nothing more annoying than having a worse experience in surfing just because you switch devices.
94/100
95/100
Firefox is very popular on mobile devices. What are the benefits compared to default web browsers?
Firefox Mobile is a speedy, powerful and customised upgrade to mobile browsing for Android phones and tablets. It puts people in control of their online lives and enables them to synchronise their personal Web experience across devices - taking browsing history and passwords everywhere they go. It offers the highest level of privacy and security features in mobile browsing and offers lots of add-ons to enhance the experience. And it has more predictable and much better documented HTML5 support. It is the free upgrade to the browser that doesnt mean you have to wait till Android upgrades.
Developers talk a lot about the War of browsers. Do you feel there is merit to this?
Ive blogged about this lately - I really think the passion we have for seeing browser makers going at each others throats and the fanboyism in developers is very much holding the web back. I am really happy that I work for an organisation that builds a browser that is not part of an operation system strategy or a means to get more users to use our online services. There are a lot of different goals and targets to meet by the different browser vendors. I think it is time that, as developers, we demand more predictability in support across browser and stop getting excited about innovation for the sake of innovation. No web developer I know builds a big customer-facing product without resorting to libraries, polyfills and frameworks. We should be allowed to concentrate on the interface experience of our users, not how to make things work across dozens of device/browser permutations. A browser war is good for browser makers, but actually makes it much harder for developers. Unless you think building for one browser only is the right way to go. Ive seen that fail a few times, and it would be sad to see people do the same mistake again.
It should be the interface and the way the browser ties in with your day to day work. You should be able to easily switch from a work to a home setting, it should always be obvious which data the browser gets from you and where it goes. My biggest pet peeve are browsers that are not available across platforms and only upgrade when the OS upgrades. This is not the 90s, we should have learned by now that browsers need to change quicker, be very easy to patch when security holes happen and I should have the option to customise and personalise my browser in the way I want and take these changes with me wherever I go. A great browser should fix and upgrade itself without interrupting me and let me enjoy the web rather than lock me in to its services.
The mobile web is limited when you want to access some Hardware APIs. Hybrid apps (with frameworks such as PhoneGap) are an efficient workaround. But do you feel that web apps will soon be able to communicate with the camera for instance?
They already do. Firefox Mobile and Boot to Gecko have phone access. The getUserMedia API (and Addy Osmanis polyfill using Flash) gives access to the camera, too and you can use an HTML5 canvas to display and modify the video stream coming from the camera. I think it crucial for web apps to access the hardware of the device - as only by using the hardware access that comes natural with a device allows you to build compelling apps. Playing a game by tilting your phone is much nicer than pressing arrow buttons on a small screen.
Web developers are living in exciting times and we see new innovations every week. Do you see a gap between those innovations and what customers need?
Tough to say. A lot of times customer need is driven by advertising. A few years ago, if you had asked people if they wanted to fling birds at pigs on their phone theyd have told you - no, Id rather call people without spending a fortune. I do see a lack of down to earth innovation though. We try to bring people interactive glasses but we fail to link for example our smartphones and public transport. We have amazingly connected devices in our pockets and we use them to 99% for entertainment. Id love to see more innovation in the field of accessibility, language learning and so on but the assistive device angle is very often overlooked. A great example Ive seen lately was cooklet. This is a recipe app that allows people to cook better food. It is tablet based but the developers realised that most of the time when you cook you have sticky fingers, so the navigation is moving your hand left or right over the camera rather than on touch. We need more of this thinking.
97/100
Do you feel that the browser is the new Operating System? In the long term, could we foresee the end of native and proprietary technologies to develop and deploy apps?
Yes I very much hope so. I am sick of having to hunt apps. OSX is a good example. You install the native apps from a market - they might as well be HTML5. The Web Runtime project of Mozilla very much targets this use case.
A few years ago, platforms such as Flash used to promote youll get the same user experience everywhere. Its not the current trend. How do you explain this?
I guess people finally realised that the promise of getting the same experience everywhere is either a lie or results in a boil-in-the-bag experience without any flavour. A good app to me gets better and more immersive by how much the device the user experiences it on supports. If you run a new computer with the latest Firefox you should get a better experience than the Windows2000 machine with IE6. You shouldnt block out IE6 but you should not give it code it chokes on.
98/100
You invite developers to become evangelists. How do you encourage them and why?
It is great to develop and to be paid for it. But when you dont get people to understand what you are doing then you are a delivery service and you will get money but never the respect you deserve. Developing is not screwing things together or repairing machines. It is a very creative and almost poetic way of dealing with logic, commands and machines that understand them. By sharing the passion that you have for a subject and making other people understand it the way you do, you have a much better chance to get more freedom and a voice when decisions are being made and goals set. We are probably the best paid market in the job world right now and there are not enough people to fill the positions that are open. That someone that wanted works on things they dont believe in or are not proud of saddens me as I think only people with a passion for what they do should be paid a lot of money. I encourage developers to reach out and speak about the things they do by example and by sharing all that I do for them to use. I know quite a few people who used my code examples, books and articles in trainings or my slide decks in company internal presentations. It is pretty incredible how much more your company listens to you when people from the outside praise you or talk about you. Much like we pay consultants to tell us the obvious we are either too busy to see or too scared to bring up.
How should people learn a new technology today? How can we stay up to date with HTML development?
Online. Of course books are a great thing to have if you want to deep-dive but print is too slow to keep up with the changes we have. Following the right people on Twitter, subscribing to good online magazines and news feeds and reading mailing lists, bug requests and statements from the big web companies, the W3C and WHATWG is what keeps you up-to-date. I know people who are totally in the know
99/100
and dont go to conferences at all. That said, good conferences and workshops give you a chance to have some real dedicated time to learning new things and people should use that time. When I was leading a team people were only allowed to go to events when they gave a presentation afterwards on what they learned and what the company could benefit from. Learn and share and it is incredible how fast you are seen as an expert.
Are there any personal projects youd like to accomplish in the coming years thanks to the web?
I want to take a crack at educating people who long to learn but cant afford it. Khan academy is a great project for learning all kind of things online but you need a good connection and a computer to do it. One idea I am playing with is talking to Google about donating Chromebooks to internet cafes worldwide or in deprived areas to allow people to learn from TED and Khan Academy. This is powerful stuff but it still smacks a bit of being elitist. It hurts me to see people live in very well-off environments and waste their time watching TV or being sports fans with a massive hatred for each other. Education is a way out of misery for a lot of people and it is despicable how we treat it in the Western world as something that is given and not cool and not needed. The web can give those who live in areas where the government censors them a voice. The web can also allow people to learn on their own terms and time. It is a wonderful thing and could change this world much like the appearance of movable type brought literacy to poor people in Europe back in the days.
to ap t d M is he c oz o im v illa er ag e B th ar e
100/100
appliness
CHEAT SHEET
css selectors
first-of-type first-child descendant child nth-child adjacent sibling
general sibling
learn css selectors with this great interactive sample by Ben Howdle
#target p:first-of-type {color: #36de4e;} <div id=target> <h2>Where the Buggalo Roam</h2> <p>Alright, lets mafia things up a bit. Joey, burn down the ship. Clamps, burn down the crew. No! Dont jump! Dr. Zoidberg, that doesnt make sense.</p> <div> <p>Does anybody else feel jealous and aroused and worried? </p> </div> <h2>The Mutants Are Revolting</h2> <p>But, okay! I just want to talk. It has nothing to do with mating. Fry, that doesnt make sense.</ p> <h2>Space Pilot 3000</h2>
ONLINE RESOURCES CSS selector on W3C http://www.w3.org/TR/CSS2/selector.html 30 CSS selectors to memorize http://net.tutsplus.com/tutorials/html-css-techniques/the-30-css-selectors-you-must-memorize/ CSS selectors http://css.maxdesign.com.au/selectutorial/
appliness
FEEDBACK
Whenever I start to play around with a new technology, platform or framework I usually plan out a small and easy to complete project that tries to address some of features I am most interested in testing out.
d n u o laygr
Difficulty
- rookie - intermediate - expert
Todo list
- optimize
by Jesse Freeman
Goals
I collaborated with Wesley Crozier (who did all the artwork) on Room112 with the goal of creating a simple PhoneGap app that looks and feels as close to native as possible. I travel a lot and always forget my hotel address, room number and floor. I set the following goals when creating this application: Create a simple one-screen app Test our local storage Make the app feel like a native iOS app Have most design done via CSS3 Test out animation on mobile Web browsers Take advantage of some simple jQuery Understand how to set up and publish a PhoneGap app in Xcode Display a Google Maps image via built-in GPS support The full source code for this project is availbile on github.
architecture
Room112 is very simple. When you launch the app it checks for saved room data. If no data exists you are taken to the check-in screen. If data does exist then the check-in card is displayed with the saved data. I also planned on being able to review past check-in data, but this feature didnt make it into the initial release.
Over the next few pages, we will discuss each of the applications screens based on the designs with functional notes on the logic.
103/117
Loading Screen/Background This represents the loading screen of the application, which is the same as the background image.
When the application is fully loaded, a small pocket is faded in to allow for easier masking of the check-in card animation.
104/117
Once the application is fully loaded, the two layers (background and pocket) work very well to mask off the card animations and offer up a little more depth to the design.
Before Check-In This is the screen you see after launching the app when no hotel information is saved. Simply enter a room number to activate the Check In button and save your data.
During this process, the user is not able to actually check in until the room is entered. All other data is optional to make adding room data as fast as possible. Once a room number is added, the Check In button is highlighted and the user can save their data. Check In When you have entered your hotel information you are ready to check in. The Check In button becomes active, allowing the data to be saved.
105/117
One thing to note is that the date is automatically filled in before checking in. Again, the goal is to simplify the check-in process by not forcing the user to have to add information we can assume is going to be contextual to the check-in process. Also, the user can add their room number as well as a map to the hotels location by pressing on the top part of the card at any time. Once the user checks in, the card slides down into the pocket and the Check In button is changed to a Check Out button indicating that the data is set. At this point, if the user exits the app and comes back, their data will be saved and re-displayed until they check out. Check Out After you have checked in, you can edit your data at any time or check out. Checking out clears the card data and a new empty card is shown allowing the user to start the process over.
Once the user hits the Check Out button, they are asked if they are sure they want to proceed.
If the user gives the OK to check out, the card slides out of the pocket and off the top of the screen and is reset before a new card slides back down into view.
106/117
Error Screen There is only one error state for the app, which is displayed when the app is unable to locate the GPS position of the check-in.
Error handling and messaging is done by swapping out images. The initial state of the application is to display the Add Your Location image. If there is a failure, the Could Not Locate Your Position image is displayed. If the location can be used, an image of the map from Google is loaded in on top of the display area.
Code Review
Due to the nature of this application, the codebase was architected to be as small and portable as possible. I did not break out the JS logic into classes and relied heavily on frameworks to help speed up my development. Lets take a look at what is going on under the hood.
107/117
Application Structure For the most part the application is very flat. There is a standard www directory, which houses all the Web content loaded by PhoneGap. In that directory are my css, images, js and index.html files.
In addition to the www folder, PhoneGap automatically adds all the needed libraries to run on iOS when you create a new PhoneGap template from Xcode.
Its important to note that once you create a PhoneGap project you will need to manually link the www directory into the project. Here is how the project looks in the finder:
Notice the www sites outside of the Xcode Room112 project and how I tend to include my own design directory in the root to keep my source designs organized, especially when I check in a project.
108/117
Lets take a quick look at each of the directories in the www folder. css - There are two css files, one for the base of the project and the other that has overrides for retina resolution graphics. Ill talk more about this in the next section. images - This contains all the images the Web side of the PhoneGap application requires to display. js - This contains all my JavaScript libraries. I am using the following libraries for this project: jquery1.7.1.min.js - to handle animation, changing data on the page, etc. jquery.animate-enhanced.min.js - allows jQuery animations to use CSS3 transitions where supported to help improve performance on mobile lawnchair-0.6.1.min.js - handles local storage phonegap-1.3.0.js - PhoneGaps APIs and native to JS bridge room112.js - application logic Room112 Core Code I designed the application to be a simple state machine. It handles three states: not checked in, checked in and checking out. From there I was able to manage the state changes and update the display accordingly. Here is a high-level overview of the apps functions and what they do: onDeviceReady - This is the main init function of the application. It handles setting up the initial visuals of the application along with requested saved room information from local storage via Lawnchair. Once everything is set up, the room card is animated in and the app is ready to be used. loadGPS - This handles making the request to the browsers built-in GPS API: navigator.geolocation.getCurrentPosition(showMap, showMapError); I decided to use the built-in browsers GPS instead of the API provided by PhoneGap to help minimize any dependencies on their library. The call to navigator.geolocation accepts two callbacks, one for success and the other for failure. When the request is made, a pop-up is shown automatically to allow the user to accept permission to use the built-in GPS.
showMap- This is called when the GPS is able to find the users location. It simply makes a request to Google Maps for an image and displays it at the top of the check-in card. The URL for the map is saved locally so the service doesnt have to be called when the app re-loads and the user is checked in. cacheMapURL = http://maps.google.com/maps/api/staticmap?center= + coords. latitude + , + coords. longitude + &zoom=13&size=+width+x+height+&maptype= roadmap&key=MyGoogleMap sAPIKey&sensor=true; The method accepts a position argument that can be used to determine the coordinates the Google Maps API needs to generate the image. I also provide the image size manually so I can support standard resolution and retna.
109/117
showMapError - This is called if the GPS is unable to return a valid position to the application. I simply show the error image allowing users to try again later.
addInputListeners - This handles adding listeners for the buttons and other UI elements such as each input field. This allows me to listen for when an input field loses focus so I can call invalidate() in order to see what data has changed. invalidate - This method compares the data in the form to what has been saved. This allows the application to automatically save any changes made while checked in and also test if the user has entered enough information in order to check in. updateDisplay - This manages updating the action button based on the state of the application.
getHotelData - This is a simple utility method for accessing saved hotel data from Lawnchair.
110/117
formAction - This is called after invalidate() and simply switches between the applications mode methods: checkIn(), checkOut() and saveRoomData(). checkIn - This is the default state of the application when no saved data is found upon launch. checkOut - This animates the card off the screen, calls resetCard() to clear the data and resets the applications mode method back to checkIn(). saveRoomData - This is called when the user is checked in and they change any values in the form. resetCard - This clears the data on the check-in card while it is off-screen. This is called after the card is animated off the screen. Design/Retina Display Support The application was designed with iPhone 4S Retina display support in mind. In order to do this you must provide two resolution images and a secondary CSS sheet to override the base image paths. This is relatively easy to set up. <link rel=stylesheet type=text/css href=css/normal.css> <link rel=stylesheet type=text/css href=css/retina.css media=only screen and (-webkit-min-device-pixel-ratio: 2)> As you can see, the initial CSS sheet is loaded and then we use a media query, which is supported on WebKit on iOS to detect if the pixel ratio is 2x larger. Here is an example of a low res image: #pocket { background: url(../images/pocket.png) no-repeat; background-size: 320px 80px; width: 320px; height: 80px; position: absolute; bottom: 0px; } and the retina override: #pocket { background-image: url(../images/pocket@2x.png); } Its important to note that in the base style we need to define the background size so that when the retina image loads its not rendered at its native resolution. Here are the two images:
111/117
All the images in the application have retina size graphics to support the higher resolution, and the difference visually on the device is noticeable. On a website, this approach would be problematic since we are loading both sets of images and would probably want to use a better solution so the application is only loading the right image to cut down on bandwidth. I didnt take this into account since it was a locally running app, but if the app is image intensive this could end up being a performance issue.
Finally, there is some mobile WebKit-specific CSS code you should add to your style sheets as well to help make your app look and feel more native. <!-* { -webkit-touch-callout: none; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); -webkit-text-size-adjust: none; -webkit-user-select: none; } --> This allows you to hide the fact that your app is running in WebKit and remove highlight colors on taps and user selection on form elements. Also, adding the following metadata block will disable scaling and zooming, which is built into the WebView by default: <meta name=viewport content=width=device-width; initial-scale=1.0; userscalable=0;> This extra line of CSS and meta tag will make your app run at native resolution and is important to have in your projects HTML code. Animation I chose to go with jQuery for the animation and ran into performance issues, which I will discuss later on. My reasoning for this was to make sure the app wasnt dependant on CSS3-specific animations that may not be supported on other platforms. To me this was a big concern even though I focused on an iOS app only, so if you have a clear understanding of where you application will be deployed to you may just want to go with CSS3 animations from the beginning. jQuery did allow me some additional control with call backs and delays, which I still dont find to be well supported with CSS3 animation right now, especially when you need to execute JS during a key point in the animation sequence. Local Storage I chose to go with a local storage wrapper framework called Lawnchair. Using local storage directly is relatively easy, but I had read good things about it and liked its implementation. It is very straightforward to set up a pointer to local storage by doing the following: hotelData = new Lawnchair({name:hoteldata}, function (e) {console. log(Storage Open, this); }); Then, at any point when I need to save data, I simply reference the Lawnchair instance and save my data out. var formData = { room:$(#room).val(), floor:$(#floor).val(), date:$(#date).val(), map: cacheMapURL } hotelData.save({key:room, value:formData}); I save out my applications state to a simple JSON object, which makes loading and parsing the data very easy.
112/117
Development Workflow
Browser Prototyping I experimented with several workflows, the first of which was doing all my development locally and testing it out in Safari on the Mac. This allowed me to quickly prototype the application using the tools I was most comfortable with along with WebKits built-in debugger. One of the biggest issues I ran into while testing was being able to simply debug my CSS and JS, which is incredibly difficult to do when running the PhoneGap application on the iPhone simulator.
Development in Xcode Once I was happy with the application and the way it ran in Safari, I moved the project over to Xcode. Development tended to slow down considerably for me since debugging issues and JS integration were difficult without better debug tools. The big downside to testing in Xcode is the compile time. While it isnt too bad, it does take a few seconds to go back and forth between the two environments. I did find Xcode to have good JS support and was even able to continue to use Xcode to write and fix my JS logic without much issue.
113/117
Deployment Once you have everything set up in a PhoneGap project, your application runs just like any other iOS application. Technically, this is a native app, so you get to take advantage of Xcodes built-in support for setting up provisioning.
Issues
I ran into several issues that in the end made it hard for me to make Room112 feel like a native app. I have outlined a few of the issues below to help you address them in your own app as well as things to keep in mind when planning out your own development. Animation Performance I ran into lots of issues trying to get native-looking animation using PhoneGap. At first my issue was the performance penalty of using jQuery for animation. Doing direct DOM-based animation is incredibly slow. There are lots of hacks you can do in order to force hardware-accelerated CSS3 animation on iOS, and it wasnt until I started using jquery.animate-enhanced that I began seeing better performance. Also, at some point everything slowed down on later builds and I was unable to debug. My suggestion for iOS is to simply use CSS3 transitions from the beginning and make sure you take advantage of the -webkit-transform: translate3d(0,0,0); hack, which is said to force all other CSS3 translations to be hardware-accelerated. This could also be problematic if you are trying to directly port over an existing mobile site to PhoneGap, which may not have support on other platforms for CSS3 transitions. I
114/117
will probably continue to experiment with this to find the best solution with good fallback support to allow the code to be as portable as possible. PhoneGap Issues I was running into a lot of issues trying to disable the native scrolling of the Web page via JS. The only way I was able to fully disable it was to add the following Objective-C code to disable scrolling and bouncing directly in the PhoneGap WebView instance: UIScrollView* scroll; for(UIView* theWebSubView in self.webView.subviews){ if([theWebSubView isKindOfClass:[UIScrollView class] ]){ scroll = (UIScrollView*) theWebSubView; scroll.scrollEnabled = false; scroll.bounces = false; } } I ended up having to add this to the AppDelegate.m class, which is auto-generated by PhoneGap because the JS code to ignore scroll events didnt block the user from scrolling from inside a text field. This is a good example of how you may need to augment your PhoneGap app with native code when JS hacks simply dont work. I was also running into issues trying to access the Google Maps APIs and had to whitelist the URL in PhoneGaps .plist file, which is located in the native project.
Once you have PhoneGap.plist open, simply go to the ExternalHosts property and add any URLs your application will need access to.
115/117
Alerts and Messages I ran into several strange issues with displaying alerts in my app. At first I was trying to avoid using the native PhoneGap hooks so I could continue to test my app in Safari on my computer, but when you call JSs default alert youll see the parent page the alert is being called into.
I wasnt really expecting this, and it certainly takes away from the native feel of the app. I tried to switch over to PhoneGaps built-in native alert message bridge but had problems getting it to run. I was using an older version of PhoneGap, so hopefully updating it will fix the issue. Other people on the forums had similar issues with it as well. Graphics Issues I didnt run into many issues, but the few that I did see are slightly annoying. The biggest issue I noticed is after the application loads there is a split second flash of white, which happens when the WebView loads right after the loading image is removed and the index.html pages background hasnt fully loaded. I believe there are ways to keep the loader image up longer to smoothe out the transition, but that would have to be done in Obj-C and there isnt much you can do about it. This just means you need to pay special attention to the loading of your main page, especially if it is graphically intensive or requires a lot of JS to initialize. The only other issue I want to highlight was the difficulty I ran into with getting fonts to match up exactly with my Photoshop designs. At first I tried to do the entire design via CSS3 and use fonts where possible. I was unable to get the layout to match my PSD to my satisfaction and ended up using rasterized images instead for most of the UI. While this app would be relatively easy to localize, since I could swap out different images via CSS based on the default language of the phone, in a production application this would not be ideal. While CSS3 and browser fonts have come a long way, there is still a gap between what can be done in the browser versus Photoshop, so that limitation should be in the back of your mind when trying to figure out how to set up the visuals of your PhoneGap app. Development Bottlenecks While I only focused on doing an iOS application, I have heard of issues building for Android. In addition, it became next to impossible to maintain a Web-only version of the app. So, while it would be ideal to be able to deploy the same code base to a mobile website and have the PhoneGap wrapper app for people who want to use native, you will end up having to modify each build for each platform. You could write a wrapper to emulate or disable the PhoneGap-specific JS logic so that your application would degrade better on the Web, but the level of work required to architect a single app that could run on the Web and in PhoneGap on all its supported platforms would be a huge undertaking. Its not impossible but I just dont think that it ends up being worth the level of effort. In that case you are better off defining blocks of code that are portable and spending the last 10-20% of your development customizing the code base to each platform.
116/117
Moving Forward
While this was a fun little exercise to help me get up and running in PhoneGap and vet out Web-based app building, I still have a lot to do and learn. Deploying to Multiple OSs The next steps are going to be getting this app to run on different OSs such as Android and Windows Phone 7. The biggest reservation I have with porting the app to other platforms is that each one has its own UI and navigation paradigm. While Room112 was designed according to what most iOS apps are starting to look like, using real-world textures to look photo realistic, this may look out of place on Android and Windows Phone 7. Luckily, I could easily swap out the CSS and images and quickly reskin the app; its just extra work and platform-specific customization I dont want to do. This is just another problem with the dream of having a single app that runs and uses the same code base across multiple platforms. iPad/Tablet Support I would also like to eventually support the iPad, tablets and other higher-resolution devices but would have to rethink my design approach. Right now the app doesnt warrant a larger-resolution design, but I would like to test out how to handle scaling up in a PhoneGap app. I may just try this on another project. Again, I hope it would be a few quick CSS changes, but most phone apps need to be rethought out for tablets so it would be interesting to see how much of the application logic I could keep and what the performance would be on larger screen devices.
Conclusion
While this wasnt the most awe inspiring application I have ever built, it did give me a great opportunity to learn more about PhoneGap as well as how to style for iOS mobile browsers. All in all, while PhoneGap is easy to use and being able to leverage a Web Stack for development is a great advantage, its also incredibly difficult to get a native feel and responsiveness most users would be expecting on iOS. I think if you approach your PhoneGap app understanding the limitations and pain points, you can actually produce something really polished and portable across multiple platforms. I wouldnt rule this out because over time, as devices get faster and support more HTML5 features, this may turn out to be a viable development solution.
MORE INFORMATION
>
ONLINE RESOURCES PhoneGap official website http://phonegap.com Room 112 Source Code http://github.com JQuery http://jquery.com/
>
appliness
IS A WARM GUN
e want to showcase in this section the best applications built with web standards. If you want to showcase your application, contact us by email - contact@appliness.net. This month, find professional contacts, see who the noisy tweeters are and check in to what your friends are drinking.
LinkedIn has very talented in-house JavaScript developers. The new iPad application is the best access to your professional network. The interesting fact is that it has been unveiled by VentureBeat. com. Guess how much of LinkedIns new iPad app is actually mobile web and not native? 95% is using web standards! Only one screen in the entire LinkedIn iPad app is actually native. The rest is good ol HTML5-based mobile web technology, running in the browser and leaning heavily on Node.js. Its a brand new experience created for iPad users. LinkedIn didnt try to adapt the desktop web application or to extend the mobile app, they built a tablet experience. They estimate that in the base of complex apps, responsive design cannot answer users needs. Here is a quote of Prasad, leader of the mobile LinkedIn team: You cant take a mobile app and just scale it up to tablet or desktop, he said. A lot of responsive design is building one site that works everywhere, and that works for websites. But its bad for apps You have to come up with a completely different design because of the use case. (source - VentureBeat)
lottatweets.com
by greg wilson
Greg Wilson uses Twitter often to keep up with the latest trends, announcements, and more. He has been looking for a good project to beef up his jQuery skills, and decided to see if he could build something to meet his own requirements for a tweet rapid-reader. LottaTweets is a web-based tool that fills your screen with tweets in a multi-column, newspaper-style layout allowing super fast reading. In addition to being able to quickly scan tweets, there are a few neat features: - Color coded retweet rate: Tweets are color-coded based on the number of re-tweets per minute. - Noise factor: The noise factor is computed by number_of_tweets / number_of_followers. - Infinite horizontal scrolling: you can keep scrolling right and it continues to load more tweets for you to read.
untappd
by untappd llc Untappd is a mobile app that allows you to socially share the brew youre currently enjoying, as well as where youre enjoying it, with your friends! Known as the Foursquare for beer, user can check-in to what theyre drinking and where and share with their friends on Untappd, Twitter, Facebook, & Foursquare.
Its using PhoneGap and demonstrates that you can design beautiful experiences using web standards on iOS and Android. One of the best demonstration of the power of mobile apps.
appliness
VIDEO TUTORIAL
ONLINE RESOURCES Official website of PhoneGap Build https://build.phonegap.com/ Official website of PhoneGap http://phonegap.com/ HTML5 development http://www.adobe.com/devnet/html5.html
http://outof.me/ @pwalczyszyn
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
ABOUT WHICHELEMENT.COM
121/121
Terry Ryan is a Worldwide Developer Evangelist for Adobe. The job basically entails helping developers using Adobe technologies to be successful. His focus is on web and mobile technologies including expertise in both Flash and HTML. http://terrenceryan.com/ @tpryan
? . . . . . . .
Address
A postal address, where someone would deliver mail. Its seems straight-forward, there is an element named <address>. Case closed right? Its not so simple, the spec has something to say.
Candidates
- <address> - A collection of <div> and <span> elements. At first glance it would seem <address> would be the right choice, its called address for goodness sake. But alas, as per the specification, address in the context of an HTML5 element <address> means To whom should I address my issue with this piece of content. So in this case it is referring to the authors of the article or the maintainer of the page. If in that context, a postal address makes sense then you can use it, otherwise postal addresses should be otherwise marked up.
Verdict
Further reading
- HTML5 doctor - the address element - W3C - the address element
Raymond Camden is a 38 year old married father of three living in beautiful Lafayette, Louisiana. He is a developer evangelist for Adobe. His primary technical focus is on web standards. http://www.raymondcamden.com/ @cfjedimaster
appliness
Signal Box is A GREAT way to build the server for your WEB APPLICATIONS. IT eliminates the need for a custom backend, so you can focus on building a polished app for the Web. I HAVE DEVELOPED A CRUD SAMPLE TO EXPLAIN HOW TO IMPLEMENT THIS CLOUD SERVICE.
A simple architecture
When you plan to build web apps, especially mobile apps, you usually need to define a simple database architecture and expose the tables with web services. I see more and more services in the cloud to create and manage the data of custom applications, getsignalbox.com is one of them. For this tutorial, Ive just created a free account, Ive declared an ApplinessTest application and created one resource called subscriber in five minutes. The web dashboard lets you add properties in your resources. So Ive defined that a subscriber has an EMAIL property, which is a STRING with an email validator (built-in validator provided by the service), plus a FIRSTNAME and a LASTNAME properties. Then you can manually add records in your new resource, or use the web API to read/write/delete or update your records. As we are web application developers, Ive built a mobile app with jQuery Mobile that will display the list of subscribers listed in the cloud, and Ive added a simple form to create new subscribers. The SignalBox team has shared on GitHub a JavaScript library to directly make calls to your database using JavaScript.
d n u o laygr
- SQL - REST - JQM
Difficulty
- rookie - intermediate - expert
Todo list
- REST HTTP
by Michal Chaize
123/126
</div><!-- /page --> </body> Im using a very classic jQuery Mobile structure. The <ul> list of subscribers is empty and well feed it with the data coming from SignalBox. As you can see, you need to tap the buttons to call getAllData() and display the list of subscribers, or to call create() and add a user in the database.
124/126
125/126
feed the list. As you can see, 10 lines of code and you get everything.
https://getsignalbox.com/
126/126
appliness
BLEEDING EDGE
One of the more interesting features on the bleeding edge of HTML5 is getUserMedia. This API covers basic access to the users audio and video devices.
an interactive form
When I saw this demo, I was curious if something fun could be done with it. Along with basic color changes you can also blur the video. I thought it might be cool to create a user registration form that creates a crystal-clear image of you as you fill it out. I know many of you cant use this feature yet in your browser, so here are a few screen shots to demonstrate what I mean. Upon hitting the form, here is how things look.
How does it work? Im going to assume you read my earlier post (or the excellent HTML5 Rocks article I already linked to). The basic gist is - once youve gotten access to the web cam and have directed the output to the canvas, you simply apply different CSS filters based on how correct the form is.
allfields = $(input[required]); $(input[required]).on(input, function(e) { if(!hasGetUserMedia()) return; //count number of invalid fields var totalGood = 0; for(var i=0, len=allfields.length; i<len; i++) { if($(allfields[i]).attr(required) && allfields[i].checkValidity()) { totalGood++; } } console.log(totalGood); var video = $(#myuglyface)[0]; video.className = ; switch(totalGood) { case 0: video.classList.add(deepblur); break; case 1: video.classList.add(notdeepblur); break; case 2: video.classList.add(lesserblur); break; case 3: video.classList.add(lightblur); break; default: } }); And the CSS styles declaration: <style> #myuglyface { float: right; width: 500px;
128/129
height: 500px;
.deepblur { -webkit-filter: blur(30px) grayscale(1); } .notdeepblur { -webkit-filter: blur(20px) grayscale(0.8); } .lesserblur { -webkit-filter: blur(10px) grayscale(0.6); } .lightblur { } </style> -webkit-filter: blur(6px) grayscale(0.4);
appliness
BLEEDING EDGE
This is a JavaScript API that gives you access to (with permission) the users web cam and microphone.
}; } function noStream() { document.getElementById(errorMessage).textContent = No camera available.; } function streamError() { document.getElementById(errorMessage).textContent = Camera error.; }
The first argument to getUserMedia is the type. According to the spec, this is supposed to be an object where you enable audio, video, or both, like so: {audio:true, video:true}. However in my testing, passing a string, video, worked fine. The demo you will be seeing is based on another demo so that line possibly came from an earlier build that still works with Chrome. The second and third arguments are your success and failure callbacks respectively. You can see in the gist where the success handler assigns the video stream to an HTML5 video tag. Whats cool then is that, once you have that running, you can use the Canvas API to take pictures. For a demo of this, check out Greg Miernickis demo: http://miernicki.com/cam.html Based on Gregs demo, it occurred to me that there is something cool we can do with pictures of our web cams. (Cue the dirty jokes.) I remembered that Face.com had a very cool API for parsing pictures for faces. (I blogged a ColdFusion example back in November.) I wondered then if we could combine Gregs demo with the Face.com API to do some basic facial recognition. Turns out there are a few significant issues with this. First - while Face.com has a nice REST API, how would we use it from a JavaScript application? Secondly - Face.com requires you to either upload a picture or give it a URL. I know I could send a canvas picture to a server and have my backend upload it to Face. com, but is there a way to bypass the server and send the picture right to the API? The first issue actually turned out to be a non-issue. Face.com implements CORS (Cross-Origin Resource Sharing). CORS basically allows a server to expose itself to Ajax calls from documents on other domains. Its a great feature and I hope more services enable it. The more complex issue then was taking the canvas data and sending it to Face.com. How can I fake a file upload? Turns out theres another cool new trick - FormData. Fellow ColdFusion blogger Sagar Ganatra has an excellent blog entry on the topic. Heres how I used it: function snapshot() { $(#result).html(<p><i>Working hard for the money...</i></p>); canvas.width = video.videoWidth; canvas.height = video.videoHeight; canvas.getContext(2d).drawImage(video, 0, 0); var data = canvas.toDataURL(image/jpeg, 1.0); newblob = dataURItoBlob(data);
formdata.append(file,newblob); $.ajax({ url: http://api.face.com/faces/detect.json?attributes=age_est,gender, mood,smiling,glasses, data: formdata, cache: false, contentType: false, processData: false, dataType:json, type: POST, success: function (data) { handleResult(data.photos[0]); } } });
Lets look at this line by line. First off - I need to get the binary data from the canvas object. Theres a few ways of doing this, but I wanted a Binary Blob specifically. Notice the dataURIToBlob method. This comes from a StackOverflow post I found a few weeks back. I create a new FormData object and then simply begin setting my values. You can see I pass in a few API requirements but the crucial parts are the filename and file object itself. Below that, you can see the simple jQuery Ajax call. Face.com has a variety of options, but I basically just asked it to return an estimated age, gender, mood, and whether or not the person was smiling and wearing glasses. Thats it. I get a nice JSON packet back and format it. Now obviously no API is perfect. Ive had different levels of results from using the API. Sometimes its pretty damn accurate and sometimes it isnt. Overall though its pretty cool. Here are some scary pictures of Yours Truly testing it out.
For another look at getUserMedia, check out these examples: Its Curtains for Marital Strife Thanks to getUserMedia Testing WebRTC on Chrome Bleeding Edge HTML5, WebRTC & Device Access Capturing Audio & Video in HTML5
appliness
Data Binding Using data-* Attributes via Eric Bidelman
Fresh news about HTML and Javascript collected by Brian Rinaldi - remotesynthesis.com
Working with files in JavaScript, Part 3: Progress events and errors via Nicholas Zakas Using requestAnimationFrame to Optimize Dragging Events via Ryan Stewart Adding Filter as you type support to IndexedDB via Ray Camden
appliness
Has your sites third-party content gone rogue? via Joshua Bixby Intro to CSS 3D transforms via Dave DeSandro
JavaScript design patterns Part 2: Adapter, decorator, and factory via Joe Zim
Diving Into CSS Regions via Umar Hansa Animated 3D Bar Chart with CSS3 via Sergey Lukin
Dynamically creating jQuery Mobile radio buttons with Mustache via Andy Matthews
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
RAYMOND
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
ANDY 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
Andy is currently a Senior Web Developer for Dealerskins, Inc. and runs commadelimited.com. Hes the author of open source ColdFusion libraries: PicasaCFC, & ShrinkURL. Hes written an HTML/JS Adobe AIR Application called Shrinkadoo (in AIR Marketplace), & speaks at RIA User Groups or conferences.
MATTHEWS
MARK
DONG
Mark Dong works in Adobe for 6 years in China.
Flex, JavaScript and Java developer with much experience on enterprise RIA architect and project manager in FSI and Energy industry.
BRIAN
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
TERRENCE
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.
RYAN
PIOTR
Walczyszyn
Piotr Walczyszyn is a technology geek leaving in Warsaw, Poland, where he was born. outof.me is his new blog in which he wants to express his current interests and share some of his work. Technologies change; new trends come and go. These days nobody talks about RIAs (Rich Internet Applications) anymore, and he thinkd this phrase has become almost pass although its main concepts have not.
ANDREW
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.
TRICE
MAILE
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
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.
WILSON
Appliness is a digital magazine written by passionate web developers. You can follow our activity on Facebook, Twitter or Google+.
FOLLOW
o t t n a w ? u e Yo ribut t n co
US
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
CONTRIBUTE