Posts Tagged ‘Plugins’
Posted in 'Code Snippets, JavaScript' by James on March 19th, 2010
There are quite a few table-sorting functions/plugins out there, but I’ve yet to find something sufficiently low-level for general element-sorting. What I wanted was a simple jQuery plugin that would take a sorting function (just like Array.prototype.sort) as an argument and sort the DOM elements in-place, and would handle situations where the elements didn’t all have the same parent.
To be honest, I didn’t search for very long — I prefer making this kind of stuff myself anyway — so, I present what I think is one of the simplest ways possible to implement a reliable element-sorting function.
Name changed from sort to sortElements as per David’s comment.
/**
* jQuery.fn.sortElements
* --------------
* @param Function comparator:
* Exactly the same behaviour as [1,2,3].sort(comparator)
*
* @param Function getSortable
* A function that should return the element that is
* to be sorted. The comparator will run on the
* current collection, but you may want the actual
* resulting sort to occur on a parent or another
* associated element.
*
* E.g. $('td').sortElements(comparator, function(){
* return this.parentNode;
* })
*
* The <td>'s parent (<tr>) will be sorted instead
* of the <td> itself.
*/
jQuery.fn.sortElements = (function(){
var sort = [].sort;
return function(comparator, getSortable) {
getSortable = getSortable || function(){return this;};
var placements = this.map(function(){
var sortElement = getSortable.call(this),
parentNode = sortElement.parentNode,
// Since the element itself will change position, we have
// to have some way of storing its original position in
// the DOM. The easiest way is to have a 'flag' node:
nextSibling = parentNode.insertBefore(
document.createTextNode(''),
sortElement.nextSibling
);
return function() {
if (parentNode === this) {
throw new Error(
"You can't sort elements if any one is a descendant of another."
);
}
// Insert before flag:
parentNode.insertBefore(this, nextSibling);
// Remove flag:
parentNode.removeChild(nextSibling);
};
});
return sort.call(this, comparator).each(function(i){
placements[i].call(getSortable.call(this));
});
};
})();
Features:
- It’s low-level — you have control over how it sorts (see the “comparator” argument).
- It lets you sort any arbitrary DOM nodes, as long as none of those nodes are within another one of the nodes to be sorted.
- It lets you specify what elements will actually be moved (see the “getSortable” argument).
Usage:
Assuming the following markup:
<ul>
<li>Banana</li>
<li>Carrot</li>
<li>Apple</li>
</ul>
You could sort the items alphabetically like so:
$('li').sortElements(function(a, b){
return $(a).text() > $(b).text() ? 1 : -1;
});
That would result in:
<ul>
<li>Apple</li>
<li>Banana</li>
<li>Carrot</li>
</ul>
See a rather basic demo here.
jQuery.fn.sortElements on Github
Posted in 'JavaScript' by James on January 18th, 2010
jQuery Lint is a simple script you can download and use with jQuery. It works over the top of jQuery and diligently reports errors and any incorrect usage of jQuery. It will also, to some extent, offer guidance on best practices and performance concerns.
Unlike JSLint, jQuery Lint is a runtime reporter. To use it, you need to include it, after jQuery, in your document:
<script src="jquery.js"></script>
<script src="jquery.lint.js"></script>
jQuery lint’s main objective is to notify you of incorrect usages of jQuery’s API. So, if you pass incorrect arguments to any method then jQuery Lint will let you know. It compares your arguments to the argument signatures in jQuery’s API. It reports via Firebug, although you can quite easily plug-in your own console mechanism.
It has four different error-reporting levels (accessible via jQuery.LINT.level), zero reports nothing, three will report everything, including small things like using css().css().css() instead of css({...}). It’s quite configurable too. You can add your own checks. E.g.
jQuery.LINT.special[1].jQuery = jQuery.LINT.special[1].jQuery || [];
// Add check on error-reporting level one.
// Check jQuery method.
jQuery.LINT.special[1].jQuery.push(function(selector, context) {
if (selector === '*') {
return "Don't use the universal selector!";
}
});
jQuery Lint tries to help you in determining where the problem occurred in your code. It’s not much help to you if it just says, “Err, you called css() incorrectly!”. If it occurred as a result of an event then Lint will say so, and if you’re using a browser that provides a stack-trace as part of its Error object (like Firefox) then Lint will also provide you with the file-name and line number. E.g.

