2008-04-29

So maybe it wasn't so simple after all.

Well, as I said previously, I did come up with a way to accomplish what I was trying to accomplish.

Basically, what I wanted was to be able to say: "This group of options under this tag are a logical set, and only one of them may be considered active at any given point in time"

This is what I converged upon:



function UniqueSelection(id, extras, allowToggle, childTag) {
if(!childTag)
childTag = 'li';

var parent = document.getElementById(id);
var items = parent.getElementsByTagName(childTag);
var currentItem = false;

function choose(choice) {
if(!currentItem) {
currentItem = items[choice];
currentItem.className = 'active';
}else{
if(currentItem != items[choice]) {
currentItem.className = 'inactive';
currentItem = items[choice];
}

if(allowToggle && currentItem.className == 'active') {
currentItem.className = 'inactive';
}else {
currentItem.className = 'active';
}

}

}

for(var i = 0; i < items.length; i++) {
items[i].onclick = (function(id, func) {
if (!func) {
func = function() {
return true;
};
}

return function() {
choose(id);
func();
};
})(items[i].id,
(extras ? extras[items[i].id] : false));
if(items[i].className == 'active') {
currentItem = items[i];
}
}


}


This version does exactly what I need it to, although the creation syntax is a little funky if you're not used to passing objects as parameters:


//to create just a list, no extra actions
justAList = new UniqueSelection('simple-list');

//to create a list where three elements have extra actions:
normalUse = new UniqueSelection('normal-list',
{ 'first-element': firstElementsFunc,
'second-element': secondElementsFunc,
'third-element' : thirdElementsFunc});


This version also doesn't loop through the child elements on every click - it just works with the current element, which means that the choice function shouldn't slow down on large lists.

I'm not sure if this is the javascripty way of accomplishing this, but it works for me. It's not exactly efficient as far as memory usage goes, but it could be a lot worse (and it works). I'm still learning javascript, and it hasn't quite seeped entirely into my brain yet, but it's getting closer.

2008-04-28

A simple way to manage tab-lists, and other unique selections.

So, in the current project I'm working on, I've run into a few situations where I want to have a list of options, only one of which is allowed to be "active" at any given point in time. Examples: tabbed interfaces, editing "modes" for the shape and grid editors that I'm working on (you can be in "deleting" mode or "inserting" mode or "setting center" mode, for instance).

Basically, all I needed was to be able to say "This list of stuff is only allowed to have one thing selected at once", while showing the active selection with css.

As a first attempt, I wrote the following little bit of javascript:

function UniqueSelection(id) {
function toggle() {
UniqueSelection.active.className = "inactive";
this.className = "active";
UniqueSelection.active = this;
}

var listItems = document.getElementById(id).getElementsByTagName('li');

for(var i = 0; i < listItems.length; i++) {
listItems[i].onclick = toggle;
if(listItems[i].className == 'active'){
UniqueSelection.active = listItems[i];
}
}
}


Which works, but has one big flaw: you can only have one UniqueSelection at a time, and is a pretty ugly solution anyhow.

The following code allows you to have as many UniqueSelection elements as you want, and is shorter, clearer code:


function UniqueSelection(id) {
var listItems = document.getElementById(id).getElementsByTagName('li');

function toggle() {
for(var i = 0; i < listItems.length; i++) {
listItems[i].className = 'inactive';
}
this.className = 'active';
}

for(var i = 0; i < listItems.length; i++) {
listItems[i].onclick = toggle;
}
}


This does have some downsides - for one, it might have a visible delay on long lists. For two, you can't have multiple class names on your 'li' elements. For my purposes, this is fine - and I think that if you're using ul's in a semantic manner, it shouldn't be a problem.

The code above does show some interesting things about javascripts scoping rules though.



Update:

With a couple more lines of code, we can allow for both lists where a selection must be unique and a selection must be active, and lists where a selection must be unique, but where the current selection can be turned off without making another one:


