Mar 05 2009

2

MooDocs TextMate Command

Category: UtilitiesTags: , ,

José Prado just released the MooDocs Coda plug-in . The plug-in allows Coda to parse MooTools Classes and generates a Markdown formatted template ready to fill in with details. I took his great work and modified it for TextMate.

I packaged it as a single command that installs into the Javascript bundle. I also assigned <command>-D to the command, for even quicker generation. One minor thing I fixed with the code was the parsing of the class name. There were a few cases where classes are created without var and have a ‘dot’ in the name. Like Fx.Morph or Drag.Move.

You are still required to end your classes like so:

var MyClass = new Class({
 
 
});//end

Download MooDocs for TextMate

Update:

MooDocs for TextMate has been moved to a github repo

Tags: , ,


Feb 13 2009

0

Visual Sorting Explained

Category: Mootools, UtilitiesTags: , , ,

I am getting the impression that my previous post was a bit esoteric. It has some valid uses and I want to help visualize how you might use the ‘visualSort’ method on Elements.

Lets first take a look at the demo I put up.

In the above image we have selected 5 elements. As you can see none of them are aligned and they actually overlap. However, the human eye discerns that there are 2 lines of elements. 3 on the top row, 2 on the bottom. The ‘visualSort’ method allows you to see elements like a users would in your code.

How visualSort solves this problem is two fold. First, it takes all the elements and sorts them by the ‘top’ coordinate. Once this sort is complete a second sort is performed. The first element is grabbed and an index is made based off the ‘tolerance’ (defaults to .5 or 50%). What this means is the height of the element is taken and multiplied by the ‘tolerance’. This result is added to the to the top value to get a tolerance range.

For example if chocolate had a top of 10px and was 20px in height. The tolerance would be within 10-20px. Any following element that has a top pixel within this range will be added to the same row. As an element is added to a row they are sorted by the left pixel to make sure they are in the correct order. If an element is not within that range a new row is created along with a new tolerance. The cycle repeats until all elements have been processed.

Continue reading “Visual Sorting Explained”

Tags: , , ,


Feb 13 2009

1

Visual Sorting

Category: Mootools, UtilitiesTags: , , ,

As promised I have been cleaning up the code to my most recent demo. I will be releasing a much more polished API along with documentation in the near future. Stay tuned.

I just completed one of the biggest headaches. Visual sorting. This allows DOM elements to be sorted in the same way humans would visually. I tried to make this as simple as possible to use.

I extended ‘Elements’ with a new method ‘visualSort’. The tricky part with a visual sort is the fuzzy logic needed to handle elements being offset. If you play with the demo you will get a feel for what I am talking about. In the demo, there is no need for pixel perfect alignment of elements to be considered on the same row. To require this would make the UI completely useless. To have this kind of fuzzy range matching ‘visualSort’ has a tolerance parameter. This allows you to define how much elements can be offset before it is considered a new ‘row’. Currently, tolerance defaults to .5 (50%). I also established a second parameter ‘flatten’. If set to true the sorted list will be flattened and returned as an Elements object. Currently ‘visualSort’ defaults to false which returns a multidimensional array.

In writing this code I tried to optimize the sorting as much as possible. I see a few places that can be tweaked but overall it should be fast. I didn’t use any sort() methods. I handle all my own sorting as I iterate through the elements. Feel free to ask questions about the logic or code.

Enjoy! My Brain still hurts.

 
Elements.implement({
 
	visualSort : function(tolerance,flatten){
 
		var tolerance = (tolerance) || .5;
		var idx = [], el, c1, c2, placed;
 
		for(var i = 0, l = this.length; i < l; i++){
			el = this[i]; c1 = el.getCoordinates();
			if(!i) idx[0] = [el, c1];
			else {
				j = 0; placed = false;
				while(j < i && !placed ){
					c2 = idx[j][1];
					if(c1.top < c2.top) placed = true;
					else j++;
				}
				idx.splice(j,0,[el,c1]);
			}
		}
 
		var rows = [], row = 0, sorted = [], slen, threshold;
		for(i = 0; i < l; i++){
			c1 = idx[i][1];
			if(!i){
				rows[row] = [c1.top,(c1.top + c1.height*tolerance)];
				sorted[row] = [ idx[i] ];
			}
			else {
				threshold = rows[row];
				if((threshold[0] <= c1.top) && (c1.top <= threshold[1]) ){
					j = 0; placed = false; slen = sorted[row].length;
					while(j < slen && !placed){
						c2 = sorted[row][j][1];
						if(c1.left < c2.left) placed = true;
						else j++
					}
					sorted[row].splice(j,0,idx[i]);
				} else {
					row++;
					rows[row] = [c1.top,(c1.top + c1.height*tolerance)];
					sorted[row] = [idx[i]];
				}
			}
		}
 
		var result = [];
		for(i = 0, l = sorted.length; i < l; i++){
			result[i] = [];
			for(j = 0, len = sorted[i].length; j < len; j++){
				result[i][j] = sorted[i][j][0];
			}
		}
 
		if(flatten) return $$(result.flatten());
		return result;
 
	}
 
});

