General app development tutorial

  • Revision slug: Apps/Tutorials/General
  • Revision title: General app development tutorial
  • Revision id: 233049
  • Created:
  • Creator: jswisher
  • Is current revision? No
  • Comment 9 words added, 16 words removed

Revision Content

{{ draft() }}

Unlike other platforms like iOS and Android, the first-tier languages of web applications are HTML, CSS, and JavaScript, backed by a world wide web of developer resources. The web stack is available on all modern mobile and desktop hardware; this lets you maximize code reuse and reach a massive audience on different platforms and devices with little additional effort. In this tutorial, we'll explore the different aspects of web app creation, the strategies for designing a flexible, functional app, coding an app to completion.

Over the course of the tutorial, we'll be employing these techniques and technologies to create a Twitter-based application meant for desktop, mobile phone, and mobile tablet devices. Once the app is completed, we'll create the appropriate manifests for placing our app up for download on the Mozilla Marketplace!

Elements of an HTML5 app

While the role of HTML, CSS, and JavaScript are obvious to some, let's do a quick recap of how each plays its own important role in an HTML5 app.

HTML

HTML is used to create the content structure for the web application. New features to HTML5 include new {{ HTMLElement("input") }} types, form validation support, media tags like {{ HTMLElement("audio") }} and {{ HTMLElement("video") }}, and more semantic HTML elements.

CSS

CSS provides the visual presentation, letting you control the basic layout of content. CSS can do more than just format content though; you can use the power of CSS to animate elements, create precise gradients to avoid having to unnecessarily use images, and create media queries which let you adjust the appearance of your content based on the type of device it's being viewed on.

JavaScript

JavaScript provides the level of dynamism and user interaction for the web app. JavaScript lets you listen for and respond to user interactions, load content dynamically, and get access to device-specific features, like the Camera API and Geolocation API.

It's important to note that support for individual features varies from browser to browser; feature detection and research should be done before using each feature. How to use these strategies will be covered in depth below.

With the technologies laid out, let’s get started with an introduction to a few popular developer tools that can help increase your efficiency.

Configuring your development environment

Before you can dive into creating your web application, you need to make sure you have the tools required.

Text editors

A solid text editor is the most crucial tool. There are several free text editors available, including:

Cross-platform

Windows only

Mac only

These are not, of course, exhaustive lists.

Web developer tools

As you would expect, testing and debugging of your application will be done within the browser. You’ll want to snag a few handy developer tools for your browser. These tools will help with everything from the inspection and styling of visual elements of your app, to observing network traffic and debugging JavaScript. We strongly suggest you find a combination of tools that works for you, they can be a lifesaver.

Tools for Firefox users

Firefox also has good built-in developer tools; see the Tools->Web Developer submenu.

Tools for Google Chrome users

Additional resources can be added to your development environment as needed, but a text editor, browser, and developer tools will get you well on your way to creating a great web app!

Design

There are many considerations to ponder before designing your web app.

Design considerations

Device support and design emulation

Knowing the types of devices your application should work on is of utmost importance. Knowing the target devices and their capabilities tells us what features we can likely count on, what UI components should look like, and so on. Many mobile JavaScript frameworks, Dojo Mobile being one of them, provide multiple device themes for easy device theme implementation. Even if you prefer not to use the given JavaScript framework, you can still study the device theme stylesheet and borrow styles as desired.

Orientation support

Orientation support is a huge consideration when creating a web app capable of working on mobile devices. One obvious orientation consideration is that desktop apps use horizontal orientation by default, whereas most mobile devices use portrait as the default orientation. An ideal web application looks good and works well in both orientations. Both JavaScript and CSS media queries provide developers the capability to detect and react to orientation changes as they happen.

Gestures vs. simple touch events

Consider the navigation interaction paths you desire for your application. Will the application be navigable by button touches or gestures? The answer to that question decides whether your application must make room for static controls or must subtly communicate to the user that gestures should be available. JavaScript libraries like jGestures exist to aid in gesture detection.

Basic app design principles

Regardless of the specific devices you plan to support, there are a few basic principles which should be obeyed when creating web applications:

  • Avoid pixel-based widths when designing for multiple devices and/or multiple orientations
  • Use vector graphics so that their dimensions may be elegantly adjusted between devices
  • Don't assume features on any device; feature detection is still important
  • The more flexible the app design, the more portable it will be when considering broader device support

The design of our app will be very typical, with two panes. The first pane will provide a search box for field for entering the user's location, as well as a list of previous location searches. The second pane will simply show a list of tweets from Twitter. Each pane will use a standard heading.

Our app will also be dynamic in that it will layout properly in both landscape and portrait orientation, respond to a simple swipe gesture, and display reasonably on desktop and mobile devices. The file structure of the app will look like this:

- app
	-  app.css
	-  app.manifest
	-  app.js
	-  images/
		-  icon-16.png
		-  icon-48.png
		-  icon-128.png
	-  index.html

The structure of your application may very; since this is a small sample application, there's no need for more specific directory structures. The images are provided in different sizes for different devices. For example, the icon-128.png file will be used for Mac OS X desktop installations.

Code

Outside the different colors and imagery that apps use, an app's design isn't necessarily dynamic: the principles of designing a flexible app are largely the same. The style and tools with which a developer uses to code their application is a completely different story; numerous libraries and frameworks are available for coding mobile application.

JavaScript libraries

jQuery Mobile

jQuery's official mobile framework, jQuery Mobile. jQuery mobile provides a unified, HTML5-based user interface system for all popular mobile device platforms. jQuery Mobile also provides a theme builder for application design as well as development.

Dojo Mobile

Dojo Mobile is the Dojo Toolkit's mobile framework, boasting a series of flexible views and widgets, automatic device detection and theme, and more. The Dojo Mobile Showcase shows advanced Dojo Mobile usage in action.

MooTools Moobile

The unofficial mobile framework of MooTools is called Moobile. Moobile provides a mobile application boilerplate, as well as a host of simple mobile widgets.

Numerous other mobile JavaScript frameworks are available to aid the development of mobile web applications. When looking for a good mobile web app JavaScript framework, look for multi-device support, touch and gesture event support, and a unified API with its host framework.

The web app built within this tutorial will utilize jQuery Mobile. Experiment and evaluate different mobile frameworks based on the goals of your app before selecting one (or deciding against using any at all). In many cases, a framework app will be save you time; in other cases, a framework could be overkill.

CSS libraries, helpers, and techniques

CSS plays an important role in any web-based technology. There are a variety of CSS libraries than may aid you in creating, maintaining, and organizing your CSS.

CSS preprocessors

While CSS is a simple language, its lack of variables and the need for repeated style assignments with vendor prefixes can make CSS difficult to maintain—a pain no mobile app developer needs. CSS preprocessors ease development of apps, allowing for better code organization and faster development.

With one of those CSS preprocessors, LESS, CSS can be written like this:

@someColor: #000; /* color var */

.rounded-corners (@radius: 5px) { /* function */
  border-radius: @radius;
  -webkit-border-radius: @radius;
  -moz-border-radius: @radius;
}

p {
  color: @someColor;
  a {
    color: #fff;
    background: @someColor;
    
    .rounded-corners;
  }
}
	

This gets converted into the following by the LESS preprocessor:

p { 
  color: #000;
}

p a {
  color: #fff;
  background: #000;
  border-radius: 5px;
  -webkit-border-radius: 5px;
  -moz-border-radius: 5px;
}
	

While LESS is the most popular CSS preprocessor, SASS and Stylus are also available.

CSS3 techniques

Web apps may take advantage of numerous CSS techniques which allow for enriched design and strategies for avoiding the need for imagery.

Gradients

CSS3 provides the ability to create linear and radial gradients with some simple CSS code:

