In-memory Javascript Database

I wrote an in-memory Javascript database for a project at work. “What?!” you say? You heard me. In-memory…Javascript…database. Yes, there is a use-case for it.

So our current HTML5 project has moved back its target coverage to IE8. Darn. No CSS3, standard event model, or implicit getters/setters (meaning no data-binding). But it still has localStorage and sessionStorage, the ~5MB data store that an HTML5 app can use. So I wrote a JS database which is really just an array of objects with some easy API for filtering, sorting, limiting, and finding the object you need. Now I can store a bunch of data in memory, getting only the newest content when I poll the server, and much more quickly sort, filter, etc. the data for the user without round-trips to the server. And then when they close the app, I can JSONify the data in the localStorage and load their app much more quickly when the come back. They’ll immediately see where they left off, then when the first server poll finishes they’ll see they’ve got unread items that they can scroll up to view.

I found taffydb.com already existed, but I sure hate unreadable code, and I thought how I could make it faster using the built-in Array filter() method. So I built my own. I also added a full-text search index that can be used for finding based off of keyword matching. I’m working on refactoring for a different query API that supports ORs and sub-expressions–or expressions within parenthesis (e.g. name == “Jacob” and (age == null or age > 10) and cool == true).

Follow the progress of JaDE (Javascript Database Engine) on github.

Runtime Performance with CSS3 vs Images

I’m pretty happy with the great stuff CSS3 (and HTML5) brings. However, some care should be taken in balancing how many images you load versus the load you put on the CSS engine. And there are a lot of articles on the web encouraging use of the new CSS features such as gradients and shadows in order to optimize for images in your page. But that’s only half the story.

Image Optimization

