Posted by: digdug2k | August 11, 2014

Playing with WebComponents

I’ve been meaning to do some more random blogs lately, so this will hopefully be the start of that. I spent a bit of time lately playing with WebComponents. I always really loved XBL. The idea of shipping small compartmentalized widgets for the web is probably one of the things that made me most interested in the web to begin with. I’ve been pretty excited to see what the follow up was (and frustrated that XBL never got the love it deserved, and even more frustrated to see XBL2 get made fun of while at the same time everyone tried to replicate it).

Polymer

Turns out, its kinda hard to figure out what web components are right now anyway! When I started searching for some examples, right now you’ll be overcome with results pointing to Polymer components. i.e a really basic example looks something like:

<polymer-element name="my-counter" attributes="counter">
  <template>
    <style> /*...*/ </style>
    <div><content></content></div>
  </template>
  <script>
    Polymer({
      counter: 0, // Default value
    });
  </script>
</polymer-element>

Surprised? Probably not, but I was. What is the word polymer doing all over this content? What is this “Polymer” method that’s being called? I thought Polymer was a POLY-fill, hence its name. Turns out its not (anymore?). Now its just some sort of framework on top of a polyfill? A shim?

I was a bit frustrated at this point, as I really just wanted to write something standard and know that it would fallback gracefully as browser support came out. I also wanted to learn the WebComponents spec, not some shim on top of it. So I tossed that aside and glanced at a few other projects I thought were aiming to do the same thing.

X-Tag

First Mozilla’s x-tag. I haven’t heard anything about x-tag in a long time, so i assumed it was dead. The site’s still there though, and, even though the blog posts are a bit old, I didn’t see any “This is deprecated warnings”. Glancing a little harder, I did see that they had given up on writing their own polyfill at some point, and had fallen back to using some of Polymer’s code. Unfortunately, the API STILL looks like its actually a shim on top of that polyfill. Not what I quite wanted:

xtag.register('x-accordion', {
  extends: 'div',
  lifecycle:{
    created: function(){ },
    inserted: function(){ },
    removed: function(){ },
    attributeChanged: function(){ }
  },
  events: { },
  accessors: {
  },
  methods: {
  }
});

At this point I actually gave up. I decided that x-tag was the simplest solution I knew of, and decided to just use it. A single file to import, and I’d be done. The API looks nothing, nothing, NOTHING, like what I thought WebComponents should look like, but neither did Polymer’s. So on I charged. I actually converted a chunk of my project, graph.js, to use it. But I recently stumbled on webcomponents.org and thought it would be fun to upload this stuff there once I have it working using the real standard. With that in mind, I decided to try again to convert over to the real spec.

Brick

The only other work I’ve really heard about in this area is Mozilla’s Brick, which isn’t really a polyfill, but just a set of components you could use if you had a polyfill. A little digging there told me they were actually using the core part of Polymer that I hadn’t found before. A file hidden in the bowels of Polymer named platform.js.

This seemed really promising, I opened some Brick files and started editing a bit trying to get things into the shape I wanted. Brick’s code looks like:

<template>
  <style></style>
  <content></content>
</template>

<script src="something.js"></script>

The old spec

These Brick files are actually very close the spec, but I didn’t know that at the time. You see, the w3c actually hosts a nice set of WebComponent examples already. If you glance at them, they look like:

<element extends="table" name="x-table-chart" constructor="TableChart">
    <script>
        this.lifecycle({
                    created: function(shadowRoot) { },
                    inserted: function() { },
                    removed: function() { }
        });

        TableChart.prototype.draw = function() { }

        this.reflectAttribute('x-chart-type', 'chartType', TableChart.prototype.draw);
        this.reflectAttribute('x-chart-color', 'chartColor', TableChart.prototype.draw);
        this.setupEvent('draw');
    </script>
    <template>
        <canvas></canvas>
    </template>
</element>

Notice the <element> tag wrapping everything, and the use of some special functions inside the element tag (i.e. lifecycle, reflectAttribute, and setupEvent). It also has some attributes to declare the node name and its constructor. This all makes sense to me at a glance. I assumed there’d be some sort of warning at the top if it was seriously deprecated. I was wrong about that.

