Skip to the content...

Welcome to the David Walsh Blog. I'm a MooTools, Dojo, jQuery, CSS, and PHP Web Developer located in Madison, Wisconsin, United States. Please contact me if I can make your experience on my website better.

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

25 Responses »

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)?

Discussion

  1. November 4, 2009 @ 9:51 am

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

  2. November 4, 2009 @ 10:01 am

    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’);
    }

  3. rich
    November 4, 2009 @ 11:57 am

    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.

  4. mr.x.
    November 4, 2009 @ 3:32 pm

    Very nice thanks!

  5. November 5, 2009 @ 1:42 am

    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:)

  6. November 5, 2009 @ 3:15 pm

    Pretty sweet, always enjoy your blog.

  7. November 7, 2009 @ 11:25 pm

    nice article dev….:)

  8. November 8, 2009 @ 6:51 pm

    Is the plugin you’re using on this website?

  9. November 8, 2009 @ 6:52 pm

    Yep — it was really easy to implement too!

  10. November 10, 2009 @ 11:04 am

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

  11. November 10, 2009 @ 11:07 am

    @Graeme Coultrip: Updated!

  12. November 10, 2009 @ 11:07 am

    @David Walsh: It was simple opacity mistake.

  13. November 10, 2009 @ 11:33 am

    Cool. I think this could be very useful.

  14. willian
    December 1, 2009 @ 10:32 am

    Hi,

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

  15. December 7, 2009 @ 12:16 pm

    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

  16. December 11, 2009 @ 11:32 pm

    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!

Share your thoughts with fellow developers of all skill levels! I want to hear from you!

Name*:
Email*:
Website:  
Wrap your code with <code> tags, f00!