Set your Setter and Get your Getter

January 3rd, 2009

Getters and Setters are a lot of fun to use. Unfortunately not all browsers implement them. According to John Resig’s post JavaScript Getters and Setters only two browsers currently support them (Opera 9.5 has since been release so make it three). Even before I was really into Javascript programming I used PHP’s Magic Methods __set and __get.

It is with much happiness that I think I can finally say, without seeming like a fool, that: “JavaScript Getters and Setters are now prevalent enough to become of actual interest to JavaScript developers.” Wow, I’ve been waiting a long time to be able to say that.
John Resig – JavaScript Getters and Setters

As much as I would love this to be true, I still do not quite think we are there. Rhino adding support was good, because with that John was able to implement window.location in env.js

So now that we have some background on setters and getters in Javascript. Here is my implementation for browsers that do not already support it.

                        (function()
                        {
                                var gettysetty =
                                {
                                        clock: 0,
                                        gets: Array(),
                                        sets: Array()
                                }; 

                                function procVars()
                                {
                                        // run through all the getters, update the var from the function
                                        for(var i = 0; i < gettysetty.gets.length; i++)
                                                gettysetty.gets[i][0][gettysetty.gets[i][1]] = gettysetty.gets[i][2](); 

                                        // same thing here, but instead check that the var has not changed, if it has, run the setter func
                                        for(i = 0; i < gettysetty.sets.length; i++)
                                                if(gettysetty.sets[i][0][gettysetty.sets[i][1]] != gettysetty.sets[i][2]["ogVar"])
                                                {
                                                        gettysetty.sets[i][2].apply(gettysetty.sets[i][0], [ gettysetty.sets[i][0][gettysetty.sets[i][1]] ]);
                                                        gettysetty.sets[i][2]["ogVar"] = gettysetty.sets[i][0][gettysetty.sets[i][1]];
                                                }
                                } 

                                var getterName = (Object.__defineGetter__ != "undefined") ? "defineGetter" : "__defineGetter__";
                                Object.prototype[getterName] = function(v, f)
                                {
                                        this[v] = f(); 

                                        gettysetty.gets.push([this, v, f]); 

                                        if(!gettysetty.clock)
                                                setInterval(procVars, 13); 

                                        return this;
                                } 

                                Object.prototype[(Object.__defineSetter__ != "undefined") ? "defineSetter" : "__defineSetter__"] = function(v, f)
                                {
                                        f["ogVar"] = this[v];
                                        gettysetty.sets.push([this,v,f]);
                                        if(!gettysetty.clock)
                                                setInterval(procVars, 13);
                                }

                                function lookup(gs, v)
                                {
                                        for(var i = 0; i < gettysetty[gs].length; i++)
                                                if(gettysetty[gs][i][0] == this && gettysetty[gs][i][1] == v)
                                                        return gettysetty[gs][i][2];
                                                else if(gettysetty[gs][i][0] == this)
                                                        return;
                                        return;
                                }

                                Object.prototype[(Object.__lookupSetter__ != "undefined") ? "lookupSetter" : "__lookupSetter"] = function(v)
                                {
                                        return lookup.apply(this, ["sets", v]);
                                };

                                Object.prototype[(Object.__lookupGetter__ != "undefined") ? "lookupGetter" : "__lookupGetter"] = function(v)
                                {
                                        return lookup.apply(this, ["gets", v]);
                                };
                        })();

                        var x = {};
                        x.defineGetter("time", function()
                        {
                                return (new Date()).valueOf();
                        });

                        x.defineSetter("x", function(val)
                        {
                                this["x"] = val+1;
                                alert("new value: " + val);
                        });

The code here is fairly simple. When the first getter or setter is define a timer is started. It iterates through all the defined getters and executes their function updating the value it is responsible for. Then it iterates the setters, checking if the current value is different from value it had when set. If they are different it runs then setters function and updates the ‘old’ variable to reflect the new one.