h1 { 
  background-image: -moz-linear-gradient(#6facd5, #497bae);
}
Box and text shadows

Box shadows and text shadows provide a subtle depth enhancement to block elements and text:

.shadower {
  -moz-box-shadow: 10px 5px 5px #000;
  text-shadow: 1px 1px 2px black, 0 0 1em blue, 0 0 0.2em blue;
  color: white;
  font: 1.5em Georgia, "Bitstream Charter", "URW Bookman L", "Century Schoolbook L", serif;
}
Shapes with CSS

CSS also provides the ability to cleverly create shapes likes triangles and circles:

.arrowRight {
  width:0px; 
  height:0px; 
  border-bottom:5px solid transparent;
  border-top:5px solid transparent;
  border-left:5px solid #2f2f2f;
  font-size:0px;
  line-height:0px;
}

.circle {
  border-radius: 50%;
  width: 200px;
  height: 200px;
}

Creating responsive layouts

Coding responsive layouts is paramount to creating flexible apps that will work on multiple devices and in multiple orientations. The following are some techniques for creating such a design.

Our desktop layout

desktop-screenshot1.png

Our mobile device & phone layouts

iphone-screenshot1.png     iphone-screenshot2.png

Percentage widths

Fixed pixel widths should rarely be used; percentage widths are preferred as they let elements adjust to device viewport dimensions. Fixed widths (and heights) should generally be used only for small, genuinely fixed-sized items.

Viewport size-dependent element display

Showing and hiding elements based on viewport size is a common practice. Instead of cramming a lot of content into a smaller space, or changing an app's design completely, simply hiding those "supporting" elements may be the best option.

Viewport size-dependent imagery

Adapting image sizes to the device viewport size is also a common practice, making vector images (using SVG, for example) the best practice for your web app.

Media queries

CSS media queries let developers adjust layout and element styles to viewport size, orientation, aspect ratio, and more:

/* screen size media queries */
@media only screen and (min-device-width : 768px) and (max-device-width : 1024px) {

}


/* orientation media queries */
@media (orientation:portrait) {

}
@media (orientation:landscape) {

}

/* advanced media query usage */
@media all and (max-width: 699px) and (min-width: 520px), (min-width: 1151px) {

}

/* aspect ratio */
@media screen and (device-aspect-ratio: 16/9) {

}
orientationchange and resize events

Orientation changes may also be detected with JavaScript. Most browsers fire an orientationchange event while all browsers are known to fire the resize event.

window.addEventListener("resize", function() { 
  // Detect orientation based on width
  var orientation = window.innerWidth > window.innerHeight ? "landscape" : "portrait";
  
  // Execute more code accordingly...
}, false);

Web app bootstraps

Server side processing of information happens on the app host's servers, so any server side technology may be used. Popular server side languages include PHP, Python, and NodeJS + express. There's a likelihood that your application will want to implement BrowserID for app sign in; you can find the code required to implement BrowserID on MDN.

App manifests

Apps submitted to the Mozilla Marketplace require an application manifest. This manifest contains basic information that a web browser needs to interact with an app. Manifests are written in JSON syntax; a sample manifest could look like:

{
  "version": "0.1",
  "name": "Area Tweet",
  "description": "Find tweets by for any location",
  "icons": {
    "16": "http://areatweet.com/images/icon-16.png",
    "48": "http://areatweet.com/images/icon-48.png",
    "128": "http://areatweet.com/images/icon-128.png"
  },
  "developer": {
    "name": "David Walsh",
    "url": "http://areatweet.com"
  },
  "installs_allowed_from": [
    "https://marketplace.mozilla.org",
    "http://areatweet.com"
  ],
  "default_locale": "en"
}

The application manifest lives on the host server, not the Mozilla Marketplace. It's recommended that your manifest be saved with a .webapp extension and served with a Content-Type HTTP header of application/x-web-app-manifest+json via HTTPS.

A complete listing of all manifest properties can be found here. There's also a Frequently Asked Questions document which provides tips for creating your manifest and explanations for why the manifest hosting process is the way it is.

It's best to use absolute paths within the manifest, even for images. The Mozilla Marketplace will not currently accept manifests with relative paths.

AppCache manifests

See Using the application cache for details.

Creating the Area Tweet app

With all of the design goals and coding standards laid out, it's time to get into the coding of our app. As with any web application template, we need an HTML page with the HTML5 doctype, {{ HTMLElement("head") }}, and {{ HTMLElement("body") }} elements:

<!doctype html>
<html>
<head>
  <title></title>
 
  <meta charset="utf-8" />
  <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
 
  <meta name="viewport" content="width=device-width, initial-scale=1">
 
  <!-- stylesheets go here -->
 
</head>
</html>
<body>
 
  <!-- HTML app structure goes here -->
 
 
  <!-- javascript goes here -->
 
</body>
</html>

We'll be using jQuery Mobile as the JavaScript framework; that means we must pull in the CSS and JavaScript resources required by jQuery Mobile:

<!-- stylesheets -->
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" />
	
<!-- scripts -->
<script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script>

With our basic application boilerplate and jQuery Mobile resource in place, it's time to add content and widgets to the page. Since we've decided on using jQuery Mobile for our application framework, our app's HTML structure will follow their prescribed widget structures. The first pane provides a search box and a history list:

<!-- home pane -->
<div data-role="page" id="home">
 
  <div data-role="header">
    <h1>Area Tweet</h1>
  </div>
 
  <div data-role="content">
    
    <div class="ui-body ui-body-b">
      <h2>Location Search</h2>
      <form id="locationForm">
        <input type="search" name="location" id="locationInput" placeholder="Your Location" />
        <button type="submit" data-role="button" data-theme="b">Search</button>
      </form>
    </div>
    
    <div id="prevLocationsContainer" class="opaque">
      <h2>
        Previous Locations
        <a href="#" id="clearHistoryButton" data-role="button" data-icon="delete" data-iconpos="notext"
                data-theme="b" data-inline="true" style="top: 5px;">Clear History</a>
      </h2>
      <ul id="prevLocationsList" data-role="listview" data-inset="true" data-filter="true"></ul>
    </div>
    
  </div>
</div>

There are a few things to notice with the code above:

  • The structure of the HTML5 sticks to semantics; that ensures maximum accessibility.
  • As with any web-based app, we assign CSS classes and IDs to elements we'll want styled and access to from JavaScript code.

If you have questions about individual jQuery mobile functionalities, node attributes, or structures, please consult the jQuery Mobile Documentation.

The second pane will be used for displaying a list of tweets:

<!-- tweets pane -->
<div data-role="page" id="tweets">
 
  <div data-role="header">
    <a href="#home" id="tweetsBackButton">Back</a>
    
    <h1><span id="tweetsHeadTerm"></span> Tweets</h1>
  </div>
 
  <ul id="tweetsList" data-role="listview" data-inset="true"></ul>
 
</div>

Our web app's CSS contains a CSS animation for fading in any element, as well as overriding jQuery Mobile styles, and general element styling.

/* animations */
@-moz-keyframes fadeIn {
  0%    { opacity: 0; }
  100%  { opacity: 1; }
}
@-webkit-keyframes fadeIn {
  0%    { opacity: 0; }
  100%  { opacity: 1; }
}

.fadeIn {
  -moz-animation-name: fadeIn;
  -moz-animation-duration: 2s;
 
  -webkit-animation-name: fadeIn;
  -webkit-animation-duration: 2s;
 
  opacity: 1 !important;
}

/* Custom CSS classes */
.clear        { clear: both; }
.hidden       { display: none; }
.opaque       { opacity: 0; }


/* Basic styling */
#prevLocationsContainer { margin-top: 40px; }

/* Customizing jQuery Styles */
#tweetsList li.ui-li-divider,
#tweetsList li.ui-li-static     { font-weight: normal !important; }


/* Tweet list */
#tweetsList li {
 
}

#tweetsList li .tweetImage {
  float: left;
  margin: 10px 10px 0 10px;
}

#tweetsList li .tweetContent {
  float: left;
  /* margin: 10px 0 0 0; */
}

#tweetsList li .tweetContent strong {
  display: block;
  padding-bottom: 5px;
}

/* Media Queries for device support */
@media screen and (max-device-width: 480px) {
  #prevLocationsContainer { margin-top: 10px; }
}

JavaScript is the last major component to add to our web app. The following encompasses all of the functionality for the app:

