Computer Coding
Home |  ColdFusion |  IBM |  Java |  JavaScript |  Spring |  Misc |  Sign in



HTML5Rocks


Help users checkout faster with Autofill

People hate filling out web forms, especially on mobile devices. They can be slow and frustrating to complete and often contain multi-page steps and validation issues. This leads to high user drop-off and frustration. To help make things easier for users, browsers have long been able to autocomplete fields on behalf of the user. Chrome took this a step further in 2011 by introducing Autofill, which fills in entire forms based on a user?s Autofill profile.

Starting in the next major version of Chrome (M43), we?re taking yet another step to help users fill out forms faster by expanding our support for credit cards and addresses in Google. This means that the same information users use to purchase things inside of the Google Play store are now available to them on websites. By using the standard autocomplete attributes, you can ensure your users? happiness by helping Chrome autofill your checkout forms with 100% accuracy.

Autocomplete attributes are a way for you, the developer, to control how the browser should populate a given form field. For example, if you are expecting a street address you can hint to the browser that you are expecting it by using autocomplete="address-line1". This prevents the browser from incorrectly guessing form fields on your website which can result in a poor user experience.

We?ve found that by correctly using autocomplete attributes on your forms, users complete them up to 30% faster. And since autocomplete is part of the WHATWG HTML standard, we hope that other browsers will support it in the near future.

autofill git to show the power of fast and easy form filling

In the past, many developers would add autocomplete=?off? to their form fields to prevent the browser from performing any kind of autocomplete functionality. While Chrome will still respect this tag for autocomplete data, it will not respect it for autofill data. So when should you use autocomplete=?off?? One example is when you?ve implemented your own version of autocomplete for search. Another example is any form field where users will input and submit different kinds of information where it would not be useful to have the browser remember what was submitted previously.

The most common autocomplete attributes are shown in the table below and are documented in Web Fundamentals.

Common Attributes

Credit Card

name attribute

autocomplete attribute

ccname
cardnumber
cvc
ccmonth
ccyear
exp-date
card-type

cc-name
cc-number
cc-csc
cc-exp-month
cc-exp-year
cc-exp
cc-type

<label for="frmNameCC">Name on card</label>
<input name="ccname" id="frmNameCC" required placeholder="Full Name" autocomplete="cc-name">    

<label for="frmCCNum">Card Number</label>
<input name="cardnumber" id="frmCCNum" required autocomplete="cc-number">    

<label for="frmCCCVC">CVC</label>
<input name="cvc" id="frmCCCVC" required autocomplete="cc-csc"> 
  
<label for="frmCCExp">Expiry</label>
<input name="cc-exp" id="frmCCExp" required placeholder="MM-YYYY" autocomplete="cc-exp">

Name

name attribute

autocomplete attribute

name
fname
mname
lname

name (full name)
given-name (first name)
additional-name (middle name)
family-name (last name)

<label for="frmNameA">Name</label>
<input name="name" id="frmNameA" placeholder="Full name" required autocomplete="name">

Email

name attribute

autocomplete attribute

email

email

<label for="frmEmailA">Email</label>
<input type="email" name="email" id="frmEmailA" placeholder="name@example.com" required autocomplete="email">

<label for="frmEmailC">Confirm Email</label>
<input type="email" name="emailC" id="frmEmailC" placeholder="name@example.com" required autocomplete="email">

Address

name attribute

autocomplete attribute

address
city
region
province
state
zip
zip2
postal
country

For one address input: street-address
For two address inputs: address-line1 , address-line2
address-level1 (state or province)
address-level2 (city)
postal-code (zip code)
country

<label for="frmAddressS">Address</label>
<input name="ship-address" required id="frmAddressS" placeholder="123 Any Street" autocomplete="shipping street-address">

<label for="frmCityS">City</label>
<input name="ship-city" required id="frmCityS" placeholder="New York" autocomplete="shipping address-level2">