You can read more about jQuery Lint and download it at Github:
jQuery Lint @ Github
The idea of a lint-like script for jQuery has been floating around for some time. I want to thank Dave Methvin in particular, for it was his idea that sparked my interest originally.
This is quite a young project, so there will be bugs. Please report them!
Posted in 'Code Snippets, JavaScript' by James on December 16th, 2009
A while ago I wrote a little “pulse” plugin for jQuery which would make an element pulse between two or more states. I won’t bother linking to it because it’s offline. I decided to have another go at developing it, this time with a more refined and intuitive API.
I’ve tried to emulate the characteristics of jQuery’s animate() method as much as possible. There are only a few slight differences. Here’s a typical call to the new “pulse” plugin:
jQuery(element).pulse({
opacity: [0, 1],
backgroundColor: ['red', 'yellow']
}, 1000, 5, 'linear', function(){
alert("I'm done pulsing!");
});
It’s almost exactly the same parameter pattern as animate(), except that you have to specify an array of values for each CSS property, and also an additional numerical parameter, after the duration, which signifies how many times you want the pulse to run (the above code will run the pulse five times).
It also works with an “options” object, just like animate():
jQuery(element).pulse({
opacity: [0,1]
}, {
duration: 100, // duration of EACH individual animation
times: 3, // Will go three times through the pulse array [0,1]
easing: 'linear', // easing function for each individual animation
complete: function() {
alert("I'm done pulsing!");
}
});
You should note that the duration option only defines how long each individual animation will run, not the entire pulse. To dictate the length of the entire pulse you need to use the times option. Also note that the times option refers to an entire run-through of the largest array found in the properties option.
You can “pulse” through as many values as you want:
jQuery(element).pulse({
backgroundColor: ['red', 'yellow', 'green', 'blue'],
opacity: [0, 1],
});
The arrays don’t all have to be of equal length – with the above code, the opacity would keep changing as is defined by its array.
The plugin itself is quite small. I’ve decided to start a new repo at Github, just for small and useful jQuery plugins like this.
Pulse plugin on Github
I haven’t tested it extensively yet, so, as usual please notify me of any bugs/issues. Thanks!
Posted in 'Code Snippets, JavaScript' by James on August 20th, 2009
Satisfy is a development-only jQuery plugin* that you can use to quickly generate HTML for testing/debugging. The idea is that you provide a CSS selector and then the plugin will “satisfy” it by generating an HTML structure in accordance with that selector.
* – UPDATE: This is no longer just a jQuery plugin – as of version 0.2 Satisfy has no dependencies. See the comments for more info.
For example:
jQuery('div a').satisfy();
… would return the following HTML structure:
A more snazzy example:
jQuery('ul li:5 span[innerHTML="link"]').satisfy();
… which would return the following:
<ul>
<li><span>link</span></li>
<li><span>link</span></li>
<li><span>link</span></li>
<li><span>link</span></li>
<li><span>link</span></li>
</ul>
(Note: It ignores combinators (+|~|>) and pseudo-classes (:pseudo). It adds support for numerical pseudo-classes (e.g. “:5″) which you can use to specify how many of a particular element you want.)
More information and source available at Github – “satisfy” @ GitHub
Posted in 'Code Snippets, JavaScript' by James on May 17th, 2009
This is an experimental bookmarklet which lists the jQuery plugins being used on any page. Try it out now:
Detect plugins
To save the bookmarklet simply drag the above link to your bookmarks toolbar. It’s been tested successfully in Opera 9, Safari 4, FF2/3, IE6/7, and Chrome.
The list shown includes google links for each plugin; obviously not all plugins on all sites are available to the public so the links aren’t always very useful.
Posted in 'Accessibility, JavaScript, Usability' by James on April 1st, 2009
According to a recently completed report commissioned by the Web Standards Authority, the majority of popular websites do not reach the desired readability standards. Contrast, colour, sizing, positioning and other various aspects all have an effect on the readability of your site. Readability itself is of central importance; without it your message is lost!
As per the details digressed in the mentioned report I have created a jQuery plugin which deals with this issue. By implementing the following enhancements, the plugin ensures your users a visit worth remembering!
- Continuously varying textual colour makes words easier to focus on while progressing through any particular sentence.
- In addition, constantly changing background colours ensure the necessary inconsistency when reading text. As mentioned in the report, contrast is of central importance, – this is integrated into the plugin.
- Whenever a word is hovered over, the report states that the user must be looking for a deeper meaning – to fulfill this need the word in question is subtly re-sized.
You can experience a fully working demo over here. If you are epileptic please don’t visit this link: THE DEMONSTRATION
This plugin is very easy to integrate. Just call the “readability” plugin like so:
Once initiated the plugin will automatically enhance the page in the ways mentioned.
Readability isn’t something to be taken lightly, it’s a serious issue and has been known to have widespread lethal affects across the globe. Web designers and developers have advanced recently in this area but the job isn’t yet done; we have to push for absolute readability. This plugin is only a tool, a tool to enable the world to get that one step closer to an entirely readable internet!
Please consider donating as I had to scour the entire WSA’s report just to uncover the key to readability. The plugin took a considerable amount of time to develop; throughout its creation I continually became parched and/or hungry so please consider buying me whatever you can afford (i.e. this). Thank you for supporting me!
UPDATE: APRIL FOOLS!!!
Posted in 'Code Snippets, JavaScript' by James on March 7th, 2009
I remember googling for something of this nature a while ago but all I found were countless attempts using the cols and/or rows attribute of the textarea, thus making it pretty useless if you weren’t using a fixed-width font.
Inspired by Jason Frame’s method, I’ve created an animating ‘autoResize’ jQuery plugin. Although it was inspired by his plugin it has a few slight differences, most notably the way in which the off-screen "testing" takes place. In his plugin (apparently inspired by Facebook’s implementation) a DIV is created off-screen and is filled with the textarea’s value whenever it changes. The height of this DIV is retrieved and then applied to the textarea. My plugin makes use of the scrollTop DOM property to gain the true height of the text and then applies that directly (or via animation) to the textarea.
Demo
Note: this demo only works if you have JavaScript enabled!
Usage
The following options are available:
- onResize - (type: Function) - A callback function fired every time the textarea is resized. Within the function 'this' refers to the textarea being resized.
- animate - (type: Boolean) - If set to
false no animation will take place, the height will immediately change when necessary. By default it's set to true.
- animateDuration - (type: Number) - Millisecond duration of animation, by default it's set to
150.
- animateCallback - (type: Function) - A callback function fired every time an animation completes. Note: not the same as the
onResize callback.
- extraSpace - (type: Number) - A pixel value to be added to the total necessary height when applied to the textarea. By default it's set to 20. The idea behind this is to reassure users that they have more space to continue writing.
- limit - (type: Number) - Once the textarea reaches this height it will stop expanding. By default it's set to 1000.
The textarea will expand when required until the limit is reached, at which time it brings back the scrollbar. If you were to then delete all the contents of the textarea it would only return to it's original size (no smaller). Also note that, even if you set 'animate' to true, the animation will only occur if the element is set to display:block; in the CSS.
An example implementation:
$('textarea#comment').autoResize({
// On resize:
onResize : function() {
$(this).css({opacity:0.8});
},
// After resize:
animateCallback : function() {
$(this).css({opacity:1});
},
// Quite slow animation:
animateDuration : 300,
// More extra space:
extraSpace : 40
});
The plugin has been tested successfully in IE6/7, FF2/3, Opera9, Safari3 & Chrome.
Download
Posted in 'Cool Stuff, JavaScript, My Life, News' by James on February 19th, 2009
I was going to do a bit of a series, releasing a jQuery tip every day or week or something, but I think I’m a little too lazy to commit to something like that. So I’ve compiled them all into one post! I’ll probably add to the list at later dates so make sure to bookmark it!
Do you have a tip nobody knows about? – Add it in the comments…
$.fn is just a shortcut to jQuery.prototype.
- You can test if a jQuery collection contains any elements by trying to access the first element, e.g.
if($(selector)[0]){...}.
- jQuery normalizes the event object across all browsers! Have a look at all the available properties/methods over here: http://docs.jquery.com/Events/jQuery.Event.
- When you create a plugin you have access to the jQuery chain’s previous object:
jQuery.fn.doSomething = function() {
this; // => $('a')
this.prevObject; // => $('li')
// Remember chaining in your plugins:
return this;
};
jQuery('li').show()
.find('a').doSomething();
// You could even create a new 'root' plugin:
// (Returns the 'root' of a chain)
jQuery.fn.root = function() {
// Root is always document so we have to
// go back to one before the last:
var root = this;
while(root.prevObject.prevObject) {
root = root.prevObject;
}
return root;
};
$('li').find('a').children().root(); // <= $('li') is returned
// Using root() is the same as using end().end() in this situation
- You can namespace events! This is especially useful for plugin development:
jQuery.fn.myPlugin = function() {
// Clean up after yourself!
jQuery.myPlugin = {
cleanUp: function() {
// Remove all click handlers binded
// as a result of the plugin:
jQuery('*').unbind('click.myPlugin');
// ALternatively, remove ALL events:
jQuery('*').unbind('.myPlugin');
}
};
return this.bind('click.myPlugin', function() {
// Do something...
});
};
// Note, you can also namespace data:
// E.g. $(elem).data('whatever.myPlugin',value);
- You can access all event handlers bound to an element (or any object) through jQuery’s event storage:
// List bound events:
console.dir( jQuery('#elem').data('events') );
// Log ALL handlers for ALL events:
jQuery.each($('#elem').data('events'), function(i, event){
jQuery.each(event, function(i, handler){
console.log( handler.toString() );
});
});
// You can see the actual functions which will occur
// on certain events; great for debugging!
- jQuery natively supports JSONP (‘JSON with padding’) which effectively means you can make cross-domain "Ajax" requests (although not strictly Ajax since it doesn’t use XHR). For this to work the requested domain must have some JSONP API in place (it must be able wrap the JSON with a specified callback function). An example:
function getLatestFlickrPics(tag,callback) {
var flickrFeed = 'http://api.flickr.com/services/feeds/photos_public.gne?tags='
+ tag + '&tagmode=any&format=json&jsoncallback=?';
jQuery.getJSON(flickrFeed, callback);
}
// Usage:
getLatestFlickrPics('ferrari', function(data){
jQuery.each(data.items, function(i, item){
$("<img/>").attr("src", item.media.m).appendTo('body');
});
});
- You might find it a little messy but jQuery enables us to create an entire DOM structure within a single chain:
// Create and inject in one chain:
jQuery('<div/>')
.append('<p><a href="#">Foo</a></p>')
.find('p a')
.click(function(){
// Do something...
return false;
})
.end()
.append('<p><a href="#">Bar</a></p>')
.find('p:eq(1) a')
.click(function(){
// Do something else...
return false;
})
.end()
.appendTo('body');
- Accessing the DOM elements within a jQuery collection is incredibly easy:
var HTMLCollection = $('div').get();
// Alternatively, if you only want the first element:
$('div').get(0);
$('div').get()[0];
$('div')[0];
- Not only can you bind events to DOM elements; you can also bind a custom event to ANY object!
function Widget() {
// Do something...
};
var myPhotoWidget = new Widget('photos');
jQuery(myPhotoWidget).bind('photoAdd', function() {
// Custom event handling...
});
// Trigger event:
jQuery(myPhotoWidget).trigger('photoAdd');
- Finding the index of a selected element is very easy. jQuery gives us the ‘index’ method:
$('table tr').click(function(){
// Find index of clicked table row:
var index = $('table tr').index(this);
});
- You can create your own filter selectors. I did a post on this a while back, but take a look at an example anyway:
$.expr[':'].external = function(elem,index,match) {
var url = elem.href || elem.src,
loc = window.location;
return !!url.match(new RegExp('^' + loc.protocol + '//' + '(?!' + loc.hostname + ')' ));
};
// You can now use it within your selectors:
// Find all external anchors:
$('a:external');
// Find all external script elements:
$('script:external');
// Determine if link is external:
$('a#mylink').is(':external'); // true/false
- I see quite a lot of people still using JavaScript’s FOR or WHILE constructs to create loops in their jQuery scripts. There’s nothing wrong with this but be aware that jQuery’s ‘each’ method can also iterate over arrays and objects!
var myArr = ['apple','banana','orange'];
$.each(myArr, function(index, item) {
// Do something with 'item'
// return false to BREAK
// return true to CONTINUE
});
- The ‘filter’ method accepts a String selector or a function. When using it with a function you must return false to remove the element from the stack and true to keep it:
$('div').filter(function(){
return this.childNodes.length > 10; // Must return a Boolean
});
- You don’t have to give new elements IDs or classes to reference them later, just cache them into a variable:
var myInjectedDiv = $('<div/>').appendTo('body');
// Use 'myInjectedDiv' to reference the element:
myInjectedDiv.bind('click', function(){
// ...
});
- jQuery’s ‘map’ method is incredibly useful, the passed function will be run on every item of the passed array (or object) and whatever the function returns each time is added to the new array, take a look:
// Create an array containing all anchor HREF attributes:
var URLs = $.map($('a'), function(elem, index){
return elem.href;
});
// URLs = ['http://google.com', 'http://whatever.com', 'http://yahoo.com']
- This isn’t jQuery related but it can be very useful. When you need to compare two different ways of doing something (performance-wise) you can use the Firebug console to log the time taken to complete a chunk of code, for example:
console.time('My first method');
// Do something...
console.timeEnd('My first method');
console.time('My second method');
// Do something else...
console.timeEnd('My second method');
// Firebug will log the time (in milliseconds) taken
// to complete each chunk...
Posted in 'JavaScript' by James on February 10th, 2009
This is an experimental jQuery plugin which animates according to a CSS selector. The plugin looks up the selectors in the StyleSheet/s of a document and then animates according to the specified properties. It’s similar to jQuery UI’s ‘classTransitions‘ although it’s much more capable; not only can it animate to classes but any selector, as long as it’s specified in the CSS.
Probably the most useful thing about this plugin, and the main reason I created it, is that it can animate to pseudo classes such as ‘:hover’. This means the plugin can animate your hover states too; and because they’re specified in the CSS they won’t fail when JavaScript is disabled. This is what progressive enhancement is really about!
See demonstration and documentation (& download)!
With the plugin I’ve included Resig’s color extension so not only can it animate size properties like ‘width’, ‘left’ or ‘padding’ but it can also handle color properties like ‘border-color’, ‘color’ or ‘background-color’.
It’s not a simple “call n’ go” type of plugin, you do need to specify a selector (which must exist in the document’s StyleSheet/s) and you also need to specify properties to retrieve from that selector. Here’s an example of how one might call the plugin:
$('#navigation a').animateToSelector({
// One or more selectors; must exist
// within the CSS StyleSheet. First one
// has precedence ([0]):
selectors: ['#navigation a:hover'],
// You need to specify what properties to
// animate within the selector:
properties: [
'background-color',
'padding-left',
'color'
],
// An optional setting, without this setting
// the animation proceeds straight away:
events: ['mouseover', 'mouseout'],
// Duration of animation:
duration: 300
});
The above code would make all anchors within #navigation animate to the specified properties of the specified selector onMouseOver and then will revert the animation onMouseOut. So, the plugin get’s the properties from here:
#navigation a:hover {
padding-left: 20px;
background-color: #bdd70d;
color: #222;
}
The name of the plugin can be misleading – when you pass selectors into the ’selectors’ array as a setting you are not selecting elements within the DOM – the plugin doesn’t even touch the DOM – it simply scans through the StyleSheets for the corresponding selectors and properties.
If you missed it earlier, here’s a link to the demo and documentation. There are a few issues (not bugs) with the implementation; it works in all modern browsers (only tested on Windows XP though). Comments and crits welcome!
Posted in 'Code Snippets, JavaScript' by James on February 4th, 2009
I was recently looking for a decent way of shuffling a set of elements. I found a jQuery plugin which claimed to do exactly that but unfortunately it only works if all elements are direct descendants of a single parent, like all list items under an unordered list.
I needed something that would work with any elements, regardless of their position within the DOM. In the end I didn’t find a solution so I attempted it myself, and here’s the end result:
$.fn.shuffle
(function($){
$.fn.shuffle = function() {
var allElems = this.get(),
getRandom = function(max) {
return Math.floor(Math.random() * max);
},
shuffled = $.map(allElems, function(){
var random = getRandom(allElems.length),
randEl = $(allElems[random]).clone(true)[0];
allElems.splice(random, 1);
return randEl;
});
this.each(function(i){
$(this).replaceWith($(shuffled[i]));
});
return $(shuffled);
};
})(jQuery);
Usage
// Shuffle all list items within a list:
$('ul#list li').shuffle();
// Shuffle all DIVs within the document:
$('div').shuffle();
// Shuffle all <a>s and <em>s:
$('a,em').shuffle();
This plugin can be used on any set of elements, obviously performance needs to be taken into account when shuffling many elements.
If you are worried about performance then you might prefer this pure JavaScript method (~10% faster):
// WARNING: I haven't yet tested this
// - It's likely that it will strip events upon shuffling
function shuffle(elems) {
allElems = (function(){
var ret = [], l = elems.length;
while (l--) { ret[ret.length] = elems[l]; }
return ret;
})();
var shuffled = (function(){
var l = allElems.length, ret = [];
while (l--) {
var random = Math.floor(Math.random() * allElems.length),
randEl = allElems[random].cloneNode(true);
allElems.splice(random, 1);
ret[ret.length] = randEl;
}
return ret;
})(), l = elems.length;
while (l--) {
elems[l].parentNode.insertBefore(shuffled[l], elems[l].nextSibling);
elems[l].parentNode.removeChild(elems[l]);
}
}
// Usage:
shuffle( document.getElementsByTagName('li') );