$(document).ready(function() {
 
  // Start from scratch on page load
  if(window.location.hash) {
    window.location = "index.html";
  }
 
  // Feature tests and settings
  var hasLocalStorage = "localStorage" in window,
    maxHistory = 10;
 
  // List of elements we'll use
  var $locationForm = $("#locationForm"),
    $locationInput = $("#locationInput"),
    
    $prevLocationsContainer = $("#prevLocationsContainer"),
    
    $tweetsHeadTerm = $("#tweetsHeadTerm"),
    $tweetsList = $("#tweetsList");
    
  // Hold last request jqXHR's so we can cancel to prevent multiple requests
  var lastRequest;
 
  // Create an application object
  app = {
    
    // App initialization
    init: function() {
      var self = this;
      
      // Focus on the search box
      focusOnLocationBox();
      
      // Add the form submission event
      $locationForm.on("submit", onFormSubmit);
      
      // Show history if there are items there
      this.history.init();
      
      // When the back button is clicked in the tweets pane, reset the form and focus
      $("#tweetsBackButton").on("click", function(e) {
        $locationInput.val("");
        setTimeout(focusOnLocationBox, 1000);
      });
      
      // Geolocate!
      geolocate();
      
      // When the tweets pane is swipe, go back to home
      $("#tweets").on("swiperight", function() {
        window.location.hash = "";
      });
      
      // Clear history when button clicked
      $("#clearHistoryButton").on("click", function(e) {
        e.preventDefault();
        localStorage.removeItem("history");
        self.history.hideList();
      })
    },
    
    // History modules
    history: {
      $listNode: $("#prevLocationsList"),
      $blockNode: $("#homePrev"),
      init: function() {
        var history = this.getItemsFromHistory(),
          self = this;
        
        // Add items to the list
        if(history.length) {
          history.forEach(function(item) {
            self.addItemToList(item);
          });
          self.showList();
        }
        
        // Use event delegation to look for list items clicked
        this.$listNode.delegate("a", "click", function(e) {
          $locationInput.val(e.target.textContent);
          onFormSubmit();
        });
      },
      getItemsFromHistory: function() {
        var history = "";
        
        if(hasLocalStorage) {
          history = localStorage.getItem("history");
        }
        
        return history ? JSON.parse(history) : [];
      },
      addItemToList: function(text, addToTop) {
        var $li = $("<li><a href='#'>" + text + "</a></li>"),
          listNode = this.$listNode[0];
          
        if(addToTop && listNode.childNodes.length) {
          $li.insertBefore(listNode.childNodes[0]);
        }
        else {
          $li.appendTo(this.$listNode);
        }
        
        this.$listNode.listview("refresh");
      },
      addItemToHistory: function(text, addListItem) {
        var currentItems = this.getItemsFromHistory(),
          newHistory = [text],
          self = this,
          found = false;
        
        // Cycle through the history, see if this is there
        $.each(currentItems, function(index, item) {
          if(item.toLowerCase() != text.toLowerCase()) {
            newHistory.push(item);
          }
          else {
            // We've hit a "repeater"; signal to remove from list
            found = true;
            self.moveItemToTop(text);
          }
        });
        
        // Add a new item to the top of the list
        if(!found && addListItem) {
          this.addItemToList(text, true);
        }
        
        // Limit history to 10 items
        if(newHistory.length > maxHistory) {
          newHistory.length = maxHistory;
        }
        
        // Set new history
        if(hasLocalStorage) {
          // Wrap in try/catch block to prevent mobile safari issues with private browsing
          // http://frederictorres.blogspot.com/2011/11/quotaexceedederr-with-safari-mobile.html
          try {
            localStorage.setItem("history", JSON.stringify(newHistory));
          }
          catch(e){}
        }
        
        // Show the list
        this.showList();
      },
      showList: function() {
        $prevLocationsContainer.addClass("fadeIn");
        this.$listNode.listview("refresh");
      },
      hideList: function() {
        $prevLocationsContainer.removeClass("fadeIn");
      },
      moveItemToTop: function(text) {
        var self = this,
          $listNode = this.$listNode;
        
        $listNode.children().each(function() {
          if($.trim(this.textContent.toLowerCase()) == text.toLowerCase()) {
            $listNode[0].removeChild(this);
            self.addItemToList(text, true);
          }
        });
        
        $listNode.listview("refresh");
      }
    }
    
  };
 
  // Search submission
  function onFormSubmit(e) {
    if(e) e.preventDefault();
    
    // Trim the value
    var value = $.trim($locationInput.val());
    
    // Move to the tweets pane
    if(value) {
      
      // Add the search to history
      app.history.addItemToHistory(value, true);
      
      // Update the pane 2 header
      $tweetsHeadTerm.html(value);
      
      // If there's another request at the moment, cancel it
      if(lastRequest && lastRequest.readyState != 4) {
        lastRequest.abort();
      }
      
      // Make the JSONP call to Twitter
      lastRequest = $.ajax("http://search.twitter.com/search.json", {
        cache: false,
        crossDomain: true,
        data: {
          q: value
        },
        dataType: "jsonp",
        jsonpCallback: "twitterCallback",
        timeout: 3000
      });
    }
    else {
      // Focus on the search box
      focusOnLocationBox();
    }
    
    return false;
  }
 
  // Twitter reception
  window.twitterCallback = function(json) {
    
    var template = "<li><img src='{profile_image_url}' class='tweetImage' /><div class='tweetContent'>"
                   +"<strong>{from_user}</strong>{text}</div><div class='clear'></div></li>",
      tweetHTMLs = [];
      
    // Basic error handling
    if(json.error) { // Error for twitter
      showDialog("Twitter Error", "Twitter cannot provide tweet data.");
      return;
    }
    else if(!json.results.length) { // No results
      showDialog("Twitter Error", "No tweets could be found in your area.");
      return;
    }
    
    // Format the tweets
    $.each(json.results, function(index, item) {
      item.text = item.text.
            replace(/(https?:\/\/\S+)/gi,'<a href="$1" target="_blank">$1</a>').
            replace(/(^|\s)@(\w+)/g,'$1<a href="http://twitter.com/$2" target="_blank">@$2</a>').
            replace(/(^|\s)#(\w+)/g,'$1<a href="http://search.twitter.com/search?q=%23$2" target="_blank">#$2</a>')
      tweetHTMLs.push(substitute(template, item));
    });
    
    // Place tweet data into the form
    $tweetsList.html(tweetHTMLs.join(""));
    
    // Refresh the list view for proper formatting
    try {
      $tweetsList.listview("refresh");
    }
    catch(e) {}
    
    // Go to the tweets view
    window.location.hash = "tweets";
  };
 
  // Template substitution
  function substitute(str, obj) {
    return str.replace((/\\?\{([^{}]+)\}/g), function(match, name){
      if (match.charAt(0) == '\\') return match.slice(1);
      return (obj[name] != null) ? obj[name] : "";
    });
  }
 
  // Geolocates the user
  function geolocate() {
    if("geolocation" in navigator) {
      // Attempt to get the user position
      navigator.geolocation.getCurrentPosition(function(position) {
        // Set the address position
        if(position.address && position.address.city) {
          $locationInput.val(position.address.city);
        }
      });
    }
  }
 
  // Focuses on the input box
  function focusOnLocationBox() {
    $locationInput[0].focus();
  }
 
  // Modal function
  function showDialog(title, message) {
    $("#errorDialog h2.error-title").html(title);
    $("#errorDialog p.error-message").html(message);
    $.mobile.changePage("#errorDialog");
  }
 
  // Init the app
  app.init();
 
});

I wont go over every part of the app's JavaScript, but a few items are worth pointing out:

  • The script above uses feature testing for both localStorage and geolocation. The app wont attempt to use either feature it they aren't present in the browser.
  • The geolocation API is used to detect the user's current location and the localStorage API is used to keep the user's search history
  • The application JavaScript has been written modularly for easier testing
  • A swipe event is listened for on the tweet pane; when the pane is swiped, the user taken back to the first pane
  • Twitter is the source of all data; no custom server side processing is included for this app

Testing the app

App testing is of immense importance, especially when supporting multiple platforms and devices. The number of tests and types of testing needed depend on the devices and platforms supported. Test types include:

  • Speed
  • Performance efficiency
  • Input and output validation
  • Touch and interactivity

While those are the basic test types, there are more ideas to consider while testing.

Web environment differences

Here are some things to keep in mind when dealing with different web environments:

Vendor prefixes

Both advanced JavaScript and CSS features within browsers may be vendor prefixed with -webkit, -moz, -o, or -ms. Know the environments you plan to use and prefix features appropriately.

Note: You should try to avoid using features that are only available on certain devices, unless you either provide appropriate fallbacks or specifically intend your app to be used on a more limited set of devices.

Feature detection

Some environments will support a specific feature, others may not. Feature detection is the best way of knowing which tools are available for a given platform. For example, to detect support of the Geolocation API, you would code:

if("geolocation" in navigator) {
  // Geolocation available, use it!
}

CanIUse.com provides detailed tables of browser and device support for specific features. A helping library like Modernizr automatically detects features upon page load and provides that information accordingly.

Responsive design

Using media queries and foresight in design will prevent design issues. Common pitfalls include not using vector graphics for elements which may grow or shrink, using fixed-dimension elements throughout all devices, not testing different orientations, and simply not looking at your app at different resolutions. Services like Screenfly and responsivepx help aid in testing an app at different sizes, but there's no substitute for having a supported device handy for manual testing.

Consider also the problems that can arise when different devices have different screen resolutions. A case in point: the problems that cropped up when Apple introduced the third-generation iPad, with its new 2048x1536 display:

Unit testing

Unit testing is a common practice in all walks of development, and web app testing is no different. Unit testing of CSS and JavaScript is also incredibly easy when an application is coded in a modular fashion. Popular JavaScript unit testing frameworks include Jasmine, QUnit, and YUI Test. Each unit testing website provides code samples for how to use their test framework.

Performance

Performance testing can be difficult to prescribe since it's wholly dependent upon the tasks performed by the app. Basic web coding principles like minimizing HTTP requests (JavaScript concatenation or CSS sprites help), JS and CSS minification, placing scripts at the bottom of the page, and properly setting Expires headers all apply. The YSlow team provides more helpful web performance best practices to follow, all of which will enhance your web app. The HTML5Rocks website also provides a list of performance best practices.

Publishing your app

Deployment

Once you’ve finished your app, host it on a publicly accessible web server like any other website. There are numerous ways to deploy your app.

GitHub

If the web app is purely static (HTML/CSS/JavaScript, but no server scripting), GitHub Pages is a solid hosting option. Cloud storage service Dropbox can also be used for this purpose.

Generic hosting solutions

For dynamic websites, use a generic hosting option (like a web server you may already own or have access to) with the right capabilities or a hosting provider specifically tailored to the needs of your app, like Heroku or Google App Engine.

Publishing

Once your web app has been deployed, you obviously want to make it installable by your intended user base. There are two options for publishing your app.

Publish on your website

If you want to let people install your app from a website you own, you must implement some JavaScript code on your web site to manage installing and updating your app into users' browsers.

Submit to Mozilla Marketplace

Submitting your app to the Mozilla Marketplace method has many advantages, such as increased publicity, no need to implement special APIs on your own web site, and the possibility of publishing paid apps more easily.

Maintaining your app

Managing and maintaining your web app is as important as releasing it. Bugs will pop up, users will request more features, and over time, new devices will be released and their software updated.

App update process

This section needs to be written once the marketplace is closer to complete.

Receiving and responding to user feedback

Receiving and responding to user feedback is an integral part of engaging users. User feedback provides invaluable insight into:

  • what the general reception of the app is
  • criticisms of the app
  • ideas for improvement and feature requests
  • device-specific bugs

The right response can illicit buzz and faithfulness from app purchasers; an unprofessional or negative response can ruin your chance to fix app problems.

App refunds

Mozilla Marketplace users are entitled to refunds within 30 minutes of purchases. After that 30 minutes, developers can review refund requests on an individual basis. Read the Marketplace Payments FAQ for more information about payments and refunds.

Profiting from your web app

Creating web apps is also a great way to turn your passion into revenue!

Mozilla Marketplace

The Mozilla Marketplace is an outstanding marketplace for web app developers. The Mozilla Marketplace supports both paid and free apps, in-app purchasing, a variety of device platform apps, and more. The Mozilla Marketplace provides competitive pricing and offers consumers a variety of payment methods. Read the Marketplace Payments FAQ to learn more about monetizing your app on the Mozilla Marketplace.

In-app payments

In-App payments are another way to monetize your app with the added bonus of enhancing an existing app instead of requiring the user to add purchase a new one. Mozilla's in-app payment model works very similarly to Google's In-Apps Payments system. This system flows as follows:

  • The app initiates a payment by signing a JWT request and calling a JavaScript function
  • This starts the buyflow in a lightbox (served from an {{ HTMLElement("iframe") }})
    • The buyer logs in with Mozilla Persona (formerly called BrowserID)
    • The buyer completes the purchase
  • The app receives a JavaScript callback when the buyer closes the window
  • The app server receives a signed POST request with a Mozilla transaction ID indicating that the purchase was completed successfully

The Mozilla Marketplace provides a JavaScript utility library to aid in this process.

The In-App Payments FAQ provides a wealth of information on how in-app payments work and sample code for implementation. Keep this reference handy as the in-app payment process is currently in an experimental state.

Third party payment providers

What does this refer to? PayPal? Bank processors? ¿Que?

Create your web app!

Using open web technologies to create rich, powerful applications for numerous devices is a fun, rewarding, and potentially profitable process. The open web provides the tools needed to make app creation possible, while Mozilla provides an excellent marketplace for showcasing and distributing your app. Use the information provided within this document to create your incredible app and share it with the world!

You can see a live demonstration of the app we created in this tutorial by visiting AreaTweet.com Want to install it on your desktop or mobile device? You can download it for free in the Mozilla Marketplace!

Revision Source

<p>{{ draft() }}</p>
<p>Unlike other platforms like iOS and Android, the first-tier languages of web applications are HTML, CSS, and JavaScript, backed by a world wide web of developer resources. The web stack is available on all modern mobile and desktop hardware; this lets you maximize code reuse and reach a massive audience on different platforms and devices with little additional effort. In this tutorial, we'll explore the different aspects of web app creation, the strategies for designing a flexible, functional app, coding an app to completion.</p>
<p class="tutBlock">Over the course of the tutorial, we'll be employing these techniques and technologies to create a Twitter-based application meant for desktop, mobile phone, and mobile tablet devices. Once the app is completed, we'll create the appropriate manifests for placing our app up for download on the <a class="link-https" href="https://marketplace.mozilla.org/">Mozilla Marketplace</a>!</p>
<h2>Elements of an HTML5 app</h2>
<p>While the role of HTML, CSS, and JavaScript are obvious to some, let's do a quick recap of how each plays its own important role in an HTML5 app.</p>
<h4>HTML</h4>
<p>HTML is used to create the content structure for the web application. <a href="/en/HTML/HTML5" title="en/HTML/HTML5">New features to HTML5</a> include new {{ HTMLElement("input") }} types, <a href="/en/HTML/HTML5/Constraint_validation" title="en/HTML/HTML5/Constraint_validation">form validation support</a>, media tags like {{ HTMLElement("audio") }} and {{ HTMLElement("video") }}, and <a href="/en/Sections_and_Outlines_of_an_HTML5_document" title="en/Sections_and_Outlines_of_an_HTML5_document">more semantic HTML elements</a>.</p>
<div class="infoBlock"> <ul> <li><a href="/en/HTML" title="en/HTML">HTML documentation</a></li> <li><a href="/en/HTML/HTML5" title="en/HTML/HTML5">HTML5 features</a></li> <li><a href="/en-US/learn/html" title="https://developer.mozilla.org/en-US/learn/html">Learn HTML</a></li> <li><a class="external" href="http://www.html5rocks.com/en/">HTML5 Rocks!</a></li> <li><a class="external" href="http://html5test.com/">HTML5 Test</a></li> <li><a class="external" href="http://html5boilerplate.com/">HTML5 Boilerplate</a></li> <li><a class="external" href="http://www.whatwg.org/specs/web-apps/current-work/multipage/">HTML Living Standard</a></li> <li><a class="external" href="http://developers.whatwg.org/">Simple HTML5 Guide</a></li> </ul>
</div>
<h4>CSS</h4>
<p>CSS provides the visual presentation, letting you control the basic layout of content. CSS can do more than just format content though; you can use the power of CSS to <a href="/en/CSS/CSS_animations" title="en/CSS/CSS_animations">animate elements</a>, create <a href="/en/CSS/Using_CSS_gradients" title="en/CSS/Using_CSS_gradients">precise gradients</a> to avoid having to unnecessarily use images, and create <a href="/en/CSS/Media_queries" title="en/CSS/Media_queries">media queries</a> which let you adjust the appearance of your content based on the type of device it's being viewed on.</p>
<div class="infoBlock"> <ul> <li><a href="/en/CSS" title="en/CSS">CSS documentation</a></li> <li><a href="/en/CSS/CSS_Reference" title="/en/CSS/CSS_Reference">CSS Reference</a></li> <li><a class="external" href="http://dev.w3.org/csswg/css3-animations/">CSS Animations Specification</a></li> <li><a class="external" href="http://www.colorzilla.com/gradient-editor/">CSS Gradient Generator</a></li> <li><a class="external" href="http://www.w3.org/TR/css3-mediaqueries/">CSS Media Queries Specification</a></li> <li><a class="external" href="http://css-tricks.com/snippets/css/media-queries-for-standard-devices/">Media Queries for Standard Devices</a></li> <li><a class="external" href="http://developer.apple.com/library/safari/#documentation/appleapplications/reference/safaricssref/articles/standardcssproperties.html">Mobile Safari Supported CSS Properties</a></li> </ul>
</div>
<h4>JavaScript</h4>
<p>JavaScript provides the level of dynamism and user interaction for the web app. JavaScript lets you <a href="/en/DOM/element.addEventListener" title="en/DOM/element.addEventListener">listen for and respond to user interactions</a>, <a href="/en/AJAX" title="en/AJAX">load content dynamically</a>, and get access to device-specific features, like the <a href="/en/DOM/Using_the_Camera_API" title="en/DOM/Using_the_Camera_API">Camera API</a> and <a href="/En/Using_geolocation" title="En/Using_geolocation">Geolocation API</a>.</p>
<div class="infoBlock"> <ul> <li><a href="/en/JavaScript/Guide" title="/en/JavaScript/Guide">JavaScript Guide</a></li> <li><a href="/en/JavaScript/Reference" title="en/JavaScript/Reference">JavaScript Reference</a></li> <li><a href="/en/JavaScript" title="en/JavaScript">All JavaScript documentation on MDN</a></li> <li><a href="/en/Canvas_tutorial" title="en/Canvas_tutorial">Canvas Tutorial</a></li> <li><a href="/en/DOM/element.classList" title="en/DOM/element.classList">Element.classList API</a></li> <li><a href="/en/DOM/Storage" title="en/DOM/Storage">DOM Storage API</a></li> <li><a class="external" href="http://addyosmani.com/writing-modular-js/">Writing Modular JavaScript With AMD, CommonJS &amp; ES Harmony</a></li> <li><a href="/en/DOM/window.navigator.battery" title="en/DOM/window.navigator.battery">Battery API</a></li> <li><a href="/en/DOM/Document.querySelectorAll" title="en/DOM/Document.querySelectorAll">document.querySelectorAll API</a></li> <li><a href="/en/DOM/Using_the_Page_Visibility_API" title="en/DOM/Using_the_Page_Visibility_API">Using the Page Visibility API</a></li> <li><a href="/en/WebSockets" title="en/WebSockets">WebSockets</a></li> </ul>
</div>
<p class="callout">It's important to note that support for individual features varies from browser to browser; <a href="/en/Browser_Feature_Detection" title="en/Browser_Feature_Detection">feature detection</a> and research should be done before using each feature. How to use these strategies will be covered in depth below.</p>
<p>With the technologies laid out, let’s get started with an introduction to a few popular developer tools that can help increase your efficiency.</p>
<h2>Configuring your development environment</h2>
<p>Before you can dive into creating your web application, you need to make sure you have the tools required.</p>
<h3>Text editors</h3>
<p>A solid text editor is the most crucial tool. There are several free text editors available, including:</p>
<h4>Cross-platform</h4>
<ul> <li><a class="external" href="http://www.sublimetext.com/">Sublime Text</a></li> <li><a class="external" href="http://jedit.org/">jEdit</a></li>
</ul>
<h4>Windows only</h4>
<ul> <li><a class="external" href="http://notepad-plus-plus.org/">Notepad++</a></li>
</ul>
<h4>Mac only</h4>
<ul> <li><a class="external" href="http://www.barebones.com/products/TextWrangler/" title="http://www.barebones.com/products/TextWrangler/">TextWrangler</a></li>
</ul>
<p>These are not, of course, exhaustive lists.</p>
<h3>Web developer tools</h3>
<p>As you would expect, testing and debugging of your application will be done within the browser. You’ll want to snag a few handy developer tools for your browser. These tools will help with everything from the inspection and styling of visual elements of your app, to observing network traffic and debugging JavaScript. We strongly suggest you find a combination of tools that works for you, they can be a lifesaver.</p>
<h4>Tools for Firefox users</h4>
<ul> <li><a class="external" href="http://getfirebug.com/">Firebug</a></li> <li><a class="link-https" href="https://addons.mozilla.org/en-US/firefox/collections/mozilla/webdeveloper/">Web Developer's Toolbox Collection</a></li> <li><a class="link-https" href="https://addons.mozilla.org/en-US/firefox/addon/web-developer/">Web Developer Toolbar</a></li> <li>Firepicker</li> <li><a class="link-https" href="https://addons.mozilla.org/en-US/firefox/addon/firecookie/">Firecookie</a></li> <li><a class="link-https" href="https://addons.mozilla.org/en-US/firefox/addon/user-agent-switcher/">User Agent Switcher</a></li> <li><a class="link-https" href="https://addons.mozilla.org/en-US/firefox/addon/colorzilla/">ColorZilla</a></li>
</ul>
<p>Firefox also has good built-in developer tools; see the Tools-&gt;Web Developer submenu.</p>
<h4>Tools for Google Chrome users</h4>
<ul> <li>Web Inspector</li> <li><a class="link-https" href="https://chrome.google.com/webstore/detail/bfbameneiokkgbdmiekhjnmfkcnldhhm">Web Developer</a> <span class="inlineNote">Official port of Firefox's plugin</span></li> <li><a class="link-https" href="https://chrome.google.com/webstore/detail/gbkffbkamcejhkcaocmkdeiiccpmjfdi">Pendule</a></li>
</ul>
<p>Additional resources can be added to your development environment as needed, but a text editor, browser, and developer tools will get you well on your way to creating a great web app!</p>
<h2>Design</h2>
<p>There are many considerations to ponder before designing your web app.</p>
<h3>Design considerations</h3>
<h4>Device support and design emulation</h4>
<p>Knowing the types of devices your application should work on is of utmost importance. Knowing the target devices and their capabilities tells us what features we can likely count on, what UI components should look like, and so on. Many mobile JavaScript frameworks, <a class="external" href="http://dojotoolkit.org/features/mobile">Dojo Mobile</a> being one of them, provide multiple device themes for easy device theme implementation. Even if you prefer not to use the given JavaScript framework, you can still study the device theme stylesheet and borrow styles as desired.</p>
<h4>Orientation support</h4>
<p>Orientation support is a huge consideration when creating a web app capable of working on mobile devices. One obvious orientation consideration is that desktop apps use horizontal orientation by default, whereas most mobile devices use portrait as the default orientation. An ideal web application looks good and works well in both orientations. Both JavaScript and CSS media queries provide developers the capability to detect and react to orientation changes as they happen.</p>
<h4>Gestures vs. simple touch events</h4>
<p>Consider the navigation interaction paths you desire for your application. Will the application be navigable by button touches or gestures? The answer to that question decides whether your application must make room for static controls or must subtly communicate to the user that gestures should be available. JavaScript libraries like <a class="external" href="http://jgestures.codeplex.com/">jGestures</a> exist to aid in gesture detection.</p>
<h3>Basic app design principles</h3>
<p>Regardless of the specific devices you plan to support, there are a few basic principles which should be obeyed when creating web applications:</p>
<ul> <li><strong>Avoid pixel-based widths</strong> when designing for multiple devices and/or multiple orientations</li> <li><strong>Use vector graphics</strong> so that their dimensions may be elegantly adjusted between devices</li> <li><strong>Don't assume features</strong> on any device; feature detection is still important</li> <li>The more flexible the app design, the more portable it will be when considering broader device support</li>
</ul>
<div class="tutBlock"> <p>The design of our app will be very typical, with two panes. The first pane will provide a search box for field for entering the user's location, as well as a list of previous location searches. The second pane will simply show a list of tweets from Twitter. Each pane will use a standard heading.</p> <p>Our app will also be dynamic in that it will layout properly in both landscape and portrait orientation, respond to a simple swipe gesture, and display reasonably on desktop and mobile devices. The file structure of the app will look like this:</p> <pre>- app
	-  app.css
	-  app.manifest
	-  app.js
	-  images/
		-  icon-16.png
		-  icon-48.png
		-  icon-128.png
	-  index.html
</pre> <p>The structure of your application may very; since this is a small sample application, there's no need for more specific directory structures. The images are provided in different sizes for different devices. For example, the <code>icon-128.png</code> file will be used for Mac OS X desktop installations.</p>
</div>
<h2>Code</h2>
<p>Outside the different colors and imagery that apps use, an app's design isn't necessarily dynamic: the principles of designing a flexible app are largely the same. The style and tools with which a developer uses to code their application is a completely different story; numerous libraries and frameworks are available for coding mobile application.</p>
<h3>JavaScript libraries</h3>
<h4>jQuery Mobile</h4>
<p><a class="external" href="http://jquery.com">jQuery's</a> official mobile framework, <a class="external" href="http://jquerymobile.com/">jQuery Mobile</a>. jQuery mobile provides a unified, HTML5-based user interface system for all popular mobile device platforms. jQuery Mobile also provides a <a class="external" href="http://jquerymobile.com/themeroller/">theme builder</a> for application design as well as development.</p>
<div class="infoBlock"> <ul> <li><a class="external" href="http://jquerymobile.com/blog/">jQuery Mobile Blog</a></li> <li><a class="external" href="http://jquerymobile.com/demos/1.1.0/">jQuery Mobile API</a></li> <li><a class="external" href="http://api.jquery.com">jQuery API</a></li> </ul>
</div>
<h4>Dojo Mobile</h4>
<p><a class="external" href="http://dojotoolkit.org/features/mobile">Dojo Mobile</a> is the <a class="external" href="http://dojotoolkit.org">Dojo Toolkit's</a> mobile framework, boasting a series of flexible views and widgets, automatic device detection and theme, and more. The <a class="external" href="http://demos.dojotoolkit.org/demos/demos.php?cat=mobile">Dojo Mobile Showcase</a> shows advanced Dojo Mobile usage in action.</p>
<div class="infoBlock"> <ul> <li><a class="external" href="http://dojotoolkit.org/documentation/tutorials/1.7/mobile/tweetview/getting_started/">Getting Started with dojox/mobile</a></li> <li><a class="external" href="http://livedocs.dojotoolkit.org/dojox/mobile">Dojo Mobile Documentation</a></li> <li><a class="link-https" href="https://www.ibm.com/developerworks/mydeveloperworks/blogs/ykami/entry/dojox_mobile_pane_dojox_mobile_container_and_dojox_mobile_contentpane9">Dojo Mobile 1.8 Work-In-Progress</a></li> <li><a class="external" href="http://dojotoolkit.org/api/">Dojo Toolkit API</a></li> </ul>
</div>
<h4>MooTools Moobile</h4>
<p>The unofficial mobile framework of <a class="external" href="http://mootools.net">MooTools</a> is called <a class="external" href="http://moobilejs.com/">Moobile</a>. Moobile provides a mobile application boilerplate, as well as a host of simple mobile widgets.</p>
<div class="infoBlock"> <ul> <li><a class="link-https" href="https://github.com/cpojer/mootools-mobile">MooTools Mobile</a></li> <li><a class="external" href="http://mootools.net/docs/core">MooTools Documentation</a></li> <li><a class="external" href="http://mootools.net/forge/">MooTools Forge</a></li> </ul>
</div>
<p>Numerous other mobile JavaScript frameworks are available to aid the development of mobile web applications. When looking for a good mobile web app JavaScript framework, look for multi-device support, touch and gesture event support, and a unified API with its host framework.</p>
<p class="tutBlock">The web app built within this tutorial will utilize jQuery Mobile. Experiment and evaluate different mobile frameworks based on the goals of your app before selecting one (or deciding against using any at all). In many cases, a framework app will be save you time; in other cases, a framework could be overkill.</p>
<h3>CSS libraries, helpers, and techniques</h3>
<p>CSS plays an important role in any web-based technology. There are a variety of CSS libraries than may aid you in creating, maintaining, and organizing your CSS.</p>
<h4>CSS preprocessors</h4>
<p>While CSS is a simple language, its lack of variables and the need for repeated style assignments with vendor prefixes can make CSS difficult to maintain—a pain no mobile app developer needs. CSS preprocessors ease development of apps, allowing for better code organization and faster development.</p>
<p>With one of those CSS preprocessors, <a class="external" href="http://lesscss.org/">LESS</a>, CSS can be written like this:</p>
<pre class="brush: css">@someColor: #000; /* color var */

.rounded-corners (@radius: 5px) { /* function */
  border-radius: @radius;
  -webkit-border-radius: @radius;
  -moz-border-radius: @radius;
}

p {
  color: @someColor;
  a {
    color: #fff;
    background: @someColor;
    
    .rounded-corners;
  }
}
	</pre>
<p>This gets converted into the following by the LESS preprocessor:</p>
<pre class="brush: css">p { 
  color: #000;
}

p a {
  color: #fff;
  background: #000;
  border-radius: 5px;
  -webkit-border-radius: 5px;
  -moz-border-radius: 5px;
}
	</pre>
<p>While LESS is the most popular CSS preprocessor, <a class="external" href="http://sass-lang.com/">SASS</a> and <a class="external" href="http://learnboost.github.com/stylus/">Stylus</a> are also available.</p>
<h4>CSS3 techniques</h4>
<p>Web apps may take advantage of numerous CSS techniques which allow for enriched design and strategies for avoiding the need for imagery.</p>
<h5>Gradients</h5>
<p>CSS3 provides the ability to create <a href="/en/CSS/Using_CSS_gradients" title="en/CSS/Using_CSS_gradients">linear and radial gradients</a> with some simple CSS code:</p>
<pre class="brush: css">h1 { 
  background-image: -moz-linear-gradient(#6facd5, #497bae);
}
</pre>
<h5>Box and text shadows</h5>
<p><a href="/En/CSS/Box-shadow" title="En/CSS/Box-shadow">Box shadows</a> and <a href="/en/CSS/text-shadow" title="en/CSS/text-shadow">text shadows</a> provide a subtle depth enhancement to block elements and text:</p>
<pre class="brush: css">.shadower {
  -moz-box-shadow: 10px 5px 5px #000;
  text-shadow: 1px 1px 2px black, 0 0 1em blue, 0 0 0.2em blue;
  color: white;
  font: 1.5em Georgia, "Bitstream Charter", "URW Bookman L", "Century Schoolbook L", serif;
}
</pre>
<h5>Shapes with CSS</h5>
<p>CSS also provides the ability to cleverly create shapes likes triangles and circles:</p>
<pre class="brush: css">.arrowRight {
  width:0px; 
  height:0px; 
  border-bottom:5px solid transparent;
  border-top:5px solid transparent;
  border-left:5px solid #2f2f2f;
  font-size:0px;
  line-height:0px;
}

.circle {
  border-radius: 50%;
  width: 200px;
  height: 200px;
}
</pre>
<h4>Creating responsive layouts</h4>
<p>Coding responsive layouts is paramount to creating flexible apps that will work on multiple devices and in multiple orientations. The following are some techniques for creating such a design.</p>
<div class="tutBlock"> <h5>Our desktop layout</h5> <p><img alt="desktop-screenshot1.png" class="internal default" src="/@api/deki/files/6277/=desktop-screenshot1.png" style=""></p> <h5>Our mobile device &amp; phone layouts</h5> <p style="width: auto;"><img alt="iphone-screenshot1.png" class="internal default" src="/@api/deki/files/6278/=iphone-screenshot1.png">     <img alt="iphone-screenshot2.png" class="internal default" src="/@api/deki/files/6279/=iphone-screenshot2.png"></p>
</div>
<h5>Percentage widths</h5>
<p>Fixed pixel widths should rarely be used; percentage widths are preferred as they let elements adjust to device viewport dimensions. Fixed widths (and heights) should generally be used only for small, genuinely fixed-sized items.</p>
<h5>Viewport size-dependent element display</h5>
<p>Showing and hiding elements based on viewport size is a common practice. Instead of cramming a lot of content into a smaller space, or changing an app's design completely, simply hiding those "supporting" elements may be the best option.</p>
<h5>Viewport size-dependent imagery</h5>
<p>Adapting image sizes to the device viewport size is also a common practice, making vector images (using <a href="/en/SVG" title="en/SVG">SVG</a>, for example) the best practice for your web app.</p>
<h5>Media queries</h5>
<p><a href="/en/CSS/Media_queries" title="en/CSS/Media_queries">CSS media queries</a> let developers adjust layout and element styles to viewport size, orientation, aspect ratio, and more:</p>
<pre class="brush: css">/* screen size media queries */
@media only screen and (min-device-width : 768px) and (max-device-width : 1024px) {

}


/* orientation media queries */
@media (orientation:portrait) {

}
@media (orientation:landscape) {

}

/* advanced media query usage */
@media all and (max-width: 699px) and (min-width: 520px), (min-width: 1151px) {

}

/* aspect ratio */
@media screen and (device-aspect-ratio: 16/9) {

}
</pre>
<h5><code>orientationchange</code> and <code>resize</code> events</h5>
<p>Orientation changes may also be detected with JavaScript. Most browsers fire an <code>orientationchange</code> event while all browsers are known to fire the <code>resize</code> event.</p>
<pre class="brush: js">window.addEventListener("resize", function() { 
  // Detect orientation based on width
  var orientation = window.innerWidth &gt; window.innerHeight ? "landscape" : "portrait";
  
  // Execute more code accordingly...
}, false);

</pre>
<h3>Web app bootstraps</h3>
<p>Server side processing of information happens on the app host's servers, so any server side technology may be used. Popular server side languages include PHP, Python, and <a class="external" href="http://nodejs.org/">NodeJS</a> + <a class="external" href="http://expressjs.com/">express</a>. There's a likelihood that your application will want to implement <a href="/en/BrowserID" title="en/BrowserID">BrowserID</a> for app sign in; you can find the code required to implement BrowserID on <a href="/en/BrowserID" title="en/BrowserID">MDN</a>.</p>
<h3>App manifests</h3>
<p>Apps submitted to the Mozilla Marketplace require an <a href="/en/Apps/Manifest" title="en/Apps/Manifest">application manifest</a>. This manifest contains basic information that a web browser needs to interact with an app. Manifests are written in <a href="/en/JSON" title="en/JSON">JSON</a> syntax; a sample manifest could look like:</p>
<pre>{
  "version": "0.1",
  "name": "Area Tweet",
  "description": "Find tweets by for any location",
  "icons": {
    "16": "http://areatweet.com/images/icon-16.png",
    "48": "http://areatweet.com/images/icon-48.png",
    "128": "http://areatweet.com/images/icon-128.png"
  },
  "developer": {
    "name": "David Walsh",
    "url": "http://areatweet.com"
  },
  "installs_allowed_from": [
    "https://marketplace.mozilla.org",
    "http://areatweet.com"
  ],
  "default_locale": "en"
}</pre>
<p>The application manifest lives on the host server, <strong>not the Mozilla Marketplace</strong>. It's recommended that your manifest be saved with a <code>.webapp</code> extension and served with a <code>Content-Type</code> <a href="/en/HTTP" title="en/HTTP">HTTP</a> header of <code>application/x-web-app-manifest+json</code> via HTTPS.</p>
<p class="callout">A complete listing of all manifest properties can be <a href="/en/Apps/Manifest" title="en/Apps/Manifest">found here</a>. There's also a <a href="/en/Apps/FAQs/About_app_manifests" title="en/Apps/FAQs/About_app_manifests">Frequently Asked Questions</a> document which provides tips for creating your manifest and explanations for why the manifest hosting process is the way it is.</p>
<p class="callout">It's best to use absolute paths within the manifest, even for images. The Mozilla Marketplace will not currently accept manifests with relative paths.</p>
<h2>AppCache manifests</h2>
<p class="todo">See <a href="/en/HTML/Using_the_application_cache" title="en/Using_Application_Cache">Using the application cache</a> for details.</p>
<div class="tutBlock"> <h2>Creating the Area Tweet app</h2> <p>With all of the design goals and coding standards laid out, it's time to get into the coding of our app. As with any web application template, we need an HTML page with the HTML5 doctype, {{ HTMLElement("head") }}, and {{ HTMLElement("body") }} elements:</p> <pre class="brush: html">&lt;!doctype html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;title&gt;&lt;/title&gt;
 
  &lt;meta charset="utf-8" /&gt;
  &lt;meta http-equiv="content-type" content="text/html; charset=UTF-8" /&gt;
 
  &lt;meta name="viewport" content="width=device-width, initial-scale=1"&gt;
 
  &lt;!-- stylesheets go here --&gt;
 
&lt;/head&gt;
&lt;/html&gt;
&lt;body&gt;
 
  &lt;!-- HTML app structure goes here --&gt;
 
 
  &lt;!-- javascript goes here --&gt;
 
&lt;/body&gt;
&lt;/html&gt;</pre> <p>We'll be using jQuery Mobile as the JavaScript framework; that means we must pull in the CSS and JavaScript resources required by jQuery Mobile:</p> <pre class="brush: html">&lt;!-- stylesheets --&gt;
&lt;link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" /&gt;
	
&lt;!-- scripts --&gt;
&lt;script src="http://code.jquery.com/jquery-1.7.1.min.js"&gt;&lt;/script&gt;
&lt;script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"&gt;&lt;/script&gt;
</pre> <p>With our basic application boilerplate and jQuery Mobile resource in place, it's time to add content and widgets to the page. Since we've decided on using jQuery Mobile for our application framework, our app's HTML structure will follow their prescribed widget structures. The first pane provides a search box and a history list:</p> <pre class="brush: html">&lt;!-- home pane --&gt;
&lt;div data-role="page" id="home"&gt;
 
  &lt;div data-role="header"&gt;
    &lt;h1&gt;Area Tweet&lt;/h1&gt;
  &lt;/div&gt;
 
  &lt;div data-role="content"&gt;
    
    &lt;div class="ui-body ui-body-b"&gt;
      &lt;h2&gt;Location Search&lt;/h2&gt;
      &lt;form id="locationForm"&gt;
        &lt;input type="search" name="location" id="locationInput" placeholder="Your Location" /&gt;
        &lt;button type="submit" data-role="button" data-theme="b"&gt;Search&lt;/button&gt;
      &lt;/form&gt;
    &lt;/div&gt;
    
    &lt;div id="prevLocationsContainer" class="opaque"&gt;
      &lt;h2&gt;
        Previous Locations
        &lt;a href="#" id="clearHistoryButton" data-role="button" data-icon="delete" data-iconpos="notext"
                data-theme="b" data-inline="true" style="top: 5px;"&gt;Clear History&lt;/a&gt;
      &lt;/h2&gt;
      &lt;ul id="prevLocationsList" data-role="listview" data-inset="true" data-filter="true"&gt;&lt;/ul&gt;
    &lt;/div&gt;
    
  &lt;/div&gt;
&lt;/div&gt;</pre> <p>There are a few things to notice with the code above:</p> <ul> <li>The structure of the HTML5 sticks to semantics; that ensures maximum accessibility.</li> <li>As with any web-based app, we assign CSS classes and IDs to elements we'll want styled and access to from JavaScript code.</li> </ul> <p class="callout">If you have questions about individual jQuery mobile functionalities, node attributes, or structures, please consult the <a class="external" href="http://jquerymobile.com/demos">jQuery Mobile Documentation</a>.</p> <p>The second pane will be used for displaying a list of tweets:</p> <pre>&lt;!-- tweets pane --&gt;
&lt;div data-role="page" id="tweets"&gt;
 
  &lt;div data-role="header"&gt;
    &lt;a href="#home" id="tweetsBackButton"&gt;Back&lt;/a&gt;
    
    &lt;h1&gt;&lt;span id="tweetsHeadTerm"&gt;&lt;/span&gt; Tweets&lt;/h1&gt;
  &lt;/div&gt;
 
  &lt;ul id="tweetsList" data-role="listview" data-inset="true"&gt;&lt;/ul&gt;
 
&lt;/div&gt;</pre> <p>Our web app's CSS contains a CSS animation for fading in any element, as well as overriding jQuery Mobile styles, and general element styling.</p> <pre>/* animations */
@-moz-keyframes fadeIn {
  0%    { opacity: 0; }
  100%  { opacity: 1; }
}
@-webkit-keyframes fadeIn {
  0%    { opacity: 0; }
  100%  { opacity: 1; }
}

.fadeIn {
  -moz-animation-name: fadeIn;
  -moz-animation-duration: 2s;
 
  -webkit-animation-name: fadeIn;
  -webkit-animation-duration: 2s;
 
  opacity: 1 !important;
}

/* Custom CSS classes */
.clear        { clear: both; }
.hidden       { display: none; }
.opaque       { opacity: 0; }


/* Basic styling */
#prevLocationsContainer { margin-top: 40px; }

/* Customizing jQuery Styles */
#tweetsList li.ui-li-divider,
#tweetsList li.ui-li-static     { font-weight: normal !important; }


/* Tweet list */
#tweetsList li {
 
}

#tweetsList li .tweetImage {
  float: left;
  margin: 10px 10px 0 10px;
}

