Mozilla

Articles

Sort by:

View:

  1. From Map/Reduce to JavaScript Functional Programming

    Since ECMAScript 5.1, Array.prototype.map & Array.prototype.reduce were introduced to major browsers. These two functions not only allow developers to describe a computation more clearly, but also to simplify the work of writing loops for traversing an array; especially when the looping code actually is for mapping the array to a new array, or for the accumulation, checksum, and other similar reducing operations.

    Left: using ordinary loop; Right: using map & reduce

    Left: using ordinary loop; Right: using map & reduce

     

    Map/Reduce

    Map actually means to compute things with the original array without doing structural changes to the output. For example, when map receives an array, you can make sure the output will be another array, and the only difference is that the elements inside it may be transformed from the original value/type to another value/type. So we can say the doMap function from the above example comes with the following type signature:

    doMap signature

    The signature reveals that [Number] means this is an array of numbers. So we now can read the signature as:

    doMap is a function, which would turn an array of numbers to an array of booleans

    On the other hand, the reducing operation means we may change the structure of the input data type to a new one. For example, the signature of the doReduce is:

    doReduce signature

    Here, the Array of [Number] is gone. So we can see the major difference between map and reduce1.

    Functional Programming

    In fact, the concepts of map and reduce are older even than JavaScript and are widely used in other functional programming languages, such as Lisp or Haskell2. This observation is noted in the famous article ‘JavaScript: The World’s Most Misunderstood Programming Language’ by Douglas Crockford 3:

    JavaScript’s C-like syntax, including curly braces and the clunky for statement, makes it appear to be an ordinary procedural language. This is misleading because JavaScript has more in common with functional languages like Lisp or Scheme than with C or Java.

    This is one reason why JavaScript can do some functional-like things which other orthogonal OOP languages can’t or won’t do. For example, before Java 8 4 5, if we wanted to do some ‘callback’ things common in JavaScript, we’d need to create a redundant ‘anonymous class.':

    Button button =
      (Button) findViewById(R.id.button);
    button.setOnClickListener(
      new OnClickListener() {
        public void onClick(View v) {
          // do something
        }
      }
    );

    Of course, using anonymous callbacks or not in JavaScript is always controversial. We may encounter callback hell especially when the component keeps growing. However, first-class functions can do lots of things beyond the callback. In Haskell, we can organize our whole GUI program similar to the Quake-like games6 with only functions7. That is, we can even make it without the classes, methods, inheritance, templates and other stuff8 people usually expect to have when a program needs to be constructed.

    Frag

    Frag, the Quake-like game in Haskell

    Therefore, in the JavaScript world, it’s possible to follow similar patterns to construct our programs, rather than hurriedly implementing our own ‘class’ and ‘class system,’ as programmers often do when starting on a problem9. Adding some functional flavor in JavaScript is not so bad after all, especially when features like map and reduce are supported by native APIs. To adopt this approach also means we can write more concise code10 by combining features instead of redefining them. The only limitation is the language itself is still not functional enough, so we may run into trouble if we play too many tricks, although this should be solvable with the right library11.

    map and reduce receive other functions as arguments and output them as results. This is important because in this way they present the basic idea of composing computations in the functional world, and are able to glue small pieces together with flexibility and scalability. For example, let’s take a look at the signature of our map expression mentioned above:

    map signature

    You’ll notice that the second argument indicates a function with type Number -> Boolean. In fact, you can give it any function with a -> b type. This may not be so odd in the world of JavaScript — we write tons of callbacks in our daily work. However, the point is that higher-order functions are functions as well. They can be composed into larger ones till we generate the complete program with only first-class functions and some powerful high-order functions like id, reduce, curry, uncurry, arrow and bind12.

    Map/Reduce in Practice

    Since we may encounter language limitations, we can’t write our JavaScript code in fully functional style; however, we can borrow the idea of types and composition to do lots of things. For example, when you think in types, you will find that map is not only for data handling:

    map & fold signatures

    This is what the type signatures for map and reduce would look like in Haskell. We can substitute the a and b with anything. So, what if a becomes SQL and b becomes IO x ? Remember, we’re thinking in type, and IO x is nothing more than an ordinary type like Int or URL:

    -- Let's construct queries from SQL statements.
    makeQueries strs = map str  prepare conn str
    doQuery qrys = foldl (results query  results >> query) (return ()) qrys 
    -- Do query and get results.
    let stmts = [ "INSERT INTO Articles ('Functional JavaScript')"
                , "INSERT INTO Gecko VALUES ('30.a1')"
                , "DELETE FROM Articles WHERE version='deprecated'"
                ]
    main = execute (doQuery (makeQuery stmts))`

    (Note: This is a simplified Haskell example for demo only. It can’t actually be executed.)

    The example creates a makeQueries function with map, which will turn the SQL into IO ()13; this also means we generate several actions which can be performed.

    makeQueries signature

    And then, the doQuery function, which is actually a reducing operation, will execute the queries:

    doQueries signature

    Note its reducing operation performs IO action with the help of the bind function (>>) of the specific Monad. This topic is not covered in this article, but readers should imagine this as a way to compose functions to execute them step by step, just as a Promise does24.

    The technique is useful not only in Haskell but also in JavaScript. We can use this idea with Promises and ES6 arrow functions to organize a similar computation:

      // Use a Promise-based library to do IO.
      var http = require("q-io/http")
         ,noop = new Promise(()=>{})
         ,prepare =
            (str)=> http.read('http://www.example.com/' + str)
                      .then((res)=> res.body.toString())
                      // the 'then' is equal to the '>>'
         ,makeQuery = 
            (strs)=> strs.map((str)=> prepare(str))
         ,doQuery = 
            (qrys)=> qrys.reduce((results, qry)=> results.then(qry), noop)
         ,stmts = [ "articles/FunctionalJavaScript"
                  , "blob/c745ef73-ece9-46da-8f66-ebes574789b1"
                  , "books/language/Haskell"
                  ]
         ,main = doQuery(makeQuery(stmts));

    (NOTE: In Node.js, the similar querying code with map/reduce and Promise would not run like the Haskell version, since we need Lazy Promise14 and Lazy Evaluation15)

    We’re very close to what we want: define computations with functions, and then combine them to perform it later, although the idea of ‘later’ is not actually true since we don’t have real lazy evaluation in JavaScript. This can be accomplished if we play the trick of keeping an undone Promise — a resolve function which is only resolved when we want to do so. However, even this is tricky, and there are still some unsolvable issues.

    Another thing to note is that our program doesn’t need variable variables, but some computation results are transformed and forwarded at every step of our program. In fact, this is just one reason why functional languages can stay pure, and thus they can benefit from the optimization and getting rid of unexpected side-effects 1617.

    More on Functional Programming

    Map/reduce are the most common functional features in JavaScript. With other not-so-functional features like Promise, we can use tricks like Monad-style computation control, or we can easily define curried functions with ES6’s fat-arrow functions18 and so on. Also, there are some excellent libraries which provide nice functional features19 20 21, and some Domain Specific Languages (DSLs) are even born with functional spirit 22 23. Of course, the best way to understand functional programming is to learn a language designed for it, like Haskell, ML or OCaml. Scala, F#, and Erlang are good choices, too.


    1. In fact, map can be implemented with reduce. The most basic operation for structure like this is reduce.
    https://github.com/timoxley/functional-javascript-workshop/blob/440da6737f34b4550301ba3a77b2e4b7721e99fd/problems/implement_map_with_reduce/solution.js#L11

    2. http://en.wikipedia.org/wiki/Lisp_(programming_language)#Control_structures

    3. http://javascript.crockford.com/javascript.html

    4. Java 8 now includes the lambda function: https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html

    5. C++ traditionally has not been a functional language, but C++11 introduces lambda functions: http://en.wikipedia.org/wiki/C%2B%2B11#Lambda_functions_and_expressions

    6. https://www.haskell.org/haskellwiki/Frag

    7. Haskell can represent data structure in function sense, even though declaring a function and a data type are still not the same thing: http://book.realworldhaskell.org/read/data-structures.html

    8. Yes, I’m cheating: we have Typeclass, Functor, instance and type variable in Haskell.

    9. For those who can’t live without classes, ES6 is in your future: http://wiki.ecmascript.org/doku.php?id=strawman:maximally_minimal_classes

    10. I’ve found that some ‘bad functional code’ can be refactored as concisely as possible by strictly following some functional patterns. The most problematic ‘functional’ code happens when the coder mixes two programming styles badly. This can mix problems from two paradigms in a way that makes the code more complicated.

    11. I always hit a wall when I want to have nice Monad and lazy Promise in JavaScript. However, if you don’t mind a ‘crazy’ implementation, these are doable, and we can even have ‘Monad Transformer’ in JavaScript. Other features, like tail-recursion optimization and real lazy-evaluation, are impossible to do without runtime support.

    12. The functions arrow and bind are actually >>> and >>= in Haskell. They’re the keys In Haskell to compose our computation and program with specific effects; hence we can have state machine, networking, event handling, IO statements, and asynchronous flow control. Importantly, these are still plain functions.

    13. The type IO () means ‘do IO without any value returned.’ The IO a means some IO actions may get value a when the function had been performed, although some actions only get (). For example, the function to get a string from user input would be: ask:: IO String, while the function to print string out is print:: String -> IO String.

    14. http://www.jroller.com/vaclav/entry/promises_getting_lazy

    15. http://www.haskell.org/haskellwiki/Lazy_evaluation

    16. JavaScript can do this with a library for structures like map, set, and list. Facebook created a library of immutable data structures called immutable-js for this: https://github.com/facebook/immutable-js

    17. You can do almost the same thing with immutable-js and convince everyone to use only let and const to define variables.

    18. http://wiki.ecmascript.org/doku.php?id=harmony:arrow_function_syntax

    19. wu.js: http://fitzgen.github.io/wu.js/

    20. Ramda: http://ramdajs.com/ramdocs/docs/

    21. transducer.js: http://jlongster.com/Transducers.js–A-JavaScript-Library-for-Transformation-of-Data

    22. LiveScript: http://livescript.net/

    23. Elm: http://elm-lang.org/

    24. No, they’re not really the same, but you *could* implement Promise in Monad

  2. Project Silk

    Editor’s Note: An earlier version of this post appeared on Mason Chang’s personal blog.

    For the past few months, I’ve been working on Project Silk which improves smoothness across the browser. Very much like Project Butter for Android, part of it is finally live on Firefox OS. Silk does three things:

    1. Align Painting with hardware vsync
    2. Resample touch input events based on hardware vsync
    3. Align composites with hardware vsync

    What is vsync, why vsync, and why does it matter at all?

    Vertical synchronization (vsync) occurs when the hardware display shows a new frame on the screen. This rate is set by specific hardware, but major displays in the US occur at a rate of 60 times a second, or every 16.6 ms (milliseconds). This is where you hear about 60 frames per second, one frame each time the hardware display refreshes. What this means in reality is that no matter how many frames are produced in software, the hardware display will still only show at most 60 unique frames per second.

    Currently in Firefox, we mimic 60 frames per second and therefore vsync with a software timer that schedules rendering every 16.6 ms. However, the software scheduler has two problems: (a) it’s noisy and (b) it can be scheduled at bad times relative to vsync.

    In regards to noise, software timers are much noisier than hardware timers. This creates micro-jank for a number of reasons. First, many animations are keyed off timestamps that are generated by the software scheduler to update the position of the animation. If you’ve ever used requestAnimationFrame, you get a timestamp from a software timer. If you want smooth animations, the timestamp provided to requestAnimationFrame should be uniform. Non-uniform timestamps will create non-uniform and janky animations. Here is a graph showing software versus hardware vsync timer uniformity:

    timer

    Wow! Big improvement with a hardware timer. We get a much more uniform, and therefore smoother, timestamp to key animations off of. So that addresses problem (a), noisy timers in software versus hardware.

    With part (b), software timers can be scheduled at bad times relative to vsync. Regardless of what the software does, the hardware display will refresh on its own clock. If our rendering pipeline finishes producing a frame before the next vsync, the display is updated with new content. If we fail to finish producing a frame before the next vsync, the previous frame will be displayed, causing jankiness. Some rendering functions can occur close to vsync and overflow until the next interval. Thus, we actually introduce more potential latency since the frame won’t be displayed on the screen anyway until the next vsync. Let’s look at this in graphic form:

    frames

    At time 0, we start producing frames. For example, let’s say all frames take a constant time of 10 ms. Our frame budget is 16.6 ms because we only have to finish producing a frame before the next hardware vsync occurs. Since frame 1 is finished 6 ms before the next vsync (time t=16 ms), everything is successful and life is good. The frame is produced in time and the hardware display will be refreshed with the updated content.

    Now let’s look at Frame 2. Since software timers are noisy, we start producing a frame 9 ms from the next vsync (time t=32). Since our frame takes 10 ms to produce, we actually finish producing this frame at 1 ms AFTER the next vsync. That means at vsync number 2 (t=32), there is no new frame to display, so the display still shows the previous frame. In addition, the frame just produced won’t be shown until vsync 3 (t=48), because that’s when the hardware updates itself. This creates jank since now the display will have skipped one frame and will try to catch up in the upcoming frames. This also produces one extra frame of latency, which is terrible for games.

    Vsync addresses both of these problems since we get a much more uniform timer and the maximum amount of frame budget time to produce a new frame. Now that we know what vsync is, we can finally go on to what Project Silk is and how it helps create smooth experiences in Firefox.

    The Rendering Pipeline

    In super simplified terms, Gecko’s rendering pipeline does three things:

    1. Paint / draw the new frame on the main thread.
    2. Send the updated content to the Compositor via a LayerTransaction.
    3. Composite the new content.

    In an ideal world, we’d be able to do all three steps within 16.6 ms, but that’s not the case most of the time. Both steps (1) and (3) occur on independent software timers. Thus, there is no real synchronizing clock between the three steps, they are all ad hoc. They also have no relation to vsync, so the timing of the pipeline isn’t related to when the display actually updates the screen with content. With Silk, we replace both independent software timers with the hardware vsync timer. For our purposes, (2) doesn’t really affect the outcome, but is presented here for completeness.

    Align Painting with Hardware Vsync

    Aligning the timer used to tick the refresh driver with vsync creates smoothness in a couple of ways. First, many animations are still done on the main thread, which means any animation using timestamps to set the position of an animation should be smoother. This includes requestAnimationFrame animations! The other nice thing is that we now have a very strict ordering of when rendering is kicked off. Instead of (1) and (3), which occur at separate synched offsets, we start rendering at a specific time.

    Resample Touch Input Events Based on Vsync

    With Silk, we can enable touch resampling, which improves smoothness while tracking your finger. Since I’ve already blogged about touch resampling quite a bit, I’ll keep this short. With Silk, we can finally enable it!

    Align Composites with Hardware Vsync

    Finally, the last part of Silk is about aligning composites with hardware vsync. Compositing takes all the painted content and merges it together to create the single image you see on the display. With Silk, all composites start right after a hardware vsync occurs. This has actually produced a rather nice side benefit — the reduced composite times seen here:

    compositeTimes

    Within the device driver on a Flame device, there’s a global lock that’s grabbed when close to vsync intervals. This lock can take 5-6 ms to get, greatly increasing the composite times. However, when we start a composite right after a vsync, there is little contention to grab the lock. Thus we can shave off the wait, therefore reducing composite times quite a bit. Not only do we get smoother animations, but also reduced composite times, and therefore better battery life. What a nice win!

    With all three pieces, we now have a nice strict ordering of the rendering pipeline. We paint and send the updated content to the Compositor within 16.6 ms. At the next vsync, we composite the updated content. At the vsync after that, the frame should have gone through the rendering pipeline and will be displayed on the screen. Keeping this order reduces jank because we reduce the chance that the timers will schedule each step at a bad time. In a best-case scenario in the current implementation without Silk, a frame could be painted and composited within a single 16.6 ms frame. This is great. However, if the next frame takes 2 frames instead, we’ve just created extra jank, even though no stage in the pipeline was really slow. Aligning the whole pipeline to create a strict sequence of events reduces the chance that we mis-schedule a frame.

    master

    Here’s a picture of the rendering pipeline without Silk. We have Composites (3) at the bottom of this profile. We have painting (1) in the middle, where you see Styles, Reflow, Displaylist, and Rasterize. We have Vsync, represented by those small orange boxes at the top. Finally we have Layer Transactions (2) at the bottom. At first, when we start, compositing and painting are not aligned, so animations are at different positions depending on whether they are on the main thread or the compositor thread. Second, we see long composites because the compositor is waiting on a global lock in the device driver. Lastly, it’s difficult to read any ordering or see if there is a problem without deep knowledge of why / when things should be happening.

    silk

    Here is a picture of the same pipeline with Silk. Composites are a little shorter, and the whole pipeline only starts at vsync intervals. Composite times are reduced because we start composites exactly at vsync intervals. There is a clear ordering of when things should happen. Both composites and painting are keyed off the same timestamp, ensuring smoother animations. Finally, there is a clear indicator that as long as everything finishes before the next Vsync, things will be smooth.

    Ultimately, Silk aims to create a smoother experience across Firefox and the Web. Numerous people contributed to the project. Thanks to Jerry Shih, Boris Chou, Jeff Hwang, Mike Lee, Kartikaya Gupta, Benoit Girard, Michael Wu, Ben Turner, and Milan Sreckovic for their help in making Silk happen.

  3. The P2P Web: Wi-Fi Direct in Firefox OS

    At Mozilla, we foresee that the future of the Web lies in its ability to connect people directly with multiple devices, without using the Internet. Many different technologies exist and are already implemented to allow peer-to-peer connections. Today is the first in a series of articles presenting these technologies. Let me introduce you to Wi-Fi Direct.

    What is it about?

    Wi-Fi Direct is a communication standard from the Wi-Fi Alliance that allows several devices to connect without using a local network. It has the advantage of using Wi-Fi, a fast and commonly available technology.

    This standard allows devices to discover peers and connect to them by enabling a portable Wi-Fi access point on your device that others can connect to. In Wi-Fi Direct parlance, the access point is called a group owner. The devices connected to a group owner are called clients, or peers.

    Wi-Fi Direct diagram

    Enable Wi-Fi Direct on a Flame

    In order to be usable the device driver must support Wi-Fi Direct, and that’s the case on the Flame. But before starting, the first thing to do is to enable support. Run the code in this gist with a rooted device connected to your computer.

    The Wi-Fi Direct API in Firefox OS is only available to certified apps at this time. Don’t forget to request the wifi-manage permission in your manifest.webapp file. This also means that you cannot distribute such an app in the Firefox Marketplace, but you can still use it and play with the technology.

    The JavaScript code in this article uses promises and some of the ES6 structures supported in the latest release of Firefox OS. Make sure you are familiar with these!

    Let’s see who’s around

    The Wi-Fi Direct API is accessible via the navigator.mozWifiP2pManager object.
    The first thing to do: enable Wi-Fi Direct to get a list of the peers that are around. The methods to enable and get the peers are respectively setScanEnabled(true) and getPeerList() and both return promises.

    navigator.mozWifiP2pManager.setScanEnabled(true)
      .then(result => {
        if (!result) {
          throw(new Error('wifiP2pManager activation failed.'));
        }
     
        // Wi-Fi Direct is enabled! Now, let's check who's around.
        return navigator.mozWifiP2pManager.getPeerList();
      })
      .then(peers => {
        console.log(`Number of peers around: ${peers.length}!`);
      });

    Pass true to navigator.mozWifiP2pManager.setScanEnabled() to start Wi-Fi Direct and the promises will return true if activation was successful. Use this to check whether your device supports Wi-Fi Direct or not.

    The promise returned by navigator.mozWifiP2pManager.getPeerList() will return an array of objects representing the peers located around you with Wi-Fi Direct enabled:

    {
      name: "Guillaume's Flame",
      connectionStatus: "disconnected",
      address: "02:0a:f5:f7:38:44", // MAC address of the device
      isGroupOwner: false
    }

    The peer name can be set using navigator.mozWifiP2pManager.setDeviceName(`Guillaume's Flame`). It is a string that allows a human to identify a device.
    As you can guess, the connectionStatus property tells us whether the device is connected or not. It has 4 possible values:

    • ‘disconnected’
    • ‘connecting’
    • ‘connected’
    • ‘disconnecting’

    You can listen to the peerinfoupdate event fired by navigator.mozWifiP2pManager to know when any peer status changes (new peer appears or disappears ; a peer connection status changes). You need then to call getPeerList() to get the update.

    Knock knock. Who’s there?

    Now that we know the devices located around you, let’s connect with them. We’re going to use navigator.mozWifiP2pManager.connect(address, wps, intent). The 3 parameters stand for:

    1. The MAC address of the device
    2. The WPS method (e.g. ‘pbc’)
    3. A value for intent from 0 to 15

    The MAC address is given in the peer object retrieved with getPeerList().
    The WPS method can be safely ignored for now but keep an eye on MDN for more on this.
    For initial connections, the value of intent will decide who will be the group owner of the Wi-Fi Direct network. The higher the value, the more likely it is that the device issuing the connection is the group owner.

    // Given `peer`, a peer object.
    navigator.mozWifiP2pManager.connect(peer.address, 'pbc', 1)
      .then(result => {
        if (!result) {
          throw(new Error(`Cannot request a connection with ${peer.name}.`));
        }
     
        // The connect request was successfully issued.
      });

    At this stage, you’re still not connected to the peer. The value returned will tell you whether the connection could be initiated or not.
    To know the status of your connection, you need to listen to an event.

    Breaking the ice

    The Wi-Fi Direct object emits different types of events. When another device gets connected the statuschange event is fired.

    The details of the connection are available in navigator.mozWifiP2pManager.groupOwner. Use the information provided by the following properties:

    • isLocal: whether the device is a group owner or not.
    • ipAddress: the IP address of the group owner.

    More properties are also exposed, but the ones above are enough to build a basic application.

    statuschange is also triggered when the other peer is disconnected using navigator.mozWifiP2pManager.disconnect(address).

    Say hello

    Wi-Fi Direct is merely a connection protocol, it’s now up to you to decide how to communicate. Once connected, you get the IP address of the group owner. This can be used with fxos-web-server, a web server running on your device to request information. The group owner will then act as a server.

    You can also use p2p-helper.js, a convenient helper library developed by Justin D’Arcangelo to abstract away the complexity of the Wi-Fi Direct API and build an app with ease.

    I recommend you have a look at the following example apps:

    • Firedrop, a sample app to share media files between devices.
    • Wi-Fi Columns, a game working across multiple devices. See the demo below.

    Now, it’s your turn to create mind-blowing apps where multiple devices can interact together without cellular data or Internet connection!

  4. Canvas 2D: New docs, Path2D objects, hit regions

    Over the last year, a couple of new HTML Canvas 2D features were implemented in Firefox and other recent browsers, with the help of the Adobe Web platform team. Over on MDN, the documentation for Canvas 2D got a major update to reflect the current canvas standard and browser implementation status. Let’s have a look what is new and how you can use it to enhance your canvas graphics and gaming content.

    Path2D objects

    The new Path2D API (available from Firefox 31+) lets you store paths, which simplifies your canvas drawing code and makes it run faster. The constructor provides three ways to create a Path2D object:

    new Path2D();     // empty path object
    new Path2D(path); // copy from another path
    new Path2D(d);    // path from from SVG path data

    The third version, which takes SVG path data to construct, is especially handy. You can now re-use your SVG paths to draw the same shapes directly on a canvas as well:

    var p = new Path2D("M10 10 h 80 v 80 h -80 Z");

    When constructing an empty path object, you can use the usual path methods, which might be familiar to you from using them directly on the CanvasRenderingContext2D context.

    // create a circle
    var circle = new Path2D();
    circle.arc(50, 50, 50, 0, 2 * Math.PI);
    // stroke the circle onto the context ctx
    ctx.stroke(circle);

    To actually draw the path onto the canvas, several APIs of the context have been updated to take an optional Path2D path:

    Hit regions

    Starting with Firefox 32, experimental support for hit regions has been added. You need to switch the canvas.hitregions.enabled preference to true in order to test them. Hit regions provide a much easier way to detect if the mouse is in a particular area without relying on manually checking coordinates, which can be really difficult to check for complex shapes. The Hit Region API is pretty simple:

    CanvasRenderingContext2D.addHitRegion()
    Adds a hit region to the canvas.
    CanvasRenderingContext2D.removeHitRegion()
    Removes the hit region with the specified id from the canvas.
    CanvasRenderingContext2D.clearHitRegions()
    Removes all hit regions from the canvas.

    The addHitRegion method, well, adds a hit region to a current path or a Path2D path. The MouseEvent interface got extended with a region property, which you can use to check whether the mouse hit the region or not.

    Check out the code example on MDN to see it in action (and be sure to enable flags/preferences in at least Firefox and Chrome).

    Focus rings

    Also in Firefox 32, the drawFocusIfNeeded(element) property has been made available without a preference switch. This API allows you to draw focus rings on a canvas, if a provided fallback element inside the <canvas></canvas> element gains focus. If the fallback element gets focused (for example when tabbing through the page that contains the canvas), the pixel representation / shape of that element on the canvas can draw a focus ring to indicate the current focus.

    CSS/SVG filters exposed to Canvas

    Although still behind a preference (canvas.filters.enabled), and not yet in the latest canvas specification (but expected to be added), Firefox 35 gained support for filters on the canvas rendering context. The syntax is the same as the CSS filter property.

    Misc

    Documentation

    If you would like to read more about Canvas 2D graphics, check out the Canvas tutorial on MDN, which guides you through the Canvas APIs. A good bookmark is also the large CanvasRenderingContext2D interface, which you will use often when working with Canvas.

  5. Web Animation tools, Network Security insights, Font Inspector improvements and more – Firefox Developer Tools Episode 37

    A handful of bug fixes, improvements and some new features, of course, just landed in Firefox 37. Update your Firefox Developer Edition, or Nightly builds to try them out!

    Animation Inspector Panel

    A new API that’s quickly gaining traction is the Web Animations API, allowing developers to construct more complex animations using web technologies, rather than proprietary plugins. The foundation for animation tooling has begun in Firefox’s Developer Tools, with the first release revealing play/pause controls and a timeline scrubber. When selecting an element in the Inspector, an animations panel is now available alongside the rules, fonts, and other panels, if the element contains animations. Check out other videos of the animation inspector in action, or try it yourself in this web animation demo.

    This is the first iteration of the web animation tools, and we are looking to hear from you on where we should go with this, and what we should build! Share detailed feedback with us on UserVoice, leave us a comment right here, or tweet to @FirefoxDevTools. (More detail on how to reach us in the closing paragraph below.)

    Security Panel

     
    The Network Monitor is the home of our other new tool, the security panel. Selecting a request in the network panel now displays a security panel in the request inspector. The panel reveals a list of information about the request’s connection, host, as well as the certificate used.

    The security panel can help debug issues related to SSL protocol versions, such as sites not working because of the POODLEBITE issue, and can help ensure that sufficiently strong security measures are implemented.

    DevTools Security Panel, new in Firefox 37

    Some other features and small improvements in this release:

    • Font inspector now shows all fonts (including fonts in iframes) when clicking “show all fonts” button. (Bug 1097150)
    • Addons can now register custom actors. (Bug 1107888)
    • The inspector sidebar now loads and refreshes lazily, leading to better performance of the inspector. (Bug 1103993)
    • Box Model Highlighter colors have been updated so they are easier to see on a wider range of backgrounds, as well as more accessible. (Bug 989053)
    • A new Firefox CLI option was added, –start-debugging-server, for starting the Firefox debugging server on a specific port. (Bug 1119894)
    • The tools tabbar height has decreased to allow more vertical space in the toolbox. (Bug 1109288)

    As we mentioned above, your feedback guides our priorities. Add your comments here, talk to us on Twitter @FirefoxDevTools, or propose changes on the Developer Tools feedback channel. If you’d like to help out with Dev Tools, check out the guide to getting involved.

  6. 2014: Mozilla Hacks looks back

    Wherever you live, it’s a season of work holidays, school vacations, year-end blog posts, and lists. The Hacks blog will be back in early January 2015 to continue writing for developers about the products and technologies created by Mozilla and by builders of the Open Web around the world.

    In the (chronological) list below, we celebrate some 2014 milestones and memorable moments for Mozilla, Firefox, and the web platform:

    • The new improved Firefox Sync launched early in 2014, built atop Firefox Accounts. Here’s a deeper look at the new Sync protocol.
    • Mozilla worked with the Apache Cordova team to integrate Firefox OS with Cordova’s open source device APIs, enabling mobile app developers to access native device functions from JavaScript, and release Cordova apps for the Firefox OS platform. Cordova is the underlying software in Adobe PhoneGap: the integration made it possible for PhoneGap developers to easily port their apps to the Firefox Marketplace.
    • Mozilla Research made great progress on Servo, a prototype browser engine. Servo is written in Rust, a systems programming language designed to support concurrency and parallelism for modern hardware. Another Big Milestone for Servo—Acid2 was reported in the spring.
    • Australis was the codename for our major redesign of the Firefox Desktop browser, which launched in late April. Designer Stephen Horlander wrote a post about the process, titled (Re)Designing Firefox.
    • The summer release of Firefox 31 brought new capabilities for game developers, including access to emscripten for compiling to JavaScript. In Resources for HTML5 game developers, we described some of the tools and techniques for coding and debugging sophisticated, performant HTML5 games. On the Mozilla blog, we featured the first commercial games to leverage asm.js, demonstrating the readiness of HTML5 as a game platform.
    • In October, we shared a Preview of Firefox Hello, a WebRTC-powered voice/video chat service.
    • As part of the festivities surrounding Firefox’s 10th birthday, Mozilla Research launched MozVR to help bring virtual reality to the Web. Grab your oculi and hold on to your hats.
    • At the same time, the Firefox Developer Tools team released Firefox Developer Edition, the first browser created specifically for developers. Though still in its early days, the Developer Edition features Valence, an integrated add-on to let you develop and debug your app across multiple browsers and devices, as well as WebIDE, providing an editing environment for app development and remote debugging.
    • The evolution of asm.js continued with the release of Massive, an open source benchmarking tool that measures asm.js performance specifically. You can run Massive here.
    • Mozilla and partners announced the formation of the Internet Security Research Group (ISRG) and launched the Let’s Encrypt initiative. Let’s Encrypt is a new Certificate Authority that’s free, automated, and open. It’s due to arrive in summer 2015.
    • Our friends at Telenor introduced Gonzo, an ongoing project which explores the use of Firefox OS as an embedded platform. Telenor engineer and Firefox OS evangelist Jan Jongboom is hacking together a wireless camera and sharing what he learns along the way.
    • Firefox OS Expands to Nearly 30 Countries – It’s been an expansive year. At last count, Firefox OS is now up and running on 16 smartphones offered in 29 countries. And in December news, Mozilla and KDDI announced the release of Japan’s first Firefox OS smartphone, which went on sale on December 25. The Fx0 is the first high-spec Firefox OS smartphone and it’s a beauty!

    If you’re interested in writing for the Hacks blog in 2015, we’d love to hear from you. Email us. In the meantime, have a safe and hacky holiday!

  7. You can’t go wrong watching JavaScript talks

    Late last week, I was collecting suggestions for year-end Hacks blog posts. As she headed out for the winter holidays, apps engineer Soledad Penadés gifted me “a bunch of cool talks I watched this year.”

    In fact, it’s a curated collection of presentations from JSConf, JSConf EU, and other recent developer conferences. Presenters include notable Mozillians and opinionated friends: hackers, JavaScripters, teachers, preachers, and hipsters. Many talks come with links to slides. They cover diverse topics: software development, developer culture and practices, developer tools, open source, JavaScript, CSS, new APIs.

    Part 1: Sole’s list

    Part 2: Making video better on Firefox

    Binge-watching JavaScript talks not your idea of a holiday break? If you’re watching video at all, Mozilla could use your help improving the video experience on Firefox.

    Here’s how you can contribute: Download Firefox Nightly, and help us test the implementation of Media Source Extensions (MSE) to support YouTube videos running in HTML5. Over recents weeks, Firefox engineers have been working hard addressing top bugs. To get this into the hands of users as quickly as possible, we need more help testing the experience. Here’s a detailed description of the testing task, thanks to Bugmaster Liz Henry from the QA team.

    File bugs using this link. Describe your platform, OS, and the steps needed to reproduce the problem.

    Thank you for helping to make the Firefox Desktop video experience awesome. See you in the new year.

  8. Pseudo elements, promise inspection, raw headers, and much more – Firefox Developer Edition 36

    Firefox 36 was just uplifted to the Developer Edition channel, so let’s take a look at the most important Developer Tools changes in this release. We will also cover some changes from Firefox 35 since it was released shortly before the initial Developer Edition announcement. There is a lot to talk about, so let’s get right to it.

    Inspector

    You can now inspect ::before and ::after pseudo elements.  They behave like other elements in the markup tree and inspector sidebars. (35, development notes)

    before-after-inspection

    There is a new “Show DOM Properties” context menu item in the markup tree. (35, development notes, documentation about this feature on MDN)

    show-dom-properties

    The box model highlighter now works on remote targets, so there is a full-featured highlighter even when working with pages on Firefox for Android or apps on Firefox OS. (36, development notes, and technical documentation for building your own custom highlighter)

    Shadow DOM content is now visible in the markup tree; note that you will need to set dom.webcomponents.enabled to true to test this feature (36, development notes, and see bug 1053898 for more work in this space).

    We borrowed a useful feature from Firebug and are now allowing more paste options when right clicking a node in the markup tree.  (36, development notes, documentation about this feature on MDN)

    paste-options

    Some more changes to the Inspector included in Firefox 35 & 36:

    • Deleting a node now selects the previous sibling instead of the parent (36, development notes)
    • There is higher contrast for the currently hovered node in the markup view (36, development notes)
    • Hover over a CSS selector in the computed view to highlight all the nodes that match that selector on the page. (35, development notes)

    Debugger / Console

    DOM Promises are now inspectable. You can inspect the promises state and value at any moment. (36, development notes)

    promise-inspection

    The debugger now recognizes and works with eval’ed sources. (36, development notes)

    Eval’ed sources support the //# sourceURL=path.js syntax, which will make them appear as a normal file in the debugger and in stack traces reported by Error.prototype.stack. See this post: http://fitzgeraldnick.com/weblog/59/ for much more information. (36, development notes,  more development notes)

    Console statements now include the column number they originated from. (36, development notes)

    WebIDE

    You are now able to connect to Firefox for Android from the WebIDE.  See documentation for debugging firefox for android on MDN.  (36, development notes).

    We also made some changes to improve the user experience in the WebIDE:

    • Bring up developer tools by default when I select a runtime app / tab (35, development notes)
    • Re-select project on connect if last project is runtime app (35, development notes)
    • Auto-select and connect to last used runtime if available (35, development notes)
    • Font resizing (36, development notes)
    • You can now adding a hosted app project by entering the base URL (eg: “http://example.com”) instead of requiring the full path to the manifest.webapp file (35, development notes)

    Network Monitor

    We added a plain request/response headers view to make it easier to view and copy the raw headers on a request. (35, development notes)

    net-headers-raw

    Here is a list of all the bugs resolved for Firefox 35 and all the bugs resolved for Firefox 36.

    Do you have feedback, bug reports, feature requests, or questions? As always, you can comment here, add/vote for ideas on UserVoice or get in touch with the team at @FirefoxDevTools on Twitter.

  9. Mozilla and Web Components: Update

    Editor’s note: Mozilla has a long history of participating in standards development. The post below shows a real-time slice of how standards are debated and adopted. The goal is to update developers who are most affected by implementation decisions we make in Firefox. We are particularly interested in getting feedback from JavaScript library and framework developers.

    Mozilla has been working on Web Components — a technology encompassing HTML imports, custom elements, and shadow DOM — for a while now and testing this approach in Gaia, the frontend of Firefox OS. Unfortunately, our feedback into the standards process has not always resulted in the changes required for us to ship Web Components. Therefore we decided to reevaluate our stance with members of the developer community.

    We came up with the following tentative plan for shipping Web Components in Firefox and we would really appreciate input from the developer community as we move this forward. Web Components changes a core aspect of the Web Platform and getting it right is important. We believe the way to do that is by having the change be driven by the hard learned lessons from JavaScript library developers.

    • Mozilla will not ship an implementation of HTML Imports. We expect that once JavaScript modules — a feature derived from JavaScript libraries written by the developer community — is shipped, the way we look at this problem will have changed. We have also learned from Gaia and others, that lack of HTML Imports is not a problem as the functionality can easily be provided for with a polyfill if desired.
    • Mozilla will ship an implementation of custom elements. Exposing the lifecycle is a very important aspect for the creation of components. We will work with the standards community to use Symbol-named properties for the callbacks to prevent name collisions. We will also ensure the strategy surrounding subclassing is sound with the latest work on that front in JavaScript and that the callbacks are sufficiently capable to describe the lifecycle of elements or can at least be changed in that direction.
    • Mozilla will ship an implementation of shadow DOM. We think work needs to be done to decouple style isolation from event retargeting to make event delegation possible in frameworks and we would like to ensure distribution is sufficiently extensible beyond Selectors. E.g Gaia would like to see this ability.

    Our next steps will be working with the standards community to make these changes happen, making sure there is sufficient test coverage in web-platform-tests, and making sure the specifications become detailed enough to implement from.

    So please let us know what you think here in the comments or directly on the public-webapps standards list!

  10. Introducing the JavaScript Internationalization API

    Firefox 29 issued half a year ago, so this post is long overdue. Nevertheless I wanted to pause for a second to discuss the Internationalization API first shipped on desktop in that release (and passing all tests!). Norbert Lindenberg wrote most of the implementation, and I reviewed it and now maintain it. (Work by Makoto Kato should bring this to Android soon; b2g may take longer due to some b2g-specific hurdles. Stay tuned.)

    What’s internationalization?

    Internationalization (i18n for short — i, eighteen characters, n) is the process of writing applications in a way that allows them to be easily adapted for audiences from varied places, using varied languages. It’s easy to get this wrong by inadvertently assuming one’s users come from one place and speak one language, especially if you don’t even know you’ve made an assumption.

    function formatDate(d)
    {
      // Everyone uses month/date/year...right?
      var month = d.getMonth() + 1;
      var date = d.getDate();
      var year = d.getFullYear();
      return month + "/" + date + "/" + year;
    }
     
    function formatMoney(amount)
    {
      // All money is dollars with two fractional digits...right?
      return "$" + amount.toFixed(2);
    }
     
    function sortNames(names)
    {
      function sortAlphabetically(a, b)
      {
        var left = a.toLowerCase(), right = b.toLowerCase();
        if (left > right)
          return 1;
        if (left === right)
          return 0;
        return -1;
      }
     
      // Names always sort alphabetically...right?
      names.sort(sortAlphabetically);
    }

    JavaScript’s historical i18n support is poor

    i18n-aware formatting in traditional JS uses the various toLocaleString() methods. The resulting strings contained whatever details the implementation chose to provide: no way to pick and choose (did you need a weekday in that formatted date? is the year irrelevant?). Even if the proper details were included, the format might be wrong e.g. decimal when percentage was desired. And you couldn’t choose a locale.

    As for sorting, JS provided almost no useful locale-sensitive text-comparison (collation) functions. localeCompare() existed but with a very awkward interface unsuited for use with sort. And it too didn’t permit choosing a locale or specific sort order.

    These limitations are bad enough that — this surprised me greatly when I learned it! — serious web applications that need i18n capabilities (most commonly, financial sites displaying currencies) will box up the data, send it to a server, have the server perform the operation, and send it back to the client. Server roundtrips just to format amounts of money. Yeesh.

    A new JS Internationalization API

    The new ECMAScript Internationalization API greatly improves JavaScript’s i18n capabilities. It provides all the flourishes one could want for formatting dates and numbers and sorting text. The locale is selectable, with fallback if the requested locale is unsupported. Formatting requests can specify the particular components to include. Custom formats for percentages, significant digits, and currencies are supported. Numerous collation options are exposed for use in sorting text. And if you care about performance, the up-front work to select a locale and process options can now be done once, instead of once every time a locale-dependent operation is performed.

    That said, the API is not a panacea. The API is “best effort” only. Precise outputs are almost always deliberately unspecified. An implementation could legally support only the oj locale, or it could ignore (almost all) provided formatting options. Most implementations will have high-quality support for many locales, but it’s not guaranteed (particularly on resource-constrained systems such as mobile).

    Under the hood, Firefox’s implementation depends upon the International Components for Unicode library (ICU), which in turn depends upon the Unicode Common Locale Data Repository (CLDR) locale data set. Our implementation is self-hosted: most of the implementation atop ICU is written in JavaScript itself. We hit a few bumps along the way (we haven’t self-hosted anything this large before), but nothing major.

    The Intl interface

    The i18n API lives on the global Intl object. Intl contains three constructors: Intl.Collator, Intl.DateTimeFormat, and Intl.NumberFormat. Each constructor creates an object exposing the relevant operation, efficiently caching locale and options for the operation. Creating such an object follows this pattern:

    var ctor = "Collator"; // or the others
    var instance = new Intl[ctor](locales, options);

    locales is a string specifying a single language tag or an arraylike object containing multiple language tags. Language tags are strings like en (English generally), de-AT (German as used in Austria), or zh-Hant-TW (Chinese as used in Taiwan, using the traditional Chinese script). Language tags can also include a “Unicode extension”, of the form -u-key1-value1-key2-value2..., where each key is an “extension key”. The various constructors interpret these specially.

    options is an object whose properties (or their absence, by evaluating to undefined) determine how the formatter or collator behaves. Its exact interpretation is determined by the individual constructor.

    Given locale information and options, the implementation will try to produce the closest behavior it can to the “ideal” behavior. Firefox supports 400+ locales for collation and 600+ locales for date/time and number formatting, so it’s very likely (but not guaranteed) the locales you might care about are supported.

    Intl generally provides no guarantee of particular behavior. If the requested locale is unsupported, Intl allows best-effort behavior. Even if the locale is supported, behavior is not rigidly specified. Never assume that a particular set of options corresponds to a particular format. The phrasing of the overall format (encompassing all requested components) might vary across browsers, or even across browser versions. Individual components’ formats are unspecified: a short-format weekday might be “S”, “Sa”, or “Sat”. The Intl API isn’t intended to expose exactly specified behavior.

    Date/time formatting

    Options

    The primary options properties for date/time formatting are as follows:

    weekday, era
    "narrow", "short", or "long". (era refers to typically longer-than-year divisions in a calendar system: BC/AD, the current Japanese emperor’s reign, or others.)
    month
    "2-digit", "numeric", "narrow", "short", or "long"
    year
    day
    hour, minute, second
    "2-digit" or "numeric"
    timeZoneName
    "short" or "long"
    timeZone
    Case-insensitive "UTC" will format with respect to UTC. Values like "CEST" and "America/New_York" don’t have to be supported, and they don’t currently work in Firefox.

    The values don’t map to particular formats: remember, the Intl API almost never specifies exact behavior. But the intent is that "narrow", "short", and "long" produce output of corresponding size — “S” or “Sa”, “Sat”, and “Saturday”, for example. (Output may be ambiguous: Saturday and Sunday both could produce “S”.) "2-digit" and "numeric" map to two-digit number strings or full-length numeric strings: “70” and “1970”, for example.

    The final used options are largely the requested options. However, if you don’t specifically request any weekday/year/month/day/hour/minute/second, then year/month/day will be added to your provided options.

    Beyond these basic options are a few special options:

    hour12
    Specifies whether hours will be in 12-hour or 24-hour format. The default is typically locale-dependent. (Details such as whether midnight is zero-based or twelve-based and whether leading zeroes are present are also locale-dependent.)

    There are also two special properties, localeMatcher (taking either "lookup" or "best fit") and formatMatcher (taking either "basic" or "best fit"), each defaulting to "best fit". These affect how the right locale and format are selected. The use cases for these are somewhat esoteric, so you should probably ignore them.

    Locale-centric options

    DateTimeFormat also allows formatting using customized calendaring and numbering systems. These details are effectively part of the locale, so they’re specified in the Unicode extension in the language tag.

    For example, Thai as spoken in Thailand has the language tag th-TH. Recall that a Unicode extension has the format -u-key1-value1-key2-value2.... The calendaring system key is ca, and the numbering system key is nu. The Thai numbering system has the value thai, and the Chinese calendaring system has the value chinese. Thus to format dates in this overall manner, we tack a Unicode extension containing both these key/value pairs onto the end of the language tag: th-TH-u-ca-chinese-nu-thai.

    For more information on the various calendaring and numbering systems, see the full DateTimeFormat documentation.

    Examples

    After creating a DateTimeFormat object, the next step is to use it to format dates via the handy format() function. Conveniently, this function is a bound function: you don’t have to call it on the DateTimeFormat directly. Then provide it a timestamp or Date object.

    Putting it all together, here are some examples of how to create DateTimeFormat options for particular uses, with current behavior in Firefox.

    var msPerDay = 24 * 60 * 60 * 1000;
     
    // July 17, 2014 00:00:00 UTC.
    var july172014 = new Date(msPerDay * (44 * 365 + 11 + 197));

    Let’s format a date for English as used in the United States. Let’s include two-digit month/day/year, plus two-digit hours/minutes, and a short time zone to clarify that time. (The result would obviously be different in another time zone.)

    var options =
      { year: "2-digit", month: "2-digit", day: "2-digit",
        hour: "2-digit", minute: "2-digit",
        timeZoneName: "short" };
    var americanDateTime =
      new Intl.DateTimeFormat("en-US", options).format;
     
    print(americanDateTime(july172014)); // 07/16/14, 5:00 PM PDT

    Or let’s do something similar for Portuguese — ideally as used in Brazil, but in a pinch Portugal works. Let’s go for a little longer format, with full year and spelled-out month, but make it UTC for portability.

    var options =
      { year: "numeric", month: "long", day: "numeric",
        hour: "2-digit", minute: "2-digit",
        timeZoneName: "short", timeZone: "UTC" };
    var portugueseTime =
      new Intl.DateTimeFormat(["pt-BR", "pt-PT"], options);
     
    // 17 de julho de 2014 00:00 GMT
    print(portugueseTime.format(july172014));

    How about a compact, UTC-formatted weekly Swiss train schedule? We’ll try the official languages from most to least popular to choose the one that’s most likely to be readable.

    var swissLocales = ["de-CH", "fr-CH", "it-CH", "rm-CH"];
    var options =
      { weekday: "short",
        hour: "numeric", minute: "numeric",
        timeZone: "UTC", timeZoneName: "short" };
    var swissTime =
      new Intl.DateTimeFormat(swissLocales, options).format;
     
    print(swissTime(july172014)); // Do. 00:00 GMT

    Or let’s try a date in descriptive text by a painting in a Japanese museum, using the Japanese calendar with year and era:

    var jpYearEra =
      new Intl.DateTimeFormat("ja-JP-u-ca-japanese",
                              { year: "numeric", era: "long" });
     
    print(jpYearEra.format(july172014)); // 平成26年

    And for something completely different, a longer date for use in Thai as used in Thailand — but using the Thai numbering system and Chinese calendar. (Quality implementations such as Firefox’s would treat plain th-TH as th-TH-u-ca-buddhist-nu-latn, imputing Thailand’s typical Buddhist calendar system and Latin 0-9 numerals.)

    var options =
      { year: "numeric", month: "long", day: "numeric" };
    var thaiDate =
      new Intl.DateTimeFormat("th-TH-u-nu-thai-ca-chinese", options);
     
    print(thaiDate.format(july172014)); // ๒๐ 6 ๓๑

    Calendar and numbering system bits aside, it’s relatively simple. Just pick your components and their lengths.

    Number formatting

    Options

    The primary options properties for number formatting are as follows:

    style
    "currency", "percent", or "decimal" (the default) to format a value of that kind.
    currency
    A three-letter currency code, e.g. USD or CHF. Required if style is "currency", otherwise meaningless.
    currencyDisplay
    "code", "symbol", or "name", defaulting to "symbol". "code" will use the three-letter currency code in the formatted string. "symbol" will use a currency symbol such as $ or £. "name" typically uses some sort of spelled-out version of the currency. (Firefox currently only supports "symbol", but this will be fixed soon.)
    minimumIntegerDigits
    An integer from 1 to 21 (inclusive), defaulting to 1. The resulting string is front-padded with zeroes until its integer component contains at least this many digits. (For example, if this value were 2, formatting 3 might produce “03”.)
    minimumFractionDigits, maximumFractionDigits
    Integers from 0 to 20 (inclusive). The resulting string will have at least minimumFractionDigits, and no more than maximumFractionDigits, fractional digits. The default minimum is currency-dependent (usually 2, rarely 0 or 3) if style is "currency", otherwise 0. The default maximum is 0 for percents, 3 for decimals, and currency-dependent for currencies.
    minimumSignificantDigits, maximumSignificantDigits
    Integers from 1 to 21 (inclusive). If present, these override the integer/fraction digit control above to determine the minimum/maximum significant figures in the formatted number string, as determined in concert with the number of decimal places required to accurately specify the number. (Note that in a multiple of 10 the significant digits may be ambiguous, as in “100” with its one, two, or three significant digits.)
    useGrouping
    Boolean (defaulting to true) determining whether the formatted string will contain grouping separators (e.g. “,” as English thousands separator).

    NumberFormat also recognizes the esoteric, mostly ignorable localeMatcher property.

    Locale-centric options

    Just as DateTimeFormat supported custom numbering systems in the Unicode extension using the nu key, so too does NumberFormat. For example, the language tag for Chinese as used in China is zh-CN. The value for the Han decimal numbering system is hanidec. To format numbers for these systems, we tack a Unicode extension onto the language tag: zh-CN-u-nu-hanidec.

    For complete information on specifying the various numbering systems, see the full NumberFormat documentation.

    Examples

    NumberFormat objects have a format function property just as DateTimeFormat objects do. And as there, the format function is a bound function that may be used in isolation from the NumberFormat.

    Here are some examples of how to create NumberFormat options for particular uses, with Firefox’s behavior. First let’s format some money for use in Chinese as used in China, specifically using Han decimal numbers (instead of much more common Latin numbers). Select the "currency" style, then use the code for Chinese renminbi (yuan), grouping by default, with the usual number of fractional digits.

    var hanDecimalRMBInChina =
      new Intl.NumberFormat("zh-CN-u-nu-hanidec",
                            { style: "currency", currency: "CNY" });
     
    print(hanDecimalRMBInChina.format(1314.25)); // ¥ 一,三一四.二五

    Or let’s format a United States-style gas price, with its peculiar thousandths-place 9, for use in English as used in the United States.

    var gasPrice =
      new Intl.NumberFormat("en-US",
                            { style: "currency", currency: "USD",
                              minimumFractionDigits: 3 });
     
    print(gasPrice.format(5.259)); // $5.259

    Or let’s try a percentage in Arabic, meant for use in Egypt. Make sure the percentage has at least two fractional digits. (Note that this and all the other RTL examples may appear with different ordering in RTL context, e.g. ٤٣٫٨٠٪ instead of ٤٣٫٨٠٪.)

    var arabicPercent =
      new Intl.NumberFormat("ar-EG",
                            { style: "percent",
                              minimumFractionDigits: 2 }).format;
     
    print(arabicPercent(0.438)); // ٤٣٫٨٠٪

    Or suppose we’re formatting for Persian as used in Afghanistan, and we want at least two integer digits and no more than two fractional digits.

    var persianDecimal =
      new Intl.NumberFormat("fa-AF",
                            { minimumIntegerDigits: 2,
                              maximumFractionDigits: 2 });
     
    print(persianDecimal.format(3.1416)); // ۰۳٫۱۴

    Finally, let’s format an amount of Bahraini dinars, for Arabic as used in Bahrain. Unusually compared to most currencies, Bahraini dinars divide into thousandths (fils), so our number will have three places. (Again note that apparent visual ordering should be taken with a grain of salt.)

    var bahrainiDinars =
      new Intl.NumberFormat("ar-BH",
                            { style: "currency", currency: "BHD" });
     
    print(bahrainiDinars.format(3.17)); // د.ب.‏ ٣٫١٧٠

    Collation

    Options

    The primary options properties for collation are as follows:

    usage
    "sort" or "search" (defaulting to "sort"), specifying the intended use of this Collator. (A search collator might want to consider more strings equivalent than a sort collator would.)
    sensitivity
    "base", "accent", "case", or "variant". This affects how sensitive the collator is to characters that have the same “base letter” but have different accents/diacritics and/or case. (Base letters are locale-dependent: “a” and “ä” have the same base letter in German but are different letters in Swedish.) "base" sensitivity considers only the base letter, ignoring modifications (so for German “a”, “A”, and “ä” are considered the same). "accent" considers the base letter and accents but ignores case (so for German “a” and “A” are the same, but “ä” differs from both). "case" considers the base letter and case but ignores accents (so for German “a” and “ä” are the same, but “A” differs from both). Finally, "variant" considers base letter, accents, and case (so for German “a”, “ä, “ä” and “A” all differ). If usage is "sort", the default is "variant"; otherwise it’s locale-dependent.
    numeric
    Boolean (defaulting to false) determining whether complete numbers embedded in strings are considered when sorting. For example, numeric sorting might produce "F-4 Phantom II", "F-14 Tomcat", "F-35 Lightning II"; non-numeric sorting might produce "F-14 Tomcat", "F-35 Lightning II", "F-4 Phantom II".
    caseFirst
    "upper", "lower", or "false" (the default). Determines how case is considered when sorting: "upper" places uppercase letters first ("B", "a", "c"), "lower" places lowercase first ("a", "c", "B"), and "false" ignores case entirely ("a", "B", "c"). (Note: Firefox currently ignores this property.)
    ignorePunctuation
    Boolean (defaulting to false) determining whether to ignore embedded punctuation when performing the comparison (for example, so that "biweekly" and "bi-weekly" compare equivalent).

    And there’s that localeMatcher property that you can probably ignore.

    Locale-centric options

    The main Collator option specified as part of the locale’s Unicode extension is co, selecting the kind of sorting to perform: phone book (phonebk), dictionary (dict), and many others.

    Additionally, the keys kn and kf may, optionally, duplicate the numeric and caseFirst properties of the options object. But they’re not guaranteed to be supported in the language tag, and options is much clearer than language tag components. So it’s best to only adjust these options through options.

    These key-value pairs are included in the Unicode extension the same way they’ve been included for DateTimeFormat and NumberFormat; refer to those sections for how to specify these in a language tag.

    Examples

    Collator objects have a compare function property. This function accepts two arguments x and y and returns a number less than zero if x compares less than y, 0 if x compares equal to y, or a number greater than zero if x compares greater than y. As with the format functions, compare is a bound function that may be extracted for standalone use.

    Let’s try sorting a few German surnames, for use in German as used in Germany. There are actually two different sort orders in German, phonebook and dictionary. Phonebook sort emphasizes sound, and it’s as if “ä”, “ö”, and so on were expanded to “ae”, “oe”, and so on prior to sorting.

    var names =
      ["Hochberg", "Hönigswald", "Holzman"];
     
    var germanPhonebook = new Intl.Collator("de-DE-u-co-phonebk");
     
    // as if sorting ["Hochberg", "Hoenigswald", "Holzman"]:
    //   Hochberg, Hönigswald, Holzman
    print(names.sort(germanPhonebook.compare).join(", "));

    Some German words conjugate with extra umlauts, so in dictionaries it’s sensible to order ignoring umlauts (except when ordering words differing only by umlauts: schon before schön).

    var germanDictionary = new Intl.Collator("de-DE-u-co-dict");
     
    // as if sorting ["Hochberg", "Honigswald", "Holzman"]:
    //   Hochberg, Holzman, Hönigswald
    print(names.sort(germanDictionary.compare).join(", "));

    Or let’s sort a list Firefox versions with various typos (different capitalizations, random accents and diacritical marks, extra hyphenation), in English as used in the United States. We want to sort respecting version number, so do a numeric sort so that numbers in the strings are compared, not considered character-by-character.

    var firefoxen =
      ["FireFøx 3.6",
       "Fire-fox 1.0",
       "Firefox 29",
       "FÍrefox 3.5",
       "Fírefox 18"];
     
    var usVersion =
      new Intl.Collator("en-US",
                        { sensitivity: "base",
                          numeric: true,
                          ignorePunctuation: true });
     
    // Fire-fox 1.0, FÍrefox 3.5, FireFøx 3.6, Fírefox 18, Firefox 29
    print(firefoxen.sort(usVersion.compare).join(", "));

    Last, let’s do some locale-aware string searching that ignores case and accents, again in English as used in the United States.

    // Comparisons work with both composed and decomposed forms.
    var decoratedBrowsers =
      [
       "A\u0362maya",  // A͢maya
       "CH\u035Brôme", // CH͛rôme
       "FirefÓx",
       "sAfàri",
       "o\u0323pERA",  // ọpERA
       "I\u0352E",     // I͒E
      ];
     
    var fuzzySearch =
      new Intl.Collator("en-US",
                        { usage: "search", sensitivity: "base" });
     
    function findBrowser(browser)
    {
      function cmp(other)
      {
        return fuzzySearch.compare(browser, other) === 0;
      }
      return cmp;
    }
     
    print(decoratedBrowsers.findIndex(findBrowser("Firêfox"))); // 2
    print(decoratedBrowsers.findIndex(findBrowser("Safåri")));  // 3
    print(decoratedBrowsers.findIndex(findBrowser("Ãmaya")));   // 0
    print(decoratedBrowsers.findIndex(findBrowser("Øpera")));   // 4
    print(decoratedBrowsers.findIndex(findBrowser("Chromè")));  // 1
    print(decoratedBrowsers.findIndex(findBrowser("IË")));      // 5

    Odds and ends

    It may be useful to determine whether support for some operation is provided for particular locales, or to determine whether a locale is supported. Intl provides supportedLocales() functions on each constructor, and resolvedOptions() functions on each prototype, to expose this information.

    var navajoLocales =
      Intl.Collator.supportedLocalesOf(["nv"], { usage: "sort" });
    print(navajoLocales.length > 0
          ? "Navajo collation supported"
          : "Navajo collation not supported");
     
    var germanFakeRegion =
      new Intl.DateTimeFormat("de-XX", { timeZone: "UTC" });
    var usedOptions = germanFakeRegion.resolvedOptions();
    print(usedOptions.locale);   // de
    print(usedOptions.timeZone); // UTC

    Legacy behavior

    The ES5 toLocaleString-style and localeCompare functions previously had no particular semantics, accepted no particular options, and were largely useless. So the i18n API reformulates them in terms of Intl operations. Each method now accepts additional trailing locales and options arguments, interpreted just as the Intl constructors would do. (Except that for toLocaleTimeString and toLocaleDateString, different default components are used if options aren’t provided.)

    For brief use where precise behavior doesn’t matter, the old methods are fine to use. But if you need more control or are formatting or comparing many times, it’s best to use the Intl primitives directly.

    Conclusion

    Internationalization is a fascinating topic whose complexity is bounded only by the varied nature of human communication. The Internationalization API addresses a small but quite useful portion of that complexity, making it easier to produce locale-sensitive web applications. Go use it!

    (And a special thanks to Norbert Lindenberg, Anas El Husseini, Simon Montagu, Gary Kwong, Shu-yu Guo, Ehsan Akhgari, the people of #mozilla.de, and anyone I may have forgotten [sorry!] who provided feedback on this article or assisted me in producing and critiquing the examples. The English and German examples were the limit of my knowledge, and I’d have been completely lost on the other examples without their assistance. Blame all remaining errors on me. Thanks again!)