Sunday, September 15, 2013

svg + img == awesome

I used an SVG file as the src attribute of an HTML img to solve two problems over the last couple weeks. First, I was working on an HTML5 replacement for the flash (.swf) banner at the top of http://mysticriver.org/. The slideshow worked fine, but we ran into a problem compositing the logo over the animating background images. The logo was created in illustrator. We were loading the logo as a gif with transparent background, and we ran into a problem where the logo would render with a white outline artifact. We found a trick to remove the artifact when compositing against a solid background, but that didn't work for an animating sequence of background images. We finaly tried referencing an svg version of the logo from the img tag, and that worked great - the browser (we tested IE10, Firefox, Chrome, iPhone Safari, Android Chrome) smoothly rendered the svg over the img background. We kept the gif around too as a fallback for older browsers.

I was so happy with how well svg worked with the banner that I decided to use inkscape to create an svg icon for little ToDo:

little ToDo icon

Another benefit of an svg icon is that it nicely scales to the different sizes that various devices prefer:

<link rel="shortcut icon" href="/littleware_apps/resources/img/appIcons/littleToDo/checkbox.16x16.ico" type="image/x-icon" />
<link rel="apple-touch-icon" href="/littleware_apps/resources/img/appIcons/littleToDo/checkbox.57x57.png" />
<link rel="apple-touch-icon" sizes="72x72" href="/littleware_apps/resources/img/appIcons/littleToDo/checkbox.72x72.png" />
<link rel="apple-touch-icon" sizes="114x114" href="/littleware_apps/resources/img/appIcons/littleToDo/checkbox.114x114.png" />
<link rel="apple-touch-icon" sizes="144x144" href="/littleware_apps/resources/img/appIcons/littleToDo/checkbox.144x144.png" />

I did run into a couple weird svg corner cases. First, internet explorer required that the svg file specify the viewBox and preserveAspectRatio properties in order to properly override the img dimensions via CSS or the width and height img attributes. Next, and related, inkscape does not set the viewBox and preserveAspectRatio attributes, so I set them by hand with inkscape's XML editor.

Saturday, September 14, 2013

little to do

I finally have an initial version of a little to do application running using the "tree control flow" stuff I described earlier.

LittleToDo is a simple app, but it took me a little while to wire it all up, and I think it has a couple interesting features. First - littleToDo implements nested to-do's, so each to-do item can itself have a list of child to-do's, and grand children, etc. The UI currently only allows four or five generations, but increasing that limit just requires changing a constant in the code.

The other interesting features are under the hood. Most of the code is implemented as typescript YUI modules. I had to tweak the YUI typescript definition file I'm using to make the typescript YUI module trick work with typescript's 0.9.1.1 release (which tightens up some syntax rules that were more relaxed in typescript 0.8), but I eventually wound up with code like this:

...

import importY = require("../../libts/yui");
importY; // workaround for typescript bug: https://typescript.codeplex.com/workitem/1531
import Y = importY.Y;
Y = exports;

import littleAsset = require("littleAsset");
littleAsset;
import ax = littleAsset.littleware.asset;


/**
 * @module littleware-asset-base
 * @namespace littleware.asset
 */
export module littleware.asset.manager {

...

    /**
     * API tool for interacting with the asset repo.
     * @class AssetManager
     */
    export interface AssetManager {
        /**
         * @method addListener
         * @param listener {function}
         * @return YUI subscription with "detach" method to unsubscribe
         */
        addListener(listener: (ev: RefEvent) => void ): Y.EventHandle;

        /**
         * @method saveAsset
         * @return {Y.Promise[AssetRef]}
         */
        saveAsset(value: ax.Asset, updateComment: string): Y.Promise<AssetRef>;
        /**
         * @method deleteAsset
         * @return {Y.Promise[void]}
         */
        deleteAsset(id: string, deleteComment: string): Y.Promise<void>;

        /**
         * Return a reference to the asset with the given id if any - otherwise null.
         * @method loadAsset
         * @return {Y.Promise[AssetRef]}
         */
        loadAsset(id: string): Y.Promise<AssetRef>;

        /**
         * Load the child of the given parent with the given name -
         * every child has a unique name within its set of siblings.
         * Usually implemented as a shortcut for loadAsset( listChildren( parentId )[name] ).
         * @method loadChild
         * @param parentId {string}
         * @param name {string}
         * @return {Y.Promise{AssetRef}}
         */
        loadChild(parentId: string, name: string): Y.Promise<AssetRef>;

        /**
         * Load the asset at the given path if any - same as loadSubpath( null, path )
         * @method loadPath
         * @param path {string}
         * @return {Y.Promise{AssetRef}}
         */
        loadPath(path: string): Y.Promise<AssetRef>;