After trying to hack my code into using platform.js for a bit and then trying to hack the W3C false-example code above into working with it, I was again frustrated. After a long battle, I glanced at the script file in the Brick demos a little harder and noticed things like:

BrickDeckElementPrototype.attachedCallback = function() {
    var importDoc = currentScript.ownerDocument;
    var template = importDoc.querySelector('template');

    // create shadowRoot and append template to it.
    var shadowRoot = this.createShadowRoot();
    shadowRoot.appendChild(template.content.cloneNode(true));
};

It looks like Brick is doing all the work I basically thought WebComponents was supposed to do for me. i.e. Its mirroring the template into its parent manually. Its even creating the ShadowDOM AND ShadowCSS manually! What? What in the world is platform.js good for then?

polyfill.js

I got really frustrated. All these polyfills, and none of them seemed to support the standard in any way. Last night, I got really angry and decided to write my own polyfill for the <element> node above. Turns out, its not that hard. I don’t even need that polyfill to be “good”. I just wanted something general enough to know my components would work. A few hours later I had a file named polyfill.js working pretty well.

At that point I started firming up polyfill.js a little bit. I opened the actual specs and implemented a bunch of easy link[rel="import"] behaviors (and a native fallback if available). I then started looking for things like the <element> node or the life cycle object, and realized they don’t exist there. Turns out, the example code I had found was old, and drastically out of date.

I had been avoiding simple task until this point, reading some HTML5 Rocks articles on WebComponents. HTML5Rocks is basically a site for Google PR. Up until this point, I had assumed the articles there would basically be “Use Polymer! Its great!” Happily these aren’t.

So one of these articles has, carefully buried at the bottom, a comment about the old <element> syntax, essentially pointing out that its deprecated. The new WebComponents syntax looks a whole lot like whats in the Brick code above. There are a few pieces available to you:

The Shadow DOM
This is the spec I care about LEAST, so I haven’t bothered tor read much of it. I assume its a lot like Anonymous content in XBL. i.e. Nodes that are in the document, but that don’t show up in your normal walking of the tree. From what little I’ve read, there’s been some hard work here to make sure components are encapsulated so that CSS and JS don’t affect the main document. There’s also a strange bit here, where every node can contain a “shadow-root”, which is the start of its internal content (unless you decide to not use the ShadowDOM at all). It seems a bit silly and redundant to me to have that shadow-root. Your markup moves one level deeper with no significant gain. But I assume there was a long debate and people agreed it was necessary at some point.
Custom elements

This is the heart of the WebComponents that I cared about. Its basically a way to “register” a new node “type” with the DOM. i.e. you call

document.registerElement(name, { prototype: something })

Every time a node is created that says it “is” whatever your node name is, your prototype will be applied. Your prototype can also include methods like createdCallback, attachedCallback, detachedCallback, or attributeChangedCallback, which will be hit when those things happen (why they decided to use the terms “attached” and “detached” is confusing to me, since they don’t really appear anywhere else in the DOM).

HTML Imports
HTML Imports it turns out, don’t really do that much. They just pull in some HTML, and if its a script, they execute it in the context of this page’s document. They’re a handy way to encapsulate a bunch of scripts, css, and html in a single document.

I like this separation. I like that this stuff is low level. In fact, it would be neat to see it go evern lower level. It means you can build shims on top of the setup if you want. You don’t have to use imports if you don’t want. You don’t have to use the ShadowDOM if you don’t want. Things like Polymer or x-tags if it was still alive could build abstractions on top if they want. Its neat, clean, and fairly low-level. Its the way I wish web apis were built more often. I tinkered around in the web-screens spec recently this year, and got fairly frustrated with it for NOT being low level.

