Mozilla

Found 443 results for “html5”

Sort by:

View:

  1. Videos and Firefox OS

    Before HTML5

    Those were dark times Harry, dark times – Rubeus Hagrid

    Before HTML5, displaying video on the Web required browser plugins and Flash.

    Luckily, Firefox OS supports HTML5 video so we don’t need to support these older formats.

    Video support on the Web

    Even though modern browsers support HTML5, the video formats they support vary:

    In summary, to support the most browsers with the fewest formats you need the MP4 and WebM video formats (Firefox prefers WebM).

    Multiple sizes

    Now that you have seen what formats you can use, you need to decide on video resolutions, as desktop users on high speed wifi will expect better quality videos than mobile users on 3G.

    At Rormix we decided on 720p for desktop, 360p for mobile connections, and 180p specially for Firefox OS to reduce the cost in countries with high data charges.

    There are no hard and fast rules — it depends on who your market audience is.

    Streaming?

    The best streaming solution would be to automatically serve the user different videos sizes depending on their connection status (adaptive streaming) but support for this technology is poor.

    HTTP live streaming works well on Apple devices, but has poor support on Android.

    At the time of writing, the most promising technology is MPEG DASH, which is an international standard.

    In summary, we are going to have to wait before we get an adaptive streaming technology that is widely accepted (Firefox does not support HLS or MPEG DASH).

    DIY Adaptive streaming

    In the absence of adaptive streaming we need to try to work out the best video quality to load at the outset. The following is a quick guide to help you decide:

    Wifi or 3G

    Using a certified Firefox OS app you can check to see if the user is on wifi or not.

    var lock    = navigator.mozSettings.createLock();
    var setting = lock.get('wifi.enabled');
     
    setting.onsuccess = function () {
      console.log('wifi.enabled: ' + setting.result);
    }
     
    setting.onerror = function () {
      console.warn('An error occured: ' + setting.error);
    }

    https://developer.mozilla.org/en-US/docs/Web/API/Settings_API

    There is some more information at the W3C Device API.

    Detecting screen size

    There is no point sending a 720p video to a user with a screen smaller than 720p. There are many ways to get the different bounds of a user’s screen; innerWidth and width allow you to get a good idea:

    function getVidSize()
    {
      //Get the width of the phone (rotation independent)
      var min = Math.min($(window).innerHeight(),$(window).innerWidth());
      //Return a video size we have
      if(min < 320)      return '180';
      else if(min < 550) return '360';
      else               return '720';
    }

    http://www.quirksmode.org/m/tests/widthtest.html

    Determining internet speed

    It is difficult to get an accurate read of a user’s internet speed using web technologies — usually they involve loading a large image onto the user’s device and timing it. This has the disadvantage of having to send more data to the user. Some services such as: http://speedof.me/api.html exist, but still require data downloads to the user’s device. (Stackoverflow has some more options.)

    You can be slightly more clever by using HTML5, and checking the time it takes between the user starting the video and a set amount of the video loading. This way we do not need to load any extra data on the user’s device. A quick VideoJS example follows:

    var global_speedcount = 0;
    var global_video = null;
    global_video = videojs("video", {}, function(){
    //Set up video sources
    });
     
    global_video.on('play',function(){
      //User has clicked play
      global_speedcount = new Date().getTime();
    });
     
    function timer()
    {
      var diff = new Date().getTime() - global_speedcount;
      //Remove this handler as it is run multiple times per second!
      global_video.off('timeupdate',timer);
    }
     
    global_video.on('timeupdate',timer);

    This code starts timing when the user clicks play, and when the browser starts to play the video it sends timing information to timeupdate. You can also use this function to detect if lots of buffering is happening.

    Detect high resolution devices

    One final thing to determine is whether or not a user has a high pixel density screen. In this case even if they have a small screen it can still have a large number of pixels (and therefore require a higher resolution video).

    Modernizr has a plugin for detecting hi-res screens.

    if (Modernizr.highresdisplay)
    {
      alert('Your device has a high resolution screen');
    }

    WebP Thumbnails

    Not to get embroiled in an argument, but at Rormix we have seen an average decrease of 30% in file size (WebP vs JPEG) with no loss of quality (in some cases up to 50% less). And in countries with expensive data plans, the less data the better.

    We encode all of our thumbnails in multiple resolutions of WebP and send them to every device that supports them to reduce the amount of data being sent to the user.

    Mobile considerations

    If you are playing HTML5 videos on mobile devices, their behavior differs. On iOS it automatically goes to full screen on iPhones/iPods, but not on tablets.

    Some libraries such as VideoJS have removed the controls from mobile devices until their stability increases.

    Useful libraries

    There are a few useful HTML5 video libraries:

    Mozilla links

    Mozilla has some great articles on web video:

    Other useful Links

  2. An easier way of using polyfills

    Polyfills are a fantastic way to enable the use of modern code even while supporting legacy browsers, but currently using polyfills is too hard, so at the FT we’ve built a new service to make it easier. We’d like to invite you to use it, and help us improve it.

    Image from https://www.flickr.com/photos/hamur0w0/6984884135

    More pictures, they said. So here’s a unicorn, which is basically a horse with a polyfill.

    The challenge

    Here are some of the issues we are trying to solve:

    • Developers do not necessarily know which features need to be polyfilled. You load your site in some old version of IE beloved by a frustratingly large number of your users, see that the site doesn’t work, and have to debug it to figure out which feature is causing the problem. Sometimes the culprit is obvious, but often not, especially when legacy browsers also lack good developer tools.
    • There are often multiple polyfills available for each feature. It can be hard to know which one most faithfully emulates the missing feature.
    • Some polyfills come as a big bundle with lots of other polyfills that you don’t need, to provide comprehensive coverage of a large feature set, such as ES6. It should not be necessary to ship all of this code to the browser to fix something very simple.
    • Newer browsers don’t need the polyfill, but typically the polyfill is served to all browsers. This reduces performance in modern browsers in order to improve compatibility with legacy ones. We don’t want to make that compromise. We’d rather serve polyfills only to browsers that lack a native implementation of the feature.

    Our solution: polyfills as a service

    To solve these problems, we created the polyfill service. It’s a similar idea to going to an optometrist, having your eyes tested, and getting a pair of glasses perfectly designed to correct your particular vision problem. We are doing the same for browsers. Here’s how it works:

    1. Developers insert a script tag into their page, which loads the polyfill service endpoint.
    2. The service analyses the browser’s user-agent header and a list of requested features (or uses a default list of everything polyfillable) and builds a list of polyfills that are required for this browser
    3. The polyfills are ordered using a graph sort to place them in the right dependency order.
    4. The bundle is minified and served through a CDN (for which we’re very grateful to Fastly for their support)

    Do we really need this solution? Well, consider this: Modernizr is a big grab bag of feature detects, and all sensible use cases benefit from a custom build, but a large proportion of Modernizr users just use the default build, often from cdnjs.com or as part of html5boilerplate. Why include Modernizr if you aren’t using its feature detects? Maybe you misunderstand the purpose of the library and just think that Modernizr “fixes stuff”? I have to admit, I did, when I first heard the name, and I was mildly disappointed to find that rather than doing any actual modernising, Modernizr actually just defines modernness.

    The polyfill service, on the other hand, does fix stuff. There’s really nothing wrong with not wanting to spend time gaining intimate knowledge of all the foibles of legacy browsers. Let someone figure it out once, and then we can all benefit from it without needing or wanting to understand the details.

    How to use it

    The simplest use case is:

    <script src="//cdn.polyfill.io/v1/polyfill.min.js" async defer></script>

    This includes our default polyfill set. The default set is a manually curated list of features that we think are most essential to modern web development, and where the polyfills are reasonably small and highly accurate. If you want to specify which features you want to polyfill though, go right ahead:

    <!-- Just the Array.from polyfill -->
    <script src="//cdn.polyfill.io/v1/polyfill.min.js?features=Array.from" async defer></script>
     
    <!-- The default set, plus the geolocation polyfill -->
    <script src="//cdn.polyfill.io/v1/polyfill.min.js?features=default,Navigator.prototype.geolocation" async defer></script>

    If it’s important that you have loaded the polyfills before parsing your own code, you can remove the async and defer attributes, or use a script loader (one that doesn’t require any polyfills!).

    Testing and documenting feature support

    This table shows the polyfill service’s effect for a number of key web technologies and a range of popular browsers:

    Polyfill service support grid

    The full list of features we support is shown on our feature matrix. To build this grid we use Sauce Labs’ test automation platform, which runs each polyfill through a barrage of tests in each browser, and documents the results.

    So, er, user-agent sniffing? Really?

    Yes. There are several reasons why UA analysis wins out over feature detection for us:

    • In some cases, we have multiple polyfills for the same feature, because some browsers offer a non-compliant implementation that just needs to be bashed into shape, while others lack any implementation at all. With UA detection you can choose to serve the right variant of the polyfill.
    • With UA detection, the first HTTP request can respond directly with polyfill code. If we used feature detection, the first request would serve feature-detect code, and then a second one would be needed to fetch specific polyfills.

    Almost all websites with significant scale do UA detection. This isn’t to say the stigma attached to it is necessarily bad. It’s easy to write bad UA detect rules, and hard to write good ones. And we’re not ruling out making a way of using the service via feature-detects (in fact there’s an issue in our tracker for it).

    A service for everyone

    The service part of the app is maintained by the FT, and we are working on expanding and improving the tools, documentation, testing and service features all the time. The source is freely available on GitHub so you can easily host it yourself, but we also host an instance of the service on cdn.polyfill.io which you can use for free, and our friends at Fastly are providing free CDN distribution and SSL.

    We’ve made a platform. We need the community’s help to populate it. We already serve some of the best polyfills from Jonathan Neal, Mathias Bynens and others, but we’d love to be more comprehensive. Bring your polyfills, improve our tests, and make this a resource that can help move the web forward!

  3. Massive: The asm.js Benchmark

    asm.js is a subset of JavaScript that is very easy to optimize. Most often it is generated by a compiler, such as Emscripten, from C or C++ code. The result can run at very high speeds, close to that of the same code compiled natively. For that reason, Emscripten and asm.js are useful for things like 3D game engines, which are usually large and complex C++ codebases that need to be fast, and indeed top companies in the game industry have adopted this approach, for example Unity and Epic, and you can see it in action in the Humble Mozilla Bundle, which recently ran.

    As asm.js code becomes more common, it is important to be able to measure performance on it. There are of course plenty of existing benchmarks, including Octane which contains one asm.js test, and JetStream which contains several. However, even those do not contain very large code samples, and massive codebases are challenging in particular ways. For example, just loading a page with such a script can take significant time while the browser parses it, causing a pause that is annoying to the user.

    A recent benchmark from Unity measures the performance of their game engine, which (when ported to the web) is a large asm.js codebase. Given the high popularity of the Unity engine among developers, this is an excellent benchmark for game performance in browsers, as real-world as it can get, and also it tests large-scale asm.js. It does however focus on game performance as a whole, taking into account both WebGL and JavaScript execution speed. For games, that overall result is often what you care about, but it is also interesting to measure asm.js on its own.

    Benchmarking asm.js specifically

    Massive is a benchmark that measures asm.js performance specifically. It contains several large, real-world codebases: Poppler, SQLite, Lua and Box2D; see the FAQ on the massive site for more details on each of those.

    Massive reports an overall score, summarizing it’s individual measurements. This score can help browser vendors track their performance over time and point to areas where improvements are needed, and for developers it can provide a simple way to get an idea of how fast asm.js execution is on a particular device and browser.

    Importantly, Massive does not only test throughput. As already mentioned, large codebases can affect startup time, and they can also affect responsiveness and other important aspects of the user experience. Massive therefore tests, in addition to throughput, how long it takes the browser to load a large codebase, and how responsive it is while doing so. It also tests how consistent performance is. Once again, see the FAQ for more details on each of those.

    Massive has been developed openly on github from day one, and we’ve solicited and received feedback from many relevant parties. Over the last few months Massive development has been in beta while we received comments, and there are currently no substantial outstanding issues, so we are ready to announce the first stable version, Massive 1.0.

    Massive tests multiple aspects of performance, in new ways, so it is possible something is not being measured in an optimal manner, and of course bugs always exist in software. However, by developing Massive in the open and thereby giving everyone the chance to inspect it and report issues, and by having a lengthy beta period, we believe we have the best possible chance of a reliable result. Of course, if you do find something wrong, please file an issue! General feedback is of course always welcome as well.

    Massive performance over time

    Massive is brand-new, but it is still interesting to look at how it performs on older browsers (“retroactively”), because if it measures something useful, and if browsers are moving in the right direction, then we should see Massive improve over time, even on browser versions that were released long before Massive existed. The graph below shows Firefox performance from version 14 (released 2012-07-17, over 2 years ago) and version 32 (which became the stable version in September 2014):

    Higher numbers are better, so we can indeed see that Massive scores do follow the expected pattern of improvement, with Firefox’s Massive score rising to around 6x its starting point 2 years ago. Note that the Massive score is not “linear” in the sense that 6x the score means 6x the performance, as it is calculated using the geometric mean (like Octane), however, the individual scores it averages are mostly linear. A 6x improvement therefore does represent a very large and significant speedup.

    Looking more closely at the changes over time, we can see which features landed in each of those versions of Firefox where we can see a significant improvement:

    There are three big jumps in Firefox’s Massive score, each annotated:

    • Firefox 22 introduced OdinMonkey, an optimization module for asm.js code. By specifically optimizing asm.js content, it almost doubled Firefox’s Massive score. (At the time, of course, Massive didn’t exist; but we measured speedups on other benchmarks.)
    • Firefox 26 parses async scripts off of the main thread. This avoids the browser or page becoming nonresponsive while the script loads. For asm.js content, not only parsing but also compilation happens in the background, making the user experience even smoother. Also in Firefox 26 are general optimizations for float32 operations, which appear in one of the Massive tests.
    • Firefox 29 caches asm.js code: The second time you visit the same site, previously-compiled asm.js code will just be loaded from disk, avoiding any compilation pause at all. Another speedup in this version is that the previous float32 optimizations are fully optimized in asm.js code as well.

    Large codebases, and why we need a new benchmark

    Each of those features is expected to improve asm.js performance, so it makes sense to see large speedups there. So far, everything looks pretty much as we would expect. However, a fourth milestone is noted on that graph, and it doesn’t cause any speedup. That feature is IonMonkey, which landed in Firefox 18. IonMonkey was a new optimizing compiler for Firefox, and it provided very large speedups on most common browser benchmarks. Why, then, doesn’t it show any benefit in Massive?

    IonMonkey does help very significantly on small asm.js codebases. But in its original release in Firefox 18 (see more details in the P.S. below), IonMonkey did not do well on very large ones – as a complex optimizing compiler, compilation time is not necessarily linear, which means that large scripts can take very large amounts of time to compile. IonMonkey therefore included a script size limit – over a certain size, IonMonkey simply never kicks in. This explains why Massive does not improve on Firefox 18, when IonMonkey landed – Massive contains very large codebases, and IonMonkey at the time could not actually run on them.

    That shows exactly why a benchmark like Massive is necessary, as other benchmarks did show speedups upon IonMonkey’s launch. In other words, Massive is measuring something that other benchmarks do not. And that thing – large asm.js codebases – is becoming more and more important.

    (P.S. IonMonkey’s script size limit prevented large codebases from being optimized when IonMonkey originally launched, but that limit has been relaxed over time, and practically does not exist today. This is possible through compilation on a background thread, interruptible compilation, and just straightforward improvements to compilation speed, all of which make it feasible to compile larger and larger functions. Exciting general improvements to JavaScript engines are constantly happening across the board!)

  4. Matchstick Brings Firefox OS to Your HDTV: Be the First to get a Developer Stick

    The first HDMI streaming stick powered by Firefox OS has arrived. It’s called Matchstick and we’re looking for your help to create apps for this new device.

    Background

    Matchstick stems from a group of coders that spent way too much time mired in the guts of platforms such as Boot to Gecko, XBMC, and Boxee. When Google introduced Chromecast we were excited about the possibilities but ultimately were disappointed when they pulled back on the device’s ultimate promise – any content on any HD screen, anywhere, anytime.

    We decided to make something better and more open, and to accomplish this we had to choose an operating system that would become the bedrock for the adaptable and open-sourced platform that is Matchstick. That platform is Firefox OS, which allows us to build the first streaming stick free of any walled garden ecosystem.

    Matchstick and Firefox OS combined offers a totally open platform (both software and hardware), that lets developers explore content and applications from video to games, and bring it right into the living room. That’s right Developers! An open SDK means you can build out your own personalized streaming and interactive experiences without the need for approval or review.

    Apps for Matchsticks

    We have opened up a full developer site with access to everything you need to begin working with Matchstick. Support for Firefox OS will be available at launch, and we look forward to adding TV applications to the Firefox OS Marketplace. For now, we have included a full API library, of sender apps with support for Android and iOS, as well as receiver apps that are compatible with the Matchstick Receiver.

    When we say Apps for Matchsticks, we mean both sender and receiver apps. You can use the sender APIs to enable your Firefox OS, Android or iOS device to discover a Matchstick device, then communicate with your receiver app. It’s not difficult to embed sender APIs into existing apps or create new sender apps, please refer to the sample code we have included with the SDK.

    Matchstick sender apps typically follow this execution flow:

    1. Scan for Matchstick
      The sender app searches for Matchstick devices residing in the same Wi-Fi network as the sender device. The scanning reveals a friendly display name, model and manufacturer, icon, and the device’s IP address. Presented with a list, a user may then select a target device from all those discovered.
    2. Connect to Matchstick
      We support both TLS and NON-TLS communication between sender and receiver.
    3. Launch Receiver App
      The sender initiates a negotiation with the target device, launching a receiver app either with the URL of a HTML5 receiver app, or even a Chromecast App ID.
    4. Establish Message Channels
      With the receiver app now launched, Matchstick establishes message channels between the sender and receiver. In addition to a media control channel common to all Matchstick and Chromecast apps, you may establish any number of application-specific channels to convey whatever customized data that your app might require.

    The receiver app is a combination of HTML5, CSS and Javascript, loaded into a “receiver container” which is a certified app of Firefox OS. To use the Matchstick receiver APIs, you need only include fling_receiver.js in your app.

    Here is an example of a simple video receiver app:

    <!DOCTYPE html>
    <html>
        <head>
         <title>Example simplest receiver</title>
         <meta charset="UTF-8">
         <!--(need) include matchstick receiver sdk-->
         <script src="//fling.matchstick.tv/sdk/libs/receiver/2.0.0/fling_receiver.js"></script>
        </head>
        <body>
         <!--(need) Give a video tag-->
         <video id="media"></video>
         <script>
             // (need) Get video element
             window.mediaElement = document.getElementById("media");
             // (need) For media applications, override/provide any event listeners on the MediaManager.
             window.mediaManager = new fling.receiver.MediaManager(window.mediaElement);
     
             // (need) Get and hold the provided instance of the FlingReceiverManager.
             // Override/provide any event listeners on the FlingReceiverManager.
             window.flingReceiverManager = fling.receiver.FlingReceiverManager.getInstance();
     
             // (need) Call start on the FlingReceiverManager to indicate the receiver application is ready to receive messages.
             window.flingReceiverManager.start();
         </script>
        </body>
    </html>

    Matchsticks for Apps

    Rather than relying on emulators, we want to be sure developers can get their hands on Matchstick prototypes and start coding without delay. As a result, we are inviting app developers who will commit to building and porting apps for Firefox OS on Matchstick to apply for a free developer-preview device through our Matchsticks for Apps program.

    Similar to the phones-for-apps program launched by Mozilla, our Matchsticks for Apps program is aimed at developers who have built apps for Firefox OS, Chrome, Android, iOS …. Even for Chromecast! Let’s bring those visions to the big screen.

    image

    Developer (pre-production) version of Matchstick (pic by Christian Heilmann)

    We are now looking for good ideas, video content, new channels, as well as games, tools, utilities, pictures, even skins for the UI. If you have a plan to build apps or do something for Matchstick, please share your plan and we’ll send you a stick so you can start coding ASAP.

    Who Should Apply:

    • Those interested in building apps on a big screen TV
    • Those with existing Web or mobile apps, who would like to expand to the big screen
    • HDMI dongle developers, who want to build their own Matchstick
    • Chromecast developers, who want to port their apps to an open platform
    • You!

    Matchstick workshop in November

    On Tuesday, November 18th, we plan to host an invitation-only Firefox OS App Workshop for Matchstick in the Mozilla office in San Francisco. The enrollment form is open and we are accepting applications from qualified developers.

    Apply now for the San Francisco workshop!

    If you don’t live near San Francisco, don’t worry! We plan to offer several other app workshops in the near future and we’ll announce them here, of course!

    Happy Hacking!

  5. 350 posts on Hacks in 2 years!

    Two years ago, we made a number of changes to the Mozilla Hacks blog. Since then we’ve had over three million unique visitors and 350 quality posts in just less than two years – almost one every second day!

    Part of these changes included:

    • A clear focus on learning about the Open Web & open source – more detail in What Mozilla Hacks is
    • A dedicated Editor, me, working with ensuring consistency, quality & versatility of the articles
    • Articles covering both interesting technologies and possibilities but also learning lessons of how to build exciting solutions and work with a number of different technical opportunities
    • To be a credible and independent go-to resource for developers

    Testimonials

    I’ve gathered a few testimonials from authors behind the most popular articles during this time, with their experiences writing for Mozilla Hacks.

    And you know what? You could write for Hacks too!

    If you have experience with a great solution or idea for the Open Web/open source, just let me know and Mozilla can help you share it with a lot of developers out there! Send an e-mail to robert [at] mozilla [dot] com or talk to me via @robertnyman on Twitter and we’ll talk!

    Here are the thoughts from Peter Cooper of HTML5 Weekly & JavaScript Weekly, Dave Camp, Director of Firefox Developer Tools and Thorben Bochenek from Opera on writing for Mozilla Hacks.

    Austin Hallock from Clay.io:

    My co-founder Zoli and I have both written articles for Mozilla Hacks and we agree that it was a very worthwhile experience. The process of getting our posts on the site was easy and both articles generated more response than we expected. Mozilla has a fantastic mission, and the Mozilla Hacks blog is a great extension of that.

    Their articles:

    Also, thanks to the authors on Mozilla Hacks for their great contributions! And those in that page are only authors with 2 posts and more – in total we have 230 authors all time who have published a post on Hacks!

    Most popular content

    During these two years, these are the most popular posts, written by Mozilla staff:

    The most popular posts, written by 3rd party developers/writers:

    Read & write

    If you like our articles, please spread the word about them! Ask your friends to read too and follow @mozhacks on Twitter for the latest articles and announcements.

    And if you have experiences and learnings to share, let us know and help you with sharing that knowledge!

  6. Webapplate – Maintainable web app template for Firefox OS and Chrome Apps

    There are many powerful tools and technologies surrounding the Web, and we can reuse them to develop cross platform mobile and desktop apps, especially in light of installable apps appearing on platforms such as Firefox OS. This article looks at the best way to do this, and presents Webapplate, a powerful new template to help facilitate this.

    Why invent the wheel (for the new frontier)

    As is the nature of the whole web, web apps are simple to write but hard to get done right. Even though the Web doesn’t provide an SDK or simple ready-to-use templates like other mobile platforms, you can still come out with a workable web app from candidates like Mozilla Open Web Apps, Chrome Apps, or Apache Cordova. But developers who want to quickly build a web app usually take longer time than say, an iOS developer.

    Here is the state of web app support by those candidates:

    • Firefox (desktop), Firefox OS, Firefox for Android support hosted web apps. Those web apps could be hosted on a static or dynamic web server just like normal web sites. Hosted web apps don’t allow some certified web APIs such as the TCP socket API because of security concerns.
    • Firefox OS and Chrome (desktop) support packaged web apps with different APIs for different purposes, because currently they focus on different types of devices.
    • Cordova provides device adapters for many platforms, including Android, iOS and Firefox OS.
    • Google has its Cordova variant to adapt Chrome App’s specific APIs to run on Android devices.

    In quick summary, the web app concept is not totally unified yet, but powerful enough to compete with native apps. Currently packaged web apps are mainstream because of the security concerns with new web API’s. Mozilla is mainly focusing on exposing new web APIs to mobile devices, Google is developing new web APIs for desktop. Apache Cordova is a good container to expose web APIs to different platforms.

    To make things harder, provided examples are often focused on teaching you how to pick up new web APIs rather than utilizing proper web app concepts with your development process.

    I’ve had the chance to join the development of an evolving web app project called Gaia, the Firefox OS user interface. The Gaia project contains the very first Mozilla installable web app implementation, including apps for music, photo gallery, e-mail, calendar and much more. According to GitHub’s pulse monthly, there are about 850 commits per month to the Gaia web apps. In the Gaia project, Mozilla developers and community members devoted lots of time and effort to bring it from the prototype stage to a shippable product within 2 years, and iteratively make it a competitive option for smartphone consumers. As a living large web app project, there are many lessons that can be learned from it, and applied to general web app development.

    Introducing webapplate

    Like other software projects, there are many things beside commiting code to develop a web app, such as:

    • How to organize the source code
    • How to handle library dependencies
    • How to keep the coding style in convention
    • How to optimize web app load performance
    • How to unit/integrate test your web app
    • How to localize your web app
    • How to automate those processes

    Those are topics that need to be resolved to develop a quality web app. In Gaia we have addressed these issues by utilizing a bunch of build scripts (Makefiles).

    You may wonder why we didn’t use Grunt or gulp for building? The answer: at the time Firefox OS was started, these tools didn’t exist. And the module owner wanted to make the core build process run in a Firefox extension one day.

    For general web app development, we didn’t have to follow those constraints. And we could do some experiments rapidly by reusing 3rd-party tools and libraries. From 2013, I’ve initiated a side project called webapplate, the open-sourced web app template that attempts to make Gaia’s solutions compatible with emerging toolkits like npm, Grunt and Bower. It also tries to transport good practices from Gaia to make new web apps more maintainable.

    How to setup webapplate

    Webapplate utilizes many powerful tools. With node.js, Grunt, Bower, Karma, Mocha and l20n, we come out with a maintainable full stack and self-contained web app template with JavaScript. So you could just copy or download the webapplate from Github, and develop and deploy to a hosting server or correspondent web app store.

    You need to install node.js in your desktop first. With Node.js installed, you’ll have the npm tool to manage Node.js modules. Now run this command:

    $ npm install -g grunt-cli bower karma

    to install the primary tools.

    Grunt is a JavaScript task runner tool (like Make) and grunt-cli is its command interface. Gruntfile.js file is similar to Makefile, but written in Javascript.

    Bower is a management tool for the front-end libraries. It helps developer manage different library versions. In webapplate, Bower will download client side libraries into the public/vendor folder when you run

    $ bower install

    command.

    Karma is the test runner that runs test code for each of the browsers. karma.conf.js defines the detail settings to specify how the test runner goes.

    Next, enter the webapplate folder and run:

    $ npm install

    npm will reference package.json to install all dependent node modules. The command will trigger Bower to install client-side library dependencies as well.

    Then you are all set! What you get is:

    • Pre-commit lint checking
    • Firefox and Chrome web app-compatible templates
    • Library dependency management
    • Client-side localization framework
    • Unit test and mock framework
    • Deployable web server

    If you use Firefox nightly, you could open the webapplate/public folder as a packaged app in the WebIDE developer tool.

    WebIDE allows you to edit, debug or execute your web app in the Simulator or on the device, with your favorite Firefox Developer Tools.

    With the Chrome Apps & Extensions developer tool, you can import the webapplate/public folder as a Chrome App and check the UI on desktop.

    webapplate on Chrome devtool

    Pre-commit lint checking

    The very first good practice that Gaia and webapplate provide is git pre-commit lint checking.

    Since in Gaia every commit needs to get reviewed and verified by the module owner before the code is checked in, we have followed the Google JavaScript style conventions. At that time we used gjslint to test it. It sounds good but actually forcing people to follow the exact same discipline manually is hard; asking the reviewer to pick through those style errors is another waste of time. So some genius introduced a git pre-commit hook to check several kinds of lint errors when the developer tries to commit their code, and provide a whitelist for the code that isn’t fully lint-free but should be allowed. Currently in Gaia we have pre-commit checks for JavaScript, CSS and JSON! This is a big relief.

    Currently webapplate utilizes code quality and style checking for JavaScript, JSON via JSHint, JSCS and JSONLint.

    It has exactly the same settings as Gaia for JSHint and also comes with the whitelist. Gaia is also planning to migrate to jscs to replace gjslint. If you use git for version control, run:

    $ grunt githooks

    to bind the git pre-commit code style check to your development process.

    Firefox OS- and Chrome App- compatible templates

    Webapplate uses HTML5 mobile boilerplate as the template base, and adds web app install helpers, icon links and usemin annotation for web app optimization on top. The main web app source is located in the public/ folder. You could check the webapplate wiki to see the full webapplate structure.

    Currently, Firefox web apps use manifest.webapp and Chrome Apps use manifest.json as the manifest file. The syntaxes are mutually compatible, except the localization part (we’ll address this issue later).

    After you edit one of these files, use:

    # firefox to chrome
    $ grunt f2c

    or

    # chrome to firefox
    $ grunt c2f

    to overwrite manifest.webapp with manifest.json, or viceversa.

    To generate a Firefox OS packaged app or Chrome App, run this command:

    $ grunt pack

    to package your web app to an uploadable zip file. With the default settings, webapplate-generated packaged web apps could be uploaded to the Firefox Marketplace and the Chrome App store.

    Library dependency management

    For Gaia we manage development tools via npm and generally don’t use many 3rd-party client side libraries. We host commonly-used libraries between apps in a shared/ folder, and then copy them in at build time via a build script.

    webapplate defines these libraries in package.json, uses npm to require build tools, and doesn’t assume any app framework (e.g. Backbone or Angular.js, or a UI framework such as Bootstrap.) Client-side libraries could be managed via Bower in bower.json.

    Client side localization framework

    Since web apps might be run without an Internet connection, we can’t count on the server to detect multiple languages. Currently Firefox OS uses navigator.mozL10n and Chrome Apps uses chrome.i18n for localization. Both of them are non-standard.

    In webapplate we take the l20n library to address the client-side localization issue. l20n is crafted by Mozilla and the developers are currently working on enhancing the Firefox OS localization framework as well.

    Check out index.html; the localization syntax looks exactly like what we used in Gaia:

    <h1 data-l10n-id="hello">Hello WebApplate</h1>

    The locale file however is in a different format, locales.en.l20n:

    <projectName "WebApplate">
    <hello "Hello {{ projectName }}">

    Also, check out the Multiple Language Support Framework section for how l20n is integrated with webapplate.

    Unit test and mock framework

    Gaia uses its own test-agent to trigger unit tests on Firefox. Gaia uses the Mocha test framework, Chai assertion library and the Sinon test helper library for unit tests.

    Webapplate uses the above unit test libraries plus the Karma test runner to run unit tests on all mainstream browsers.

    Deployable web server

    For developing Firefox OS hosted web apps, we need a working web server and maybe some dynamic web server support. Now that’s what we call the 21st century: it is possible to write server-side code in JavaScript as well.

    Running the command:

    $ grunt server

    will trigger the Express-powered server with django-like Swig template support. It’s been pre-configured for performance. Measure with YSlow and you’ll get a pretty good grade for your web site.

    Webapplate has been tested on some free dynamic web page hosting providers such as openshift, heroku and appfog. Check the deployment section to find out more details.

    If you like to host your web apps on a static web server, run:

    $ grunt static

    to generate optimized web pages for hosting.

    If you want to deploy your web app on a GitHub page (as a free static hosting server), run:

    $ grunt github

    Start your new web app project with webapplate!

    Webapplate is the web app template that borrows good practices for web app maintenance from the Gaia project. It provides ready-to-use Firefox OS and Chrome App support, an integrated toolbox to optimize your web app and maintain quality, and uses JavaScript through client/server side build/test frameworks. If you are about to make a web app or want to see how to maintain a web app, webapplate is a good start.

    References

  7. Building Interactive HTML5 Videos

    The HTML5 <video> element makes embedding videos into your site as easy as embedding images. And since all major browsers support <video> since 2011, it’s also the most reliable way to get your moving pictures seen by people.

    A more recent addition to the HTML5 family is the <track> element. It’s a sub-element of <video>, intended to make the video timeline more accessible. Its main use case is adding closed captions. These captions are loaded from a separate text file (a WebVTT file) and printed over the bottom of the video display. Ian Devlin has written an excellent article on the subject.

    Beyond captions though, the <track> element can be used for any kind of interaction with the video timeline. This article explores 3 examples: chapter markers, preview thumbnails, and a timeline search. By the end, you will have sufficient understanding of the <track> element and its scripting API to build your own interactive video experiences.

    Chapter Markers

    Let’s start with an example made popular by DVD disks: chapter markers. These allow viewers to quickly jump to a specific section. It’s especially useful for longer movies like Sintel:

    The chapter markers in this example reside in an external VTT file and are loaded on the page through a <track> element with a kind of **chapters. The track is set to load by default:

    <video width="480" height="204" poster="assets/sintel.jpg" controls>
      <source src="assets/sintel.mp4" type="video/mp4">
      <track src="assets/chapters.vtt" kind="chapters" default>
    </video>

    Next, we use JavaScript to load the cues of the text track, format them, and print them in a controlbar below the video. Note we have to wait until the external VTT file is loaded:

    track.addEventListener('load',function() {
        var c = video.textTracks[0].cues;
        for (var i=0; i<c.length; i++) {
          var s = document.createElement("span");
          s.innerHTML = c[i].text;
          s.setAttribute('data-start',c[i].startTime);
          s.addEventListener("click",seek);
          controlbar.appendChild(s);
        }
    });

    In above code block, we’re adding 2 properties to the list entries to hook up interactivity. First, we set a data attribute to store the start position of the chapter, and second we add a click handler for an external seek function. This function will jump the video to the start position. If the video is not (yet) playing, we’ll make that so:

    function seek() {
      video.currentTime = this.getAttribute('data-start');
      if(video.paused){ video.play(); }
    };

    That’s it! You now have a visual chapter menu for your video, powered by a VTT track. Note the actual live Chapter Markers example has a little bit more logic than described, e.g. to toggle playback of the video on click, to update the controlbar with the video position, and to add some CSS styling.

    Preview Thumbnails

    This second example shows a cool feature made popular by Hulu and Netflix: preview thumbnails. When mousing over the controlbar (or dragging on mobile), a small preview of the position you’re about to seek to is displayed:

    This example is also powered by an external VTT file, loaded in a metadata track. Instead of texts, the cues in this VTT file contain links to a separate JPG image. Each cue could link to a separate image, but in this case we opted to use a single JPG sprite – to keep latency low and management easy. The cues link to the correct section of the sprite by using Media Fragment URIs.Example:

    http://example.com/assets/thumbs.jpg?xywh=0,0,160,90

    Next, all important logic to get the right thumbnail and display it lives in a mousemove listener for the controlbar:

    controlbar.addEventListener('mousemove',function(e) {
      // first we convert from mouse to time position ..
      var p = (e.pageX - controlbar.offsetLeft) * video.duration / 480;
     
      // ..then we find the matching cue..
      var c = video.textTracks[0].cues;
      for (var i=0; i<c.length; i++) {
          if(c[i].startTime <= p && c[i].endTime > p) {
              break;
          };
      }
     
      // ..next we unravel the JPG url and fragment query..
      var url =c[i].text.split('#')[0];
      var xywh = c[i].text.substr(c[i].text.indexOf("=")+1).split(',');
     
      // ..and last we style the thumbnail overlay
      thumbnail.style.backgroundImage = 'url('+c[i].text.split('#')[0]+')';
      thumbnail.style.backgroundPosition = '-'+xywh[0]+'px -'+xywh[1]+'px';
      thumbnail.style.left = e.pageX - xywh[2]/2+'px';
      thumbnail.style.top = controlbar.offsetTop - xywh[3]+8+'px';
      thumbnail.style.width = xywh[2]+'px';
      thumbnail.style.height = xywh[3]+'px';
    });

    All done! Again, the actual live Preview Thumbnails example contains some additional code. It includes the same logic for toggling playback and seeking, as well as logic to show/hide the thumbnail when mousing in/out of the controlbar.

    Timeline Search

    Our last example offers yet another way to unlock your content, this time though in-video search:

    This example re-uses an existing captions VTT file, which is loaded into a captions track. Below the video and controlbar, we print a basic search form:

    <form>
        <input type="search" />
        <button type="submit">Search</button>
    </form>

    Like with the thumbnails example, all key logic resides in a single function. This time, it’s the event handler for submitting the form:

    form.addEventListener('submit',function(e) {
      // First we’ll prevent page reload and grab the cues/query..
      e.preventDefault();
      var c = video.textTracks[0].cues;
      var q = document.querySelector("input").value.toLowerCase();
     
      // ..then we find all matching cues..
      var a = [];
      for(var j=0; j<c.length; j++) {
        if(c[j].text.toLowerCase().indexOf(q) > -1) {
          a.push(c[j]);
        }
      }
     
      // ..and last we highlight matching cues on the controlbar.
      for (var i=0; i<a.length; i++) {
        var s = document.createElement("span");
        s.style.left = (a[i].startTime/video.duration*480-2)+"px";
        bar.appendChild(s);
      }
    });

    Three time’s a charm! Like with the other ones, the actual live Timeline Search example contains additional code for toggling playback and seeking, as well as a snippet to update the controlbar help text.

    Wrapping Up

    Above examples should provide you with enough knowledge to build your own interactive videos. For some more inspiration, see our experiments around clickable hot spots, interactive transcripts, or timeline interaction.

    Overall, the HTML5 <track> element provides an easy to use, cross-platform way to add interactivity to your videos. And while it definitely takes time to author VTT files and build similar experiences, you will see higher accessibility of and engagement with your videos. Good luck!

  8. Time to get hacking – Introducing Rec Room

    It’s no secret that the best frameworks and tools are extracted, not created out of thin air. Since launching Firefox OS, Mozilla has been approached by countless app developers and web developers with a simple question: “How do I make apps for Firefox OS?” The answer: “It’s the web; use existing web technologies.” was—and still is—a good answer.

    But if you don’t already have an existing toolchain as a web developer, I’ve been working on extracting something out of the way I’ve been creating web apps at Mozilla that you can use to write your next web app. From project creation to templating to deployment, Mozilla’s Rec Room will help you create awesome web apps in less time with more ease.

    Rec Room is a Node.js utility belt you can wear to build client side web apps. It includes:

    • Brick to add components like appbars and buttons to your UI.
    • Ember for your app’s controllers, models, and views.
    • Handlebars to write your app’s templates.
    • Grunt to run the tasks for your app, including building for production.
    • I18n.js to localize your app.
    • Mocha to test your app.
    • Stylus to write your CSS.
    • Yeoman to scaffold new code for your app’s models and templates.

    In this post I’ll walk through how to create a simple world clock web app with Rec Room, how to deploy it, and how you can try out Rec Room for yourself.

    Where Does Rec Room Come From?

    Much of Rec Room came from a recent rewrite of the HTML5 podcast app. I started working on this app well over a year ago, but its original version wasn’t as easy to work on; it had a lot of global state and a lot of by-hand data-binding. I liked the look of Ember for app development, but back when I started it didn’t quite feel mature enough. These days it’s much better, and I’ve tweaked it in Rec Room to work perfectly without a server.

    I tried to take the best from that system and extract it into a set of tools and documentation that anyone can use.

    Create your own Rec Room app

    Rec Room has just recently been extracted from my experiences with Podcasts; it hasn’t been tested by more than a handful of developers. That said: we’d love your help trying to build your own app for Firefox OS using these tools. They integrate well with tools you probably already know and use–like Node.js and Firefox’s own Web IDE.

    To get started, install Rec Room using Node.js:

    npm install -g recroom

    Clock App

    We’ll create a simple clock app with (minimal) time zone support for our example. The app will let you have a clock and compare it with a few time zones.

    The recroom binary is your entry point to all of the cool things Rec Room can do for you. First, create your app using recroom new world-clock. This creates the basic app structure. To see the basic app skeleton that Rec Room creates we can now enter that directory and run our app: cd world-clock and then type recroom run. The app will open in your default browser.

    First, we’ll add the current time to the main tab. Rec Room supports Ember’s MVC app structure, but also offers simple “pages” for a controller without a 1:1 relationship to a model. We’ll generate a new page that will show our actual clock:

    recroom generate page Clock

    We can edit its template by opening app/templates/clock.hbs. Let’s change clock.hbs to include the variable that will output our local time:

    <h2>Local Time: {{localTime}}</h2>

    That won’t do much yet, so let’s add that variable to our ClockController, in app/scripts/controllers/clock_controller.js:

    WorldClock.ClockController = Ember.ObjectController.extend({
        localTime: new Date().toLocaleTimeString()
    });

    You can see that any property inside the controller is accessible inside that controller’s template. We define the 1ocalTime property and it gets carried into our template context.

    Now our clock app will show the current local time when we navigate to http://localhost:9000/#clock. Of course, it just shows the time it was when the controller was initialized; there is no live updating of the time. We should update the time every second inside the controller:

    WorldClock.ClockController = Ember.ObjectController.extend({
        init: function() {
            // Update the time.
            this.updateTime();
     
        // Run other controller setup.
            this._super();
        },
     
        updateTime: function() {
            var _this = this;
     
            // Update the time every second.
            Ember.run.later(function() {
                _this.set('localTime', new Date().toLocaleTimeString());
                _this.updateTime();
            }, 1000);
        },
     
        localTime: new Date().toLocaleTimeString()
    });

    Now we can go to our clock URL and see our clock automatically updates every second. This is thanks to Ember’s data-binding between controllers and templates; if we change a value in a controller, model, or view that’s wired up to a template, the template will automatically change that data for us.

    Adding Timezones

    Next, we want to add a few timezones that the user can add to their own collection of timezones to compare against local time. This will help them schedule their meetings with friends in San Francisco, Buenos Aires, and London.

    We can create a timezone model (and accompanying controllers/routes/templates) with the same generate command, but this time we’ll generate a model:

    recroom generate model Timezone

    We want each timezone we’re to include in our app to have a name and an offset value, so we should add them as model attributes. We use Ember Data for this, inside app/scripts/models/timezone_model.js:

    WorldClock.Timezone = DS.Model.extend({
        name: DS.attr('string'),
        offset: DS.attr('number')
    });

    Next we’ll want a list of all timezones to offer the user. For this we’ll grab a copy of Moment Timezone. It’s an awesome JavaScript library for dealing with dates and times in JavaScript. We’ll install it with bower:

    bower install moment-timezone --save

    And then add it to our app inside app/index.html:

    <!-- build:js(app) scripts/components.js -->
    <!-- [Other script tags] -->
    <script src="bower_components/moment/moment.js"></script>
    <script src="bower_components/moment-timezone/builds/moment-timezone-with-data-2010-2020.js"></script>
    <!-- endbuild -->

    Adding that tag will automatically add moment-timezone-with-data-2010-2020.js to our built app. We’ll add a tab to the page that lets us edit our timezones, on a different screen than the clocks. To add a tab, we just need to open app/templates/application.hbs and add a tab. While we’re there, we’ll change the main tab from the useless {{#linkTo 'index'}} and point it to {{#linkTo 'clock'}}. The new application.hbs should look like this:

    <x-layout>
      <header>
        <x-appbar>
          <h1>{{t app.title}}</h1>
        </x-appbar>
      </header>
      <section>
        {{outlet}}
      </section>
      <footer>
        <x-tabbar>
          <x-tabbar-tab>
            {{#link-to 'clock'}}Clock{{/link-to}}
          </x-tabbar-tab>
          <x-tabbar-tab>
            {{#link-to 'timezones'}}Timezones{{/link-to}}
          </x-tabbar-tab>
        </x-tabbar>
      </footer>
    </x-layout>

    Side note: notice the root URL points to a useless welcome page? We probably want the default route to be our ClockController, so we can set the index route to redirect to it. Let’s do that now, in app/scripts/routes/application_route.js:

    WorldClock.ApplicationRoute = Ember.Route.extend({
        redirect: function() {
            this.transitionTo('clock');
        }
    });

    Interacting with Timezone models

    We’ll keep things simple for our example and allow users to select a timezone from a <select> tag and add it with a button. It will show up in their list of timezones, and they can delete it if they want from there. The clock tab will show all times. First, we’ll add our timezone data from Moment.js into our TimezonesController in app/scripts/controllers/timezones_controller.js. We’re also going to implement two actions: “add” and “remove”. These will be used in our template:

    WorldClock.TimezonesController = Ember.ObjectController.extend({
        init: function() {
            var timezones = [];
     
            for (var i in moment.tz._zones) {
              timezones.push({
                  name: moment.tz._zones[i].name,
                  offset: moment.tz._zones[i].offset[0]
              });
          }
     
          this.set('timezones', timezones);
     
          this._super();
      },
     
      selectedTimezone: null,
     
      actions: {
          add: function() {
              var timezone = this.store.createRecord('timezone', {
                  name: this.get('selectedTimezone').name,
                  offset: this.get('selectedTimezone').offset
              });
     
              timezone.save();
          },
     
          remove: function(timezone) {
              timezone.destroyRecord();
          }
      }
    });

    So we create a list of all available timezones with offsets. Then we add methods that allow us to add or remove timezones from our offline data store. Next we modify the timezones template in app/templates/timezones.hbs to use the actions and variables we created. All we need to utilize these variables is the Ember SelectView and the {{action}} helper to call our add and remove methods:

    <h2>Add Timezone</h2>
     
    <p>{{view Ember.Select content=timezones selection=selectedTimezone
           optionValuePath='content.offset' optionLabelPath='content.name'}}</p>
     
    <p><button {{action add}}>Add Timezone</button></p>
     
    <h2>My Timezones</h2>
     
    <ul>
      {{#each model}}
        <li>{{name}} <button {{action remove this}}>Delete</button></li>
      {{/each}}
    </ul>

    Now we have a Timezones tab that allows us to add and remove Timezones we want to track. This data persists between app refreshes. The last thing we need to do is show these times relative to our local time in our clock tab. To do this we need to load all the Timezone models in the ClockRoute. They’re automatically loaded in the TimezonesRoute, but it’s easy to add them in the ClockRoute (in app/scripts/routes/clock_route.js):

    WorldClock.ClockRoute = Ember.Route.extend({
        model: function() {
            return this.get('store').find('timezone');
        }
    });

    Because of the way our Ember app is wired up, we load all our models in the route and they are sent to the controller once the data store has asynchonously loaded all of the models. The request to find('timezone') actually returns a Promise object, but Ember’s router handles the Promise resolving for us automatically so we don’t have to manage callbacks or Promises ourselves.

    Now we have access to all the user’s Timezones in the ClockController, so we can make times in each timezone the user has requested and show them in a list. First we’ll add each Timezone’s current time to our ClockController in app/scripts/controllers/clock_controller.js using Moment.js:

    WorldClock.ClockController = Ember.ObjectController.extend({
        updateTime: function() {
            var _this = this;
     
            // Update the time every second.
            Ember.run.later(function() {
                _this.set('localTime', moment().format('h:mm:ss a'));
     
                _this.get('model').forEach(function(model) {
                    model.set('time',
                              moment().tz(model.get('name')).format('h:mm:ss a'));
                });
     
                _this.updateTime();
            }, 1000);
        }.on('init'),
     
        localTime: moment().format('h:mm:ss a')
    });

    Our final app/templates/clock.hbs should look like this:

    <h2>Local Time: {{localTime}}</h2>
     
    <p>
      {{#each model}}
        <h3>{{name}}: {{time}}</h3>
      {{/each}}
    </p>

    And that’s it! Now we have an offline app that shows us time zones in various places, saves the data offline, and updates every second without us having to do much work!

    Command Line Tools

    The old Podcasts app used a (rather awful) Makefile. It wasn’t very useful, and I don’t think it ran on Windows without some serious effort. The new build system uses Node so it runs comfortably on Windows, Mac, and Linux. Commands are proxied via the recroom binary, also written in Node, so you don’t have to worry about the underlying system if you don’t need to modify build steps. recroom new my-app creates a new app; recroom serve serves up your new app, and recroom generate model Podcast creates a new model for you.

    To build your app, you just need to run recroom build and a version with minified CSS, JS, and even HTML will be created for you in the dist/ folder. This version is ready to be packaged into a packaged app or uploaded to a server as a hosted app. You can even run recroom deploy to deploy directory to your git repository’s GitHub pages branch, if applicable.

    See the app in action!

    This entire sample app is available at worldclock.tofumatt.com and the source code is available on GitHub.

    Try Using Rec Room for Your Next Web App

    You can try out Rec Room on Github. Right now some docs and tools are still being abstracted and built, but you can start building apps today using it and filing bugs for missing features. We’d really love it if you could give it a try and let us know what’s missing. Together we can build a cohesive and polished solution to the all-too-common question: “How do I build a web app?”

  9. Building the Firefox browser for Firefox OS

    As soon as the Boot to Gecko (B2G) project was announced in July 2011 I knew it something I wanted to contribute to. I’d already been working on the idea of a browser based OS for a while but it seemed Mozilla had the people, the technology and the influence to build something truly disruptive.

    At the time Mozilla weren’t actively recruiting people to work on B2G, the team still only consisted of the four co-founders and the project was little more than an empty GitHub repository. But I got in touch the day after the announcement and after conversations with Chris, Andreas and Mike over Skype and a brief visit to Silicon Valley, I somehow managed to convince them to take me on (initially as a contractor) so I could work on the project full time.

    A Web Browser Built from Web Technologies

    On my first day Chris Jones told me “The next, highest-priority project is a very basic web browser, just a URL bar and back button basically.”

    Chris and his bitesize browser, Taipei, December 2011

    The team was creating a prototype smartphone user interface codenamed “Gaia”, built entirely with web technologies. Partly to prove it could be done, but partly to find the holes in the web platform that made it difficult and fill those holes with new Web APIs. I was asked to work on the first prototypes of a browser app, a camera app and a gallery app to help find some of those holes.

    You might wonder why a browser-based OS needs a browser app at all, but the thinking for this prototype was that if other smartphone platforms had a browser app, then B2G would need one too.

    The user interface of the desktop version of Firefox is written in highly privileged “chrome” code using the XUL markup language. On B2G it would need to be written in “content” using nothing but HTML, CSS and JavaScript, just like all the other apps. That would present some interesting challenges.

    In the beginning, there was an <iframe>

    It all started with a humble iframe, a text input for the URL bar and a go button, in fact you can see the first commit here. When you clicked the go button, it set the src attribute of the iframe to the contents of the text input, which caused the iframe to load the web page at that URL.

    First commit, November 2011

    The first problem with trying to build a web browser using an iframe is that the same-origin policy in JavaScript prevents you accessing just about any information about what’s going on inside it if the content comes from a different origin than the browser itself. In particular, it’s not possible to access the contentWindow property and all of the information that gives access to. This policy exists for good reasons so in order to build a fully functional web browser we would have to figure out a way for a privileged web app to safely poke holes in that cross-origin boundary to get just enough information to do its job, but without creating serious security vulnerabilities or compromising the user’s privacy.

    Another problem we came across quite quickly was that many web authors will go to great lengths to prevent their web site being loaded inside an iframe in order to prevent phishing attacks. A web server can send an X-Frame-Options HTTP response header instructing a user agent to simply not render the content, and there are also a variety of techniques for “framebusting” where a web site will actively try to break out of an iframe and load itself in the parent frame instead.

    It was quickly obvious that we weren’t going to get very far building a web browser using web technologies without evolving the web technologies themselves.

    The Browser API

    I met Justin Lebar at the first B2G work week in Taipei in December 2011. He was tasked with modifying Gecko to make the browser app on Boot to Gecko possible. To me Gecko was (and largely still is) a giant black box of magic spells which take the code I write and turn it into dancing images on the screen. I needed a wizard who had a grasp on some of these spells, including a particularly strong spell called Docshell which only the most practised of wizards dare peer into.

    Justin at the first B2G Work Week in Taipei, December 2011

    When I told Justin what I needed he made the kinds of sounds a mechanic makes when you take your car in for what you think is a simple problem but turns out costing the price of a new car. Justin had a better idea than I did as to what was needed, but I don’t think either of us realised the full scale of the task at hand.

    With the adding of a simple boolean “mozbrowser” attribute to the HTML iframe element in Gecko, the Browser API was born. I tried adding features to the browser app and every time I found something that wasn’t possible with current web technologies, I went back to Justin to get him to cast a new magic spell.

    There were easier approaches we could have taken to build the browser app. We could have added a mechanism to allow the browser to inject scripts into the iframe and communicate freely with the content inside, but we wanted to provide a safe API which anyone could use to build their own browser app and this approach would be too risky. So instead we built an explicit privileged API into the DOM to create a new class of iframe which could one day become a new standard HTML tag.

    Keeping the Web Contained

    The first thing we did was to try to trick web pages loaded inside an iframe into thinking they were not in fact inside an iframe. At first we had a crude solution which just ignored X-Frame-Options headers for iframes in whitelisted domains that had the mozbrowser attribute. That’s when we discovered that some web sites are quite clever at busting out of iframes. In the end we had to take other measures like making sure window.top pointed at the iframe rather than its parent so a web site couldn’t detect that it had a parent, and eventually also run every browser tab in its own system process to completely isolate them from each other.

    Once we had the animal that is the web contained, we needed to poke a few air holes to let it breathe. There’s some information we need to let out of the iframe in the form of events: when the location, title or icon of a web page changes (locationchange, titlechange and iconchange); when a page starts and finishes loading (loadstart, loadend) and when the security characteristics of the currently loaded page changes (securitychange). This all allows us to keep the address bar and title bar up to date and show a progress indicator.

    The browser app needs to be able to navigate the iframe by telling it to goBack(), goForward(), stop() and reload(). We also need to be able to explicitly ask for information like characteristics of the session history (getCanGoBack(), getCanGoForward()) to determine which navigation buttons to display.

    With these basics in place it was possible to build a simple functional browser app.

    The Prototype

    The Gaia project’s first UX designer was Josh Carpenter. At an intensive work week in Paris the week before Mobile World Congress in February 2012, Josh created UI mockups for all the basic features of a smartphone, including a simple browser, and we built a prototype to those designs.

    Josh and me plotting over a beer in Paris.

     

    The prototype browser app could navigate web content, keep it contained and display basic information about the content being viewed. This would be the version demonstrated at MWC in Barcelona that year.

    Simple browser demo for Mobile World Congress, February 2012

    Building a Team

    At a work week in Qualcomm’s offices in San Diego in May 2012 I was able to give a demo of a slightly more advanced basic browser web app running inside Firefox on the desktop. But it was still very basic. We needed a team to start building something good enough that we could ship it on real devices.

    “Browser Inception”, San Diego May 2012

    San Diego was also where I first met Dale Harvey, a brave Scotsman who came on board to help with Gaia. His first port of call was to help out with the browser app.

    Dale Getting on Board in San Diego, May 2012

    One of the first things Dale worked on was creating multiple tabs in the browser and even adding a screenshotting spell to the Browser API to show thumbnails of browser tabs (I told you he was brave).

    By this time we had also started to borrow Larissa Co, a brilliant designer from the Firefox team, to work on the interaction design and Patryk Adamczyk, formerly of RIM, to work on the visual design for the browser on B2G. That was when it started to look more like a Firefox browser.

    Early UI Mockup, July 2012

    Things that Pop Up

    Web pages like to make things pop up. For a start they like to alert(), prompt() or confirm() things with you. Sometimes they like to open() a new browser window (and close() them again), open a link in a _blank window, ask you for a password, ask for your permission to do something, ask you to select an option from a menu, open a context menu or confirm re-sending the contents of a form.

    An alert(), version 1.0

    All of this required new events in the Browser API, which meant more spells for Justin to cast.

    Scroll, Pan and Zoom

    Moving around web pages on web devices works a little differently from on the desktop. Rather than scroll bars or a scroll wheel on a mouse it uses touch input and a system called Asynchronous Pan and Zoom to allow the user to pan around a web page by dragging it and scrolling it using “kinetic scrolling” which feels like it has some physics to it.

    The first implementation of kinetic scrolling was written in JavaScript by Frenchman and Gaia leader Vivien Nicolas, specifically for Gaia, but it would later be written in a cross-platform way in Gecko to unify the code used on B2G and Android.

    One of the trickier interactions to get right was that we wanted the address bar to hide as you scrolled down the page in order to make more room for content, then show again when you scroll back to the top of the page.

    This required adding asyncscroll events which tapped directly into the Asynchronous Pan and Zoom code so that the browser knew not only when the user directly manipulated the page, but how much it scrolled based on physics, asynchronously from the user’s interaction.

    Storing Stuff

    One of the most loved features of Firefox is the “Awesomebar”, a combined address bar, search bar (and on mobile, title bar) which lets you quickly get to the content you’re looking for. You type a few characters and immediately start to see matching web pages from your browsing history, ranked by a “frecency” algorithm.

    On the desktop and on Android all of this data is stored in the “Places” database as part of privileged “chrome” code. In order to implement this feature in B2G we would need to use the local storage capabilities of the web, and for that we chose IndexedDB. We built a Places database in IndexedDB which would store all of the “places” a user visits on the web including their URL, title and icon, and store all the times the user visited that page. It would also be used to store the users bookmarks and rank top sites by “frecency”.

    Awesomebar, version 1.0

    Clearing Stuff

    As you browse around the web Gecko also stores a bunch of data about the places you’ve been. That can be cookies, offline pages, localStorage, IndexedDB databases and all sorts of other bits of data. Firefox browsers provide a way for you to clear all of this data, so methods needed to be added to the Browser API to allow this data to be cleared from the browser settings in B2G.

    Browser settings, version 1.0

    Handling Crashes

    Sometimes web pages crash the browser. In B2G every web app and every browser tab runs in its own system process so that should the worst happen, it will only cause that one window/tab to crash. In fact, due to the memory constraints of the low-end smartphones B2G would initially target, sometimes the system will intentionally kill a background app or browser tab in order to conserve memory. The browser app needs to be informed when this happens and needs to be able to recover seamlessly so that in most cases the user doesn’t even realise a process was killed. Events were added to the Browser API for this purpose.

    Crashed tab, version 1.0

    Talking to Other Apps

    Common use cases of a mobile browser are for the user to want to share a URL using another app like a social networking tool, or for another app to want to view a URL using the browser.

    B2G implemented Web Activities for this purpose, to add a capability to the web for apps to interact with each other, but in an app-agnostic way. So for example the user can click on a share button in the browser app and B2G will fire a “share URL” Web Activity which can then be handled by any installed app which has registered to handle that type of Web Activity.

    Share Web Activity, version 1.2

    Working Offline

    Despite the fact that B2G and Gaia are built on the web, it is a requirement that all of the built-in Gaia apps should be able to function offline, when an Internet connection is unavailable or patchy, so that the user can still make phone calls, take photos and listen to music etc.. At first we started to use AppCache for this purpose, which was the web’s first attempt at making web apps work offline. Unfortunately we soon ran into many of the common problems and limitations of that technology and found it didn’t fulfill all of our requirements.

    In order to ship version 1.0 of B2G on time, we were forced to implement “packaged apps” to fulfill all of the offline and security requirements for built-in Gaia apps. Packaged apps solved our problems but they are not truly web apps because they don’t have a real URL on the Internet, and attempts to standardise them didn’t get much traction. Packaged apps were intended very much as a temporary solution and we are working hard at adding new capabilities like ServiceWorkers, standardised hosted packages and manifests to the web so that eventually proprietary packaged apps won’t be necessary for a full offline experience.

    Offline, version 1.4

    Spit and Polish

    Finally we applied a good deal of spit and polish to the browser app UI to make it clean and fluid to use, making full use of hardware-accelerated CSS animations, and a sprinkling of Firefoxy interaction and visual design to make the youngest member of the Firefox browser family feel consistent with its brothers and sisters on other platforms.

    Shipping 1.0

    At an epic work week in Berlin in January 2013 hosted by Deutsche Telekom the whole B2G team, including engineers from multiple competing mobile networks and device manufacturers, got together with the common cause of shipping B2G 1.0, in time to demo at Mobile World Congress in Barcelona in February. The team sprinted towards this goal by fixing an incredible 200 bugs in one week.

    Version 1.0 Team, Berlin Work Week, January 2013

    In the last few minutes of the week Andreas Gal excitedly declared “Zarro Gaia Boogs”, signifying version 1.0 of Gaia was complete, with the rest of B2G to shortly follow over the weekend. Within around 18 months a dedicated team spanning multiple organisations had come together working entirely in the open to turn an empty GitHub repository into a fully functioning mobile operating system which would later ship on real devices as Firefox OS 1.0.1.

    Zarro Gaia Boogs, January 2013

    Browser app v1.0

    So having attended Mobile World Congress 2012 with a prototype and a promise to deliver commercial devices into the market, we were able to return in 2013 having delivered on that promise by fully launching the “Firefox OS” brand with multiple devices on multiple mobile networks with a launch that really stole the show at the biggest mobile conference in the world. Firefox OS had arrived.

    Mobile World Congress, Barcelona, February 2013

    1.x

    Firefox OS 1.1 quickly followed and by the time we started working on version 1.2 the project had grown significantly. We re-organised into autonomous agile teams focused on product areas, the browser app being one. That meant we now had a dedicated team with designers, engineers, a test engineer, a product manager and a project manager.

    The browser team, London work week, July 2013

    Firefox OS moved to a rapid release “train model” of development like Firefox, where a new version is delivered every 12 weeks. We quickly added new features and worked on improving performance to get the best out of the low end hardware we were shipping on in emerging markets.

    Browser app v1.4

    “Haida”

    Version 1.0 of Firefox OS was very much about proving that we could build what already exists on other smartphones, but entirely using open web technologies. That included a browser app.

    Once we’d proved that was possible and put real devices on shelves in the market it was time to figure out what would differentiate Firefox OS as a product going forward. We wanted to build something that doesn’t just imitate what’s already been done, but which plays to the unique strengths of the web to build something that’s true to Mozilla’s DNA, is the best way to experience the web, and is the platform that HTML5 deserves.

    Below is a mockup I created right back towards the start of the project at the end of 2011, before we even had a UX team. I mentioned earlier that the Awesomebar is a core part of the Firefox experience in Firefox browsers. My proposal back then was to build a system-wide Awesomebar which could search the whole device, including your apps and their contents, and be accessible from anywhere in the OS.

    Very early mockup of a system-wide Awesomebar, December 2011

    At the time, this was considered a little too radical for version 1.0 and our focus really needed to be on innovating in the web technology needed to build a mobile OS, not necessarily the UX. We would instead take a more conservative approach to the user interface design and build a browser app a lot like the one we’d built for Android.

    In practice that meant that we in fact built two browsers in Firefox OS. One was the browser app which managed the world of “web sites” and the other was the window manager in the system app which managed the world of “web apps” .

    In reality on the web there isn’t so much of a distinction between web apps and web sites – each exists on a long continuum of user experience with a very blurry boundary in the middle.

    In March 2013, with Firefox OS 1.0 out of the door, Josh Carpenter put me in touch with Gordon Brander, a member of the UX team who had been thinking along the same lines as me. In fact Gordon being as much of an engineer as he is a designer, had gone as far as to write a basic prototype in JavaScript.

    Gordon’s Rocketbar Prototype, March 2013

    Gordon and I started to meet weekly to discuss the concept he had by then codenamed “Rocketbar”, but it was a bit of a side project with a few interested people.

    In April 2013 the UX team had a summit in London where they got together to discuss future directions for the user experience of Firefox OS. I was lucky enough to be invited along to not only observe but participate in this process, Josh being keen to maintain a close collaboration between Design and Engineering.

    We brainstormed around what was unique about the experience of the web and how we might create a unique user experience which played to those strengths. A big focus was on “flow”, the way that we can meander through the web by following hyperlinks. The web isn’t a world of monolithic apps with clear boundaries between them, it is an experience of surfing from one web site to another, flowing through content.

    Brainstorming session, London, April 2013

    In the coming weeks the UX team would create some early designs for a concept (eventually codenamed “Haida”) which would blur the lines between web apps and web sites and create a unique user experience which flows like the web does. This would eventually include not only the “Rocketbar”, which would be accessible across the whole OS and seamlessly adapt to different types of web content, but also “sheets”, which would split single page web apps into multiple pages which you could swipe through with intuitive edge gestures. It would also eventually include a content model based around live apps which you can surf to, use, and then bookmark if you choose to, rather than monolithic apps which you have to install from a central app store before you can use them.

    In June 2013 a small group of designers and engineers met in Paris to develop a throwaway prototype of Haida, to rapidly iterate on some of the more radical concepts and put them through user testing.

    Haida Prototyping, Paris, June 2013

    Josh and Gordon working in a highly co-ordinated fashion, Paris, June 2013

    Wizards at work, Paris, June 2013

    2.x and the Future

    Fast forward to the present and the browser team has been merged into the “Systems Front End” team. The results of the Haida prototyping and user testing are slowly starting to make their way into the main Firefox OS product. It won’t happen all at once, but it will happen in small pieces as we iterate and learn.

    In version 2.0 of Firefox OS the homescreen search feature from 1.x will be replaced with a new search experience developed in conjunction with a new homescreen, implemented by Kevin Grandon, which will lay the foundations for “Rocketbar”. In version 2.1 our intention is to completely merge the browser app into the system app so that browser tabs become “sheets” alongside apps in the task manager and the “Rocketbar” is accessible from anywhere in the OS. The Rocketbar will adapt to different types of web content and shrink down into the status bar when not in use. Edge gestures will allow you to swipe between web apps and browser windows and eventually apps will be able to spawn multiple sheets.

    UI Mockups of Rocketbar in expanded and collapsed state, July 2014

    In parallel we see the evolution of web standards around manifests, packages and webviews and ongoing discussions around what defines the scope of an “app”.

    Rounding up

    Version 1.x of Firefox OS was built with web technologies but still has quite a similar user experience to other mobile platforms when it comes to installing and using apps, and browsing the web. Going forward I think you can expect to see the DNA of the web come through into the user interface with a unified experience which breaks down the barriers between web apps and web sites, allowing you to freely flow between the two.

    Firefox OS is an open source project developed completely in the open. If you’re interested in contributing to Gaia, take a look at the “Developing Gaia” page on MDN. If you’re interested in creating your own HTML5 app to run on Firefox OS take a look at the “App Center“.

  10. Building applications for Firefox OS using AngularJS

    When you start developing for Firefox OS you might be underwhelmed by the tools that are provided. There is no standard UI toolkit, or a JavaScript framework that all apps build on. This is not a situation that’s inherently bad because in essence Firefox OS is the web; and thus gives you complete freedom in the toolchain you use. This gives us the advantage to use any new technology that pops up also on Firefox OS. The downside is that you’ll miss out on things you might be used to on Android or iOS, like built-in templates; view transitions and UI components.

    In Telenor Digital we decided to build a ready-to-go application framework that deals with these shortcomings, built on top of AngularJS, the MVW framework by Google. The template is the result of iterating over our internal applications that we built for Firefox OS, and addresses the following things:

    1. Built on top of AngularJS, that has provides data binding; templating; routes; and code structure
    2. Built in set of UI components
      and transitions, in the style of Firefox OS
    3. Ability to publish apps as a mobile web page (hosted app),
      or as a packaged app for the Firefox OS marketplace
    4. Offline first approach. Every app built on top of the template works offline,
      also when hosted on your own web server.
    5. A build system to create release builds with one command,
      that does minification and template caching for optimal performance

    Let’s look at how the demo application looks like. It’s a standard CRUD app that shows a list-detail pattern: http://janjongboom.com/ffos-list-detail/. You can click on items to go to the detail view, you can edit items, or add new items. The ‘+’ button is an install button (only visible in Firefox) and allows you to add the app to your phone (Android / FxOS).

    Getting the code

    To start building, do this:

    • git clone git@github.com:comoyo/ffos-list-detail.git
    • npm install
    • ./node_modules/bower/bin/bower install
    • Now you can open www/index.html in any browser, or use the app manager and add the
      www folder as a packaged app.

    Structure

    The application lives in the www/ folder, and is made up of the following subfolders:

    • components/, third party libraries, loaded through bower
    • css/, style sheets. List all styles used by your app in
      css/main.css.
      They will be combined into one big stylesheet, for optimal performance.
    • img/, holds the icons for the app in three formats.
    • js/, our code
      • controllers/, the code that binds data to our UI
      • lib/, external libraries that are not in bower
      • services/, data providers, or code that is not bound to UI
      • app.js, starting point of the application, contains global configuration like routes
      • main.js, bootstrap file based on RequireJS.
        Lists all the JavaScript files we use. When you create a new JS file, add it here.
    • views/, view templates
    • index.html, bootstrap file where we load the application. You probably never will touch this.
    • manifest.appcache, AppCache file.
      You’ll need to list all the images & other resources (other than CSS/JS) that your app needs here,
      to enable offline for hosted applications.
    • manifest.webapp, Firefox OS App manifest file.

    You don’t need any build chain set up during development, you can just edit files in www, and refresh index.html at will. That’s the power of the web :-) Of course if you’re developing in the app manager, press UPDATE to refresh the app.

    Now let’s add some new functionality to this application, so we can see how developing new features works in practice.

    Adding a new button

    Let’s say that we want to add a credits screen that shows who built the application. First thing we need to do is add a button somewhere. In our case let’s put it on the home screen of the app. The code of the view is in www/views/list.html

    The components that you see come from the Firefox OS Building Blocks, which are the same blocks that are used to build Firefox OS itself. Let’s add a new button at the bottom of the screen (below the </ul> and the </section>:

    <a class="recommend" role="button" ng-tap="go('/credits', 'popup')">Credits</a>

    Important here is the ng-tap attribute. When we tap this item we go to /credits URL, with animation popup. There are four built in animations: forward, backward, popup and popdown; but you can create your own using simple CSS.

    Now when we look at this it doesn’t look like a button yet, because we didn’t tell that we needed the button building block. Go to css/main.css and add the following line to make it look nice:

    @import url("../components/building-blocks/style/buttons.css");

    All this is always documented on the page on the Building Blocks website.

    Hooking it up

    When we click on the button nothing happens though (well, we get redirected back to the list view), and that’s because we don’t listen on the /credits URL yet. To fix that we need to create a route handler (like in any MV* server side framework as well). Open the list of routes in js/app.js, and add a handler for the credits URL (before the otherwise handler):

    .when('/credits', {
      templateUrl: 'views/credits.html',
      controller: 'CreditsCtrl'
    })

    Here we tell which controller we want to consult (with JS code), and which view (with HTML) belongs to that. Let’s create the view first. Add a new file called credits.html in the views folder.

    <section role="region">
      <!-- Header building block http://buildingfirefoxos.com/building-blocks/headers.html -->
      <header>
        <!-- here we handle the back click and we do a popdown animation -->
        <a ng-tap="go('/', 'popdown')"><span class="icon icon-back">back</span></a>
        <h1>Credits</h1>
      </header>
    </section>
    <!-- The content of the view should have a 'view' class, and add the name of
         the view to easily style the view later -->
    <section class="view credits">
      This application is made by {{ name }}. <!-- AngularJS does data binding for us -->
    </section>

    To style this view we can add some content in css/app.css, f.e. add some padding and make the text bigger:

    .view.credits {
      padding: 1.5rem;
      font-size: 2rem;
    }

    Now write a simple controller to fill the content of {{ name }}, using standard AngularJS data binding. Add a new file called credits.js in www/js/controllers:

    /* We use RequireJS AMD style modules to get a reference to the app object */
    define(['app'], function(app) {
      /* Tell that we're defining a controller with name
        CreditsCtrl, and with dependencies on $scope, we specify this as string
        to not break when minifying
      */
      app.controller('CreditsCtrl', ['$scope',
        /* Implementation. AngularJS does dependency injection to fill the $scope var */
        function CreditsCtrl($scope) {
          /* Data binding to the view */
          $scope.name = 'Your name';
        }
      ]);
    });

    Last thing is to tell RequireJS that we have a new JS file that needs to be included in our builds, by editing js/main.js and adding a line above 'js/controllers/edit.js':

    'js/controllers/credits.js',

    When we now click the button in the app, everything works as expected. The view pops in, we have data, and we can dismiss by clicking the back button. What’s also great is that when you send the URL to someone else (f.e. http://your/url/index.html#/credits) they will go to the same view by default. That’s because we do proper state management through URLs by default.

    Talking to a third party data source

    The app currently only talks static data, so we want to hook it up to a real data source. In our case the project list should come from GitHub’s page with projects by mozilla-b2g. They have an API at: https://api.github.com/users/mozilla-b2g/repos.

    AngularJS has an idea of services, that abstract data away from your controller. For this app we have a database service that currently returns in-mem data. We can modify the service to talk to a web service instead. Clear out www/js/services/database.js and replace the content with:

    /*global define */
    "use strict";
    define(['app'], function(app) {
      /* Add a new factory called database, with a dependency on http */
      app.factory('database', ['http', function(http) {
        var getItems = function() {
          /* getItems makes a HTTP get call to github */
          return http.get('https://api.github.com/users/mozilla-b2g/repos', {
            // this is the cache configuration, we want to always cache requests
            // because it gives better UX. Plus when there is no internet, we can
            // get the data from cache and not break for the user...
            idbCache: {
              cacheKey: 'api.index',
              // expiration time in ms. from now (this is 5 minutes)
              // This is only obeyed if there is an internet connection!
              expiresInMs: 5 * 60 * 1000
            }
          }).then(function(res) {
            // Format it, sort it and map it to have the same format as our previous in mem dataset
            return res.data.sort(function(a, b) {
              return a.stargazers_count < b.stargazers_count;
            }).map(function(item) {
              return {
                title: item.name,
                description: item.description,
                id: item.name
              };
            });
          });
        };
     
        // Similar story but now for just one item
        var getItemById = function(id) {
          return http.get('https://api.github.com/repos/mozilla-b2g/device-flatfish', {
            idbCache: {
              cacheKey: 'api.detail.' + id,
              expiresInMs: 10 * 60 * 1000
            }
          }).then(function(res) {
            var repo = res.data;
            return {
              title: repo.name,
              description: repo.description,
              id: repo.name,
              date: new Date((repo.pushed_at || "").replace(/-/g,"/").replace(/[TZ]/g," "))
            };
          });
        };
     
        return {
          getItems: getItems,
          getItemById: getItemById
        };
      }]);
    });

    This API is now asynchronous though, but that doesn’t matter for Angular. If you data-bind to a promise, Angular will wait until the promise resolves until data binding happens.

    The beauty here is now that even when there is no Internet connection, the data will still load (as long as it was loaded at least once), and the data is auto-cached. No need for the controller to worry about that.

    Publishing the app

    These were two ways we quickly added some functionality to this application. First, adding a new button and a new view; and second, showing data binding and offline caching of server data. Please note that this application template can be used for much more than just list->detail applications, you’ve got the whole power of AngularJS at your hands!

    Now when we want to share this application with the rest of the world, we can go two ways:

    • Create a hosted application. This is an app that lives on your own server, like any mobile website. Hosted apps can still be published on the marketplace, and will work offline, but cannot use all the APIs in Firefox OS due to security limitations.
    • Create a packaged application. This is a ZIP file, similar to APK files on Android, that contain all the assets of your app, and are distributed through the marketplace.

    Both of these applications can be generated using our build script. The script will create a new folder dist/ that lists all the files the app needs. If you want to publish the app to your own server, just copy over the contents of the folder. If you want to publish the app as a packaged app, ZIP up the content and publish to the marketplace.

    To build, run:

    • Packaged: node build.js
    • Hosted: node build.js appcache

    Happy coding!