function UniqueSelection(id, allowToggle) {
var listItems = document.getElementById(id).getElementsByTagName('li');

function choose() {
for(var i = 0; i < listItems.length; i++) {
if(listItems[i] != this)
listItems[i].className = 'inactive';
}

if(allowToggle && this.className == 'active') {
this.className = 'inactive';
}else{
this.className = 'active';
}

}

for(var i = 0; i < listItems.length; i++) {
listItems[i].onclick = choose;
}
}




Update 2: The above function clobbers the onclick attribute, and in some cases I need it to not do so. Getting it to not clobber is turning out to be frustrating though. . .


Update 3: Got it working, through a bit of education and head-banging. The new code and an explanation of what was going on deserves it's own post though. Will write it up later.

2008-04-24

More editor UI improvements

Most of what I got done today was improvements to the different "modes" you can be in while editing shapes - by mode, I simply mean "adding blocks" "deleting blocks" or "setting the center of the shape". Worked on styling li items as buttons, realizing that it is very easy to use too much markup to describe something on the page, and remembering that to write solid javascript, you really need to code as if everything in the world is out to get you.

On that last point, it's always a good practice to code defensively, but I've noticed a greater need for it in javascript, due partially to the nature of the language, partially to differing implementations in different browsers, and partially due to the inconsistency of how different libraries implement their functionality. For instance, I need to pass data about shapes, game rules, and such back and forth between the client and server. I've been using JSON for that, and it works quite well - but the javascript file provided by json.org breaks prototype. The solution to this is to use the newest stable version of prototype, which has JSON support built in. Or you could always roll your own JSON encoder / decoder - it's not really all that complicated.

On the rails side, I've just been using YAML.load, since JSON tends to be valid YAML (god, not to be confused with YAML...), and I was running into some issues with getting rails' json support working correctly.

Another thing that bit me about javascript was NaN being typeof "number". This is documented, and pretty common among languages, and there's a isNaN test, but for some reason, I tend to never expect it. Bah.

2008-04-23

Improving the color picker.

Today, I improved the color-picker for the shape and removal-rule editors. The color-picker itself is very simple - just a collection of square divs that you can click on to change the color of the next blocks you click on in the shape grid.

Prior to today, I was just using a simple ROYGBV list, packing it into an array and rendering the divs server-side. I'm still rendering the divs server side, but I'm iterating through color values, stepping from 0 to 255 by 64. This provides a nicer range of colors to choose from.

Ideally, I'd like to implement a photoshop-style color chooser, or at least order the divs into blues, reds, and greens (I may do this here in a day or two) - but this can wait for a bit.

2008-04-22

Getting more familiar with CSS

Today I realized that I absolutely suck at using CSS. It's not something that I ever really spent a lot of time working with, and I've always had a bit of a hateful relationship with web-development.

For a long time, doing any sort of serious web development work was nothing but a pain in the ass - there were so many shitty hacks around browser inconsistencies that you could probably live off of the print-up of them for a few months. Recently, things have gotten quite a bit better, and frankly the only browser that really plays "bad" when it comes to standards is IE - and even it has gotten lots, lots better.

So anyhow, doing CSS work is not nearly as painful as it used to be, although for someone who is not a designer type (like me), it can be a bit hard to make a site look pretty, not to mention that there are a bunch of "accepted" ways of doing things that may not be really obvious, like using lis for tabs.

Three things helped me out a great deal - one was this talk by Douglas Bowman. While he didn't spend too much time talking about actual CSS code (it was assumed that you were already familiar with the workings of CSS), some of the points made were very good, even if they seem a bit obvious, like "Design your site in something else - pen & paper, photoshop, the gimp, whatever. Don't design your site using CSS because then you'll be limited to how much CSS you know, instead of having to learn more to get your site looking how you want it."

The second thing that helped me out a whole lot was YAML builder , which is a tool for designing multi-column layouts using YAML (not to be confused with YAML). While I won't be using YAML for my extendable tetris game, the tool was really nice for getting a look at how to properly structure an XHTML skeleton for doing a layout, as well as some CSS techniques.

One last useful thing I found for getting more familiar with CSS and how it's used was Eric's CSS Reset Reloaded, which basically sets everything to nothing, as far as CSS goes. Not only does this get rid of a good bit of cross-browser pain, it also forces you to manually set up, well everything - which is really useful for learning.