CSS3 allows you to add drop shadows to your elements, gradients as their backgrounds, and rounded corners on their… corners. Using these few capabilities (you might throw in a couple more like custom fonts and you can put together much of the web’s design with only a few icons needed for images. This allows for much smaller page download because the definition for a shadow or gradient is only a few bytes but an image of these same things are usually kilobytes larger. Pages download much more quickly.

CSS Optimization

While you can do lots of great things with CSS3, drawing shadows and gradients dynamically can affect responsiveness in your page. If you find your page is not scrolling smoothly or dynamic pieces don’t pop like you’d want them to, you might want to optimize your CSS and use more images. Your page may download slower, but once it’s there it will be more responsive.

Case-study on Page Performance

I had a page with a lot of these gradients and shadows (see the previous picture, the original version was 100% CSS, it had no images at all), however, scrolling the page left and right was very clunky and unresponsive. I thought perhaps I had too many HTML elements on the page, but I’ve seen much more work better. After playing around with code a bit it occurred to me that the dynamic calculations and drawing of the gradient’s and shadows was affecting performance. This should have been more apparent to me since it is a common optimization in Flash when you use too much drawing API. After removing the shadows and gradients from my stylesheet the scrolling was smooth again, just like I would expect it to be. Removing the shadow helped out a lot more than removing the gradients. I theorized that the browser may have a better time layering images than it does calculating shadows and gradients, so I tested it out.

After replacing all the gradients and shadows with images, I found my page still scrolled smoothly even though the same shadows and gradients caused it problems with CSS. For my particular case, I am creating a web application which users will come to and stay at for awhile. There is a lot of elements on the page, a lot of design parts to it, and in this particular developer-art incarnation of it, a lot of shadows.

On a side note, the process to replacing the CSS shadows etc. with images was much less painful with CSS3. I didn’t have to alter any HTML because you can layer backgrounds onto an element now so my elements had- background: url(topimage.png) no-repeat left top, url(bottomimage.png) left bottom, url(middleimage.png) repeat-y left; So even though I was forgoing CSS3 shadows it still made my life easier and my page simpler with the images.

The Right Balance

For many web pages out there adding a few shadows or gradients to the page will help make your page look that much nicer and doing it in CSS3 is easier to tweak when you don’t have to re-export images from your site-design-file. But if you have performance problems in your page, you might try using images for some of the heavily repeated elements or the shadows in your page.

Creating a Hover Menu with HTML5 and Simpli5

A More Usable Application

I decided to build my own version of a contextual hover menu to make my applications more usable. It is meant to appear when you select a piece of data and give you quick access to all the actions you might perform on it. Forget long toolbars and hidden right-click menus. I wanted something that a user didn’t have to dig around to find, that wouldn’t be hard to navigate, and that wasn’t hidden (a right-click on the web is not common enough for users to rely on).

I’ll walk you through the beginning process I took to create the HoverMenu component using Simpli5 and then I’ll cover at a higher level the UX considerations that went into making it even better. You can check out the component in action first (using Safari, Chrome, or Firefox).

Base Simpli5 Component

To start, Simpli5 encourages using tags that provide good semantics for the application, ignoring whether or not they are valid HTML tags. It makes your application easier to read and understand, and since Simpli5 was made for creating full web applications, SEO and other content-based concerns are thrown out the window. I will start with the component definition in HoverMenu.js. I have the base component, menu containers, and menu items that I’ll need. There will also be separators, but that has no code or logic and so can just be added in the stylesheet.

var HoverMenu = new Component({
	extend: Component, // the base when using custom tags
	template: new Template('<hover-menu></hover-menu>'), // component template used when creating from code
	register: 'hover-menu', // css selector to convert matching elements into a HoverMenu

	constructor: function() {
		// the constructor
		this.submenu = this.find(simpli5.selector('menu'));
		if (this.submenu) this.submenu.hide();
	}
});

var HoverMenuSubmenu = new Component({
	extend: Component,
	template: new Template('<menu></menu>'),
	register: 'hover-menu menu'
});

var HoverMenuItem = new Component({
	extend: Component,
	template: new Template('<menu-item></menu-item>'),
	register: 'hover-menu menu-item',

	constructor: function() {

	}
});

I’ll give it a stylesheet HoverMenu.css to make it look good.

What I want is when the user hovers over the button, the menu pops up.

constructor: function() {
	...
	this.on('rollover', this.open.boundTo(this));
	this.on('rollout', this.close.boundTo(this));
},

open: function() {
	var rect = this.rect();
	this.submenu.show(true);

	this.addClass('open');
	this.submenu.rect({left: rect.right, top: rect.top});
},

close: function() {
	this.submenu.close();
}

Of course, sometimes I might want to have the user click to popup the menu, for ones that are used less often or in the case that there are many on the screen (don’t want to have popups all over the place by moving your mouse around).

var HoverMenu = new Component({
	extend: Component,
	template: new Template('<hover-menu></hover-menu>'),
	register: 'hover-menu',
	properties: ['click-only'], // add attributes that translate to properties in this array

	constructor: function() {
		...
		this.on('click', this.open.boundTo(this)); // click will always open it
		this.clickOnly = false;
	},

	get clickOnly() {
		return this._clickOnly;
	},
	set clickOnly(value) {
		if (this._clickOnly == value) return;
		this._clickOnly = value;
		if (this.submenu) {
			value ? this.un('rollover', this.open.boundTo(this)) : this.on('rollover', this.open.boundTo(this));
		}
	},
});

Here I added an implicit getter/setter that by default is false so hovering will open the menu. But if hoverMenu.clickOnly = false or <hover-menu click-only=”false”>…</hover-menu> then you’ll have to click the button to open the menu.

I’ve also added other settings for customization: autoClose to close the menu automatically when the mouse moves off of it for a few milliseconds, menuDelay to turn off the delay menus take to close (I talk about this later), and openBelow to cause the menu to open up beneath the button instead of to the side of it.

Next we need to allow menu items to hold submenus and to dispatch events when the user selects them. It would be nice if these can be triggered by code too.

// HoverMenuItem
events: ['select'], // add custom events that can be listened to via onevent attributes

constructor: function() {
	this.on('click', this.select.boundTo(this));
	this.on('rollover', this.hovered.boundTo(this));
	this.submenu = this.find('menu');
	if (this.submenu) {
		this.submenu.hide();
		this.addClass('submenu');
	}
},

open: HoverMenu.prototype.open, // use the same function from HoverMenu

close: function() {
	if (this.submenu) {
		this.submenu.close();
		this.removeClass('open');
		this.parentNode.hoveredItem = null;
	}
},

select: function() {
	if (this.disabled || this.submenu) return;
	this.dispatchEvent(new CustomEvent('select', true)); // this is our own event and we will bubble it
	this.menu.close(); // once selected, close the whole menu
},

hovered: function() {
	if (this.disabled) return;
	if (this.parentNode.hoveredItem && this.parentNode.hoveredItem != this) {
		this.parentNode.hoveredItem.close();
	}

	if (this.submenu) {
		this.open();
	}
}

Hopefully you can understand the logic by reading through the code, but there are a couple of things I want to point out. The “events” property holds a list of custom events for the component to look for when initializing its attributes. Because I specified the select event there you can add onselect=”alert(‘item selected’)” to the tag and it will work. Also, our first usability tidbit for the menu, don’t close submenus until the user moves their mouse to a sibling menu item. That wraps up our basic-component-building-101-in-Simpli5 overview and brings us to our user experience in using this component. Now I realize that UX encompasses so much more than a component, but the usability and experience the user has with this component is what I am referring to when I say UX.

Making it Shine with Usability

Most of these things were added because I tried using the menu and noticed spots of frustration. Some were added from suggestions of others.

The first thing I did to enhance the usability of the menu was to keep the entire menu and submenus from closing immediately. The less accurate a user has to be with their mouse, the quicker they can get things done and the easier it is to use an application. If the menu closes because a user accidentally moves the mouse a little beyond the menu then they have to start all over again opening the menu up from the beginning. When the hover menu’s autoClose is true, the menu waits 600 milliseconds before closing. This allows a user to make mouse mistakes and recover from them before having to reopen the menu.

The next usability piece came from testing with longer submenus. I noticed that if I wanted to click the last item in a submenu and I moved my mouse strait to it, the mouse path went over the edge of the next sibling menu item, closing the previous item’s submenu. In order to select that last submenu item I had to alter my mouse path to a 7 shape, moving across to the submenu first, then down to the desired item. In order to allow some forgiveness in the mouse movement while trying not to hamper the speed at opening the next submenu if that is the real desired action, I added a 150ms delay in opening and closing submenus. This seemed to be enough time for a quick mouse movement down across sibling menu items into the submenu, while not being too much time if you wanted to open the sibling submenu. I also added the menuDelay option that defaults to true, but can be set to false if you want to get rid of this 150ms delay.

I added an alternate element style in the stylesheet for elements called <menu-content> which is an alternative to holding menu items in a submenu and allows robust components like color pickers or lists of images to be used, adding to the overall UX of the UI.

I added positioning support for them menus to popup above or to the left of their parent if they are near the edge of the screen. I made the menus append to the body of the document so that they wouldn’t get cut off by any overflow auto/hidden elements. There were also other small things I added too, such as a style on items with open submenus so they can be seen easier and allowing the menu to be closed by clicking elsewhere or pressing Esc.

Overall the component turned out quite well. Here is a demo page of it in action (view source to see the markup): http://jacwright.github.com/simpli5/demos/hover-menu.html

The Joys of HTML5

HTML5 is SOOOooooo much nicer to program for than previous versions of HTML. Here’s why, but first a little context.

We’re creating a power-user interface for the next version of our app using HTML5. It will be similar to tweet deck with multiple columns, and it needs to have all sorts of functionality crammed into the column views. This will require a lot of custom UI components and iterative work on UX. But it’s not so daunting a task when you don’t have to support really old browsers. Browsers which forcing you to compromise your user’s experience.

I’ve been putting time into creating a Javascript library for HTML5 applications, and I’ve open sourced it with the name Simpli5 (hosting on github). Many of the things I’m doing there will make traditional Javascript purists cry in horror, but it’s focused on building rich applications that are easy to understand and maintain. But I’ll come back to Simpli5 later. Today it’s about HTML5 and the CSS and Javascript that comes with it.

These are some of the golden gleaming granules of goodness that gives me goosebumps with HTML5. (now THAT is some alliteration!)

CSS Selectors do what they’re supposed to. Using the child selector “>” I can remove blocks of CSS that exist solely to nullify cascading styles. I can add a margin to all but the first element using the sibling selector “+”. I can exclude using :not(.someclass) and skip items using :nth-child(odd). :hover works on all elements. And I can use a[href~=jive] if I want to highlight Jive links all special.

CSS Styles prevent much of the need for extra HTML cluttering up the page for styling sake. I can layer on multiple backgrounds to elements (background: url(1), url(2), etc), round out corners (border-radius:5px), reliably use opacity for a whole element or for just the border/background color (rgba(0, 0, 0, .5)), and even create gradients and reflections. Everything I need for a Web 2.0 application . Between this and the selectors, I can cook up some pretty decent looking prototypes without any images at all.

Javascript Consistency allows me to reliably make use of implicit getters and setters, add to the prototype of DOM elements (gasp, he wouldn’t dare!), select elements in the DOM using all the above mentioned CSS selector coolness (natively BTW), and all the Array methods and DOM methods that you SHOULD be able to use but usually can’t because you have to support browser X (being, of course, IE).

HTML5 also has newer tags, micro formats, and such, but that hasn’t been something I’ve really benefited from so much. I’m not building a website. I’m building an application. And those have different needs. I’m excited to use some of the other new features such as the client-side storage and database for speed and offline support.

Javascript Rollover Rollout Events

Javascript has mouseover and mouseout events. Flash has these, but they also have rollover and rollout events. There is a difference, and it can be painful developing Javascript components without the rollover and rollout events. So I put together a little script that provides them for us.

Problem

You want to perform some action when the cursor rolls onto and off of an HTML element. When you use the mouseover/mouseout events, you get a mouseout and immediately another mouseover when the cursor is over a child element. Technically the mouse is still over the parent element, why does the mouseout happen? What the… you want it to work like CSS :hover. The way you’d think it SHOULD work. You figure, maybe it’s just you’re catching because bubbling child events, so you return out of your listener if the target does not equal your element. This removes the second mouseover, but you still get a mouseout when hovering over a child element.

Solution

Flash’s solution was to build in a non-bubbling rollover/rollout event that works like you’d expect. I’ve never used a mouseover/mouseout in Flash since these new events came about. So, assuming you’ve got a modern standards-compliant browser (tested on Safari/Chrome & Firefox), this little bit of code will provide rollover/rollout events for your HTML and is non-intrusive. It saves a lot of headache and works great.

Updated: The code did not previously take into account siblings, only ancestors. Fixed to find the common ancestor.

(function() {

	function listener(event) {
		var child = event.relatedTarget;
		var ancestor = event.target;
		// cancel if the relatedTarget is a child of the target
		while (child) {
			if (child.parentNode == ancestor) return;
			child = child.parentNode;
		}

		// dispatch for the child and each parentNode except the common ancestor
		ancestor = event.target.parentNode;
		var ancestors = [];
		while (ancestor) {
			ancestors.push(ancestor);
			ancestor = ancestor.parentNode;
		}
		ancestor = event.relatedTarget;
		while (ancestor) {
			if (ancestors.indexOf(ancestor) != -1) break;
			ancestor = ancestor.parentNode;
		}
		child = event.target;
		while (child) {
			var mouseEvent = document.createEvent('MouseEvents');
			mouseEvent.initEvent(event.type.replace('mouse', 'roll'),
					false, // does not bubble
					event.cancelable,
					event.view,
					event.detail, event.screenX, event.screenY,
					event.ctrlKey, event.altKey, event.metaKey, event.button,
					event.relatedTarget);
			child.dispatchEvent(mouseEvent);
			child = child.parentNode;
			if (child == ancestor) break;
		}
	}

	// setup the rollover/out events for components to use
	document.addEventListener('mouseover', listener, false);
	document.addEventListener('mouseout', listener, false);
})();

I hope this helps someone having a rough time with Javascript mouseovers.

Javascript Data Binding

Simpli5 has been coming along nicely as I’ve been able to put time into it. I’m very excited to announce data-binding.

Data Binding

Data binding is a technique we have and use in Flash quite a bit that allows one property to stay in sync with another. If obj.x is bound to obj.y then whenever obj.x is changed, obj.y will automatically update to the same value. I’ve built my own data binding frameworks in ActionScript 3 and I wanted it for my Javascript work as well.

Since Simpli5 has a base-line of HTML5, I was easily able to create data binding in Javascript using implicit getters and setters. Any property on an object can be bound. My binding supports one-way, two-way, and bind-setters, and it allows deep binding.

One-way binding propagates the changes of the source object’s property to the target object’s property. Whenever the source’s property changes, the target’s property updates. If the target’s property is changed however, nothing will happen to the source.

Two-way binding keeps the properties of the source and target in sync. When first bound, the source’s property will be the value used, but if either the source’s property is changed or the target’s property is changed the other will update to stay in sync.

Deep binding is being able to bind the property of a property of the source. As an example, obj.x would be shallow binding where obj.x.y.z would be deep binding.

Binding Usage

The following shows how binding can be used.

var obj1 = { name: 'Bob' };
var obj2 = { name: 'Henry' };

Bind.property(obj1, 'name', obj2, 'name');

alert(obj2.name); // will be Bob
obj1.name = 'Patricia'; // the binding makes obj2.name update as well
alert(obj2.name); // will be Patricia

var obj1 = { name: 'Bob', address: { zip: 12345 } };
var obj2 = { name: 'Henry', address: { zip: 56789 } };

Bind.property(obj1, 'address.zip', obj2, 'address.zip', true); // the last param (true) means a two way bind

alert(obj2.address.zip); // 12345

obj2.address.zip = 'unknown';
alert(obj1.address.zip); // will be 'unknown' because we are 2-way binding
obj1.address.zip = 12345;
alert(obj2.address.zip); // will be 12345 again, same as obj1

Binding added to Template

I’ve added a new method to Template called createBound(). The Template.create() method will give you back an HTML element created from the template’s HTML, replacing anything in curly braces with the evaluated javascript equivalent. With Template.createBound() you get back an HTML element which continues to update its attributes or text content as properties in the data or element change. Perhaps the best way to explain is to show some code.

var template = new Template('<button><img src="{this.src}" alt="{this.label}"/> Say {this.label}</button>');
var btn = template.createBound();
alert(btn.outerHTML); // <button><img src="" alt=""/> Say 

btn.label = 'Hello World';
btn.src = 'images/hello_world.png';

alert(btn.outerHTML); // <button><img src="images/hello_world.png" alt="Hello World"/> Say Hello World</button>

I’ve made it the component creation method of course, so now the properties on your components can update the HTML directly. And it isn’t setting the innerHTML of the component, which would replace all the sub-elements and destroy any listeners that were on the old ones. It’s binding smartly so that attributes and text get updated carefully.

Limitations

There are properties on elements that binding will not work the way you’d expect. Things like element.id, element.firstChild, img.src, et cetera, which the browser treats in a special way but are not getters and setters (as far as the javascript can tell anyway), these cannot be bound to reliably. They cannot be the source of a bind, but they could be the target of a one-way (non-deep) bind just fine.

Testing

I’ve started adding unit tests to the framework, especially since data binding can be such a tricky thing. I’ve got tests around the binding and the templates right now and feel confident that they are working pretty well. I’m using js-test-driver. I’ve also added a maven build file for the tests and for compressing the library into a single file and a compressed file.

The Simpli5 project is being hosted on Github: http://github.com/jacwright/simpli5.

Next Page »