With some new knowledge, I went back to my polyfill and made the changes to work with this syntax. It actually works pretty well right now. As I said earlier, I don’t intend to support the ShadowDOM much. I don’t need it here (although I do support creating a shadow root node). My polyfill is up on github at polyfill.js. graph.js is completely broken right now, but I think I’ll port it over. I should at this point try to make platform.js work instead, but quickly flipping it on resulted in some strange errors. Debugging is painful enough that I haven’t started yet. Feel free to use/alter/patch/whatever you need. I have a feeling there are much better ways to do some things like attaching a prototype to a node), but this is VooDoo no matter how you do it now.

Posted by: digdug2k | July 30, 2014

Better tiles in Fennec

We recently reworked Firefox for Android‘s homescreen to look a little prettier on first-run by shipping “tile” icons and colors for the default sites. In Firefox 33, we’re allowing sites to designate their own tiles images by supporting  msApplication-Tile and Colors in Fennec. So, for example, you might start seeing tiles that look like:

appear as you browse. Sites can add these with just a little markup in the page:

<meta name="msapplication-TileImage" content="images/myimage.png"/>
<meta name="msapplication-TileColor" content="#d83434"/>

As you can see above in the Boston Globe tile, sometimes we don’t have much to work with. Firefox for Android already supports the sizes attribute on favicon links, and our fabulous intern Chris Kitching improved things even more last year. In the absence of a tile, we’ll show a screenshot. If you’ve designated that Firefox shouldn’t cache the content of your site for security reasons, we’ll use the most appropriate size we can find and pull colors out of it for the background. But if sites can provide us with this information directly its 1.) must faster and 2.) gives much better results.

AFAIK, there is no standard spec for these types of meta tags, and none in the works either. Its a bit of the wild wild west right now. For instance, Apple supports apple-mobile-web-app-status-bar-style for designating the color of the status bar in certain situations, as well as a host of images for use in different situations.

Opera at one point supported using a minimized media query to designate a stylesheet for thumbnails (sadly they’ve removed all of those docs, so instead you just get a github link to an html file there). Gecko doesn’t have view-mode media query support currently, and not many sites have implemented it anyway, but it might in the future provide a standards based alternative. That said, there are enough useful reasons to know a “color” or a few different “logos” for an app or site, that it might be useful to come up with some standards based ways to list these things in pages.

Posted by: digdug2k | December 20, 2013

Action modes for Android

Assuming all goes well, Firefox will soon be shipping with our first support for Android’s ActionModes for text selection. We previously allowed text selection via some special context menu options when people long pressed on selected text. This replaces that implementation with a nice new UI:

ImageIf you’ve got an add-on that adds something to the selected text context menu:

  1. You’re likely broken in Nightly and Aurora builds right now and
  2. you can easily update your add-on to show in this menu as well.

Some astute developers have already updated themselves, but adding support is pretty easy (updated MDN docs here). We’ve added two methods to the SelectionHandler

  1. let actionId = SelectionHandler.addAction({
        label: "My addon",
        id: "my_id",
        icon: "resource://myaddon/icon", // You MUST include an icon to be shown in the ActionBar,
    // otherwise you'll always be put into the overflow menu.     action: function(aElement) {         // do something when clicked     },     selector: {
    // Just because this is being shown, doesn't mean there is a selection.
    // We may just be showing the cursor handle to let you move the cursor position.
            matches: function(aElement) { return SelectionHandler.isSelectionActive(); }     } },
  2. SelectionHandler.remove(actionId);

Text selection has had an exciting life in Firefox for Android, and is likely going to go through another transition as we land better platform support for touch friendly handles for not just Android, but also Firefox OS, and Metro Firefox. But this is a good move for the UI. We implemented it as a compatibility layer, so it should be available for all Android versions from Froyo to the newest KitKat devices.

Posted by: digdug2k | August 21, 2013

Prompt.jsm in Fennec

I realized today that one of our newer add-on features in Fennec is in Firefox Beta at this point, and I’ve never done anything to blog about it! So here it is, Prompt.jsm!

Prompt.jsm is a module that can be used to show dialogs in Fennec. We use it pretty extensively in our UI for everything from Select popups, Context menus, HTML5 date and time input elements, Certificate dialogs, etc. Previously, those were all done via a similar messaging system, but Prompt.jsm makes it a little easier to deal with and less error prone.