This only supports adding by the Object methods, so you cannot define them in an object notation. As for the future, v8 supports them, and I looks like Internet Explorer 8 may support some variation in some very Microsoft way. defineProperty anyone? While this solution is far from bullet proof and probably will scale terrible it could possibly work as an absolute fallback.

New Cometd client and server demo

November 7th, 2008

On and off for the last couple weeks I have really been pushing myself to learn Java better. I constantly find myself unable to do things I want to with the languages I usually use (PHP specifically). As I am getting better I am coming to like it a lot more. As any reader of my blog (do I actually have ‘readers’?) know, I am really into Cometd, which the most major implementation of is written in Java. So in order to utilize Cometd Java and push my jQuery plugin further along, I figured it was high time I learn Java. I am really glad I am too. Just in time for my new Android phone too :)

CometdMap
Almost every demo of Cometd out there is a chat application, next up is stock tickers. There are one or two more I can think of off hand, none of which could be made into something more useful. I have had an application idea in the back of my head for quick some time. I really like doing work with maps, have been doing professional Google Maps work for a couple years, had to get the (second) dorkiest bike computer with GPS to map my rides. I have wanted for some time to do a real-time map. CometdMap is a proof of concept of that. It has no actually data input at the moment, infact, it is really basic right now. What it really does is show how simply you can build a Cometd Java app. I was really surprised at how easily I built this with my limited knowledge of Java.

What does it do
Right now, if you build and run the application you will get a simple Google Map. Clicking on the map will place a marker. Wowee! Pretty basic yeah, but what is going on here. Clicking the map publishes the point to the server, it is not until the server returns the data to the subscription callback that it is added. That is about all for the client side. On the server side two things are going on. First, when a new client joins they are added to a list, very similar to the way the Cometd Chat demo handles clients for private messages. Second, when points are published they are tracked on another list. So what can we do with these lists? Add a couple points and reload your browser. Since you are now a new client and there are points on the list, the old points are sent back to you. This will work for any new clients joining also. With multiple clients connected markers are updated to each in real-time.

Download & Build
Download
As I have mentioned before, the Java build environment and I do not exactly get along. In the tarball there is a script call build (partially ripped from the Harmony build script). If you have built the Cometd demo from Jetty with Maven this script should work just fine. Otherwise change the paths in the build (and server) scripts to point to the directories where your Jetty and Comet components are.

Enjoy, hopefully everyone is able to build with few problems. Check back in a couple weeks to see what I have in store next. Cheers, Morgan.

Progressive Enhacement

October 15th, 2008

Just read this blog post over at Learning jQuery. It is a tip on how to avoid ’style flashing’ on large and complex pages. Read it. Read it to get the explanation as to why just CSS cannot solve this problem. If you have been unfortunate enough to work with me, especially in a JS/design roll you will have heard me bitching about CSS in jQuery. I do not like when this is done. CSS is way better at CSS then jQuery. The benefits of apply the style is this global manner are huge.

  • Speed of CSS
  • <linked> files get cached
  • Your Javacript will be simpler, smaller, faster
  • If you are working with a team a designer can work on it without causing conflicts

And this does not just apply to jQuery either, any framework or script can (and should) utilize this technique. Keep in mind this is not a cure all for progressive enhancement. You still cannot go all willy nilly AJAX without an already working base system. Thanks for the great tip.

more histarray

September 19th, 2008

I am not sure if it is even useful for anything. But I am having fun dorking on it.
New Features.
added pop() method
added splice() method
unified adding and removing for more accurate revision and length

New Home
I have been using hithub for a little now, and have put this up as my first public repo.

*Notes
There is one big, probably unresolvable issue. You have to push in new elements.

 var a = Array('one', 'two', 'three');
 a[12] = 12;
 // this would result in an array with a length of 13
 // with 3-12 undefined.

The way the getters and setters are setup, unless I where to define ervythin’ there would be nothing waiting to assign an element to the internal array.