Example Usage:

var sorted = $$('your selector').visualSort(.7);

I believe the value of this will be seen in Drag and Drop interfaces and layout managers. It could have some potential use for serializing specific components. If you find a use for it please share.

The demo has been updated with this code, it works in IE now.

Tags: , , ,


Feb 09 2009

3

Drag.Group for Mootools

Category: UtilitiesTags:
Update

Check out the demo.

I have been playing around with creating more advanced UI components recently. I ran into the need to be able to drag multiple items at a time. I created the following classes to solve my problem. It is important to know that this code is still in alpha stages and is just a proof of concept for now. I will posting a bit later how I use this to create a UI component.

Drag.Group = new Class({
 
	Implements : [Options],
 
	options : {
		'active' : true,
		'store' : 'drag-group-item',
		'filter' : $lambda(true),
		'drag' : {}
	},
 
	elements : [],
 
	initialize : function(options){
		this.setOptions(options);
	},
 
	add : function(el,options){
		var drag = new Drag.Group.Item(el, this, $merge(this.options.drag,options))
		el.store(this.options.store, drag );
		this.elements.push(el);
		return drag;
	},
 
	start : function(el,event){
		if(!this.options.active || !this.options.filter(el)) 
			el.retrieve(this.options.store).start(event,true);
		else {
			this.elements.filter(this.options.filter).each(function(match){
				match.retrieve(this.options.store).start(event,true);
			},this);
		}
	}
});
 
Drag.Group.Item = new Class({
 
	Extends : Drag.Move,
 
	initialize : function(el,group,options){
		this.group = group;
		this.parent(el,options);
	},
 
	start : function(event,alerted){
		if(alerted) this.parent(event);
		else this.group.start(this.element,event);
	}
 
});