<label for="frmStateS">State</label>
<input name="ship-state" required id="frmStateS" placeholder="NY" autocomplete="shipping address-level1">

<label for="frmZipS">Zip</label>
<input name="ship-zip" required id="frmZipS" placeholder="10011" autocomplete="shipping postal-code">

<label for="frmCountryS">Country</label>
<input name="ship-country" required id="frmCountryS" placeholder="USA" autocomplete="shipping country">

Phone

name attribute

autocomplete attribute

phone
mobile
country-code
area-code
exchange
suffix
ext

tel

<label for="frmPhoneNumA">Phone</label>
<input type="tel" name="phone" id="frmPhoneNumA" placeholder="+1-650-450-1212" required autocomplete="tel">

The autocomplete attributes can be accompanied with a section name, such as:

  • shipping - given-name
  • billing - street-address

It is recommended because it will make your markup easier to parse and understand. The browser will autofill different sections separately and not as a continuous form.

An example of a payment form

<label for="frmNameCC">Name on card</label>
<input name="ccname" id="frmNameCC" required placeholder="Full Name" autocomplete="cc-name">

<label for="frmCCNum">Card Number</label>
<input name="cardnumber" id="frmCCNum" required autocomplete="cc-number">

<label for="frmCCCVC">CVC</label>
<input name="cvc" id="frmCCCVC" required autocomplete="cc-csc">
  
<label for="frmCCExp">Expiry</label>
<input name="cc-exp" id="frmCCExp" required placeholder="MM-YYYY" autocomplete="cc-exp">

Forms best practices

  1. Use _labels_on form inputs, and ensure they?re visible when the field is in focus. The label element provides direction to the user, telling them what information is needed in a form element. Each label is associated with an input element by placing it inside the label element. Applying labels to form elements also helps to improve the touch target size: the user can touch either the label or the input in order to place focus on the input element.
  2. Use placeholder to provide guidance about what you expect. The placeholder attribute provides a hint to the user about what?s expected in the input, typically by displaying the value as light text until the the user starts typing in the element. Placeholders disappear as soon as the user starts typing in an element, thus they are not a replacement for labels. They should be used as an aid to help guide users on the required format and content.

Demo

You can see it in action over at: greenido.github.io/Product-Site-101/form-cc-example.html
Or check the code: https://github.com/greenido/Product-Site-101

An example to a form that use autocomplete tags


Notifying you of Changes to Notifications

Firstly, I apologise for that awful title, but I couldn?t not.

In Chrome 44 Notfication.data and ServiceWorkerRegistration.getNotifications() are added and open up / simplify some common use cases when dealing with notifications with push messages.

Notification Data

Notification.data allows you to associate a JavaScript object with a Notification.

What this basically boils down to, is when you receive a push message, you can create a notification with some data, then in the notificationclick event you can get the notification that was clicked and get its data.

For example, creating a data object and adding it to your notification options like so:

self.addEventListener('push', function(event) {    
  console.log('Received a push message', event);

  var title = 'Yay a message.';    
  var body = 'We have received a push message.';    
  var icon = '/images/icon-192x192.png';    
  var tag = 'simple-push-demo-notification-tag';  
  var data = {  
    doge: {  
        wow: 'such amaze notification data'  
    }  
  };

  event.waitUntil(    
    self.registration.showNotification(title, {    
      body: body,    
      icon: icon,    
      tag: tag,  
      data: data    
    })    
  );    
});

Means we can get the information in the notificationclick event:

self.addEventListener('notificationclick', function(event) {  
  var doge = event.notification.data.doge;  
  console.log(doge.wow);  
});

Before this, you had to stash data in IndexDB or put something on the end of the icon URL - eek.

ServiceWorkerRegistration.getNotifications()

One common request from developers working on push notifications is to have better control over the notifications that they display.

An example use case would be a chat application where a user sends multiple messages and the recipient displays multiple notifications. Ideally the web app would be able to notice you have several notifications which haven?t been viewed and collapse them down into a single notification.