Next Steps (if any)
Implement standard array features
Decide if push should be like an array push and create a new method for historical pushes.

Last up
I also finally got around to figuring out qunit unit testing. It is really easy to use, not sure why I have not been using it longer. I have 19(?) tests right now, and they are in /test in the repo.

histarray – An Experiment with Getters and Setters

September 18th, 2008

While doing an experiment with Getters and Setters I whipped together a small lib for a versioning array, the histarray. So far tested only in Firefox 3, it utilizes __defineGetter__(someNumber, function(){}) to return an element from an internal array (the history). Its push method will either overwrite the current revision if it is not the last, or push a new revision into the history. A Setter is also defined, so no matter where in the time line you currently are, that element will be updated.

function histarray()
{
	for(var i = 0; i < arguments.length; i++)
		this._add(arguments[i], i);

	this.__defineSetter__('revision', function(v)
	{
		return (v > this.length) ?
			this.revision :
			this._revision = v;
	});
	this.__defineGetter__('revision', function()
	{
		return this._revision;
	});
	this.__defineGetter__('prev', function()
	{
		return (this.revision != 0) ?
			(function(self)
			{
				var a = Array();
				for(var i in self._elements)
					a.push(self._elements[i][self.revision - 1]);
				return a;
			})(this) :
			null;
	});
	this.__defineGetter__('nxt', function()
	{
		return (this.revision < this.revisions) ?
			(function(self)
			{
				var a = Array();
				for(var i in self._elements)
					a.push(self._elements[i][self.revision + 1]);
				return a;
			})(this) :
			null;
	});
};

histarray.prototype =
{
	length: 0,
	revisions: 0,
	_elements: Array(),
	_revision: 0,
	_add: function(e, i)
	{
		this._elements[i] = (function(e,self)
		{
			var a = Array();
			for(var i = 0; i < self.revisions; i++)
				a.push(null);
			a.push(e);
			return a;
		})(e,this);
		this.__defineGetter__(i, function()
		{
			return this._elements[i][this.revision];
		});

		this.__defineSetter__(i, function(v)
		{
			return this._elements[i][this.revision] = v;
		});
		this.length = i + 1;
	},
	// push csv or a single array
	push: function()
	{
		if(typeof arguments[0] == 'object')
			this.push.apply(this, arguments[0]);
		else
		{
			if(this.revision == this.revisions)
			{
				this.revision++;
				this.revisions++;
			}
			for(var i = 0; i < arguments.length; i++)
			{
				if(arguments[i] == null) continue;

				if(this._elements[i])
					this._elements[i][this.revision] = arguments[i];
				else
					this._add(arguments[i], i);
			}
		}
		return this.length;
	}
};
// creates a new histarray.
var ha = new histarray('e1', 'e2', 'e3');
// this is now just like a normal array, ha[0] == 'e1'
// now using push does not add a new element, but instead adds a new revision
ha.push('e1v2', 'e2v2', 'e3v2')
// now ha[0] == 'e1v2' and ha.revision == 1 and ha.prev[0] == 'e1'
// if we change the revision back to 0
ha.revision = 0;
// ha[0] == 'e1', ha.nxt[0] == 'e1v2'
// with the revision still at 0, we can update an old element
ha[0] = 'e1a';
// this just changes the first revision of the first element.

Not certain is will be useful for anything in particular. But I still have a couple ideas to add, and am interested in hear what people have to say about this.

jQuery Comet update (finally).

September 9th, 2008

Now that I am semi-settled in here in Berlin (anyone have a room for rent? (cheap)), I am trying to get caught up on stuff. I finally pushed some fixes suggested by Jörn and got the chat demo reported. Its all in the SVN at Google Code and setup an external item in the jQuery SVN. Also sent an email to Greg Wilkins today, hopefully I can get this into the Cometd SVN also.
Next release will be a total rewrite, I made a lot of mistakes in the original, and the prefer jQuery plugin style has changed. Getting back to this point will not be too difficult, and well worth it.