You see, I'm fine on implementing the back-end stuff for this site. The technical functionality of the web-app I'm working on really isn't that hard for me, and I can test most of it (using, you know . . . tests), however on the front end the usability and functionality of the site is more or less inherently tied to the presentation of the site - and you either have to know your way around CSS, or resort to using some table-layout monstrosity shit out by Dreamweaver that will be hell to maintain and ugly as satans balls to anyone who's looking at your source (you included). I refuse to take that second option.

Anyhow, end result was that my design for the shape editor got much cleaner, and a bit more modular - which is never a bad thing.

2008-04-21

An extendable tetris.

So, I've been working on a pet project of mine - a web-based, expendable tetris game. I want to allow people to create their own shapes, and their own rules for the removal of blocks from the game grid.

I'm doing in in Ruby on Rails, and so far I have an editor for the shapes, and will be working on the game mechanics more here in the next few days.

There's nothing live yet (I don't even have a domain for it, I may end up hosting it off of my own machine for a bit at the start...), so even if this sounds really interesting to you, too bad. If you are reading this, and would be interested in testing when I get something . . . testable done, just comment or drop me an email (it's on my profile page)

It's a good exercise in abstraction - there are a whole lot of games that are very similar to tetris. Blocks fall, stuck together in a shape. Sometimes blocks get removed from the screen. They may get removed when they fill a certain shape (in the case of classical tetris, one entire row), or maybe when a certain number of the same colored blocks come into contact with one another. Blocks might fall down after removal as if gravity was in play, they might not, etc.

Some things I'd like to implement:

* I'd like people to be able to mark existing shapes, or game rules for use in a game they are defining.

* I'd like people to be able to rate games.

* I'd like to be able to attach different attributes to games, or to shapes - for instance, a game where gravity was skewed a bit towards the left, making your piece drag. Or maybe adding a rotational velocity to certain shapes.

I haven't really been working on this for very long - I need to get a base amount of pluggable functionality implemented (which is a good bit of javascript and rails work), but once that's done the rest of implementation should move pretty fast. I guess I'll post updates as I move along here, since I don't really use this blog for all that much.

2008-04-17

This programmer still reads books.

Joel Spolsky recently wrote:

Programmers seem to have stopped reading books. The market for books on programming topics is miniscule compared to the number of working programmers.

I certainly can't speak for all programmers, but as for myself, and every programmer I know in real life, we are still reading books. However, we may be reading less books.

I would guess that up until a few years ago (more, depending on how you look at it), books were the only good way to get a start in programming, or in a new programming language. The information available online was simple not good enough to give you anything more than a cursory glance at the process of software development, much less on specific languages and frameworks. Internet speeds were slower, the push for open content wasn't in nearly as much of a fervor, and there were much fewer programmers.

These days, a lot of people are picking up a scripting language, or have a need to learn some basic programming skills, and (at least partly because of this), there is a lot of information readily available about such things online. Hell, there's an entire culture surrounding programming blogs (and sure, blogs in general).

Right now, if I want to get a feel for a new framework, or a new language, or for software engineering or computer science in general, there is a whole plethora of pretty high quality material available to me online for free. Books on these subjects are expensive, and I am nowhere near rich. However, if I use a language frequently enough, I often want a dead-tree book as reference material. For example, I have gotten very heavy use out of Javascript the Definitive Guide, Agile Web Development with Ruby on Rails, and Python in a Nutshell.

If I need to remember, or look up how to do something in one of these subjects, I go to these first.

Similarily, books like SICP, The Mythical Man Month, TAOCP, The Art of the Meta Object Protocol, - and many others, while not necessarily about any one programming language or framework, are filled with things that programmers tend to find interesting, and are worthy of being read if one is wanting to improve their skill as a programmer. Some of these great reads are
available to read online for free, some of them are not.

Please note that this shouldn't be read as critical of the upcoming stackoverflow.com. I think that it would be very nice to have a popular, high-quality replacement for abhorrent beasts like expertsexchange - however, I don't think that it'll be replacing books anytime soon for me, especially not in areas that are more general than specific programming languages and frameworks.