Without getNotifications() the best you can do is replace the previous notification with the latest message. With getNotifications(), you can ?collapse? the notifications if a notification is already displayed - leading to a much better user experience.

Example of grouping notifications together

The code to do this is relatively simple. Inside your push event, call ServiceWorkerRegistration.getNotifications() to get an array of current Notifications and from there decide the right behaviour, whether that?s collapsing all notifications or by using the Notification.tag.

function showNotification(title, body, icon, data) {  
  var notificationOptions = {  
    body: body,  
    icon: icon ? icon : 'images/touch/chrome-touch-icon-192x192.png',  
    tag: 'simple-push-demo-notification',  
    data: data  
  };  
  
  self.registration.showNotification(title, notificationOptions);  
  return;  
}

self.addEventListener('push', function(event) {  
  console.log('Received a push message', event);

  // Since this is no payload data with the first version  
  // of Push notifications, here we'll grab some data from  
  // an API and use it to populate a notification  
  event.waitUntil(  
    fetch(API_ENDPOINT).then(function(response) {  
      if (response.status !== 200) {  
        console.log('Looks like there was a problem. Status Code: ' +  
          response.status);  
        // Throw an error so the promise is rejected and catch() is executed  
        throw new Error();  
      }

      // Examine the text in the response  
      return response.json().then(function(data) {  
        var title = 'You have a new message';  
        var message = data.message;  
        var icon = 'images/notification-icon.png';  
        var notificationTag = 'chat-message';

        var notificationFilter = {  
          tag: notificationTag  
        };  
        return self.registration.getNotifications(notificationFilter)  
          .then(function(notifications) {  
            if (notifications && notifications.length &gt; 0) {  
              // Start with one to account for the new notification  
              // we are adding  
              var notificationCount = 1;  
              for (var i = 0; i &lt; notifications.length; i++) {  
                var existingNotification = notifications[i];  
                if (existingNotification.data &&  
                  existingNotification.data.notificationCount) {  
                  notificationCount += 
existingNotification.data.notificationCount;  
                } else {  
                  notificationCount++;  
                }  
                existingNotification.close();  
              }  
              message = 'You have ' + notificationCount +  
                ' weather updates.';  
              notificationData.notificationCount = notificationCount;  
            }

            return showNotification(title, message, icon, notificationData);  
          });  
      });  
    }).catch(function(err) {  
      console.error('Unable to retrieve data', err);

      var title = 'An error occured';  
      var message = 'We were unable to get the information for this ' +  
        'push message';

      return showNotification(title, message);  
    })  
  );  
});

self.addEventListener('notificationclick', function(event) {  
  console.log('On notification click: ', event);

  if (Notification.prototype.hasOwnProperty('data')) {  
    console.log('Using Data');  
    var url = event.notification.data.url;  
    event.waitUntil(clients.openWindow(url));  
  } else {  
    event.waitUntil(getIdb().get(KEY_VALUE_STORE_NAME, 
event.notification.tag).then(function(url) {  
      // At the moment you cannot open third party URL's, a simple trick  
      // is to redirect to the desired URL from a URL on your domain  
      var redirectUrl = '/redirect.html?redirect=' +  
        url;  
      return clients.openWindow(redirectUrl);  
    }));  
  }  
});

The first thing to highlight with this code snippet is that we filter our notifications by passing a filter object to getNotifications(). This means we can get a list of notifications for a specific tag (in this example for a particular conversation).

var notificationFilter = {  
  tag: notificationTag  
};  
return self.registration.getNotifications(notificationFilter)

Then we look over the notifications which are visible and check to see if there is a notification count associated with that notification and increment based on that. This way if there is one notification telling the user there are two unread messages, we would want to point out that there are three unread messages when a new push arrives.

var notificationCount = 1;  
for (var i = 0; i &lt; notifications.length; i++) {  
  var existingNotification = notifications[i];  
  if (existingNotification.data && existingNotification.data.notificationCount) {  
    notificationCount += existingNotification.data.notificationCount;  
  } else {  
    notificationCount++;  
  }  
  existingNotification.close();  
}