The API is pretty simple. Like I always like to do, I wrote a little addon to show off what you could do. This one I called ReaderPlus and lets you easily add a bunch of articles to Firefox for Android’s ReadingList (i.e. cached offline to see in ReaderMode. You can access your ReadingList through Bookmarks). The code’s a bit more complex than some of my earlier demos, but you’re welcome to peruse it on github if you want (patches welcome!)

The addon loads RSS feeds for a page, and lets you pick articles from them to add to your reading list. It adds a page action on pages where it finds feeds (I used a floppy disk here because you’re kinda “saving” the article, but I’d love something better). When you click the page action, we show a dialog listing all the feeds on the page:

ImageThe code to do something like this is pretty simple, we just import Prompt.jsm and create a new Prompt object:

Cu.import("resource://gre/modules/Prompt.jsm");
var p = new Prompt({ title: "Select a source" })
.setSingleChoiceItems(list.map(function(listItem) {
return { label: listItem.title }
})).show(function(data) {
readerPlus.showSelectArticles(list[data.button].list);
});

The prompt constructor takes an object that can give some basic details about the prompt (i.e. a title, message, and the buttons to show). For more complex prompts, it exposes a Fluent interface, so we can chain a call to setSingleChoiceItems, which shows a list of items. If we had added “selected: true” to one of those items, the dialog would also have shown checkboxes to the right. (You can’t add other inputs to prompts that have lists in them… yet).

Finally, we can call show on the prompt, and pass a callback to be called when its dismissed. The callback gets data bout what was tapped or selected, or the value of any inputs, checkboxes or any time/colorpickers (coming soon!).

The second prompt in the demo app is pretty similar, but uses setMultiChoiceItems to create a dialog where you can check multiple rows:

ImageThe code here is pretty similar:

    var p = new Prompt({
        title: list.title,
        buttons: ["OK", "Cancel"]
      }).setMultiChoiceItems(list.map(function(listItem) {
        return { label: listItem.title }
      })).show(function(data) {
        for (var i = 0; i < data.button.length; i++) {
          if (data.button[i]) {
            readerPlus.addToReadingList(list[i].link, list[i].title);
          }
        }
      });

In this case, we have to be careful to add some buttons to the prompt so that users have a way to close it. They get passed in in the constructor. Because its possible for some items to initially selected, the return has an array that’s the same length as the list and tells you the final state for each row.

Like I mentioned, you can do lots of other interesting things with prompts, adding input elements, labels (which support a subset of HTML if you need to do some advanced formatting),  I’ve tried to document them as well as I can on MDN, but feel free to ping me if you have questions! Happy add-on-ing.

Posted by: digdug2k | July 18, 2013

The new Pageactions are here!

Just this week one of our intern heros, Shilpan Bagat landed a fancy new addon API for people in Fennec that we’re calling “page actions”. Essentially, they’re clickable indicators in the urlbar, a lot like what Desktop Firefox already has.

The API is pretty simple, so I thought it would be funner to show an example add-on using it here instead. So this is a short tutorial on adding a refresh button to the urlbar in Fennec. To start, we just have to fork the awesome skeleton add-on put together by mfinkle a bit ago (we’re going to update the skeleton with an example of pageactions soon too).

Image Read More…

Posted by: digdug2k | April 29, 2013

Show Urls in Fennec

One common request we get in Fennec is the ability to show url’s in the titlebar. At one point I even wrote an addon to do it. Ignoring the arguments for and against, the feature is finally available built in to Nightly builds:

Image

To enable, just open Settings -> Privacy and change the “Title Bar” pref to “Show page address”. We’ve also set up domain highlighting like you see on desktop Firefox (for both regular and private tabs show above, with or without Personas enabled, although Personas are a nice security measure for our new scroll away urlbar too!). Enjoy!

Posted by: digdug2k | January 7, 2013

HTML5 Context menus in Fennec

Last Friday I landed a patch that enables HTML5 context menus in Firefox for Android nightly builds. That means that demos like this one will now work the same in both desktop Firefox and Firefox for Android now.

