Don’t tell me what to focus on, I’ll tell you!

October 27th, 2011 § Comments Off on Don’t tell me what to focus on, I’ll tell you! § permalink

After a frustrating interaction with a form I whipped up a quick jQuery plugin for developers who don’t want to think about form field focus.

I present to you…

Polite Focus!

It’s a simple idea – use document.activeElement to determine if an existing field has focus. If not, give your field focus. Otherwise, leave the focus where it is, where someone else (user or previous programmer) decided it should be.

That’s it.

Go forth and use wisely

I’ve created a repo on GitHub so you kids can branch and comment as much as you like.

Go clone the plugin on GitHub. Now.

Using document fragment when rendering a backbone view

October 27th, 2011 § 1 comment § permalink

Backbone.js is pretty fun to use. Right out of the box it makes app development quick and organized. Fully grokking how to adapt to using view controllers is a bit of a change and the event system is happily powerful, yet blending it with jQuery events doesn’t seem immediately obvious. All the same it does a great job of giving great tools for organization and structure while staying out of your way.

One drawback to using a library that does magic is that if you’re not careful you can miss some important details. In this case I’m talking about injecting your views into the DOM. Blindly following the create view/render into element pattern as described in the documentation is usually fine. However, if you are using a view to render a list of children the $(this.el).append(view.render().el) quickly becomes costly.

For my needs I wanted to add an arbitrarily-long list of elements to an ordered list. Instead of blindly looping over models, creating views and shoving them into the list one at a time I decided to add all rendered views into a document fragment in memory and then append that fragment on to my list. Clean code for rendering, only one DOM adjustment for speed.

Example Code!

var containerView = Backbone.View.extend({
//... snip
	render: function() {
		var template = _.template($('#regular_ol_template').html()),
			self = this;

		$(self.el).html(template(self.model.toJSON()));

		self.list = $('.list', self.el);

		var frag = document.createDocumentFragment();
		_.each(self.model.things.models, function(thing) {
			frag.appendChild(self.createThing.call(this, question).render().el);
		});
		self.list.append(frag);

		return self;
	},

	createThing: function(thing) {
		return new ThingView({model:thing});
	}
//... snip
});

But why make a separate function?

What you’re not seeing is another method named addThing which uses createThing and does more work – to my model, spinning up other views, etcetera. It’s also good not to bind the creation of elements solely into your render method. You want to be able to add more things to your list without fully re-rendering it. That way, should someone else decide to use my model or view in the app, elements in the list can be adjusted without the performance overhead of creating the whole list again.

Result

There you have it! You have now rendered your Backbone.js views into memory and appended them to the DOM in one fell swoop. Instead of abusing the DOM in your loop cycle you’ve speedily created them in memory. Isn’t that much kinder to the DOM? The answer is yes, yes it is.

What do you think? How would you change this? Comments!

Accessing the browser’s stylesheets with CSSelection

October 20th, 2010 § 3 comments § permalink

When writing applications that modify the DOM there’s one thing to keep in mind: your code will not be the only code touching the DOM. Defensive code is good code.

With defensive programming in mind there sometimes exists a need to peek into the CSS that is loaded into the browser. Say an application your writing depends on user-based styles that are dynamically loaded in. It’d be nice to inject those styles into the document CSS and know you’re not overwriting anything. Perhaps your code is meant to take an existing style and modify it.

To this end I present a work-in-progress of my first jQuery plugin, CSSelection.

Code: View CSSelection on GitHub

Download jquery.CSSelection.js

CSSelection start by accepting a jQuery selector. With that selector you can read the current styles applied to that selector, add new styles, create such a selector if one does not exist or even remove the current selector from the stylesheet. I tried to keep the interface predictable to jQuery users at the expense of a bit of extra code. Passing no arguments retrieves the current rules, if any, of the selector. Passing the string “remove” does as expected to first found matching selector in the style sheets. Finally passing an object literal with rules will either add them to the stylesheet or modify the matching selector.

While this code is used in production I’ll still call it beta as bugs are cropping up in IE9 and are sure to arrive in future revs of Safari and Firefox. Enjoy!

Usage examples

How to create a rule for HTML elements:

$('p').CSSelection({rules: {'font-size': '120%', 'color': 'red', 'background-color': '#fff'}});

Modifying existing CSS rule/add new rule:

$('.important').CSSelection({rules: {'text-decoration': 'underline overline', 'background': 'yellow'}});

Delete a CSS rule:

$('.annoyingDecoration').CSSeleciton('remove');

Get attributes for existing rule:

var attrs = $('.wickedAwesomeClass').CSSelection();

The subtle art of ranges – Intro

September 21st, 2010 § Comments Off on The subtle art of ranges – Intro § permalink

You’re starting to see it more and more. You select some text on a website and — woosh — something happens. Sometimes you expect the action. Oftentimes you don’t. Regardless, these things are possible due to DOM ranges.

And DOM ranges are terrible.

I don’t mean they are a terrible idea. I mean they’re terrible to work with. Of course there is no single, standard API to work with. Of course Internet Explorer adds another level of challenge. And of course you’re going to at some point have to know how these things work if you expect to be a JavaScript ninja.

There are many reasons to deal with ranges. Some lame services will hijack your selection and inject in their own tags. If you’ve ever needed to hack around a WYSWYG editor then ranges will be on the docket. Or say you’re leading a team that allows users to select text on a page and do things like highlight it, make a note attached to it or even place a bookmark at that point in the page. That’d be my job.

The default range object seems good enough for a lot of tasks. Where it starts to show its weakness is interacting with the DOM outside of just the range.

You want to take what a user has selected and wrap it in a decorative <span>? That should be easy, right? What happens if that selection starts in the middle of an <li>, moves down a few paragraphs, enters a <div> and ends a few levels deeper in the node tree? Well, you can’t just wrap that in a single element.

The browsers all try to be helpful. Really, they do. If your range starts in the middle of an <em> tag but ends outside of it the range you get back from the browser will automatically split the tag properly if you wrap it. That’s nice. But if you remove that wrapper now you have a split tag that equates to more child nodes in memory than in code. That makes for bad assumptions later.

During my research into and development of this project I’ve found a stunning lack of comprehensive information (much less example code) for DOM ranges. Obviously PPK is the place to start but his level of detail is light and — at best — beginner. I’ve worked with some guys at Google who are on the Closure Library team and are ridiculously smart. Even they didn’t plan for the basic needs I have. Or it could be I’m doing it wrong.

In any case, I’ll be working on a series of entries to this blog that will go through what I’ve learned, show some code, talk about common pitfalls, propose some best practices and hopefully shine some light on the dark corner that is DOM ranges.