Drag.Group has the following options:

  • active : boolean ( if active grouping behavior is performed, else default Drag.Move)
  • store : string ( used to store the custom drag obj on the element )
  • filter : function ( takes one parameter (element). return true or false if it is part of the active drag group
  • drag : object ( default drag options for newly created items see Drag )

Usage :

var drag_group = new Drag.Group({
  'filter' : function(item){ return item.hasClass('active'); }
});
 
drag_group.add(el);

The ‘add’ method takes an optional second parameter which is a ‘Drag.Move’ options object. This allows for overriding the drag behavior on a single element. ‘add’ is currently limited to only taking one element at a time. I will add array support later.

My biggest concern with the current interface is the number of ‘document’ events that get created. I haven’t noticed any real issues in testing.

I will be following up with demos and extensions soon.

Tags:


Dec 18 2008

6

Compressed JSON Requests

Category: UtilitiesTags: , ,

I rarely find myself in a place where I am writing javascript applications that use AJAX in its pure form. I have long abandoned the ‘X’ and replaced it with ‘J’ (JSON). When working with Javascript, it just makes sense to return JSON. Smaller footprint, easier parsing and an easier structure are all advantages I have gained since using JSON.

In a recent project I found myself unhappy with the large size of my result sets. The data I was returning was tabular data, in the form of objects for each row. I was returning a result set of 50, with 19 fields each. What I realized is if I augment my result set I could get a form of compression.

// uncompressed
JSON = {
  data : [
     { field1 : 'data1', field2 : 'data2', field3 : 'data3' },
     { field1 : 'data4', field2 : 'data5', field3 : 'data6' },
     .....
  ]
};
 
//compressed
JSON = {
    data : [ 'data1','data2','data3','data4','data5','data6' ],
    keys : [ 'field1', 'field2', 'field3' ]
};

I merged all my values into a single array and store all my fields in a separate array. Returning a key value pair for each result cost me 8800 byte (8.6kb). Ripping the fields out and putting them in a separate array cost me 186 bytes. Total savings 8.4kb.

Now I have a much more compressed JSON file, but the structure is different and now harder to work with. So I implement a solution in Mootools to make the decompression transparent.
Continue reading “Compressed JSON Requests”

Tags: , ,


Dec 04 2008

5

Registry Class for Mootools

I have been building some pretty large apps lately and I found the need for the registry design pattern in some of my javascript. I went with this approach because I wanted to minimize the power my objects had, yet I needed some kind of blackboard where all objects could check and report to.

In addition I found that implementing events onto the class made for a very effective event handler as well.

var Registry = new Class({
 
	Implements : [Events],
 
	conf : {},
 
	set : function(path,value){
		var fragments = path.split('/');
 
		if( fragments.shift() !== '') return false; // remove empty, first component
		if(fragments.length > 0 && fragments[fragments.length - 1] == '') fragments.pop();
 
		var obj = {}; var ref = obj; var len = fragments.length;
		if( len > 0){
			for(i = 0; i < len-1; i++){
				ref[fragments[i]] = {};
				ref = ref[fragments[i]];
			}					
			ref[fragments[len-1]] = value;
			this.conf = $merge(this.conf,obj);
		} else {
			this.conf = value;
		}
	},
 
	get : function(path){
		var fragments = path.split('/');
 
		if( fragments.shift() !== '') return null;
		if(fragments.length > 0 && fragments[fragments.length -1] == '') fragments.pop();
 
		var ref = this.conf; var path_exists = true; var i = 0; var len = fragments.length;
		while(path_exists && i < len){
			path_exists = path_exists && (ref[fragments[i]] !== undefined);
			ref = ref[fragments[i]]; i++;
		}
 
		return ref;
	}
 
});

The class is pretty simple but it provides for a powerful hierarchical syntax. Only two methods are supplied ‘get’ and ’set’.

Example:

var reg = new Registry();
 
reg.set('/Options/Default',{'name' : 'test', 'version' : 1});
 
reg.set('/Options/Default/name', 'changed');
 
reg.set('/dynamically/creates/nested/objects', true);
 
reg.get('/Options/Default');
/* returns
{
 name : 'changed',
 version : 1
}
*/
 
reg.get('/Options/Default/version'); // returns 1
 
reg.get('/');
/* returns
{
 Options : {
	Default : {
		name : 'changed',
		version : 1
	}
 },
 
 dynamically : {
	creates : {
		nested : {
			objects : true
		}
	}
 }
}
*/

I found it extremely useful for configuration objects for classes that were initialized in a tree fashion. It also seemed to help with the readability and organization of code. I also had several places where I had multiple objects doing completely different things to the same Request.JSON result. With this class I just stored it in a single place and fired off my event. I found it extremely useful to use the class as a global event manager for cases such as this. I ended up using a dot notation naming convention for my events which helped greatly in documentation and API design.

reg.addEvent('App.initialize',function(){});
 
reg.addEvent('App.shutdown',function(){});
 
reg.addEvent('Data.feed1.loaded',function(){});
 
reg.fireEvent('App.shutdown');

In my actual production code I had my Registry class implement my Singleton Class Mutator. This way I could initialize the registry object multiple times in my code without the need to worry about scope.

Tags: , , ,


Oct 01 2008

1

Rubberband Select

Category: UtilitiesTags: , ,

A while back, Chris Esler wrote a terrific script for custom selection of elements within the DOM called Rubberband. I have found the use of Rubberband extremely handy when dealing with complex UI management. While Rubberband functioned exactly as described I found a few minor issues that I needed resolved before implementing.

The major annoyance I had with Rubberband was the actual selecting part. When selecting, the browser also selects and highlights the DOM in the background. I found this to be annoying and distracting, both hurt usability.

The second issue I found had to do with recycling the object. In my case, I was adding and removing elements to my selectable area. This required me to use the rebuild function. I found a slight bug that prevented this from working.

Both of these issues are no more!

Click to download Rubberband (enhanced)

Tags: , ,