#tweetsList li .tweetContent {
  float: left;
  /* margin: 10px 0 0 0; */
}

#tweetsList li .tweetContent strong {
  display: block;
  padding-bottom: 5px;
}

/* Media Queries for device support */
@media screen and (max-device-width: 480px) {
  #prevLocationsContainer { margin-top: 10px; }
}</pre> <p>JavaScript is the last major component to add to our web app. The following encompasses all of the functionality for the app:</p> <pre>$(document).ready(function() {
 
  // Start from scratch on page load
  if(window.location.hash) {
    window.location = "index.html";
  }
 
  // Feature tests and settings
  var hasLocalStorage = "localStorage" in window,
    maxHistory = 10;
 
  // List of elements we'll use
  var $locationForm = $("#locationForm"),
    $locationInput = $("#locationInput"),
    
    $prevLocationsContainer = $("#prevLocationsContainer"),
    
    $tweetsHeadTerm = $("#tweetsHeadTerm"),
    $tweetsList = $("#tweetsList");
    
  // Hold last request jqXHR's so we can cancel to prevent multiple requests
  var lastRequest;
 
  // Create an application object
  app = {
    
    // App initialization
    init: function() {
      var self = this;
      
      // Focus on the search box
      focusOnLocationBox();
      
      // Add the form submission event
      $locationForm.on("submit", onFormSubmit);
      
      // Show history if there are items there
      this.history.init();
      
      // When the back button is clicked in the tweets pane, reset the form and focus
      $("#tweetsBackButton").on("click", function(e) {
        $locationInput.val("");
        setTimeout(focusOnLocationBox, 1000);
      });
      
      // Geolocate!
      geolocate();
      
      // When the tweets pane is swipe, go back to home
      $("#tweets").on("swiperight", function() {
        window.location.hash = "";
      });
      
      // Clear history when button clicked
      $("#clearHistoryButton").on("click", function(e) {
        e.preventDefault();
        localStorage.removeItem("history");
        self.history.hideList();
      })
    },
    
    // History modules
    history: {
      $listNode: $("#prevLocationsList"),
      $blockNode: $("#homePrev"),
      init: function() {
        var history = this.getItemsFromHistory(),
          self = this;
        
        // Add items to the list
        if(history.length) {
          history.forEach(function(item) {
            self.addItemToList(item);
          });
          self.showList();
        }
        
        // Use event delegation to look for list items clicked
        this.$listNode.delegate("a", "click", function(e) {
          $locationInput.val(e.target.textContent);
          onFormSubmit();
        });
      },
      getItemsFromHistory: function() {
        var history = "";
        
        if(hasLocalStorage) {
          history = localStorage.getItem("history");
        }
        
        return history ? JSON.parse(history) : [];
      },
      addItemToList: function(text, addToTop) {
        var $li = $("&lt;li&gt;&lt;a href='#'&gt;" + text + "&lt;/a&gt;&lt;/li&gt;"),
          listNode = this.$listNode[0];
          
        if(addToTop &amp;&amp; listNode.childNodes.length) {
          $li.insertBefore(listNode.childNodes[0]);
        }
        else {
          $li.appendTo(this.$listNode);
        }
        
        this.$listNode.listview("refresh");
      },
      addItemToHistory: function(text, addListItem) {
        var currentItems = this.getItemsFromHistory(),
          newHistory = [text],
          self = this,
          found = false;
        
        // Cycle through the history, see if this is there
        $.each(currentItems, function(index, item) {
          if(item.toLowerCase() != text.toLowerCase()) {
            newHistory.push(item);
          }
          else {
            // We've hit a "repeater"; signal to remove from list
            found = true;
            self.moveItemToTop(text);
          }
        });
        
        // Add a new item to the top of the list
        if(!found &amp;&amp; addListItem) {
          this.addItemToList(text, true);
        }
        
        // Limit history to 10 items
        if(newHistory.length &gt; maxHistory) {
          newHistory.length = maxHistory;
        }
        
        // Set new history
        if(hasLocalStorage) {
          // Wrap in try/catch block to prevent mobile safari issues with private browsing
          // http://frederictorres.blogspot.com/2011/11/quotaexceedederr-with-safari-mobile.html
          try {
            localStorage.setItem("history", JSON.stringify(newHistory));
          }
          catch(e){}
        }
        
        // Show the list
        this.showList();
      },
      showList: function() {
        $prevLocationsContainer.addClass("fadeIn");
        this.$listNode.listview("refresh");
      },
      hideList: function() {
        $prevLocationsContainer.removeClass("fadeIn");
      },
      moveItemToTop: function(text) {
        var self = this,
          $listNode = this.$listNode;
        
        $listNode.children().each(function() {
          if($.trim(this.textContent.toLowerCase()) == text.toLowerCase()) {
            $listNode[0].removeChild(this);
            self.addItemToList(text, true);
          }
        });
        
        $listNode.listview("refresh");
      }
    }
    
  };
 
  // Search submission
  function onFormSubmit(e) {
    if(e) e.preventDefault();
    
    // Trim the value
    var value = $.trim($locationInput.val());
    
    // Move to the tweets pane
    if(value) {
      
      // Add the search to history
      app.history.addItemToHistory(value, true);
      
      // Update the pane 2 header
      $tweetsHeadTerm.html(value);
      
      // If there's another request at the moment, cancel it
      if(lastRequest &amp;&amp; lastRequest.readyState != 4) {
        lastRequest.abort();
      }
      
      // Make the JSONP call to Twitter
      lastRequest = $.ajax("http://search.twitter.com/search.json", {
        cache: false,
        crossDomain: true,
        data: {
          q: value
        },
        dataType: "jsonp",
        jsonpCallback: "twitterCallback",
        timeout: 3000
      });
    }
    else {
      // Focus on the search box
      focusOnLocationBox();
    }
    
    return false;
  }
 
  // Twitter reception
  window.twitterCallback = function(json) {
    
    var template = "&lt;li&gt;&lt;img src='{profile_image_url}' class='tweetImage' /&gt;&lt;div class='tweetContent'&gt;"
                   +"&lt;strong&gt;{from_user}&lt;/strong&gt;{text}&lt;/div&gt;&lt;div class='clear'&gt;&lt;/div&gt;&lt;/li&gt;",
      tweetHTMLs = [];
      
    // Basic error handling
    if(json.error) { // Error for twitter
      showDialog("Twitter Error", "Twitter cannot provide tweet data.");
      return;
    }
    else if(!json.results.length) { // No results
      showDialog("Twitter Error", "No tweets could be found in your area.");
      return;
    }
    
    // Format the tweets
    $.each(json.results, function(index, item) {
      item.text = item.text.
            replace(/(https?:\/\/\S+)/gi,'&lt;a href="$1" target="_blank"&gt;$1&lt;/a&gt;').
            replace(/(^|\s)@(\w+)/g,'$1&lt;a href="http://twitter.com/$2" target="_blank"&gt;@$2&lt;/a&gt;').
            replace(/(^|\s)#(\w+)/g,'$1&lt;a href="http://search.twitter.com/search?q=%23$2" target="_blank"&gt;#$2&lt;/a&gt;')
      tweetHTMLs.push(substitute(template, item));
    });
    
    // Place tweet data into the form
    $tweetsList.html(tweetHTMLs.join(""));
    
    // Refresh the list view for proper formatting
    try {
      $tweetsList.listview("refresh");
    }
    catch(e) {}
    
    // Go to the tweets view
    window.location.hash = "tweets";
  };
 
  // Template substitution
  function substitute(str, obj) {
    return str.replace((/\\?\{([^{}]+)\}/g), function(match, name){
      if (match.charAt(0) == '\\') return match.slice(1);
      return (obj[name] != null) ? obj[name] : "";
    });
  }
 
  // Geolocates the user
  function geolocate() {
    if("geolocation" in navigator) {
      // Attempt to get the user position
      navigator.geolocation.getCurrentPosition(function(position) {
        // Set the address position
        if(position.address &amp;&amp; position.address.city) {
          $locationInput.val(position.address.city);
        }
      });
    }
  }
 
  // Focuses on the input box
  function focusOnLocationBox() {
    $locationInput[0].focus();
  }
 
  // Modal function
  function showDialog(title, message) {
    $("#errorDialog h2.error-title").html(title);
    $("#errorDialog p.error-message").html(message);
    $.mobile.changePage("#errorDialog");
  }
 
  // Init the app
  app.init();
 
});</pre> <p>I wont go over every part of the app's JavaScript, but a few items are worth pointing out:</p> <ul> <li>The script above uses feature testing for both <code>localStorage</code> and <code>geolocation</code>. The app wont attempt to use either feature it they aren't present in the browser.</li> <li>The <code>geolocation</code> API is used to detect the user's current location and the <code>localStorage</code> API is used to keep the user's search history</li> <li>The application JavaScript has been written modularly for easier testing</li> <li>A swipe event is listened for on the tweet pane; when the pane is swiped, the user taken back to the first pane</li> <li>Twitter is the source of all data; no custom server side processing is included for this app</li> </ul>
</div>
<h2>Testing the app</h2>
<p>App testing is of immense importance, especially when supporting multiple platforms and devices. The number of tests and types of testing needed depend on the devices and platforms supported. Test types include:</p>
<ul> <li>Speed</li> <li>Performance efficiency</li> <li>Input and output validation</li> <li>Touch and interactivity</li>
</ul>
<p>While those are the basic test types, there are more ideas to consider while testing.</p>
<h3>Web environment differences</h3>
<p>Here are some things to keep in mind when dealing with different web environments:</p>
<h4>Vendor prefixes</h4>
<p>Both advanced JavaScript and CSS features within browsers may be vendor prefixed with <code>-webkit</code>, <code>-moz</code>, <code>-o</code>, or <code>-ms</code>. Know the environments you plan to use and prefix features appropriately.</p>
<div class="note"><strong>N<strong>ote:</strong></strong> You should try to avoid using features that are only available on certain devices, unless you either provide appropriate fallbacks or specifically intend your app to be used on a more limited set of devices.</div>
<h4>Feature detection</h4>
<p>Some environments will support a specific feature, others may not. Feature detection is the best way of knowing which tools are available for a given platform. For example, to detect support of the <a href="/En/Using_geolocation" title="en/Using_geolocation">Geolocation</a> API, you would code:</p>
<pre class="brush: js">if("geolocation" in navigator) {
  // Geolocation available, use it!
}
</pre>
<p><a class="external" href="http://caniuse.com/">CanIUse.com</a> provides detailed tables of browser and device support for specific features. A helping library like <a class="external" href="http://modernizr.com/">Modernizr</a> automatically detects features upon page load and provides that information accordingly.</p>
<h4>Responsive design</h4>
<p>Using media queries and foresight in design will prevent design issues. Common pitfalls include not using vector graphics for elements which may grow or shrink, using fixed-dimension elements throughout all devices, not testing different orientations, and simply not looking at your app at different resolutions. Services like <a class="external" href="http://quirktools.com/screenfly/">Screenfly</a> and <a class="external" href="http://responsivepx.com/">responsivepx</a> help aid in testing an app at different sizes, but there's no substitute for having a supported device handy for manual testing.</p>
<p>Consider also the problems that can arise when different devices have different screen resolutions. A case in point: the problems that cropped up when Apple introduced the third-generation iPad, with its new 2048x1536 display:</p>
<ul> <li>New York Times: <a class="external" href="http://bits.blogs.nytimes.com/2012/03/21/ipad-web-retina/" title="http://bits.blogs.nytimes.com/2012/03/21/ipad-web-retina/">Is The New iPad Screen Too Good For The Web?</a></li> <li>Net Magazine: <a class="external" href="http://www.netmagazine.com/news/web-devs-battle-new-ipad-s-retina-display-121859" title="http://www.netmagazine.com/news/web-devs-battle-new-ipad-s-retina-display-121859">Web devs battle new iPad's Retina Display</a></li>
</ul>
<h4>Unit testing</h4>
<p>Unit testing is a common practice in all walks of development, and web app testing is no different. Unit testing of CSS and JavaScript is also incredibly easy when an application is coded in a modular fashion. Popular JavaScript unit testing frameworks include <a class="external" href="http://pivotal.github.com/jasmine/">Jasmine</a>, <a class="external" href="http://docs.jquery.com/QUnit">QUnit</a>, and <a class="external" href="http://yuilibrary.com/yui/docs/test/">YUI Test</a>. Each unit testing website provides code samples for how to use their test framework.</p>
<h4>Performance</h4>
<p>Performance testing can be difficult to prescribe since it's wholly dependent upon the tasks performed by the app. Basic web coding principles like minimizing HTTP requests (JavaScript concatenation or CSS sprites help), JS and CSS minification, placing scripts at the bottom of the page, and properly setting Expires headers all apply. The YSlow team provides more <a class="external" href="http://yslow.org/">helpful web performance best practices</a> to follow, all of which will enhance your web app. The <a class="external" href="http://www.html5rocks.com/" title="http://www.html5rocks.com/">HTML5Rocks</a> website also provides a list of <a class="external" href="http://www.html5rocks.com/en/features/performance">performance best practices</a>.</p>
<h2>Publishing your app</h2>
<h3>Deployment</h3>
<p>Once you’ve finished your app, host it on a publicly accessible web server like any other website. There are numerous ways to deploy your app.</p>
<h4>GitHub</h4>
<p>If the web app is purely static (HTML/CSS/JavaScript, but no server scripting), <a class="external" href="http://pages.github.com/">GitHub Pages</a> is a solid hosting option. Cloud storage service <a class="external" href="http://www.dropbox.com/" title="http://www.dropbox.com/">Dropbox</a> can also <a class="external" href="http://lifehacker.com/5528104/use-dropbox-to-share-and-host-your-web-site">be used for this purpose</a>.</p>
<h4>Generic hosting solutions</h4>
<p>For dynamic websites, use a generic hosting option (like a web server you may already own or have access to) with the right capabilities or a hosting provider specifically tailored to the needs of your app, like <a class="external" href="http://www.heroku.com/">Heroku</a> or <a class="external" href="http://code.google.com/appengine/">Google App Engine</a>.</p>
<h3>Publishing</h3>
<p>Once your web app has been deployed, you obviously want to make it installable by your intended user base. There are two options for publishing your app.</p>
<h4>Publish on your website</h4>
<p>If you want to let people install your app from a website you own, you must <a href="/en/Apps/Apps_JavaScript_API" title="en/Apps/Apps_JavaScript_API">implement some JavaScript code</a> on your web site to manage installing and updating your app into users' browsers.</p>
<h4>Submit to Mozilla Marketplace</h4>
<p><a class="link-https" href="https://marketplace.mozilla.org/en-US/developers/submit/app">Submitting your app</a> to the Mozilla Marketplace method has many advantages, such as increased publicity, no need to implement special APIs on your own web site, and the possibility of publishing paid apps more easily.</p>
<h2>Maintaining your app</h2>
<p>Managing and maintaining your web app is as important as releasing it. Bugs will pop up, users will request more features, and over time, new devices will be released and their software updated.</p>
<h3>App update process</h3>
<p class="todo"><strong>This section needs to be written once the marketplace is closer to complete.</strong></p>
<h3>Receiving and responding to user feedback</h3>
<p>Receiving and responding to user feedback is an integral part of engaging users. User feedback provides invaluable insight into:</p>
<ul> <li>what the general reception of the app is</li> <li>criticisms of the app</li> <li>ideas for improvement and feature requests</li> <li>device-specific bugs</li>
</ul>
<p>The right response can illicit buzz and faithfulness from app purchasers; an unprofessional or negative response can ruin your chance to fix app problems.</p>
<h3>App refunds</h3>
<p>Mozilla Marketplace users are entitled to refunds within 30 minutes of purchases. After that 30 minutes, developers can review refund requests on an individual basis. Read the <a href="/en/Apps/Marketplace_Payments/FAQ#Refunds" title="en/Apps/Marketplace_Payments/FAQ#Refunds">Marketplace Payments FAQ</a> for more information about payments and refunds.</p>
<h2>Profiting from your web app</h2>
<p>Creating web apps is also a great way to turn your passion into revenue!</p>
<h3>Mozilla Marketplace</h3>
<p>The <a class="link-https" href="https://marketplace.mozilla.org/en-US/">Mozilla Marketplace</a> is an outstanding marketplace for web app developers. The Mozilla Marketplace supports both paid and free apps, in-app purchasing, a variety of device platform apps, and more. The Mozilla Marketplace provides competitive pricing and offers consumers a variety of payment methods. Read the <a href="/en/Apps/Marketplace_Payments" title="en/Apps/Marketplace_Payments">Marketplace Payments FAQ</a> to learn more about monetizing your app on the Mozilla Marketplace.</p>
<h4>In-app payments</h4>
<p>In-App payments are another way to monetize your app with the added bonus of enhancing an existing app instead of requiring the user to add purchase a new one. Mozilla's in-app payment model works very similarly to <a class="link-https" href="https://developers.google.com/in-app-payments/docs/">Google's In-Apps Payments</a> system. This system flows as follows:</p>
<ul> <li>The app initiates a payment by signing a JWT request and calling a JavaScript function</li> <li>This starts the buyflow in a lightbox (served from an {{ HTMLElement("iframe") }}) <ul> <li>The buyer logs in with Mozilla Persona (formerly called BrowserID)</li> <li>The buyer completes the purchase</li> </ul> </li> <li>The app receives a JavaScript callback when the buyer closes the window</li> <li>The app server receives a signed <code>POST</code> request with a Mozilla transaction ID indicating that the purchase was completed successfully</li>
</ul>
<p>The Mozilla Marketplace provides a JavaScript utility library to aid in this process.</p>
<p class="callout">The <a href="/en/Apps/In-app_payments" title="en/Apps/In-app_payments">In-App Payments FAQ</a> provides a wealth of information on how in-app payments work and sample code for implementation. Keep this reference handy as the in-app payment process is currently in an experimental state.</p>
<h4>Third party payment providers</h4>
<p class="todo"><strong>What does this refer to? PayPal? Bank processors? ¿Que?</strong></p>
<h2>Create your web app!</h2>
<p>Using open web technologies to create rich, powerful applications for numerous devices is a fun, rewarding, and potentially profitable process. The open web provides the tools needed to make app creation possible, while Mozilla provides an excellent marketplace for showcasing and distributing your app. Use the information provided within this document to create your incredible app and share it with the world!</p>
<p class="callout">You can see a live demonstration of the app we created in this tutorial by visiting <a class="external" href="http://areatweet.com">AreaTweet.com</a> Want to install it on your desktop or mobile device? You can <a class="link-https" href="https://marketplace.mozilla.org/en-US/app/area-tweet/">download it for free</a> in the Mozilla Marketplace!</p>
Revert to this revision