Posts tagged ‘Javascript’

Often, you will need to prevent users from entering data that doesn’t conform to a specific pattern. For example, you may want to allow users to enter only numbers or only valid email addresses. To this end, I’ve written a little utility function that returns the “standardised” version of a string, according to the regex you supply.

String.implement({
	limitContent: function(allowedRegex) {
		return $splat(this.match(allowedRegex)).join('');
	}
});

Basically, the function takes the result of evaluating the regular expression on the string, converts it into an array if it isn’t one, and then joins the array’s elements together with an empty string.

Examples:

console.log("12345".limitContent(/.{4}/)); // Only allow four characters
console.log("joe@mail.com".limitContent(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}/)); // Only allow email addresses

MooTools object messaging

2009-10-22 – 5:19pm

Events

In JavaScript, we often tend to use events all over the place. In MooTools, the custom ‘domready’ event is particularly prevalent. However, events suffer from a few drawbacks:

You can’t attach events to non-existent objects.

Pretty self-explanatory, really. What this means in practice, though, is that you can’t easily let object A know when object B exists.

If an object starts to listen for an event after it’s already fired, it’ll never hear it.

Because content on the web isn’t always delivered in perfect order (especially when you’re loading scripts synchronously), it’s possible for an object to try to listen for an event after it’s already been fired. Obviously, this means that your listener object will never run the code that’s dependent on that event, which could be Bad Thing™.

It’s not particularly easy to know which object is listening for which events.

There are ways around this, but you can’t just dir() the listeners in Firebug.

A messaging system

For all of these reasons (and probably a few more that I’ve forgotten about), a messaging system can be an invaluable addition to your arsenal when writing JavaScript. How does a messaging system work? Well, interested objects ‘register’ themselves as listeners for particular message ‘handles’, and other objects can send messages using those ‘handles’. Below is a very simple MooTools messaging system that I knocked up, which has a few cool features, including:

  • When you register() a listener, you can have its callback immediately fire if that message has ever been sent before.
  • You can very easily see which callbacks are associated with which messages by simply dir()-ing the ‘listeners’ member.
  • You can unregister() a listener at any time (provided you’ve got a reference to the function and the handle).
  • Handles can be any valid JavaScript type — Strings, Numbers, even Objects.

Feel free to use and extend this system — as I mentioned, this is a very simple system. If you do extend it, let me know in the comments!

Let me know what you think about this system in the comments.

barryvan.base.Messaging = new Class({
	listeners: $H(),
	sentMessages: [],

	initialize: function() {

	},

	/**
	 * Register a listener for a particular handle.
	 * handle [String]: The message 'handle' to listen for.
	 * callback [Function]: The function to be called when the handle is sent a message. The contents of the messages will be included in the function call.
	 * dontCheck [Boolean]: If falsey and the handle has had a message sent to it, immediately call the callback function (without contents), and continue to add the listener as normal.
	 */
	register: function(handle, callback, dontCheck) {
		if ($type(callback) !== 'function') return;

		if (!dontCheck && this.sentMessages[handle]) {
			callback();
		}

		if (!this.listeners.has(handle)) this.listeners[handle] = [];
		this.listeners[handle].push(callback);
	},

	/**
	 * Unregister a listener for a particular handle.
	 * handle [String]: The message 'handle' to cease listening for.
	 * callback [Function]: The function which was earlier assigned as the callback for the messages.
	 */
	unregister: function(handle, callback) {
		if (this.listeners.has(handle)) {
			this.listeners[handle].erase(callback);
		}
	},

	/**
	 * Send a message to the given handle with the given contents -- send the contents to all the registered listeners for that handle.
	 * handle [String]: The message 'handle' to transmit to.
	 * contents [Mixed]: The contents to be sent to the listeners.
	 */
	send: function(handle, contents) {
		this.sentMessages.include(handle);
		if (this.listeners.has(handle)) {
			this.listeners[handle].each(function(callback) {
				callback(contents);
			});
		}
	}
});

Quicksort an array of objects

2009-08-05 – 4:14pm

Often, you will need to sort an array of objects in Javascript. The inbuilt sort() function can’t do this, but here is a Quicksort implementation for doing just this.

Parameters

array The array to be sorted. (See below for an implementation on the Array Native itself, which makes this variable unnecessary).

key The key to sort by. Make sure every object in your array has this key.

Examples

var objs = [
	{fruit:"cherry"},
	{fruit:"apple"},
	{fruit:"banana"}
];

console.log(objs.sortObjects('fruit'));
// Logs [{fruit:"apple"},{fruit:"banana"},{fruit:"cherry"}] to the console

The code

sortObjects: function(array, key) {
	for (var i = 0; i < array.length; i++) {
		var currVal = array[i][key];
		var currElem = array[i];
		var j = i - 1;
		while ((j >= 0) && (array[j][key] > currVal)) {
			array[j + 1] = array[j];
			j--;
		}
		array[j + 1] = currElem;
	}
}

Implemented on the Array native:

Array.implement({
	sortObjects: function(key) {
		for (var i = 0; i < this.length; i++) {
			var currVal = this[i][key];
			var currElem = this[i];
			var j = i - 1;
			while ((j >= 0) && (this[j][key] > currVal)) {
				this[j + 1] = this[j];
				j--;
			}
			this[j + 1] = currElem;
		}
	}
});

Javascript string ellipsising

2009-08-05 – 4:03pm

Putting ellipses into strings that are too long has been around for a very long time. Unfortunately, Javascript doesn’t offer a native method of doing this, so below is a little function that’ll do it for you.

This function returns a copy of the string it’s called on, ellipsised, and takes three parameters:

toLength (required) The number of characters to truncate the string to (or 0 to disable ellipsising)

where (optional, default ‘end’) A string representing where the ellipsis should be placed — ‘front’, ‘middle’, or ‘end’

ellipsis (option, default ‘\u2026′) A string to be used as the ellipsis.

Examples

// Our clichéd string
var s = 'Jackdaws love my great big sphinx of quartz';

alert(s.ellipsise(10));
// Alerts "Jackdaws l…"

alert(s.ellipsise(10, 'front'));
// Alerts "… of quartz"

alert(s.ellipsise(10, 'middle', 'pony'));
// Alerts "Jackdponyuartz"

The code

String.implement({
	ellipsise: function(toLength, where, ellipsis) { // Where is one of ['front','middle','end'] -- default is 'end'
		if (toLength < 1) return this;
		ellipsis = ellipsis || '\u2026';
		if (this.length < toLength) return this;
		switch (where) {
			case 'front':
				return ellipsis + this.substr(this.length - toLength);
				break;
			case 'middle':
				return this.substr(0, toLength / 2) + ellipsis + this.substr(this.length - toLength / 2)
				break;
			case 'end':
			default:
				return this.substr(0, toLength) + ellipsis;
				break;
		}
	}
});

If you’re not using MooTools, you can use this variant instead:

String.prototype.ellipsise = function(toLength, where, ellipsis) { // Where is one of ['front','middle','end'] -- default is 'end'
	if (toLength < 1) return this;
	ellipsis = ellipsis || '\u2026';
	if (this.length < toLength) return this;
	switch (where) {
		case 'front':
			return ellipsis + this.substr(this.length - toLength);
			break;
		case 'middle':
			return this.substr(0, toLength / 2) + ellipsis + this.substr(this.length - toLength / 2)
			break;
		case 'end':
		default:
			return this.substr(0, toLength) + ellipsis;
			break;
	}
}