Posted by: digdug2k | November 28, 2012

Making great things on the mobile web

I love Firefox for Android, but find myself frustrated sometimes with the mobile web. I wanted to highlight some great things out there and point out ways you can work to make your (and others) mobile web better!

Splendid Apps

Twitter has a pretty awesome web app that showcases a lot of what makes the web great. The webapp is designed to work well on small screen devices (needs some work on tablets), and makes use of indexedDB to store data and startup up quickly, as well as including visible throbbers (since webapps have no browser chrome to tell users what is happening) and heavy use of AJAX to load content in the background. They’ve used touch events to implement a nifty pull-to-refresh implementation, have a nice fixed position header to provide easy navigation for the site, and use history apis to make it easy to navigate back and forward between “screens” of the app. If you’ve enabled posting with your location, they’ll use Geolocation to identify where you’re tweeting from. The version of the site they send as their app currently is only lacking support for photo uploads, but they work well if you visit http://m.twitter.com in Fennec (i.e. I assume they just haven’t been uplifted to the webapp yet). In short, its pretty awesome, easy to install, updates faster and more often than apps, and its safe! I’d highly recommend it to any of our Aurora/Nightly users. You can install it straight from the Firefox Marketplace! Or just bookmark the website on your Android desktop by loading it in Firefox for Android, long tap on the urlbar, and select “Add to Homescreen”.

Exquisite Hacks

For those sites that are… lets say less enlightened… the great thing about Firefox for Android is you can make the web what you want it to be! Writing extensions that extend or change sites is not much different than writing the same extensions for Desktop! Not long ago, a version of Stylish was even written that works on Firefox for Android, and today I threw up a style on userstyles.org that adds a much needed fixed position header to Facebook.com.

Learning Stuff

