New York Times-Style Text Selection Widget Using MooTools or jQuery

Written by David Walsh on Wednesday, November 4, 2009


NY Times Widget

Aaron Newton made a great request to me last week: why not make my MooTools Documentation Bookmarklet function more like the New York Time’s text selection widget. NYT’s text selection widget listens for text selection and presents the user with a “search” icon they may click on to learn more about that term. I’ve tried to answer that challenge — not in bookmarklet form but in website widget form.

The Sample HTML

<div id="content-area">
	.htaccess AJAX Apache / Server APIs Blog Bookmarking / Social Books Browsers CSS / Design Google Guest Blogger Hosting / Domain Javascript jQuery
	link() Microsoft MooTools MySQL Optimization PHP Poll rand() Security Shell Theory / Ideas Usability / Accessibility XML / XHTML
	This blog is targeted toward all levels of web designers and developers. All web topics are discussed, including CSS, Javascript (MooTools and jQuery), PHP, and more.
</div>

The above code is next to meaningless per the widget — I simply want to illustrate the area I’d like it to work in has an ID of content-area.

The MooTools Javascript

window.addEvent('domready',function(){
	(function($) {
		//gets the selected text
		var getSelection = function() {
			return $try(
				function() { return window.getSelection(); },
				function() { return document.getSelection(); },
				function() { 
			        var selection = document.selection && document.selection.createRange();
					if(selection.text) { return selection.text; }
					return false;
			      }
			) || false;
		};
		//vars 
		var url = 'http://davidwalsh.name/?s={term}', selectionImage;
		//event to listen
		$('content-area').addEvent('mouseup',function(e) {
			var selection = getSelection();
			if(selection && (selection = new String(selection).replace(/^\s+|\s+$/g,''))) {
				//ajax here { http://davidwalsh.name/text-selection-ajax }
				if(!selectionImage) {
					selectionImage = new Element('a',{
						href: url,
						opacity:0,
						id: 'selection-image',
						title: 'Click here to learn more about this term',
						target: '_blank'
					}).inject(document.body,'top');
				}
				//handle the every-time event
				//alert(selection);
				selectionImage.set('href',url.replace('{term}',encodeURI(selection))).setStyles({
					top: e.page.y - 30,	//offsets
					left: e.page.x - 13 //offsets
				}).tween('opacity',0);
			}
		});
		
		$(document.body).addEvent('mousedown',function() {
			//hider
			if(selectionImage) { selectionImage.tween('opacity',1); }
		});
		
	})(document.id);
});

During the mouseup event within the selected container (content-area), we determine if any text has been highlighted. If so, we:

  1. Insert the A element if it has not yet been injected into the body.
  2. Change the A element’s URL to accommodate for the new search term.
  3. Position the element to at an offset position above where the mouse goes up.

During every mousedown event we hide the A element.

The jQuery Javascript

/* attempt to find a text selection */
function getSelected() {
	if(window.getSelection) { return window.getSelection(); }
	else if(document.getSelection) { return document.getSelection(); }
	else {
		var selection = document.selection && document.selection.createRange();
		if(selection.text) { return selection.text; }
		return false;
	}
	return false;
}
/* create sniffer */
$(document).ready(function() {
	var url = 'http://davidwalsh.name/?s={term}', selectionImage;
	$('#content-area').mouseup(function(e) {
		var selection = getSelected();
		if(selection && (selection = new String(selection).replace(/^\s+|\s+$/g,''))) {
			//ajax here { http://davidwalsh.name/text-selection-ajax }
			if(!selectionImage) {
				selectionImage = $('<a>').attr({
					href: url, 
					title: 'Click here to learn more about this term',
					target: '_blank',
					id: 'selection-image'
				}).hide();
				$(document.body).append(selectionImage);
			}
			selectionImage.attr('href',url.replace('{term}',encodeURI(selection))).css({
				top: e.pageY - 30,	//offsets
				left: e.pageX - 13 //offsets
			}).fadeIn();
		}
	});
	$(document.body).mousedown(function() {
		if(selectionImage) { selectionImage.fadeOut(); }
	});
});

Follows the same principal as above.

Ideas & Enhancements

  • Depending on your philosophy, you may want to implement a minimum character check as well:

    if(selection && (selection = new String(selection).replace(/^\s+|\s+$/g,'')) && selection.length > 4) { //5 char min
    
  • You may want to also fidget with adding/modifying text selection with keyboard keys as well. I’ve chosen to pass on that.
  • Saving the selection content via AJAX for analytical reasons may not be a bad idea either.

Have any other ideas for improvement? Would you have any use for this on your website(s)?


Follow via RSS Epic Discussion

Commenter Avatar November 04 / #
Jenn says:

This is totally cool, and I KNOW this would be a great feature to add to a hyperlocal blog that I work for.

Commenter Avatar November 04 / #

Nice use! Could be a little neater on the MooTools side though…

if(!selectionImage) {
selectionImage = new Element(‘a’, {
‘href’: url.substitute({
‘term’: encodeURI(selection)
}),
‘id’: ’selection-image’,
‘title’: ‘Click here to learn more about this term’,
‘target’: ‘_blank’,
‘fade’: {
‘duration’: 50
},
’styles’: {
‘top’: e.page.y – 30,
‘left’: e.page.x – 13
‘opacity’:0,
}
}).inject(document.body, ‘top’);
}

Commenter Avatar November 04 / #
Rich says:

Nice man. very cool and you got the jquery version which makes it so much better for me. I might have to try this on a project. thanks again for all the work you put into your blog. Its much appreciated.

Commenter Avatar November 04 / #
Mr.X. says:

Very nice thanks!

Commenter Avatar November 05 / #
Roshan says:

I am with a PHP web development company http://www.rightwaysolution.com
Very nice article thanks for explaining this. i am bookmarking this and will surely return for more knowledge:)

Commenter Avatar November 05 / #

Pretty sweet, always enjoy your blog.

Commenter Avatar November 07 / #
IPAN says:

nice article dev….:)

Commenter Avatar November 08 / #
John Soon says:

Is the plugin you’re using on this website?

David Walsh November 08 / #

Yep — it was really easy to implement too!

Commenter Avatar November 10 / #

The mootools demo isn’t working for me (the jqery one does).

David Walsh November 10 / #

@Graeme Coultrip: Updated!

David Walsh November 10 / #

@David Walsh: It was simple opacity mistake.

Commenter Avatar November 10 / #

Cool. I think this could be very useful.

Commenter Avatar December 01 / #
Willian says:

Hi,

How can I change getSelected function to return the start and end position index?

Commenter Avatar December 07 / #
Mohammad says:

hi devid.

i am following Your blog for Years.

first of all , i appreciate you for your knowledge sharing ;)

i am using Joomla 1.5 in my New Project and as you may know, Joomla Is using Mootools 1.11 in its core.

So by know , i want to use this Useful plug-in and it does not work with this mootools version.

how do you see this problem? any solution?

i had updated the Joomla Mootools version, but some other part of the website drops :D

best Regards,

M.Rashidi

Commenter Avatar December 11 / #

That’s really wow I say because this would be a source of getting inspiration and that is all what is required to start the things, thank you.

Be Heard!

I want to hear what you have to say! Share your comments and questions below.

Name*:
Email*:
Website:  


© David Walsh 2007-2010. Contact David Walsh. Powered by the remarkable MooTools javascript framework.