Mozilla

Articles

Sort by:

View:

  1. Detecting touch: it’s the ‘why’, not the ‘how’

    One common aspect of making a website or application “mobile friendly” is the inclusion of tweaks, additional functionality or interface elements that are particularly aimed at touchscreens. A very common question from developers is now “How can I detect a touch-capable device?”

    Feature detection for touch

    Although there used to be a few incompatibilities and proprietary solutions in the past (such as Mozilla’s experimental, vendor-prefixed event model), almost all browsers now implement the same Touch Events model (based on a solution first introduced by Apple for iOS Safari, which subsequently was adopted by other browsers and retrospectively turned into a W3C draft specification).

    As a result, being able to programmatically detect whether or not a particular browser supports touch interactions involves a very simple feature detection:

    if ('ontouchstart' in window) {
      /* browser with Touch Events
         running on touch-capable device */
    }

    This snippet works reliably in modern browser, but older versions notoriously had a few quirks and inconsistencies which required jumping through various different detection strategy hoops. If your application is targetting these older browsers, I’d recommend having a look at Modernizr – and in particular its various touch test approaches – which smooths over most of these issues.

    I noted above that “almost all browsers” support this touch event model. The big exception here is Internet Explorer. While up to IE9 there was no support for any low-level touch interaction, IE10 introduced support for Microsoft’s own Pointer Events. This event model – which has since been submitted for W3C standardisation – unifies “pointer” devices (mouse, stylus, touch, etc) under a single new class of events. As this model does not, by design, include any separate ‘touch’, the feature detection for ontouchstart will naturally not work. The suggested method of detecting if a browser using Pointer Events is running on a touch-enabled device instead involves checking for the existence and return value of navigator.maxTouchPoints (note that Microsoft’s Pointer Events are currently still vendor-prefixed, so in practice we’ll be looking for navigator.msMaxTouchPoints). If the property exists and returns a value greater than 0, we have touch support.

    if (navigator.msMaxTouchPoints > 0) {
      /* IE with pointer events running
         on touch-capable device */
    }

    Adding this to our previous feature detect – and also including the non-vendor-prefixed version of the Pointer Events one for future compatibility – we get a still reasonably compact code snippet:

    if (('ontouchstart' in window) ||
         (navigator.maxTouchPoints > 0) ||
         (navigator.msMaxTouchPoints > 0)) {
          /* browser with either Touch Events of Pointer Events
             running on touch-capable device */
    }

    How touch detection is used

    Now, there are already quite a few commonly-used techniques for “touch optimisation” which take advantage of these sorts of feature detects. The most common use cases for detecting touch is to increase the responsiveness of an interface for touch users.

    When using a touchscreen interface, browsers introduce an artificial delay (in the range of about 300ms) between a touch action – such as tapping a link or a button – and the time the actual click event is being fired.

    More specifically, in browsers that support Touch Events the delay happens between touchend and the simulated mouse events that these browser also fire for compatibility with mouse-centric scripts:

    touchstart > [touchmove]+ > touchend > delay > mousemove > mousedown > mouseup > click

    See the event listener test page to see the order in which events are being fired, code available on GitHub.

    This delay has been introduced to allow users to double-tap (for instance, to zoom in/out of a page) without accidentally activating any page elements.

    It’s interesting to note that Firefox and Chrome on Android have removed this delay for pages with a fixed, non-zoomable viewport.

    <meta name="viewport" value="... user-scalable = no ...">

    See the event listener with user-scalable=no test page, code available on GitHub.

    There is some discussion of tweaking Chrome’s behavior further for other situations – see issue 169642 in the Chromium bug tracker.

    Although this affordance is clearly necessary, it can make a web app feel slightly laggy and unresponsive. One common trick has been to check for touch support and, if present, react directly to a touch event (either touchstart – as soon as the user touches the screen – or touchend – after the user has lifted their finger) instead of the traditional click:

    /* if touch supported, listen to 'touchend', otherwise 'click' */
    var clickEvent = ('ontouchstart' in window ? 'touchend' : 'click');
    blah.addEventListener(clickEvent, function() { ... });

    Although this type of optimisation is now widely used, it is based on a logical fallacy which is now starting to become more apparent.

    The artificial delay is also present in browsers that use Pointer Events.

    pointerover > mouseover > pointerdown > mousedown > pointermove > mousemove > pointerup > mouseup > pointerout > mouseout > delay > click

    Although it’s possible to extend the above optimisation approach to check navigator.maxTouchPoints and to then hook up our listener to pointerup rather than click, there is a much simpler way: setting the touch-action CSS property of our element to none eliminates the delay.

    /* suppress default touch action like double-tap zoom */
    a, button {
      -ms-touch-action: none;
          touch-action: none;
    }

    See the event listener with touch-action:none test page, code available on GitHub.

    False assumptions

    It’s important to note that these types of optimisations based on the availability of touch have a fundamental flaw: they make assumptions about user behavior based on device capabilities. More explicitly, the example above assumes that because a device is capable of touch input, a user will in fact use touch as the only way to interact with it.

    This assumption probably held some truth a few years back, when the only devices that featured touch input were the classic “mobile” and “tablet”. Here, touchscreens were the only input method available. In recent months, though, we’ve seen a whole new class of devices which feature both a traditional laptop/desktop form factor (including a mouse, trackpad, keyboard) and a touchscreen, such as the various Windows 8 machines or Google’s Chromebook Pixel.

    As an aside, even in the case of mobile phones or tablets, it was already possible – on some platforms – for users to add further input devices. While iOS only caters for pairing an additional bluetooth keyboard to an iPhone/iPad purely for text input, Android and Blackberry OS also let users add a mouse.

    On Android, this mouse will act exactly like a “touch”, even firing the same sequence of touch events and simulated mouse events, including the dreaded delay in between – so optimisations like our example above will still work fine. Blackberry OS, however, purely fires mouse events, leading to the same sort of problem outlined below.

    The implications of this change are slowly beginning to dawn on developers: that touch support does not necessarily mean “mobile” anymore, and more importantly that even if touch is available, it may not be the primary or exclusive input method that a user chooses. In fact, a user may even transition between any of their available input methods in the course of their interaction.

    The innocent code snippets above can have quite annoying consequences on this new class of devices. In browsers that use Touch Events:

    var clickEvent = ('ontouchstart' in window ? 'touchend' : 'click');

    is basically saying “if the device support touch, only listen to touchend and not click” – which, on a multi-input device, immediately shuts out any interaction via mouse, trackpad or keyboard.

    Touch or mouse?

    So what’s the solution to this new conundrum of touch-capable devices that may also have other input methods? While some developers have started to look at complementing a touch feature detection with additional user agent sniffing, I believe that the answer – as in so many other cases in web development – is to accept that we can’t fully detect or control how our users will interact with our web sites and applications, and to be input-agnostic. Instead of making assumptions, our code should cater for all eventualities. Specifically, instead of making the decision about whether to react to click or touchend/touchstart mutually exclusive, these should all be taken into consideration as complementary.

    Certainly, this may involve a bit more code, but the end result will be that our application will work for the largest number of users. One approach, already familiar to developers who’ve strived to make their mouse-specific interfaces also work for keyboard users, would be to simply “double up” your event listeners (while taking care to prevent the functionality from firing twice by stopping the simulated mouse events that are fired following the touch events):

    blah.addEventListener('touchend', function(e) {
      /* prevent delay and simulated mouse events */
      e.preventDefault();
      someFunction()
    });
    blah.addEventListener('click', someFunction);

    If this isn’t DRY enough for you, there are of course fancier approaches, such as only defining your functions for click and then bypassing the dreaded delay by explicitly firing that handler:

    blah.addEventListener('touchend', function(e) {
      /* prevent delay and simulated mouse events */
      e.preventDefault();
      /* trigger the actual behavior we bound to the 'click' event */
      e.target.click();
    })
    blah.addEventListener('click', function() {
      /* actual functionality */
    });

    That last snippet does not cover all possible scenarios though. For a more robust implementation of the same principle, see the FastClick script from FT labs.

    Being input-agnostic

    Of course, battling with delay on touch devices is not the only reason why developers want to check for touch capabilities. Current discussions – such as this issue in Modernizr about detecting a mouse user – now revolve around offering completely different interfaces to touch users, compared to mouse or keyboard, and whether or not a particular browser/device supports things like hovering. And even beyond JavaScript, similar concepts (pointer and hover media features) are being proposed for Media Queries Level 4. But the principle is still the same: as there are now common multi-input devices, it’s not straightforward (and in many cases, impossible) anymore to determine if a user is on a device that exclusively supports touch.

    The more generic approach taken in Microsoft’s Pointer Events specification – which is already being scheduled for implementation in other browser such as Chrome – is a step in the right direction (though it still requires extra handling for keyboard users). In the meantime, developers should be careful not to draw the wrong conclusions from touch support detection and avoid unwittingly locking out a growing number of potential multi-input users.

    Further links

  2. Ambient Light Events and JavaScript detection

    I think that one of the most interesting things with all WebAPIs we’re working on, is to interact directly with the hardware through JavaScript, but also, as an extension to that, with the environment around us. Enter Ambient Light Events.

    The idea with an API for ambient light is to be able to detect the light level around the device – especially since there’s a vast difference between being outside in sunlight and sitting in a dim living room – and adapt the user experience based on that.

    One use case could be to change the CSS file/values for the page, offering a nicer reading experience under low light conditions, reducing the strong white of a background, and then something with more/better contrast for bright ambient light. Another could be to play certain music depending on the light available.

    Accessing device light

    Working with ambient light is quite simple. What you need to do is apply a listener for a devicelight event, and then read out the brightness value.

    It comes returned in the lux unity. The lux value ranges between low and high values, but a good point of reference is that dim values are under 30 lux, whereas really bright ones are 10,000 and over.

    window.addEventListener("devicelight", function (event) {
        // Read out the lux value
        var lux = event.value;
        console.log(lux);});

    Web browser support

    Ambient Light Events are currently supported in Firefox on Android, meaning both mobile phones and tablets, and it’s also supported in Firefox OS. On Android devices (the ones I’ve tested), the sensor is located just right to the camera facing the user.

    It is also a W3C Working Draft, following the type of other similar events, such as devicemotion, so we hope to see more implementations of this soon!

    Demo

    Dmitry Dragilev and Tim Wright recently wrote a blog post about the Ambient Light API, with this nice demo video:

    You can also access the demo example directly, and if you test in low light conditions, you’ll get a little music. Remember to try it out on a supported device/web browser.

  3. Introducing navigator.mozPay() For Web Payments

    What’s wrong with payments on the web? Any website can already host a shopping cart and take credit card payments or something similar. The freedom of today’s web supports many business models. Here’s what’s wrong:

    • Users cannot choose how to pay; they have to select from one of the pre-defined options.
    • In most cases, the user has to type in an actual credit card number on each site. This is like giving someone the keys to your expensive car, letting them drive it around the block in a potentially dangerous neighborhood (the web) and saying please don’t get carjacked!
    • Merchants typically have to manage all this on their own: payment processor setup, costly processing fees, and possibly even PCI compliance.

    There are services to mitigate a lot of these complications such as PayPal, Stripe, and others but they aren’t integrated into web devices very well. Mozilla wants to introduce a common web API to make payments easy and secure on web devices yet still as flexible as the checkout button for merchants.

    As a first step, Mozilla will introduce navigator.mozPay() in Firefox OS so that web apps can accept payments.

    How Does It Work?

    navigator.mozPay() is a JavaScript API inspired by google.payments.inapp.buy() but modified for things like multiple payment providers and carrier billing. When a web app invokes navigator.mozPay() in Firefox OS, the device shows a secure window with a concise UI. After authenticating, the user can easily charge the payment to her mobile carrier bill or credit card. When completed, the app delivers the product. Repeat purchases are quick and easy.

    In an earlier article I talked about purchasing an app and receiving a receipt. navigator.mozPay() is different in that there is no concept of what product is purchased, it’s just an API to facilitate a payment for a digital good or service, whatever that may be.

    The payment starts and finishes in the client but further processing and notifications happen server side. This article briefly explains how it all fits together. For complete, in-depth documentation read the Firefox Marketplace guide to in-app payments.

    Integrating With A Payment Provider

    Multiple providers will facilitate payments behind the scenes of navigator.mozPay(). For example, the Firefox Marketplace will be able to facilitate payments.

    As a developer you will essentially grant permission to each provider that you would like to sell through. In the current design of the API, you do this by asking each provider for an Application Key and an Application Secret so that you can digitally sign payment requests. A signed request prevents unauthorized parties from selling your products and prevents users from tampering with the price, etc.

    Initiating A Payment

    When the user clicks a Buy button in your web app, you create a JSON Web Token (JWT) with your Application Secret. If you have agreements with multiple providers, you would create a JWT for each provider. Starting a payment looks roughly like this:

    document.querySelector('button.buy').onclick = function() {
        navigator.mozPay([mozillaJWT, otherJWT, ...]);
    };

    Defining A Product

    A JWT is a signed JSON object that defines details like the product name and price. Here is an example with some attributes removed for brevity:

    {
      "iss": APPLICATION_KEY,
      "aud": "marketplace.firefox.com",
      ...
      "request": {
        "name": "Magical Unicorn",
        "pricePoint": 1,
        "postbackURL": "https://yourapp.com/postback",
        "chargebackURL": "https://yourapp.com/chargeback"
      }
    }

    You define prices as price points so that the payment provider can handle currency conversions for you in each region. In this example, pricePoint 1 might be €0.89 or $0.99, etc. Micropayments in small amounts will be supported. Consult the navigator.mozPay() spec for details on how to construct a payment request JWT.

    Completing a Payment

    To complete the payment, you need to wait for the provider to POST a result to your server’s postbackURL (on success) or chargebackURL (on failure). A more complete example of requesting a purchase in JavaScript would involve waiting for the postback to arrive, like this:

    var request = navigator.mozPay([mozillaJWT, otherJWT]);
    request.onsuccess = function() {
      // The payment window has closed.
      whenPaymentResultReceived(function() {
        console.log('Success! User has purchased a Magical Unicorn.');
      });
    };

    To implement whenPaymentResultReceived() you might open a web socket to your server, wait for the payment result, and verify the incoming JWT signature. The navigator.mozPay() spec has details on how postback and chargeback notifications work.

    Try It Out

    Payments aren’t fully live yet in the Firefox Marketplace but you can simulate a payment to test out your code. Log into the Firefox Marketplace Developer Hub and generate an Application Key and Application Secret for simulations. With those keys you can add a special parameter to the JWT like this:

    {
      "request": {
        "name": "Magical Unicorn",
        "pricePoint": 1,
        ...
        "simulate": {"result": "postback"}
      }
    }

    This will show a payment window on Firefox OS but it won’t charge you real money. It will let you test your client side JavaScript code and your server postback handlers to make sure everything is integrated smoothly. When you go live, just remove the simulate attribute. If you’re new to Firefox OS development, check out the Firefox OS Simulator.

    If you’re already working on a game or a web app for Firefox OS try thinking about using navigator.mozPay() to offer premium content.

    This Would Be Way Easier With A Library

    We thought so too! We built libraries for Node.JS and Python to make the server side logic for navigator.mozPay() as easy as possible. Libraries for more languages are on the way. We also are experimenting with removing the server prerequisite entirely.

    Current Status

    As you can probably tell by the prefix, navigator.mozPay() is an experimental API and might change drastically or become unprefixed without notice. It will process live payments on the first Firefox OS phones and evolve quickly from real world usage.

    Mozilla plans to work with other vendors through the W3C to reach consensus on a common API that supports web payments in the best way possible. After shipping in Firefox OS, Mozilla plans to add navigator.mozPay() to Firefox for Android and desktop Firefox.

    New Business Models

    Advertising has been the primary business model on the web for a long time but users have made it clear that they don’t want to see ads. Mozilla isn’t trying to directly disrupt the ad business but it is trying to fix serious privacy issues relating to ad networks.

    What if users explicitly paid for content instead? navigator.mozPay() enables this kind of direct payment model: if something is good on the web, you can pay for it. It already seems to be working well for existing mobile apps. Will mobile ads even generate the same revenue for content producers as they do on desktop? I don’t have answers to these questions but one thing is for certain: the web should support businesses of all kinds and payments should be a first class feature of the web.

    Is It Webby?

    Mozilla’s main goal with navigator.mozPay() is to give users and merchants choice, security, and an easy to use payments system. The details about how merchants interact with payment providers is not yet specified in the API and that is clearly a gap. The first Firefox OS phones will ship with a whitelist of allowed payment providers which is also not ideal.

    In a more webby model, all parties involved in the payment would be fully decentralized so that innovation can occur naturally and unknown payment providers could emerge. Who will be the next M-Pesa? An elegant API would support that. Building a secure decentralized payment API is an ambitious challenge; the solution would need to address these core trust issues:

    • How can customers trust that they will receive the goods after paying?
    • How would customers ensure that their payment credentials are handled securely?
    • How do merchants guarantee that they’ll get paid after delivering goods?

    As with anything related to money, there is incentive for fraud every step of the way. BitCoin is a digital currency that solves some of these trust issues with block chains and PaySwarm is a web payment protocol that solves some of these issues with decentralized assets, public keys, etc. Mozilla will be watching PaySwarm as well as other models and hopefully navigator.mozPay() can incorporate some of these concepts eventually.

  4. A Social-aware Dashboard Experience with Gecko in Walls

    This article covers a Web project that rethinks how TV appliances can be used in public spaces for real-time content and interaction with social networks. Tela Social is a powered by Mozilla system application that runs in Linux appliances and creates a visual experience that presents custom and interactive content with real time data using the Web. It’s different of a standard kiosk and far from the personal browser experience because it’s not tailored for an individual. Instead, it explores how online data can be used to provide impact to users in common areas. In the following sections, you will read about the general system’s architecture; a special focus is given to how CSS3 and JavaScript is used to support the user experience with engaging animated effects.

    First, boot to the Web

    The application starts following the Linux system’s reboot. A monitor process is launched and starts to check whether the Gecko-based client is running or not. If not running, it starts the main process: a Gecko-based single window browsing engine with no toolbars in full screen.

    The following image shows an overview of the web stack infrastructure that is launched. The web application sits above the engine in a similar way to applications such as Firefox or other Powered by Mozilla apps using Gecko.

    Gecko architecture overview

    Online and Offline

    Instead of loading a remote web page, most of the resources are loaded from a local web server written in JavaScript using NodeJS — TelaSocial Mediator. This system is also monitored in order to reduce problems in the case of script execution failures.

    Once the web app comes from a local web server, a main HTML layout may bring inner HTML components that are loaded within iframes. This degree of separation exists to help developers to create isolated components in a standard test environment: all the components are made of plain pages. As part of this project, an experimental project script was created to help developers to quickly deploy new grid layouts — Gridtype.JS can take strings as arguments and can generate a grid layout that is tableless. The following example shows how to generate a grid of DIVs:

    grid('abcdabee',4);

    The above “string” specification will generate the following layout:

    Layout design

    Free of pop-ups or unwanted desktop interfaces

    There are many systems using online data to display information in TV appliances. Some of these systems are applications launched on top of the operating system graphic user interface. The following photos were taken from airports in 2012 in Brazil. These are a few of many examples of problems with unwanted user interface elements that are displayed on top of systems using operating system desktops. For this reason, and also the principle of simplicity and cost reduction, the designed approach was to launch Gecko from the basic X Window infra structure. Such approach ensures that no other visual applications are running at the same time, thus creating an improved quality experience without those unwanted pop-ups.

    Picture shows an Operating System update pop up which is common in airports in Brazil

    Picture shows an Operating System update pop up which is common in airports in Brazil

    Routing Gecko pop-ups into frames

    While OS desktop pop-ups are out of the scene, yet there are some conditions where Gecko used to display pop-ups to alert the user. The solution to this problem was to use Gecko’s preferences API and ask Gecko to display network error messages inline. With this, all errors are displayed in the iframe which is great because it is possible to track the errors and signal application logic outside the Gecko process. As an example, we can monitor the output console and change the layout depending on network error conditions. So, for example, if a weather channel frames brings a network error, the system should be able to launch an alternate layout.

    Animation library with zoom and pan

    The above elements are essential to keep the level of quality that is expected in enterprise environments. With this functional base, it’s when things can be creative and the web developer mindset rules. HTML5 and modern effects, provided by CSS3, can be used to help understand and improve the user experience in this scenario that is not the same of a desktop or a mobile.

    To help the creation of content, a small JavaScript library was also produced as part of this project. The main goal of this library is to help the creation of visual narratives out of HTML pages. The TagVisor library reads a list of <li> elements which tells how CSS3 and other transformation effects are applied with time-referenced data:

    <ul id="animation" style="display: none;">
       <li data-target="slidea" data-time="1s"
          data-effect="scalefit" data-duration="3s">
       </li>
       <li data-target="slideb" data-time="6s" 
          data-effect="scalefit" data-duration="3s">
       </li>
       <li data-target="slidec" data-time="12s"
          data-effect="scalefit" data-duration="3s">
       </li>
    </ul>

    The above script dispatches transformation functions that can modify the document using JavaScript for DOM transformations and DOM style changes that will take care of the visual effects. These effects are common in many systems, including well known JS-based solutions such as Impress.JS. However TagVisor comes with tailored functions that are very important for the scenarios in digital signage. One difference is that the script allows modifications to be performed within iframes which is good for cases where many separated HTML resources are loaded in a grid arrangement.

    The zoom and animation metaphor does a lot of the heavy work to ensure a level of smoothness in animation which is expected by users in front of a TV panel. Some effects can also be combined in time in order to produce engaging visual narratives as shown in the TagVisor video demonstration.

    Web-driven, for adaptation

    User experience is of major importance and a main reason for the use of a web-based infrastructure. Such model brings a level of dynamism supporting organisations who can tailor the system with custom data-sources using web services formats such as JSON or RSS. This approach has allowed us to test the screens with a variety of online sources; and to learn how the stream of web events can impact users in local organisations.

    The following videos are examples of systems with Tela Social. The first video refers to the system at a major science park in Brazil (Press release in Portuguese). It’s an example with a variety of content areas that are tied to a variety of sources: from journalists to editors plus open channels using social networks. The second video shows an example where the TV appliance is set in vertical position.

    People recognise that using data from events plus local interest content can build local participation. For most people, TV content is something far away and not tailored to their local community interests. To make things different, we have even used TVs in the vertical position to make a point that the whole experience was flipped and that content and interaction is bottom up.

    The objective of the project is to develop web-based solutions that can be useful in spaces and bring social-aware experiences that are positive to local communities . While social features can be used in the mobile and on desktop, we believe that our approach can help communities because it extends the physical environment — it creates a social reflection to the environment. It’s a chance for custom web experiences that build awareness about contributions made by local communities and real-time data of interest. This approach also explores challenges in user interfaces since it engages people to interact in new ways: it’s not a direct touch like standard kiosks. It’s the web in the first place and opportunities for interaction are explored based on live data.

  5. Localize Your Node.js Service, part 1 of 3 – A Node.js holiday season, part 9

    This is episode 9, out of a total 12, in the A Node.JS Holiday Season series from Mozilla’s Identity team. Now it’s time to delve into localization!

    Did you know that Mozilla’s products and services are localized into into as many as 90 languages?

    The following are just a few examples of localization:

    • Text translated into a regional language variations
    • A screen rendered right to left for a given language
    • Bulletproof designs that accommodate variable length prose
    • Label, heading, and button text that resonates with a locale audience

    In this series of posts, I’m going to cover some technical aspects of how to localize a Node.js service.

    Before we start, I’ll be using the acronyms L10n (Localization) and I18n Internationalization. I18n is the technical plumbing needed to make L10n possible.

    Mozilla Persona is a Node.js based service localized into X locales. Our team has very specific goals that inhibit us from using existing Node L10n libraries.

    Goals

    We created these modules, to meet the following goals

    • Work well with existing Mozilla L10n community
    • Let developers work with a pure JS toolkit

    The resulting toolkit contains several new Node modules:

    • i18n-abide
    • jsxgettext
    • po2json.js
    • gobbledygook

    i18n-abide is the main module you’ll use to integrate translations into your own service. Let’s walk through how to add it.

    In these examples, we’ll assume your code uses Express and EJS templates.

    Installation

    npm install i18n-abide

    Preparing your codebase

    In your code

    var i18n = require('i18n-abide');
     
    app.use(i18n.abide({
      supported_languages: ['en-US', 'de', 'es', 'zh-TW'],
      default_lang: 'en-US',
      translation_directory: 'static/i18n'
    }));

    We will look at the configuration values in detail during the third installment of this L10n series.

    The i18n abide middleware sets up request processing and injects various functions which We’ll use for translation. Below, we will see these are available in the request object and in the templating context.

    Okay, you next step is to work through all of your code where you have user visible prose.

    Here is an example template file:

    <html lang="<%= lang %>" dir="<%= lang_dir %>">
      <head>
        <title><%= gettext('Mozilla Persona') %></title>

    The key thing abide does, is it injects into the Node and express framework references to the gettext function.

    Abide also provides other variables and functions, such as lang, lang_dir.

    • lang is the language code based on the user’s browser and preferred language settings.
    • lang_dir is for bidirectional text support.
      It will be either ltr or rtl. The English language is rendered ltr or left to right.
    • gettext is a JS function which will take an English string and return a localize string, again based on the user’s preferred region and language.

    When doing localization, we refer to strings or Gettext strings: these are pieces of prose, labels, button, etc. Any prose that is visible to the end user is a string.

    Technically, we don’t mean JavaScript String, as you can have strings which are part of your program, but never shown to the user. String is overloaded to mean, stuff that must get translated.

    Here is an example JavaScript file:

    app.get('/', function(req, res) {
        res.render('homepage.ejs', {
            title: req.gettext('Hello, World!')
        });
    });

    We can see that these variables and functions (like gettext) are placed in the req object.

    So to setup our site for localization, we must look through all of our code and templates and wrap strings in calls to gettext.

    Language Detection

    How do we know what the user’s preferred language is?

    At runtime, the middleware will detect the user’s preferred language.

    The i18n-abide module looks at the Accept-Language HTTP header. This is sent by the browser and includes all of the user’s preferred languages with a preference order.

    i18n-abide processes this value and compares it with your app’s supported_languages configuration. It will make the best match possible and serve up that language.

    If a good match cannot be found, it will use the strings you’ve put into your code and templates, which are typically English strings.

    Wrapping Up

    In our next post, we’ll look at how strings like “Hello, World!” are extracted, translated, and prepared for use.

    In the third post, we’ll look more deeply at the middleware and configuration options. We’ll also test out our localization work.

    Previous articles in the series

    This was part nine in a series with a total of 12 posts about Node.js. The previous ones are:

  6. Serving Backbone for Robots & Legacy Browsers

    I like the Single Page Application model and Backbone.js, because I get it. As a former Java developer, I am used to object oriented coding and events for messaging. Within our HTML5 consultancy, SC5, Backbone has become almost a synonym for single page applications, and it is easy to move between projects because everybody gets the same basic development model.

    We hate the fact that we need to have server side workarounds for robots. Making applications crawlable is very reasonable business-wise, but ill-suited for the SPA model. Data-driven single page applications typically get only served a HTML page skeleton, and the actual construction of all the visual elements is done in browser. Any other way would easily lead into double code paths (one on a browser, one on a server). Some have even concerned on giving up the SPA model and moving the logic and representation back to the server.

    Still, we should not let the tail wag the dog. Why sacrifice the user experience of 99,9% of the users for the sake of the significant 0.1%? Instead, for such low traffic, a better suited solution would be to create a server side workaround.

    Solving the Crawling Problem with an App Proxy

    The obvious solution for the problem is running the same application code at the both ends. Like in the digital television transformation, a set-top box would fill in the gap of legacy televisions by crunching the digital signal into analog form. Correspondingly, a proxy would run the application server side and serve the resulting HTML back to the crawlers. Smart browsers would get all the interactive candy, whereas crawlers and legacy browsers would just get the pre-processed HTML document.

    Proxy pattern explained through a TV set metaphor

    Thanks to node.js, JavaScript developers have been able to use their favourite language on the both ends for some time already, and proxy-like solutions have become a plausible option.

    Implementing DOM and Browser APIs on the Server

    Single page applications typically heavily depend on DOM manipulation. Typical server applications combine several view templates into a page through concatenation, whereas Backbone applications append the views into DOM as new elements. Developer would either need to emulate DOM on the server side, or build an abstraction layer that would permit using DOM on the browser and template concatenation on the server. DOM can either be serialized into a HTML document or vice versa, but these techniques cannot be easily mixed runtime.

    A typical Backbone application talks with the browser APIs through several different layers – either by using Backbone or jQuery APIs, or accessing the APIs directly. Backbone itself has only minor dependencies to layers below – jQuery is used in DOM manipulation and AJAX requests, and application state handling is done using pushState.

    Sample Backbone layers

    Node.js has ready-made modules for each level of abstraction: JSDOM offers a full DOM implementation on the server-side, whereas Cheerio provides a jQuery API on top of a fake DOM with a better performance. Some of the other server-side Backbone implementations, like AirBnB Rendr and Backbone.LayoutManager, set the abstraction level to the level of Backbone APIs (only), and hide the actual DOM manipulation under a set of conventions. Actually, Backbone.LayoutManager does offer the jQuery API through Cheerio, but the main purpose of the library itself is to ease the juggling between Backbone layouts, and hence promote a higher level of abstraction.

    Introducing backbone-serverside

    Still, we went for our own solution. Our team is a pack of old dogs that do not learn new tricks easily. We believe there is no easy way of fully abstracting out the DOM without changing what Backbone applications essentially are. We like our Backbone applications without extra layers, and jQuery has always served us as a good compatibility layer to defend ourselves against browser differences in DOM manipulation. Like Backbone.LayoutManager, we choose Cheerio as our jQuery abstraction. We solved the Backbone browser API dependencies by overriding Backbone.history and Backbone.ajax with API compatible replacements. Actually, in the first draft version, these implementations remain bare minimum stubs.

    We are quite happy about the solution we have in the works. If you study the backbone-serverside example, it looks quite close to what a typical Backbone application might be. We do not enforce working on any particular level of abstraction; you can use either Backbone APIs or the subset of APIs that jQuery offers. If you want to go deeper, nothing stops from implementing server-side version of a browser API. Insuch cases, the actual server side implementation may be a stub. For example, needs touch event handling on the server?

    The current solution assumes a node.js server, but it does not necessarily mean drastic changes to an existing server stack. An existing servers for API and static assets can remain as-is, but there should be a proxy to forward the requests of dumb clients to our server. The sample application serves static files, API and the proxy from the same server, but they all could be decoupled with small modifications.

    backbone-serverside as a proxy

    Writing Apps That Work on backbone-serverside

    Currently the backbone-serverside core is a bare minimum set of adapters to make Backbone run on node.js. Porting your application to run on server may require further modifications.

    If the application does not already utilise a module loader, such as RequireJS or Browserify, you need to figure out on how to load the same modules on the server. In our example below, we use RequireJS and need a bit JavaScript to use Cheerio instead of vanilla jQuery on the server. Otherwise we are pretty able to use the same stack we typically use (jQuery, Underscore/Lo-Dash, Backbone and Handlebars.When choosing the modules, you may need to limit to the ones that do not play with Browser APIs directly, or be prepared to write a few stubs by yourself.

    // Compose RequireJS configuration run-time by determining the execution
    // context first. We may pass different values to browser and server.
    var isBrowser = typeof(window) !== 'undefined';
     
    // Execute this for RequireJS (client or server-side, no matter which)
    requirejs.config({
     
        paths: {
            text: 'components/requirejs-text/text',
            underscore: 'components/lodash/dist/lodash.underscore',
            backbone: 'components/backbone/backbone',
            handlebars: 'components/handlebars/handlebars',
            jquery: isBrowser ? 'components/jquery/jquery' : 'emptyHack'
        },
     
        shim: {
            'jquery': {
                deps: ['module'],
                exports: 'jQuery',
                init: function (module) {
                    // Fetch the jQuery adapter parameters for server case
                    if (module && module.config) {
                        return module.config().jquery;
                    }
     
                    // Fallback to browser specific thingy
                    return this.jQuery.noConflict();
                }
            },
            'underscore': {
                exports: '_',
                init: function () {
                    return this._.noConflict();
                }
            },
            'backbone': {
                deps: ['underscore', 'jquery'],
                exports: 'Backbone',
                init: function (_, $) {
                    // Inject adapters when in server
                    if (!isBrowser) {
                        var adapters = require('../..');
                        // Add the adapters we're going to be using
                        _.extend(this.Backbone.history,
                            adapters.backbone.history);
                        this.Backbone.ajax = adapters.backbone.ajax;
                        Backbone.$ = $;
                    }
     
                    return this.Backbone.noConflict();
                }
            },
            'handlebars': {
                exports: 'Handlebars',
                init: function() {
                    return this.Handlebars;
                }
            }
        },
     
        config: {
            // The API endpoints can be passed via URLs
            'collections/items': {
                // TODO Use full path due to our XHR adapter limitations
                url: 'http://localhost:8080/api/items'
            }
        }
    });

    Once the configuration works alright, the application can be bootstrapped normally. In the example, we use Node.js express server stack and pass specific request paths to Backbone Router implementation for handling. When done, we will serialize the DOM into text and send that to the client. Some extra code needs to be added to deal with Backbone asynchronous event model. We will discuss that more thoroughly below.

    // URL Endpoint for the 'web pages'
    server.get(/\/(items\/\d+)?$/, function(req, res) {
        // Remove preceeding '/'
        var path = req.path.substr(1, req.path.length);
        console.log('Routing to \'%s\'', path);
     
        // Initialize a blank document and a handle to its content
        //app.router.initialize();
     
        // If we're already on the current path, just serve the 'cached' HTML
        if (path === Backbone.history.path) {
            console.log('Serving response from cache');
            res.send($html.html());
        }
     
        // Listen to state change once - then send the response
        app.router.once('done', function(router, status) {
            // Just a simple workaround in case we timeouted or such
            if (res.headersSent) {
                console.warn('Could not respond to request in time.');
            }
     
            if (status === 'error') {
                res.send(500, 'Our framework blew it. Sorry.');
            }
            if (status === 'ready') {
                // Set the bootstrapped attribute to communicate we're done
                var $root = $html('#main');
                $root.attr('data-bootstrapped', true);
     
                // Send the changed DOM to the client
                console.log('Serving response');
                res.send($html.html());
            }
        });
     
        // Then do the trick that would cause the state change
        Backbone.history.navigate(path, { trigger: true });
    });

    Dealing with Application Events and States

    Backbone uses an asynchronous, event-driven model for communicating between the models views and other objects. For an object oriented developer, the model is fine, but it causes a few headaches on node.js. After all, Backbone applications are data driven; pulling data from a remote API endpoint may take seconds, and once it eventually arrives, the models will notify views to repaint themselves. There is no easy way to know when all the application DOM manipulation is finished, so we needed to invent our own mechanism.

    In our example we utilise simple state machines to solve the problem. Since the simplified example does not have a separate application singleton class, we use a router object as the single point of control. Router listens for changes in states of each view, and only notifies the express server about readiness to render when all the views are ready. In the beginning of the request, router resets the view states to pending and does not notify the browser or server until it knows all the views are done. Correspondingly, the views do not claim to be done until they know they are fed with valid data from their corresponding model/collection. The state machine is simple and can be consistently applied throughout the different Backbone objects.

    Activity diagram of a Backbone app event flow

    Beyond the Experimental Hack

    The current version is still experimental work, but it proves Backbone applications can happily live on the server without breaking Backbone APIs or introducing too many new conventions. Currently in SC5 we have a few projects starting that could utilise the this implementation, so we will
    continue the effort.

    We believe the web stack community benefits from this effort, thus we have published the work in GitHub. It is far from being finished and we would appreciate all community continueributions in the forms of ideas and code. Share the love, criticism and all in between: @sc5io #backboneserverside.

    Particularly,we plan to change and hope to get contributions for the following:

    • The current example will likely misbehave on concurrent requests. It shares a single DOM representation for all the ongoing requests, which can easily mess up each other.
    • The state machine implementation is just one idea on how to determine when to serialize the DOM back to the client. It likely can be drastically simplified for most use cases, and it is quite possible to find a better generic solution.
    • The server-side route handling is naive. To emphasize that only the crawlers and legacy browsers might need server-side rendering, the sample could use projects like express-device to detect if we are serving a legacy browser or a server.
    • The sample application is a very rudimentary master-details view application and will not likely cause any wow effect. It needs a little bit of love.

    We encourage you to fork the repository and start from modifying the example for your needs. Happy Hacking!

  7. Announcing the winners of the February 2013 Dev Derby!

    Last month, some of the most creative web developers out there pushed the limits of touch events and multi-touch interaction in the February Dev Derby contest. After looking through the entries, our three expert judges–Franck Lecollinet, Guillaume Lecollinet, and (filling in for Craig Cook this month) yours truly–decided on three winners and two runners-up.

    Not a contestant? There are other reasons to be excited. Most importantly, all of these demos are completely open-source, making them wonderful lessons in the exciting things you can do with multi-touch today.

    Dev Derby

    The Results

    Winners

    Runners-up

    Naming just a few winners is always difficult, but the task was especially hard this time around. Just about every demo I came across impressed me more than the last, and I know our other judges faced a similar dilemma. Our winners managed to take a relatively familiar form of interaction and create experiences that were more creative, more fun, and more visually stunning than we would have ever predicted. Congratulations to them and to everyone else who amazed us last month.

    Want to get a head start on an upcoming Derby? We are now accepting demos related to mobile web development in general (March), Web Workers (April), and getUserMedia (May). Head over to the Dev Derby to get started.

  8. Short sweet doc sprint for March

    This past weekend, a small band of hardy MDN contributors pitched in for the first of a monthly series of doc sprints. This sprint was organized on fairly short notice, yet a significant amount of work was accomplished.

    Web standards docs

    • Jérémie Patonnier created a bunch of API reference pages for MozMobileConnection, and SVG attributes dx and dy, and did a “crazy bunch of clean up” on the SVG documentation.
    • Michael Beckwith cleaned up writing on isNan and indexOf, and made minor touchups to :active.
    • Kevin Brosnan updated the compatibility info in Supported media formats.
    • fusionchess expanded the paragraph on passing data in Using web workers and added an example of a generic “asynchronous eval()”.

    Firefox OS and Apps

    • Gangadhar Nittala made his first contribution to MDN by changing the Apps manifest article to indicate that the .webapp extension for the file is mandatory, not just recommended.
    • Jonathan Watt added a section to Preparing for your first B2G build on how to update your B2G tree.
    • nullspace further clarified in Preparing for your first B2G build that there are gigabytes of Android libraries to download, which can take tens of hours (or days).

    Mozilla technology

    • Cory Gackenheimer updated Web Console for bug 623749.
    • Trevor Hobson updated Styling a tree to reflect changes in Gecko 22.
    • Florian Scholz worked on Firefox dev-doc-needed issues:
      • Documented that a Mac OS X backend for the DeviceLightEvent is now implemented.
      • Updated CanvasRenderingContext2D for the now-implemented isPointInStroke method.
      • Documented the rename of the allowfullscreen attribute of the HTML iframe element in Firefox 18 and WebKit Nightly (was prefixed).
      • Documented that DOMImplementation.hasFeature() and Node.isSupported() will always return true starting with Firefox 19.
      • Noted that createElement(null) works like createElement(“null”) starting with Firefox 19.
    • Tom Schuster worked on lots of little dev-doc-needed bugs.
    • donghao526 updated the simplified Chinese translation of The essentials of an extension.
    • darktrojan added a table about bootstrap data in Bootstrapped extensions.
    • Cykesiopka updated the join() example in Path manipulation so that the MDN and Gecko in-source documentation match.
    • the prisoner updated the French translations of Firefox 19 for developers and Firefox 20 for developers.
    • complynx fixed links to mutation observers in Mozilla event reference.
    • Ernest Chiang updated the traditional Chinese translation of Persona Quick Setup.
  9. Gameleon and the map editor – a WebFWD project

    More than 9 months ago, we were working on a web game, having all the nice HTML5 stuff like Canvas, WebSocket, CSS3. We were playing a lot with experimental code in NodeJS and Redis. We had all the nice scripts and plugins and quite a good architecture to make the game possible.

    We lacked one thing though: a powerful editor. Since we had 8 years of nothing but web development experience, we were keen on making this web too. We didn’t like Flash though or anything which isn’t a web standard or open technology, because it was restricting us from using what we made on all the devices we had through the office, in the same way (tablets, phones, laptops, desktops).

    Creating an editor

    So, we’ve started making Gameleon for Shay, our game architect. He did quite a lot of Dungeons and Dragons and played with many of the RPG editors out there. We thought that he was good just like that, without any programming knowledge, and we wanted to give him the means to make anything in our game, without coming to us.

    The first thing we made was the map editor. One thing was sure about this: we didn’t want to have any kind of limitations, such as tiles. What we love doing is drawing the maps ourselves, in any way we see fit. The one thing you can never know about a random picture is where the obstacles are. For that, we made a polygon editing tool, which can define just that. It is like a mesh applied on top of the map, giving it the logic for collision detection later.

    Probably this video demonstrating how a map is built will be of more help:

    Processing a map

    In this article i’ll try to discuss a bit about how the map is processed and turned into a walkable, obstacle friendly surface.

    When it comes to making a friendly way to define areas, using vectors is the way to go, as you probably saw in the above video.

    A map is defined by vertices and points. They are sent to the server via WebSocket, in JSON format.

    The struggle when having a good map is to have that good mixture between freedom to create as much content as you want, yet be able to determine what surface is an obstacle and have a very fast collision detection system and path finding.

    image

    The best mix of these two we’ve found to be in a grid. Using A* and QuadTree to determine the shortest route and the collisions between objects, no matter what size, became a lot simpler. By the way, all objects defined on a map, are treated as circles. When we determine if an object collides with another (in a combat situation for instance), we can make one of the objects move to the nearest empty area, while still being in range of the target.

    So, this is why we are going to transform the vector map we’ve just received, into a grid, having a square of the size of 8 x 8 points. Experimentally, we’ve determined it is a small enough square to have a small number of collisions, and yet be effective when searching across long distances (for instance, searching for the shortest path between two points A and B on a map of 3200 x 2000 points).

    Determining the squares

    To determine the squares a polygon is going to cover, we use a brute force technique. Yes, it may sound crude, but it is quite effective. First, we determine the rectangle covered by the polygon.

    enhance.prototype._determineRectangle = function( points, poly )
    {
        var minX = null, minY = null, maxX = null, maxY = null;
     
        for(var j=0;j<poly.coords.length;j++)
        {
            var currentPoint = points[ poly.coords[j] ];
     
            if( minX == null || currentPoint[ 0 ] < minX )
            {
                minX = currentPoint[0];
            }
     
            if( maxX == null || currentPoint[ 0 ] > maxX )
            {
                maxX = currentPoint[0];
            }
     
            if( minY == null || currentPoint[ 1 ] < minY )
            {
                minY = currentPoint[1];
            }
     
            if( maxY == null || currentPoint[ 1 ] > maxY )
            {
                maxY = currentPoint[1];
            }
        }
     
        return { minX: minX, minY: minY, maxX: maxX, maxY: maxY };
    }

    image

    Checking point positions

    Once we have that, we start going through each point of that rectangle and check if the point is inside or outside the polygon. The theory behind this is to draw a horizontal line passing through that point and check the number of intersections with the polygon’s vertices. If the number of intersections is odd, then the point is outside. If the number is even, then it is inside.

    enhance.prototype._pointInPolygon = function( x, y, poly, points )
    {
        var j = poly.coords.length - 1, oddNodes = false;
     
        for(var i = 0;i < poly.coords.length; i++)
        {
            var pointI = poly.coords[i],
                pointJ = poly.coords[j],
                _pointIY = points[ pointI ][1],
                _pointJY = points[ pointJ ][1],
                _pointIX = points[ pointI ][0],
                _pointJX = points[ pointJ ][0];
     
            if(
                _pointIX == x &&
                _pointIY == y
            )
            {
                return true;
            }
     
            if(
                ( _pointIY < y && _pointJY >= y ) ||
                ( _pointJY < y && _pointIY >= y )
            )
            {   
                if(
                    _pointIX + ( y - _pointIY ) / ( _pointJY - _pointIY ) * ( _pointJX - _pointIX ) < x
                )
                {
                    oddNodes = !oddNodes;
                }
            }
     
            j = i;
        }
     
        return oddNodes;
    }

    This way, we mark the walkable and non-walkable areas of the map. However, there are those special situations when you want to mark an area as walkable or non-walkable dynamically.

    image

    Say you have some debris and you don’t want that area to be walkable, but once the debris are destroyed, that area has to be changed. So, we keep in a separate vector, the actual points covered by each polygon.

    Setting names

    In the map editor, you are being given the ability to name polygons, both for esthetic purposes – to notify the player that he is entering “The Killing Fields” for instance, and to lookup via scripting.

    The scripting names are automatically given – ZP01, ZP02, etc. – to ensure their unique name.

    In the script editor, you can use an action named setWalkableArea, and send as parameter the polygon name. When the action is executed, the server will broadcast to every member on the map, the points which are suppose to change their state, thus updating the map grid with ease. No additional processing will be done.

    image

    Say you attach this to the event of an object being destroyed, which was right on top of that area. This would create the illusion that the object itself was an obstacle and that it is now removed.

    Neat, isn’t it?

    Part of Gameleon

    The code above is part of the editor and this coding standard can be found throughout the entire Gameleon code.

    Hope you enjoyed this short intro into how we see maps and games being created. If you want to know more, have a look at Gameleon and follow us on twitter: @gameleonMain.

    The complete source code is available on GitHub.