A subtlety to highlight is that you need to call close() on the notification to ensure the notification is removed from the notification list. This is a bug in Chrome since each notification is replaced by the next one because the same tag is used. At the moment this replacement isn?t being reflected in returned array from getNotifications().

This is only one example of getNotifications() and as you can imagine, this API opens up a range of other use cases.

Remaining Common Feature Requests

The one remaining common feature request from developers is the ability to close a notification after a certain time period or the ability to send a push notification with the purpose of just closing a notification if it?s visible.

At the moment there isn?t a way you can do this and nothing in the spec that will allow it :( but the Chrome engineering team are aware of this use case.

Android Notifications

On desktop you can create a notification with the following code:

new Notification('Hello', {body: 'Yay!'});

This was never supported on Android due to restrictions of the platform: specifically, Chrome can?t support the callbacks on the Notification object, such as onclick. But it?s used on desktop for displaying notifications for web apps you may currently have open.

The only reason I mention it is that originally, a simple feature detection like the one below would help you support desktop and not cause any errors on Android:

if (!'Notification' in window) {  
  // Notifications aren't supported  
  return;  
}

However, with push notification support now on Chrome for Android, notifications can be created from a ServiceWorker, but not from a web page, meaning this feature detect is no longer appropriate. If you try and create a notification on Chrome for Android you?ll receive this error message:

Uncaught TypeError: Failed to construct ?Notification?: Illegal constructor. Use ServiceWorkerRegistration.showNotification() instead

The best way to feature detect for Android and desktop at the moment is to do the following:

function isNewNotificationSupported() {  
    if (!window.Notification || !Notification.requestPermission)  
        return false;  
    if (Notification.permission == 'granted')  
        throw new Error('You must only call this \*before\* calling 
Notification.requestPermission(), otherwise this feature detect would bug the 
user with an actual notification!');  
    try {  
        new Notification('');  
    } catch (e) {  
        if (e.name == 'TypeError')  
            return false;  
    }  
    return true;  
}

This can be used like so:

if (window.Notification && Notification.permission == 'granted') {  
    // We would only have prompted the user for permission if new  
    // Notification was supported (see below), so assume it is supported.  
    doStuffThatUsesNewNotification();  
} else if (isNewNotificationSupported()) {  
    // new Notification is supported, so prompt the user for permission.  
    showOptInUIForNotifications();  
}

High performance video with hardware decoding

With the Chromium 42 release, H.264 hardware video decoding support has been expanded to OS X. Now Chromium on Macs, Windows 7+ and essentially all Chromebooks support power efficient decoding of video by default. Chromium?s HTML5 video implementation will automatically make the best decision on when to use this feature based on driver and hardware support.

The same hardware support is available to browser plugins as well. Pepper Flash for instance provides full access to video acceleration via the ActionScript StageVideo object. Switching from the old style Video to the StageVideo object should in most cases be simple to do. We would like to refer to Adobe?s excellent Best Practices for High Performing and Efficient Flash Video.

For best platform support and video performance, we strongly recommend moving from plugins to HTML5 video. Using plugins such as Flash may also adversely affect search ranking on mobile: see Google?s Webmaster FAQ. The video element is implemented by over 90% of browsers on mobile and desktop; Adobe ended support for Flash in Android Jelly Bean. The Web Fundamentals video section shows how to make the most of plugin-free, cross-platform media. For adaptive streaming on the web we recommend Shaka Player, an easy-to-use media player that implements DASH using MSE, with optional native support for content protection via EME. Likewise ExoPlayer for Android native apps.

More information about plugin deprecation timelines, and how to move to native APIs, is available from the NPAPI deprecation developer guide.


DevTools Timeline: Now Providing the Full Story

The DevTools Timeline panel has always been the best first stop on the path to performance optimization. This centralized overview of your app?s activity helps you analyze where time is spent on loading, scripting, rendering, and painting. Recently, we?ve upgraded the Timeline with more instrumentation so that you can see a more in-depth view of your app?s performance.

We?ve added the following features:

Note that using the Paint capture options described in this article do incur some performance overhead, so flip them on only when you want ?em.

Integrated JavaScript Profiler

If you?ve ever poked around in Profiles panel, you?re probably familiar with the JavaScript CPU profiler. This tool measures where execution time is spent in your JavaScript functions. By viewing JavaScript profiles with the Flame Chart, you can visualize your JavaScript processing over time.

Now, you can get this granular breakdown of your JavaScript execution in the Timeline panel. By selecting the JS Profiler capture option, you can see your JavaScript call stacks in the Timeline along with other browser events. Adding this feature to the Timeline helps streamline your debugging workflow. But more than that, it allows you to view your JavaScript in context and identify the parts of your code that affect page load time and rendering.

In addition to the JavaScript profiler, we also integrated a Flame Chart view into the Timeline panel. You can now view your app?s activity either as the classic waterfall of events or as a Flame Chart. The Flame Chart icon allows you to toggle between these two views.

JavaScript Profiler on Timeline Using the JS Profiler capture option and Flame Chart view to investigate call stacks in the Timeline.

Tip: Use WASD to zoom and pan through the Flame Chart. Shift-drag to draw a selection box.

Frame Viewer

The art of layer compositing is another aspect of the browser that has been mostly hidden from developers. When used sparingly and with care, layers can help avoid costly re-paints and yield huge performance boosts. But it?s often not obvious to predict how the browser will composite your content. Using the Timeline?s new Paint capture option, you can visualize composited layers at each frame of a recording.

When you select a gray frame bar above the Main Thread, its Layers panel provides a visual model of the layers that compose your app.

Tip: Play back animations by clicking through frame bars on a Timeline recording.

You can zoom, rotate, and drag the layers model to explore its contents. Hovering over a layer reveals its current position on the page. Right-clicking on a layer lets you jump to the corresponding node in the Elements panel. These features show you what was promoted to a layer. If you select a layer, you can also see why it was promoted in the row labeled Compositing Reasons.

Compositing Reasons Inspecting a layer from Codrops' Scattered Polaroids Gallery to reveal the browser?s reasons for compositing.

Paint Profiler

Last but not least, we?ve added the paint profiler to help you identify jank caused by expensive paints. This feature enriches the Timeline with more details about the work Chrome does during paint events.

For starters, it?s now easier to identify the visual content corresponding to each paint event. When you select a green paint event in the Timeline, the Details pane shows you a preview of the actual pixels that were painted.

Paint capture option Previewing pixels that the browser painted using the Paint capture option.

If you really want to dive in, switch over to the Paint Profiler pane. This profiler shows you the exact draw commands that the browser executed for the selected paint. To help you connect these native commands with actual content in your app, you can right-click on a draw* call and jump straight to the corresponding node in the Elements panel.

Paint capture option Relating native browser draw* calls to DOM elements using the Paint Profiler.

The mini-timeline across the top of the pane lets you play back the painting process and get a sense of which operations are expensive for the browser to perform. Drawing operations are color-coded as follows: pink (shapes), blue (bitmap), green (text), purple (misc.). Bar height indicates call duration, so investigating tall bars can help you understand what about a particular paint was costly.

Profile and profit!

When it comes to performance optimization, knowledge of the browser can be incredibly powerful. By giving you a peek under the hood, these Timeline updates help clarify the relationship between your code and Chrome?s rendering processes. Try out these new options in the Timeline and see what Chrome DevTools can do to enhance your jank-hunting workflow!


Permissions API for the Web

If you?ve worked with the Geolocation API before, chances are you?ve wanted to check if you had permission to use Geolocation without causing a prompt. This simply wasn?t possible. You had to request the current position and this would indicate the permission state or cause a prompt to be shown to the user.

Not all APIs work this way. The Notifications API has its own way of allowing you to check the current permission state via Notification.permission.

As the web platform grows in API?s, there needs to be a single, standard way for developers to check the status of a permission rather than having to remember how each and every API works. The Permission API, available in Chrome version 43, is intended to be this single, standard way to check the permission status of an API.

permissions.query()

Check the status of a permission using the permissions.query() method. This will return a status of granted (you have permission), denied (you are blocked from accessing the API) or prompt (user needs to be prompted). For example:

// Check for Geolocation API permissions  
navigator.permissions.query({name:'geolocation'}).then(function(permissionStatus) 
{  
  console.log('geolocation permission status is ', permissionStatus.status);  
  permissionStatus.onchange = function() {  
    console.log('geolocation permission status has changed to ', this.status);  
  };
});

The query method takes a PermissionDescriptor object, where you define the permission?s name. The response is a Promise resolving to a PermissionStatus object. From this object, you can check the status with permissionStatus.status for ?granted?, ?denied? or ?prompt?. You can also also implement an event handler for permissionStatus.onchange and handle changes to the permission status of an API.

Supported PermissionDescriptors

In the above example, we highlight how to query the permission state for geolocation with the following permission descriptor: {name:'geolocation'}.

The Notification permission descriptor is similar in that it only requires a name attribute: {name:'notifications'}.

Push and midi each have an additional parameter that is specific to that API.

For the push permission, you can supply a userVisibleOnly parameter. This indicates whether you wish to show a notification for every push message or be able to send silent push notifications (At the moment Chrome only supports push messages with notifications). You?d use it like so:

navigator.permissions.query({name:'push', userVisibleOnly:true})

Midi allows a sysex parameter. This indicates whether you need to and/or receive system exclusive messages. For midi this would be:

navigator.permissions.query({name:'midi', sysex:true})

Requesting Permissions

Requesting permission from the user depends on the specific API. For example, geolocation would show a permission prompt when you call getCurrentPosition().

navigator.geolocation.getCurrentPosition(function(position) {  
  console.log('Geolocation permissions granted');  
  console.log('Latitude:' + position.coords.latitude);  
  console.log('Longitude:' + position.coords.longitude);  
});

Whereas notifications would prompt the user when you call requestPermission().

Notification.requestPermission(function(result) {  
  if (result === 'denied') {  
    console.log('Permission wasn\'t granted. Allow a retry.');  
    return;  
  } else if (result === 'default') {  
    console.log('The permission request was dismissed.');  
    return;  
  }  
  console.log('Permission was granted for notifications');  
});

The point here is that the Permission API allows a consistent way to monitor the status of permissions while being able to support the range of APIs currently on the web.

The big advantage of this is that it allows you to build better experiences for your users, only prompting when it?s obvious to the user why you need extra privileges and taking full advantage of these APIs when you know you have been granted permission.

You can find a full set of examples here.

Browser Support

Chrome is the first browser to implement this, Mozilla are planning on shipping this, and Microsoft have shown interest in the API.

Known Issues

  • Geolocation will not re-show a prompt if the user dismisses the permission request. The permission status however remains ?prompt?. [crbug.com/476509]

Introduction to Service Worker: How to use Service Worker

Service Worker will revolutionize the way we build for the web. Learn about what it is, why it is important and how to use it.


The Hobbit Experience 2014: Adding WebRTC gameplay to the Hobbit Experience

Learn how North Kingdom built an immersive multimedia experience optimized for modern mobile browsers using Web RTC


Getting Started with CSS Shapes: Wrapping content around custom paths

Using CSS Shapes we can create experiences that we have never been able to create on the web before.


Built-in Browser Support for Responsive Images

Take advantage of the new element and new features of in your next responsive website.


DevTools Digest - Chrome 35: Updates to the Developer Tools in Chrome 35

Updates to the Chrome Developer Tools: CSS property quick search, memory stats for heap snapshots, CodeMirror upgrade and more.



@2014 CompCoding.com