Euro to USD Ubiquity command

September 5th, 2008

I have been playing quite a bit with Ubiquity lately. So far, I think it is really cool. One thing that has always prevented me from really getting into Firefox extension development is the constant restarting. I am a two or three line and test type of developer and that just does not work. But Ubiquity reload all the command every time you open it. And its got jQuery. Since I am living in German now but still earning the US Dollar, I am constantly concerned with the exchange rate and find myself visiting xe.com frequently. Perfect chance to make a new command. So far it just does Euro to USD, I hope to add all their options. Here it is.

Updates in the world of Morgan

September 3rd, 2008

With the major exception of USPS, Deutsche Post and DHL’s combined effort to loose my laptop, things are going great. I have been in Berlin for about three weeks now, landed an exciting new programming contract, looking like I found a rather cheap room to rent.

So what have I been up to….. Since I do not have my regular laptop, the programming lad been kinda limited. I am working on my ASUS EEEpc (which I finally fixed) which has been, well, a bit of a pain in the ass. But surprisingly I have gotten used to it. But I have also gotten a new laptop (free too). So tomorrow I will be back to it, getting some really work done on a full sized screen. But I still have been working on some interesting stuff. For the new job, I have spent the last day familiarizing myself with the code already in place and doing a huge amount of cleanup. A lot of redundant code, good practices used in the wrong way, bad practices making things worse. But not too bad all in all. I have also been playing a lot with V8 which I am super excited about. While I am not the best C++ programmer, I am a terrible Java programmer. So this is a great alternative to Rhino. And that’s not entirely true, I can guess and stumble through Java as well as C++, but Java’s build environment leaves me totally befuddled. I have also been playing around with FUSE again, and decided why not combined the two? So I made JsFS (I’ll post about this again later), but basically it create a jsin and jsout file, put Javascript into jsin and it is executed by V8 and the results are in jsout. Pretty useless yeah, but it was fun to make. I figure in the end I could make a Javascript interface for FUSE.
Bike News! I rode to Copenhagen two weeks ago. Well most of the way. Weather was not very cooperative and my friend I was riding with got injured to we ended up riding about half of it while hoping on and off trains. I am putting together a better mini-touring setup and will be riding to Geneva in about two weeks to race in the Swiss Bike Messengers Championship.
Also posted some pictures. Okay, thats enough out of me.

Move along

July 17th, 2008

After about a year and a half, I have decided to leave Snitsig (snappystuff.com). The decision was made mostly due to my excessively long commute, sometime spending as much as 5 hours ‘going’ (lots of missed,delayed,slow trains and standing around) to and from work. But in the last year+ I really learned a lot. I went from ‘Nah, I do not use XML much’ to a near zealot for it (I have not forgotten about you JSON). I am doing things in PHP I did not think possible (Almost there PHP), had the opportunity to do a little more hardware/Interweb interaction and play with RFIDs again. Learned a TON about API writting. Most importantly I learned about working with a team. I am so used to working either along or with just one other person. It is really nice having other people to bounce ideas off of and collaborate with. Cheers to you SnappStuff, it was a pleasure working with you all, and I look forward to collaborating with you all again.

And for me…. Meh, I’m fickle.

DBXMLAdmin updates

May 29th, 2008

After being completely annoyed by SimpleXML earlier I decided it was time to look at DBXML again. This time I ran across a forum posting saying that DBXML 2.4.11 had a bug in it preventing updating. After upgrading to 2.4.13 I was able to update documents in a container. So I made some update to the project but realized that this was more of an out of control experiment than a real project. Already started redoing it, all the PHP is going to be new but I have managed to reuse most of the Javascript.

I also found this site DBXML With PHP, it is a small wiki for, as the name says, using DBXML with PHP. It has not been updated in a while (until today) but I will keep adding things as I progress on DBXML. Hopefully other will help out too, right now there are few resources for DBXML in PHP.