New MooTools Plugin: ElementFilter

By  on  

My new MooTools plugin, ElementFilter, provides a great way for you to allow users to search through the text of any mix of elements. Simply provide a text input box and ElementFilter does the rest of the work.

The XHTML

<ul id="my-list">
	<li>ADDRESS</li>
	<li>APPLET</li>
	<li>AREA</li>
	<li>A</li>
	<li>BASE</li>
	<li>BASEFONT</li>
	<li>BIG</li>
	<li>BLOCKQUOTE</li>
	<li>BODY</li>
	<li>BR</li>
	<!-- more -->
</ul>

I've used a list for this example but you can use any type or mix of elements that you'd like.

The MooTools JavaScript

var ElementFilter = new Class({

	//implements
	Implements: [Options,Events],

	//options
	options: {
		cache: true,
        caseSensitive: false,
        ignoreKeys: [13, 27, 32, 37, 38, 39, 40],
        matchAnywhere: true,
        property: 'text',
        trigger: 'mouseup',
        onStart: $empty,
        onShow: $empty,
        onHide: $empty,
        onComplete: $empty
	},

	//initialization
	initialize: function(observeElement,elements,options) {
		//set options
        this.setOptions(options);
        //set elements and element
        this.observeElement = document.id(observeElement);
        this.elements = $$(elements);
        this.matches = this.elements;
		this.misses = [];
        //start the listener
        this.listen();
	},
	
	//adds a listener to the element (if there's a value and if the event code shouldn't be ignored)
	listen: function() {
		//add the requested event
        this.observeElement.addEvent(this.options.trigger,function(e) {
			//if there's a value in the box...
			if(this.observeElement.value.length) {
				//if the key should not be ignored...
				if(!this.options.ignoreKeys.contains(e.code)) {
					this.fireEvent('start');
					this.findMatches(this.options.cache ? this.matches : this.elements);
					this.fireEvent('complete');
				}
			}
			else{
				//show all of the elements
				this.findMatches(this.elements,false);
			}
        }.bind(this));
	},

	//check for matches within specified elements
	findMatches: function(elements,matchOverride) {
		//settings
        var value = this.observeElement.value;
        var regExpPattern = this.options.matchAnywhere ? value : '^' + value;
        var regExpAttrs = this.options.caseSensitive ? '' : 'i';
		var filter = new RegExp(regExpPattern, regExpAttrs);
		var matches = [];				
        //recurse
        elements.each(function(el){
          	var match = (matchOverride == undefined ? filter.test(el.get(this.options.property)) : matchOverride);
			//if this element matches, store it...
			if(match) { 
				if(!el.retrieve('showing')){
					this.fireEvent('show',[el]);
				}
				matches.push(el); 
				el.store('showing',true);
			}
			else {
				if(el.retrieve('showing')) {
					this.fireEvent('hide',[el]);
				}
				el.store('showing',false);
			}
			return true;
        }.bind(this));
		return matches;
	}
});

The above options are pretty self explanatory so I'll skip the formalities. As you can see, all you need to do is provide the text element to listen to, the elements to search, and your option values.

The MooTools Sample Usage

/* usage */
window.addEvent('domready',function() {
  var myFilter = new ElementFilter('search-term', '#my-list li', {
    trigger: 'keyup',
	cache: true,
    onShow: function(element) {
		element.set('morph',{
			onComplete: function() {
				element.setStyle('background-color','#fff');
			}
		});
		element.morph({'padding-left':30,'background-color':'#a5faa9'});
    },
    onHide: function(element) {
		element.set('morph',{
			onComplete: function() {
				element.setStyle('background-color','#fff');
			}
		});
		element.morph({'padding-left':0,'background-color':'#fac3a5'});
    }
  });
});

This is a sample usage of this plugin. When a match is found, the element's background turns green and fades back to white. When an element no longer matches, I do the same effect but with red.

This plugin provides a great way to search for specific text within elements on a page. I recommend using a list (UL or OL) as they are very easily searchable.

A special thanks to Jeremy Parrish for his help in developing this plugin!

Recent Features

  • By
    9 More Mind-Blowing WebGL Demos

    With Firefox OS, asm.js, and the push for browser performance improvements, canvas and WebGL technologies are opening a world of possibilities.  I featured 9 Mind-Blowing Canvas Demos and then took it up a level with 9 Mind-Blowing WebGL Demos, but I want to outdo...

  • By
    Serving Fonts from CDN

    For maximum performance, we all know we must put our assets on CDN (another domain).  Along with those assets are custom web fonts.  Unfortunately custom web fonts via CDN (or any cross-domain font request) don't work in Firefox or Internet Explorer (correctly so, by spec) though...

Incredible Demos

  • By
    MooTools Accordion: Mouseover Style

    Everyone loves the MooTools Accordion plugin but I get a lot of requests from readers asking me how to make each accordion item open when the user hovers over the item instead of making the user click. You have two options: hack the original plugin...

  • By
    Full Width Textareas

    Working with textarea widths can be painful if you want the textarea to span 100% width.  Why painful?  Because if the textarea's containing element has padding, your "width:100%" textarea will likely stretch outside of the parent container -- a frustrating prospect to say the least.  Luckily...

Discussion

  1. erkan ceran

    it’s nice plugin ! may i can use it for my search filter :) thanks..

  2. nice job!

  3. very very nice…

  4. Nice script.

  5. Andrea

    Very nice script. It would be more usable/useful if you bring matching items to the top of the list. Even if you indent element on the bottom of the list remain not visible.

  6. @Andrea: Good idea for the demo but the core plugin I’ve published is used ONLY to return the elements — you could do what you’ve mentioned pretty easily in the onComplete event.

  7. Mr.X.

    Nice script. I am reading your blog for a while now and you are doing really great job!

  8. Arvid

    Hi David,

    Nice script, I think this is what I have been looking for. I am trying to learn javascript / mootools myself (which is quite a struggle coming from MSX basic). I want to use the script on a table to hide the non-matches (in child elements of the tr element) in a search. Would this be logical or can you recommend another script?

  9. Hi David,

    Excellent plugin.

    Could there be a bug in the regexp matcher if the word has a space in it? like trying to match “good morning” after typing ‘good’ + ‘space’ and continuing with the ‘m’ it seems like no match is found.

    Thanks.

  10. @Oran: Found what was causing the issue.

    On my specific code the html spaces are written as   (because of internal reasons). I defined the options object to match the ‘text’ and in that case I expected the space to be matched correctly in the regexp, yet it didn’t. In any case, when the &nbsp is replaced with a space the text is compared correctly and matches the spaces also.

    Thanks.

  11. above should be “spaces are written as ” &nbsp;

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!