Mozilla

35 Days Articles

Sort by:

View:

  1. saving data with localStorage

    This post was written by Jeff Balogh. Jeff works on Mozilla’s web development team.

    New in Firefox 3.5, localStorage is a part of the Web Storage specification. localStorage provides a simple Javascript API for persisting key-value pairs in the browser. It shouldn’t be confused with the SQL database storage proposal, which is a separate (and more contentious) part of the Web Storage spec. Key-value pairs could conceivably be stored in cookies, but you wouldn’t want to do that. Cookies are sent to the server with every request, presenting performance issues with large data sets and the potential for security problems, and you have to write your own interface for treating cookies like a database.

    Here’s a small demo that stores the content of a textarea in localStorage. You can change the text, open a new tab, and find your updated content. Or you can restart the browser and your text will still be there.


    The easiest way to use localStorage is to treat it like a regular object:

    >>> localStorage.foo = 'bar'
    >>> localStorage.foo
    "bar"
    >>> localStorage.length
    1
    >>> localStorage[0]
    "foo"
    >>> localStorage['foo']
    "bar"
    >>> delete localStorage['foo']
    >>> localStorage.length
    0
    >>> localStorage.not_set
    null

    There’s also a more wordy API for people who like that sort of thing:

    >>> localStorage.clear()
    >>> localStorage.setItem('foo', 'bar')
    >>> localStorage.getItem('foo')
    "bar"
    >>> localStorage.key(0)
    "foo"
    >>> localStorage.removeItem('foo')
    >>> localStorage.length
    0

    If you want to have a localStorage database mapped to the current session, you can use sessionStorage. It has the same interface as localStorage, but the lifetime of sessionStorage is limited to the current browser window. You can follow links around the site in the same window and sessionStorage will be maintained (going to different sites is fine too), but once that window is closed the database will be deleted. localStorage is for long-term storage, as the w3c spec instructs browsers to consider the data “potentially user-critical”.

    I was a tad disappointed when I found out that localStorage only supports storing strings, since I was hoping for something more structured. But with native JSON support it’s easy to create an object store on top of localStorage:

    Storage.prototype.setObject = function(key, value) {
        this.setItem(key, JSON.stringify(value));
    }
     
    Storage.prototype.getObject = function(key) {
        return JSON.parse(this.getItem(key));
    }

    localStorage databases are scoped to an HTML5 origin, basically the tuple (scheme, host, port). This means that the database is shared across all pages on the same domain, even concurrently by multiple browser tabs. However, a page connecting over http:// cannot see a database that was created during an https:// session.

    localStorage and sessionStorage are supported by Firefox 3.5, Safari 4.0, and IE8. You can find more compatibility details on quirksmode.org, including more detail on the storage event.

  2. using HTML5 video with fallbacks to other formats

    The Mozilla Support Project and support.mozilla.com (SUMO for short) is an open and volunteer powered community that helps over 3 million Firefox users a week get support and help with their favorite browser. The Firefox support community maintains a knowledge base with articles in over 30 languages and works directly with users through our support forums or live chat service. They’ve put together the following demonstration of how to use open video and Flash-based video at the same time to provide embedded videos to users regardless of their browser. This demo article was written by Laura Thomson, Cheng Wang and Eric Cooper

    Note: This article shows how to add video objects to a page using JavaScript. For most pages we suggest that you read the article that contains information on how to use the video tag to provide simple markup fallbacks. Markup-based fallbacks are much more elegant than JavaScript solutions and are generally recommended for use on the web.

    One of the challenges to open video adoption on the web is making sure that online video still performs well on browsers that don’t currently support open video.  Rather than asking users with these browsers to download the video file and use a separate viewer, the new <video> tag degrades gracefully to allow web developers to provide a good experience for everyone.  As Firefox 3.5 upgrades the web, users in this transitional period can be shown open video or video using an existing plugin in an entirely seamless way depending on what their browser supports.

    At SUMO, we use this system to provide screencasts of problem-solving steps such as in the article on how to make Firefox the default browser.

    If you visit the page using Firefox 3.5, or another browser with open video support, and click on the “Watch a video of these instructions” link, you get a screencast using an Ogg-formatted file.  If you visit with a browser that does not support <video> you get the exact same user experience using an open source .flv player and the same video encoded in the .flv format, or in some cases using the SWF Flash format.  These alternate viewing methods use the virtually ubiquitous Adobe Flash plugin which is one of the most common ways to show video on the web.

    The code works as follows.

    In the page which contains the screencasts, we include some JavaScript.   Excerpts from this code follow, but you can see or check out the complete listing from Mozilla SVN.

    The code begins by setting up an object to represent the player:

    Screencasts.Player = {
    width: 640,
    height: 480,
    thumbnails: [],
    priority: { 'ogg': 1, 'swf': 2, 'flv': 3 },
    handlers: { 'swf': 'Swf', 'flv': 'Flash', 'ogg': 'Ogg' },
    properNouns: { 'swf': 'Flash', 'flv': 'Flash', 'ogg': 'Ogg Theora' },
    canUseVideo: false,
    isThumb: false,
    thumbWidth: 160,
    thumbHeight: 120
    };

    We allocate a priority to each of the possible video formats.  You’ll notice we also have the 'canUseVideo' attribute, which defaults to false.

    Later on in the code, we test the user’s browser to see if it is video-capable:

    var detect = document.createElement('video');
    if (typeof detect.canPlayType === 'function' &&
        detect.canPlayType('video/ogg;codecs="theora,vorbis"') == 'probably' ) {
          Screencasts.Player.canUseVideo = true;
          Screencasts.Player.priority.ogg =
              Screencasts.Player.priority.flv + 2
    }

    If we can create a video element and it indicates that it can play the Ogg Theora format we set canUseVideo to true and increase the priority of the Ogg file to be greater than the priority of the .flv file. (Note that you could also detect if the browser could play .mp4 files to support Safari out of the box.)

    Finally, we use the priority to select which file is actually played, by iterating through the list of files to find the one that has the highest priority:

    for (var x=0; x < file.length; x++) {
      if (!best ) {
        best = file[x];
      } else {
        if (this.priority[best] < this.priority[file[x]])
          best = file[x];
      }
    }

    With these parts in place, the browser displays only the highest priority video and in a format that it can handle.

    If you want to learn more about the Mozilla Support Project or get involved in helping Firefox users, check out their guide to getting started.

    Resources

    * Note: To view this demo using Safari 4 on Mac OSX, you will need to add Ogg support to Quicktime using the Xiph Quicktime plugin available from http://www.xiph.org/quicktime/download.html

  3. content aware image resizing

    Note: The author of the demo, Stéphane Roucheray, is a member of the PIMS team. The demo was first posted on the Pims World Labs weblog.

    View the demo in Firefox 3.5.

    Content Aware Image Resizing is a way to re-target an image size without modifying its content ratio, in other words : non-linear image resizing. The algorithm was first explained by Shai Avidan and Ariel Shamir and published in 2007 (“Seam Carving for Content-Aware Image Resizing.”)

    Since then several excellent Open Source implementations have been released. For example, there is a plugin for The Gimp and CAIR a standalone application in C++.

    But thanks to Canvas and JavaScript it’s now possible to do this in the browser without a plugin.

    Since version 1.5, Firefox offers bitmap manipulation through the Canvas API. Version 3.5 introduced not only the fastest Firefox JavaScript engine ever, but also a new Canvas method – createImageData – providing a much more powerful environment.

    For this demo, a sub part of the Content Aware Image Resizing algorithm has been implemented. The width of the image can be reduced interactively without modifying its height. This implementation uses seam carving to re-size the image, subtracting the less visible vertical lines. It is a four step iterative algorithm. One iteration is one pixel width re-size. First an image is loaded into the Canvas context and then the iteration starts :

    1. A grayscale version of the image has to be calculated
    2. The edges of the image (Sobel convolution is used in our case) and its energy matrix is computed
    3. The seam of least energy (1 pixel vertical line from the bottom to the top of the energy matrix) is detected
    4. Then the pixel of the detected seam is removed from the original image and the result is re-injected as a source image to step 1

    Each of the previous steps stores a whole matrix of data at the source image size. While these matrices are not all images but actually artifacts of the algorithm, storing them in an ImageData object is more convenient than using simple Arrays. This is why the createImageData method of the Canvas context is used. One of the benefits of this process is to allow showing the intermediate computations made under the hood.

    This demo shows that’s possible to do more intelligent image resizing than just flattening an image’s pixels with CSS. Having computational and image manipulation capabilities directly in the browser opens up a new range of possibilities of how image data can be displayed to users. This is only one small demonstration of that.

  4. audio player – HTML5 style

    Last week we featured a demo from Alistair MacDonald (@F1LT3R) where he showed how to animate SVG with Canvas and a bunch of free tools. This week he has another demo for us that shows how you can use the new audio element in Firefox 3.5 with some canvas and JS to build a nice-looking audio player.

    But what’s really interesting about this demo is not so much that it plays audio – lots of people have built audio players – but how it works. If you look at the source code for the page what you’ll find looks something like this:

    <div id="jai">
      <canvas id="jai-transport" width="320" height="20"></canvas>
      <ul class="playlist">
        <li>
          <a href="@F1LT3R - Cryogenic Unrest.ogg">
            F1LT3R - Cryogenic Unrest
          </a>
          <audio src="@F1LT3R - Cryogenic Unrest.ogg"/>.
        <li>
          <a href="@F1LT3R - Ghosts in HyperSpace.ogg">
            F1LT3R - Ghosts in HyperSpace
          </a>
          <audio src="@F1LT3R - Ghosts in HyperSpace.ogg"/>.       
      </ul>    
    </div>
    (The actual list has fallbacks and is more compact – cleaned up here for easier reading.)

    That’s right – the player above is just a simple HTML unordered list that happens to include audio elements and is styled with CSS. You’ll notice that if you right click on one of them that it has all the usual items – save as, bookmark this link, copy this link location, etc. You can even poke at it with Firebug.

    The JavaScript driver that Al has written will look for a <div> element with the jai ID and then look for any audio elements that are inside it. It then will draw the playback interface in the canvas at the top of the list. The playback interface is built with simple JS canvas calls and an SVG-derived font.

    Using this driver it’s super-easy to add an audio player to any web site by just defining a canvas and a list. Much like what we’ve seen on a lot of the web with the rise of useful libraries like jQuery, this library can add additional value to easily-defined markup. Another win for HTML5 and the library model.

    Al has a much larger write-up on the same page as the demo. If you haven’t read through it you should now.

    (Also? Al wrote the music himself. So awesome.)

  5. geolocation with open street maps

    This demo was created by René-Luc D’Hont. He created this demo for the 35 days project with open source software and open data from various projects. His company, 3Liz, specializes in open source GIS application development.

    Three days ago we had a post from Doug Turner describing how Geolocation works in Firefox 3.5. René-Luc has taken the geolocation functionality in Firefox 3.5 and blended it together with data from OpenStreetMap and a few other sources of free data. You can try the demo below. Don’t forget to click the Share Location button in the drop down when it appears on the site.

    Assuming that it was able to find your location, you should see where you are with a red marker. A blue circle surrounds the red marker indicating the accuracy of your location information. Note that since this information is based on a combination of your IP address and possibly local WiFi access points, its accuracy can vary.

    This demo also tries to pull in information from other sources about your local area. Each set of information is shown as a layer. These layers are:

    • The base layer is the map itself, provided by OpenStreetMap. OpenStreetMap is a project to create and provide free geographic data, such as street maps, to anyone who wants them. Much like Wikipedia, it’s possible for anyone to edit the maps and add their own information.
    • The next layer is based on articles in Wikipedia. In some articles, like Mountain View or Montpellier, you can find coordinates. GeoNames provides a web service to query Wikipedia’s articles by location. With this demo you can discover Wikipedia articles about things and places around you.
    • The last layer is based on GeoNames. GeoNames is a geographical database covering all countries and contains over eight million placenames. In this demo you can see things from the GeoNames database like cities, villages, lakes, parks, or even hotels.

    The map and layers are built using OpenLayers, a free JavaScript library that you can use to put a dynamic map on any web page.

    Resources

    We’ve also included a couple more screenshots of places that have data already loaded.

    geolocation-2

    geolocation-3

  6. HTML5 drag and drop in Firefox 3.5

    This post is from Les Orchard, who works on Mozilla’s web development team.

    Introduction

    Drag and drop is one of the most fundamental interactions afforded by graphical user interfaces. In one gesture, it allows users to pair the selection of an object with the execution of an action, often including a second object in the operation. It’s a simple yet powerful UI concept used to support copying, list reordering, deletion (ala the Trash / Recycle Bin), and even the creation of link relationships.

    Since it’s so fundamental, offering drag and drop in web applications has been a no-brainer ever since browsers first offered mouse events in DHTML. But, although mousedown, mousemove, and mouseup made it possible, the implementation has been limited to the bounds of the browser window. Additionally, since these events refer only to the object being dragged, there’s a challenge to find the subject of the drop when the interaction is completed.

    Of course, that doesn’t prevent most modern JavaScript frameworks from abstracting away most of the problems and throwing in some flourishes while they’re at it. But, wouldn’t it be nice if browsers offered first-class support for drag and drop, and maybe even extended it beyond the window sandbox?

    As it turns out, this very wish is answered by the HTML 5 specification section on new drag-and-drop events, and Firefox 3.5 includes an implementation of those events.

    If you want to jump straight to the code, I’ve put together some simple demos of the new events.

    I’ve even scratched an itch of my own and built the beginnings of an outline editor, where every draggable element is also a drop target—of which there could be dozens to hundreds in a complex document, something that gave me some minor hair-tearing moments in the past while trying to make do with plain old mouse events.

    And, all the above can be downloaded or cloned from a GitHub repository I’ve created expecially for this article.

    The New Drag and Drop Events

    So, with no further ado, here are the new drag and drop events, in roughly the order you might expect to see them fired:

    dragstart
    A drag has been initiated, with the dragged element as the event target.
    drag
    The mouse has moved, with the dragged element as the event target.
    dragenter
    The dragged element has been moved into a drop listener, with the drop listener element as the event target.
    dragover
    The dragged element has been moved over a drop listener, with the drop listener element as the event target. Since the default behavior is to cancel drops, returning false or calling preventDefault() in the event handler indicates that a drop is allowed here.
    dragleave
    The dragged element has been moved out of a drop listener, with the drop listener element as the event target.
    drop
    The dragged element has been successfully dropped on a drop listener, with the drop listener element as the event target.
    dragend
    A drag has been ended, successfully or not, with the dragged element as the event target.

    Like the mouse events of yore, listeners can be attached to elements using addEventListener() directly or by way of your favorite JS library.

    Consider the following example using jQuery, also available as a live demo:

        <div id="newschool">
            <div class="dragme">Drag me!</div>
            <div class="drophere">Drop here!</div>
        </div>
     
        <script type="text/javascript">
            $(document).ready(function() {
                $('#newschool .dragme')
                    .attr('draggable', 'true')
                    .bind('dragstart', function(ev) {
                        var dt = ev.originalEvent.dataTransfer;
                        dt.setData("Text", "Dropped in zone!");
                        return true;
                    })
                    .bind('dragend', function(ev) {
                        return false;
                    });
                $('#newschool .drophere')
                    .bind('dragenter', function(ev) {
                        $(ev.target).addClass('dragover');
                        return false;
                    })
                    .bind('dragleave', function(ev) {
                        $(ev.target).removeClass('dragover');
                        return false;
                    })
                    .bind('dragover', function(ev) {
                        return false;
                    })
                    .bind('drop', function(ev) {
                        var dt = ev.originalEvent.dataTransfer;
                        alert(dt.getData('Text'));
                        return false;
                    });
            });
        </script>

    Thanks to the new events and jQuery, this example is both short and simple—but it packs in a lot of functionality, as the rest of this article will explain.

    Before moving on, there are at least three things about the above code that are worth mentioning:

    • Drop targets are enabled by virtue of having listeners for drop events. But, per the HTML 5 spec, draggable elements need an attribute of draggable="true", set either in markup or in JavaScript.

      Thus, $('#newschool .dragme').attr('draggable', 'true').

    • The original DOM event (as opposed to jQuery’s event wrapper) offers a property called dataTransfer. Beyond just manipulating elements, the new drag and drop events accomodate the transmission of user-definable data during the course of the interaction.
    • Since these are first-class events, you can apply the technique of Event Delegation.

      What’s that? Well, imagine you have a list of 1000 list items—as part of a deeply-nested outline document, for instance. Rather than needing to attach listeners or otherwise fiddle with all 1000 items, simply attach a listener to the parent node (eg. the <ul> element) and all events from the children will propagate up to the single parent listener. As a bonus, all new child elements added after page load will enjoy the same benefits.

      Check out this demo, and the associated JS code to see more about these events and Event Delegation.

    Using dataTransfer

    As mentioned in the last section, the new drag and drop events let you send data along with a dragged element. But, it’s even better than that: Your drop targets can receive data transferred by content objects dragged into the window from other browser windows, and even other applications.

    Since the example is a bit longer, check out the live demo and associated code to get an idea of what’s possible with dataTransfer.

    In a nutshell, the stars of this show are the setData() and getData() methods of the dataTransfer property exposed by the Event object.

    The setData() method is typically called in the dragstart listener, loading dataTransfer up with one or more strings of content with associated recommended content types.

    For illustration, here’s a quick snippet from the example code:

        var dt = ev.originalEvent.dataTransfer;    
        dt.setData('text/plain', $('#logo').parent().text());
        dt.setData('text/html', $('#logo').parent().html());
        dt.setData('text/uri-list', $('#logo')[0].src);

    On the other end, getData() allows you to query for content by type (eg. text/html followed by text/plain). This, in turn, allows you to decide on acceptable content types at the time of the drop event or even during dragover to offer feedback for unacceptable types during the drag.

    Here’s another example from the receiving end of the example code:

        var dt = ev.originalEvent.dataTransfer;    
        $('.content_url .content').text(dt.getData('text/uri-list'));
        $('.content_text .content').text(dt.getData('text/plain'));
        $('.content_html .content').html(dt.getData('text/html'));

    Where dataTransfer really shines, though, is that it allows your drop targets to receive content from sources outside your defined draggable elements and even from outside the browser altogether. Firefox accepts such drags, and attempts to populate dataTransfer with appropriate content types extracted from the external object.

    Thus, you could select some text in a word processor window and drop it into one of your elements, and at least expect to find it available as text/plain content.

    You can also select content in another browser window, and expect to see text/html appear in your events. Check out the outline editing demo and see what happens when you try dragging various elements (eg. images, tables, and lists) and highlighted content from other windows onto the items there.

    Using Drag Feedback Images

    An important aspect of the drag and drop interaction is a representation of the thing being dragged. By default in Firefox, this is a “ghost” image of the dragged element itself. But, the dataTransfer property of the original Event object exposes the method setDragImage() for use in customizing this representation.

    There’s a live demo of this feature, as well as associated JS code available. The gist, however, is sketched out in these code snippets:

        var dt = ev.originalEvent.dataTransfer;    
     
        dt.setDragImage( $('#feedback_image h2')[0], 0, 0);
     
        dt.setDragImage( $('#logo')[0], 32, 32); 
     
        var canvas = document.createElement("canvas");
        canvas.width = canvas.height = 50;
     
        var ctx = canvas.getContext("2d");
        ctx.lineWidth = 8;
        ctx.moveTo(25,0);
        ctx.lineTo(50, 50);
        ctx.lineTo(0, 50);
        ctx.lineTo(25, 0);
        ctx.stroke();
     
        dt.setDragImage(canvas, 25, 25);

    You can supply a DOM node as the first parameter to setDragImage(), which includes everything from text to images to <canvas> elements. The second two parameters indicate at what left and top offset the mouse should appear in the image while dragging.

    For example, since the #logo image is 64×64, the parameters in the second setDragImage() method places the mouse right in the center of the image. On the other hand, the first call positions the feedback image such that the mouse rests in the upper left corner.

    Using Drop Effects

    As mentioned at the start of this article, the drag and drop interaction has been used to support actions such as copying, moving, and linking. Accordingly, the HTML 5 specification accomodates these operations in the form of the effectAllowed and dropEffect properties exposed by the Event object.

    For a quick fix, check out the a live demo of this feature, as well as the associated JS code.

    The basic idea is that the dragstart event listener can set a value for effectAllowed like so:

        var dt = ev.originalEvent.dataTransfer;
        switch (ev.target.id) {
            case 'effectdrag0': dt.effectAllowed = 'copy'; break;
            case 'effectdrag1': dt.effectAllowed = 'move'; break;
            case 'effectdrag2': dt.effectAllowed = 'link'; break;
            case 'effectdrag3': dt.effectAllowed = 'all'; break;
            case 'effectdrag4': dt.effectAllowed = 'none'; break;
        }

    The choices available for this property include the following:

    none
    no operation is permitted
    copy
    copy only
    move
    move only
    link
    link only
    copyMove
    copy or move only
    copyLink
    copy or link only
    linkMove
    link or move only
    all
    copy, move, or link

    On the other end, the dragover event listener can set the value of the dropEffect property to indicate the expected effect invoked on a successful drop. If the value does not match up with effectAllowed, the drop will be considered cancelled on completion.

    In the a live demo, you should be able to see that only elements with matching effects can be dropped into the appropriate drop zones. This is accomplished with code like the follwoing:

        var dt = ev.originalEvent.dataTransfer;
        switch (ev.target.id) {
            case 'effectdrop0': dt.dropEffect = 'copy'; break;
            case 'effectdrop1': dt.dropEffect = 'move'; break;
            case 'effectdrop2': dt.dropEffect = 'link'; break;
            case 'effectdrop3': dt.dropEffect = 'all'; break;
            case 'effectdrop4': dt.dropEffect = 'none'; break;
        }

    Although the OS itself can provide some feedback, you can also use these properties to update your own visible feedback, both on the dragged element and on the drop zone itself.

    Conclusion

    The new first-class drag and drop events in HTML5 and Firefox make supporting this form of UI interaction simple, concise, and powerful in the browser. But beyond the new simplicity of these events, the ability to transfer content between applications opens brand new avenues for web-based applications and collaboration with desktop software in general.

  7. geolocation in Firefox 3.5

    This post is from Doug Turner, one of the engineers who is behind the Geolocation support in Firefox 3.5.

    Location is all around us. As of this writing, I am in a coffee shop in Toronto, Canada. If I type google into the url bar, it takes me to www.google.ca, the Canadian version of Google, based on my IP address. And when I want to find the closest movie theater to where I am located, I typically just type in my postal code. That information is often stored with the site so that it’s easier to find the movie theater next time. In these two situations, having the web application automatically figure out where I am is much more convenient. In fact, I have no idea what the postal code is for Toronto. I know how to find it, but that is a lot of work to simply tell a web application where I am.

    Firefox 3.5 includes a simple JavaScript API that allows you to quickly geo-enable your web application. It allows users to optionally share their location with websites without having to type in a postal code. What follows is a general overview of how to use geolocation in Firefox 3.5, how it works, and examines some of the precautions you should take when using geolocation.

    The Basics

    Getting the user’s location is very easy:

    function showPosition(position) {
        alert(position.coords.latitude + “ “ +
        position.coords.longitude);
    }
     
    navigator.geolocation.getCurrentPosition(showPosition);

    The call to getCurrentPosition gets the users current location and puts it into an alert dialog. Location is expressed in terms of longitude and latitude. Yes, it’s that simple.

    When you ask for that information the user will see a notification bar like this:

    Their options are to allow or not, and to remember or not.

    Handling Errors

    It is important to handle two error cases in your code:

    First, the user can deny or not respond to the request for location information. The API allows you to set an optional error callback. If the user explicitly cancels the request your error callback will be called with an error code. In the case where the user doesn’t respond, no callback will be fired. To handle that case you should include a timeout parameter to the getCurrentPosition call and you will get an error callback when the timer expires.

    navigator.geolocation.getCurrentPosition(successCallback,
                                             errorCallback,
                                             {timeout:30000});

    With this code your errorCallback function will be called if the user cancels. It will also be called if 30 seconds pass and the user hasn’t responded.

    Second, the accuracy of the user’s location can vary quite a bit over time. This might happen for a few reasons:

    • Different methods for determining a person’s location have different levels of accuracy.
    • The user might choose not to share his or her exact location with you.
    • Many GPS devices have limited accuracy depending on the view of the sky. Over time if your view of the sky gets worse, so can the accuracy.
    • Many GPS devices can take several minutes to go from a very rough location to a very specific location, even with a good view of the sky.

    These cases can and will happen, and supporting changes in accuracy is important to provide a good user experience.

    If you want to monitor the location as it changes, you can use the watchPosition callback API:

    navigator.geolocation.watchPosition(showPosition);

    showPosition will be called every time there is a position change.

    Note that you can also watch for changes in position by calling getCurrentPosition on a regular basis. But for power savings and performance reasons we suggest that you use watchPosition when you can. Callback APIs generally save power and are only called when required. This will make the browser more responsive, especially on mobile devices.

    For more information, please take a look at the API draft specification which has other examples which may be useful.

    Under the Hood

    There are a few common ways to get location information. The most common are local WiFi networks, IP address information, and attached GPS devices. In Firefox 3.5 we use local WiFi networks and IP address information to try and guess your location.

    There are a few companies that drive cars around listening for WiFi access points spots and recording the access point’s signal strength at a specific point on the planet. They then throw all of this collected data into a big database. Then they have algorithms that allow you to ask the question “If I see these access points, where am I?”. This is Firefox 3.5′s primary way of figuring out your location.

    But not everyone has a WiFi card. And not every place has been scanned for WiFi. In that case Firefox will use your local IP address to try to figure out your location using a reverse database lookup that roughly maps your IP address to a location. IP derived locations often have much lower accuracy than a WiFi derived location. As an example, here in Toronto, a location from WiFi is accurate to within 150 meters. The same location using just an IP address is about 25 km.

    Privacy

    Protecting a user’s privacy is very important to Mozilla – it’s part of our core mission. Within the realm of data that people collect online, location can be particularly sensitive. In fact, the EU considers location information personally identifiable information (PII) and must be handled accordingly (Directive 95/46/EC). We believe that users should have strict control over when their data is shared with web sites. This is why Firefox asks before sharing location information with a web site, allows users to easily “forget” all of the places that the user has shared their location with, and surfaces sharing settings in Page Info.

    Firefox does what it can to protect our users’ privacy but in addition the W3C Geolocation working group has proposed these privacy considerations for web site developers and operators:

    • Recipients must only request location information when necessary.
    • Recipients must only use the location information for the task for which it was provided to them.
    • Recipients must dispose of location information once that task is completed, unless expressly permitted to retain it by the user.
    • Recipients must also take measures to protect this information against unauthorized access.
    • If location information is stored, users should be allowed to update and delete this information.
    • The recipient of location information must not retransmit the location information without the user’s consent. Care should be taken when retransmitting and use of HTTPS is encouraged.
    • Recipients must clearly and conspicuously disclose the fact that they are collecting location data, the purpose for the collection, how long the data is retained, how the data is secured, how the data is shared if it is shared, how users may access, update and delete the data, and any other choices that users have with respect to the data. This disclosure must include an explanation of any exceptions to the guidelines listed above.

    Obviously these are voluntary suggestions, but we hope that it forms a basis for good web site behavior that users will help enforce.

    Caveats

    We have implemented the first public draft of the Geolocation specification from the W3C . Some minor things may change, but we will encourage the working group to maintain backwards compatibly.

    The only issue that we know about that may effect you is the possible renaming of enableHighAccuracy to another name such as useLowPower. Firefox 3.5 includes the enableHighAccuracy call for compatibility reasons, although it doesn’t do anything at the moment. If the call is renamed, we are very likely to include both versions for compatibility reasons.

    Conclusion

    Firefox 3.5 represents the first step in support for Geolocation and a large number of other standards that are starting to make their way out of the various working groups. We know that people will love this feature for mapping applications, photo sites and sites like twitter and facebook. What is most interesting to us is knowing that people will find new uses for this that we haven’t even thought of. The web is changing and location information plays a huge role in that. And we’re happy to be a part of it.

  8. stylish text with text-shadow

    This post is from Frederic Wenzel, who works on Mozilla’s Web Development team.

    The text-shadow CSS property does what the name implies: It lets you create a slightly blurred, slightly moved copy of text, which ends up looking somewhat like a real-world shadow.

    The text-shadow property was first introduced in CSS2, but as it was improperly defined at the time, its support was dropped again in CSS2.1. The feature was re-introduced with CSS3 and has now made it into Firefox 3.5.

    How it Works

    According to the CSS3 specification, the text-shadow property can have the following values:

    none | [<shadow>, ] * <shadow>,

    <shadow> is defined as:

    [ <color>? <length> <length> <length>? | <length> <length> <length>? <color>? ],

    where the first two lengths represent the horizontal and vertical offset and the third an optional blur radius. The best way to describe it is with examples.

    We can make a simple shadow like this, for example:

    text-shadow: 2px 2px 3px #000;
    A simple shadow

    (All of the examples are a live example first, then a picture of the working feature — so you can compare your browser’s behavior with the one of Firefox 3.5 on OSX)

    If you are a fan of hard edges, you can just refrain from using a blur radius altogether:

    text-shadow: 2px 2px 0 #888;
    I don’t like blurs

    Glowing text, and multiple shadows

    But due to the flexibility of the feature, the fun does not stop here. By varying the text offset, blur radius, and of course the color, you can achieve various effects, a mysterious glow for example:

     text-shadow: 1px 1px 5px #fff;
    Glowing text

    or a simple, fuzzy blur:

    text-shadow: 0px 0px 5px #000;
    Blurry text

    Finally, you can add ”more than one shadow”, allowing you to create pretty “hot” effects (courtesy of http://www.css3.info/preview/text-shadow/ css3.info):

    text-shadow: 0 0 4px white, 0 -5px 4px #FFFF33, 2px -10px 6px #FFDD33, -2px -15px 11px #FF8800, 2px -25px 18px #FF2200
    Multiple shadows are hot

    The number of text-shadows you can apply at the same time in Firefox 3.5 is — in theory — unlimited, though you may want to stick with a reasonable amount. Like all CSS properties, you can modify text-shadow on the fly using JavaScript:

    Animated shadows with JavaScript

    Performance, Accessibility and Cross-Browser Compatibility

    The times of using pictures (or even worse, Flash) for text shadows on the web are numbered for two reasons:

    First, there are significant advantages to using text instead of pictures. Not using pictures saves on bandwidth and HTTP connection overhead. Accessibility, both for people who use screen readers and search engines, is greatly improved. And page zoom will work better because the text can be scaled instead of using pixel interpolation to scale up an image.

    Second this feature is largely cross-browser compatible:

    • Opera supports text-shadow since version 9.5. According to the Mozilla Developer Center, Opera 9.x supports up to 6 shadows on the same element.
    • Safari has had the feature since version 1.1 (and other WebKit-based browsers along with it).
    • Internet Explorer does not support the text-shadow property, but the feature degrades gracefully to regular text. In addition, if you want to emulate some of the text-shadow functionality in MSIE, you can use Microsoft’s proprietary ”Shadow” and ”DropShadow” filters.
    • Similarly to MSIE, when other, older browsers do not support the feature (including Firefox 3 and older), they will just show the regular text without any shadows.

    A caveat worth mentioning is the ”drawing order”: While Opera 9.x adheres to the CSS2 painting order (i.e., the first specified shadow is drawn at the bottom), Firefox 3.5 adheres to the CSS3 painting order (the first specified shadow is on top). Keep this in mind when drawing multiple shadows.

    Conclusions

    text-shadow is a subtle but powerful CSS feature that is — now that it is supported by Firefox 3.5 — likely to be widely adopted across the web in the foreseeable future. Due to its graceful degradation in older browsers, it can safely be used by developers and will, over time, be seen by more and more users.

    Finally, some words of wisdom: Like any eye candy, use it like salt in a soup — with moderation, not by the bucket. If the web developers of the world overdo it, text-shadow may die a short, yet painful death. It would be sad if we make users flinch at the sight of text shadows like typography geeks at the sight of “Papyrus”, and thus needed to bury the feature deeply in our treasure chest.

    That being said: Go try it out!

    Further resources

    Documentation

    Examples

  9. web fonts and css features – a simple demonstration

    This post is from Laurent Jouanneau, who was kind enough to build a very simple but elegant demonstration of how to use web fonts and some of the new CSS features in Firefox 3.5.

    View the Demo in Firefox 3.5
    font_shadow_radius

    Shadows and round corners

    First, we set some style properties on the toolbar:

    -moz-border-radius

    -moz-border-radius:10px 0px 10px 0px;

    This indicates that top left and bottom right border corner should be round with a radius of 10 pixels.

    -moz-box-shadow

    -moz-box-shadow: #9BD1DE 5px 5px 6px;

    This indicates that a shadow should be drawn under the div, with an offset of 5 pixels to the right and the bottom, and with a blur radius of 6 pixels.

    Second, the buttons. We still use a border-radius property. But we use also a box-shadow property which changes depending of the state of the button. In the normal state, there is a shadow outside the button. When the mouse hovers over it (the hover state), the shadow is changed to be inside the button using the inset CSS property. We do the same thing when we click on the button (the active state), but we also make the shadow is bigger and darker.

    #superbox button {
        -moz-border-radius: 5px;
        -moz-box-shadow: #000 0px 0px 8px;
    }
     
    #superbox button:hover {
        -moz-box-shadow: inset #989896 0 0 3px;
        text-shadow: red 0px 0px 8px;
    }
     
    #superbox button:active {
        -moz-box-shadow: inset #1C1C1C 0 0 5px;
    }

    You can also see that we add a red shadow under the text of the button when the mouse hovers over it using the text-shadow property.

    Web fonts

    Each button is rendered with its own font, declared using @font-face. Example:

    @font-face {
        font-family: Brock Script;
        src: url("BrockScript.ttf");
        font-style: normal;
        font-weight: normal;
    }

    With the font-family property, we indicate a name for our font. The src indicates the url of the downloadable font.

    Once we’ve defined the @font-face property we can use it in the CSS for one of the buttons:

    .first {
        font-family: Brock Script;
    }

    When you declare the font with @font-face, and then use the font in CSS, the browser will automatically download and render using that font. The browser won’t download fonts you don’t use, so it’s safe to include descriptions of fonts from a common CSS file that might not be used in the page that you’re currently displaying.

    In the demonstration there’s also a small amount of script connected to each of the buttons that changes the class of the blue box to use the downloaded font for that button showing that you can update fonts on the fly as well.

    With these relatively simple techniques we can have beautiful buttons without having to use a bitmap image.

    Note: these fonts can be downloaded from fontsquirrel.com : Brock-Script (created by Dieter Steffmann), Sniglet (created by The League of Moveable Type, under the licence CC-by-sa) and Quick End Jerk (created by Vic Fieger).