Unfortunately, Facebook users still can’t upload photos from the webapp. Facebook currently shows our users a message reading “Sorry, the browser you’re using doesn’t support uploading photos” along with a sell for their Android app. To be clear to our users, this isn’t true at all! To all the web developers out there who don’t know, Firefox for Android already supports taking photos right from web pages! All you have to do is add a file input with an accepts attribute set to “image/*”. i.e.

<input type=”file” accept=”image/*”>

You can also use “audio/*” or “video/*” for audio and video uploads respectively (I’m looking at you YouTube!).

GetUserMedia can also be enabled in some builds for photo uploads, and video support for getUserMedia is in the works, but for the simple, “upload a photo” case, HTML input’s are perfect (and will deprecate well in browsers that don’t support accept attributes).

I’ve looked into Facebook a bit and it looks like they’re depending on some proprietary api’s (opening a special fbrpc: url) they created for their native apps. Fixing this is definitely doable but is non-trivial hacking that would be fun for someone looking for a fun addon to write! Happy to help anyone interested.

I’ m hoping to keep this up for the next bit, calling out sites or apps that are doing a great job on mobile, and continue to point out things other authors can do to make their mobile pages better. If you know of any you’re especially impressed with, send ‘em my way.

Posted by: digdug2k | August 27, 2012

Testers rock!

To everyone who took time out last Friday or over the weekend to test out some webapps on Android goodness, a huge huge HUGE thanks. I wish I could bake you all cookies. We had a great turnout of testers and found a good number of bugs (more still trickling in this morning). Also, people weren’t shy about sending in the feedback! The MiniMart still exists (I moved it when Dropbox started to complain, so its available on my people.mozilla.org account now too) for anyone else who missed out or who wants to continue to test things!

One of the main things people really want (better integration with the Android launcher and Android app management stuff) is going to be tough to do. We’ve talked about doing things like dynamically building apk’s and even signing them on a Mozilla server somewhere. That opens up enough other cans of worms that we haven’t had time to chase yet. Stability and speed are our first priorities.

Thanks again!

Posted by: digdug2k | August 24, 2012

WebApps on Android are comin’!

I’ve been fairly heads down the past few weeks working hard to polish up WebApps on Android. And the good news is, its almost there! The next train leaving the beta station will be our first beta shipping with support for the Apps API turned on. You can visit any webapp store on the web and install apps directly from there. The apps you install will appear on your Android homescreen, and also be available to any app managers that you’ve given permission to. We have a default App Manager (look in the Android menu for “Apps”) we’re shipping to handle that for now.

WebApps run with their own profiles and in their own processes, like real native apps. They add desktop shortcuts. Show up in the Recent Apps lists. And they have access to pretty much everything you see on Desktop Firefox (including Canvas, CSS Transitions and Animations, and WebGL) + some shiny extras like orientation support. (Android security measures prevent putting them in your Android Launcher or modifying the correct App name/icon in the recent apps list.)

At this point, we need testers!

Testing:
Our teams eyes aren’t enough to hope to find all the problems or test all the devices out there. If you just love the open web and want to try these things out, testing is easy! File bugs (or yell in IRC, email me, reply here, or just tweet at me (DigDug2k)). Install. Start them. Quit them. Restart them. Switch between them. Uninstall them.

We need to know what works, what breaks, what you love and what you hate. There’s a Test Day tomorrow (8/24/2012) if you want to help. We’ll have an irc channel set up, or you can pop in to #mobile. BUT, you can test any time! In fact, I’d love users to keep using these things and to get some testing over more prolonged use. Some quick ways to install apps:

  1. The Mozilla marketplace isn’t quite open yet, but is available to registered Mozillians. You get their either by going to http://marketplace.mozilla.org in Firefox Beta for Android, or through the Apps Manager (Android Menu -> Apps -> Click the shopping bag in the top right).
  2. Since the market is still under active development, I put together something I call “Mini-Market” for testing as well. It contains a few curated apps that we consider ready for testing. If you’re interested you can play with it at http://bit.ly/minimart (WARNING: You will find bugs!). If you’ve got a great app you want me to add, drop me a line here. I’ll try to blog more about it in a bit.
  3. Alternatively, if you run a site that is a webapp, you can serve up an app the through the apps API all by yourself. Trust me, no one enjoys huge “Install our Android App!” banners thrown in their faces when they’re trying to view your site, but I wouldn’t be surprised to see users using a well placed (not intrusive) “One-Click Install” button!

Writing an app:

There’s a lot to write about WebApp development (Note we don’t have to write Mobile WebApp because its pretty easy to write a webapp that runs well on all sorts of devices!). That’s a different blog post But I have noticed a few tips from testing a lot of apps:

  1. Use metaviewport. It won’t affect your site on desktop. It makes things usable on mobile. Use it!
  2. Along with that, now that your site isn’t being rendered at desktop sizes on phones, you can use media queries for responsive design too! And Firefox has a pretty awesome Responsive Design tool built in. The mini market uses some really simple ones to give a two pane view on tablets/desktop and a one pane version on phones.
  3. Webapps have no chrome around them. You are responsible for showing progress if the user clicks a link or does something slow. Use XMLHttpRequest if you can. Plus, that should make it easier for you to build your own cache of responses and make your app super responsive. Desktop apps do it. Webapps need to start doing it too.
  4. If you do load content dynamically into a single page, use the history API! All Android phones have a back button, and this makes it work!
  5. Use App-Cache. I need to get some data here, but completely unscientific testing on my half with really bad mobile networks has shown apps taking 10-15 seconds to start, most of which is waiting on the network. The few (a.k.a. the one admittedly simple) app I’ve seen using App Cache is much faster.

Once you have a simple app built. Installing it is easy. You just to create an app manifest. There are some instructions and boilterplate for doing that here. The test manifest builder is also helpful if you want some boiler plate. Its mostly a simple JSON file you need to serve from the same host as your app. You can submit that manifest to the Mozilla Marketplace (or any other store’s that appear) if you want to use it for discoverability, or you can give users a link to install it from your site by simply calling

navigator.mozApps.install(“path/to/manifest.webapp”)

Thats about it. Happy testing! Once again, please provide us feedback however you can. We’re listening and we’re anxious to make the web a first class citizen for apps.

Older Posts »

Categories

Follow

Get every new post delivered to your Inbox.