        /**
         * Load the asset at the given path below the given root
         * @method loadSubPath
         * @param rootId {string} id of the asset to treat as the root, or null to use forest root
         * @param path {string}
         * @return {Y.Promise{AssetRef}}
         */
        loadSubpath(rootId: string, path: string): Y.Promise<AssetRef>;

        /**
         * Like loadSubpath, but allows specification of a builder function 
         * for each segment of the path to create a missing asset if it doesn't exist -
         * buildBranch sets the builder's fromId and name properties.
         * @method buildBranch
         * @param rootId {string} id of the asset to treat as the root, or null to use forest root
         * @param branch {{name:string,builder:(parent:Asset)=>AssetBuilder}[]}
         * @return {Y.Promise{AssetRef[]}}
         */
        buildBranch(rootId: string, branch: { name: string; builder: (parent: ax.Asset) => ax.AssetBuilder; }[]): Y.Promise<AssetRef[]>;


        /**
         * List the children if any under the given parent node
         * @method listChildren
         * @param parentId {string}
         * @return {Y.Promise{NameIdListRef}}
         */
        listChildren(parentId: string): Y.Promise<NameIdListRef>;

        /**
         * List the root (littleware.HOME-TYPE) nodes - shortcut for listChildren(null)
         * @method listRoots
         * @return {Y.Promise{NameIdListRef}}
         */
        listRoots(): Y.Promise<NameIdListRef>;
    }

...

The current implementation of the above AssetManager interface (which underlies the data-management for the app) just saves assets (nodes in a data tree) to the browser's local storage, but the API returns promises, so it will be easy in the future to swap in an implementation that saves data via AJAX to a remote service. The AssetManager also closely resembles littleware's asset manager and asset search API's (that javadoc is out of date, but that's about right), so I'm hoping to implement a littleware backend for the next release of "little to do" with littleId based authentication. We'll see how it goes ...

Thursday, September 05, 2013

promises, promises

YUI recently added a cool Promises module that I've been using the last couple weeks to implement client-side API's for a webapp. I like the way the code has come together, and I have a couple observations to record.

First, code that uses Promises is viral - it's natural for code that uses a promise-based API to itself use promises. Promises are a kind of monad like Haskell's IO() construct and Scala's Option class - which are also viral in my experience. For example, one of the first promise-based methods I wrote retrieved and compiled a handlebars template from the server:

        /**
         * Little helper loads and compiles a handlebar template via an AJAX call
         * 
         * @method loadHandlebar
         * @param url {string}
         * @return {Promise} Y.Promise delivers compiled template function or error info
         * @static
         */
        function loadHandlebar( url ) {            
            var promise = new Y.Promise( function(resolve,reject) {
                var ioconf = {
                  method:"GET",
                  on: {
                    success:function( id, resp, args ){
                        resolve( Y.Handlebars.compile( resp.responseText ) );
                    },
                    failure:function( id, resp, args ) {
                        log.log( "Failed to load " + url + ": " + resp.status + ", " + resp.statusText );
                        reject( resp );
                    }
                  },
                  timeout:60000
                };
                Y.io( url, ioconf );
            });
            return promise;
        }

That worked great, and the next thing I wanted was to dynamically load a template into a view with something like
littleUtil.loadHandlebar( url ).then( function(template){ view.template = template; } )
, but then the view couldn't use the template at render time until the promise was fulfilled. Rather than do something like
render: function() { this.templatePromise.then( function(template) { ... do render } ) ... }
, I setup a factory method for allocating views that itself returns a promise, and let the factory's client decide how to resolve the promise - which worked well in the little application I've been building that runs several asynchronous data-setup operations at start-up anyway:

    /**
     * Factory for PageView instances - maries YUI class inheritance with Typescript type system
     * @class PageViewFactory
     */
    export var PageViewFactory = {
        /**
         * Returns a Promise - the view loads various configuration 
         * information (templates, whatever) at the template, and 
         * fulfills the promise when the data is ready.
         * @method newView
         * @static
         * @return {Promise{PageView}}
         */
        newView: function (): Y.Promise {
            return templatePromise.then((template) => {
                var view = new SimplePageView();
                view.template = template;
                return view;
            });
        }
    };

This code is written in typescript - which extends javascript with support for static types. I'm only just in the process of migrating to typescript 0.9.1 which includes generic types. Hopefully after the upgrade I'll be able to modify the newView signature to something like:
newView: function(): Y.Promise<PageView> { ... }
.

Finally, it's interesting to compare yui's Promises implementation to the akka Futures implementation in scala. In javascript's single-threaded runtime promises usually coordinate callback execution between operations involving asynchronous IO. In scala's multithreaded runtime futures (promises by another name) are also used to simplify the coordination of concurrently running computations.