Sunday, September 4, 2011

How to Create Automatic Image Montage with jQuery

How to Create Automatic Image Montage with jQuery:

Arranging images in a montage like fashion can be a challenging task when considering certain constraints, like the window size when using fullscreen, the right image number to fill all the available space or also the size of the images in use.

With Automatic Image Montage with jQuery you can automatically create a montage, either for a liquid container or a fixed size container (including fullscreen), with the option to fill all the gaps.

automatic-image-montage

Requirements: jQuery Framework Demo: http://tympanus.net/Development/AutomaticImageMontage/ License: License Free

Shuffle Letters Effect: a jQuery Plugin

Shuffle Letters Effect: a jQuery Plugin:

In this short tutorial we will be making a jQuery plugin that will shuffle the text content of any DOM element – an interesting effect that can be used in headings, logos and slideshows.

The Code

The first step is to write the backbone of our jQuery plugin. We will place the code inside a self-executing anonymous function, and extend $.fn.

assets/js/jquery.shuffleLetters.js

(function($){

	$.fn.shuffleLetters = function(prop){

		// Handling default arguments
		var options = $.extend({
			// Default arguments
		},prop)

		return this.each(function(){
			// The main plugin code goes here
		});
	};

	// A helper function

	function randomChar(type){
		// Generate and return a random character
	}

})(jQuery);

Next we will turn our attention to the randomChar() helper function. It will take a type argument (one of “lowerLetter“, “upperLetter” or “symbol“) and return a random character.

function randomChar(type){
	var pool = "";

	if (type == "lowerLetter"){
		pool = "abcdefghijklmnopqrstuvwxyz0123456789";
	}
	else if (type == "upperLetter"){
		pool = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
	}
	else if (type == "symbol"){
		pool = ",.?/\\(^)![]{}*&^%$#'\"";
	}

	var arr = pool.split('');
	return arr[Math.floor(Math.random()*arr.length)];
}

We could have used a single pool string for all types of characters, but this will do for a better effect.

The Plugin In Action

The Plugin In Action

Now lets write the body of the plugin!

$.fn.shuffleLetters = function(prop){

	var options = $.extend({
		"step"	: 8,	// How many times should the letters be changed
		"fps"	: 25,	// Frames Per Second
		"text"	: "" 	// Use this text instead of the contents
	},prop)

	return this.each(function(){

		var el = $(this),
			str = "";

		if(options.text) {
			str = options.text.split('');
		}
		else {
			str = el.text().split('');
		}

		// The types array holds the type for each character;
		// Letters holds the positions of non-space characters;

		var types = [],
			letters = [];

		// Looping through all the chars of the string

		for(var i=0;i<str.length;i++){

			var ch = str[i];

			if(ch == " "){
				types[i] = "space";
				continue;
			}
			else if(/[a-z]/.test(ch)){
				types[i] = "lowerLetter";
			}
			else if(/[A-Z]/.test(ch)){
				types[i] = "upperLetter";
			}
			else {
				types[i] = "symbol";
			}

			letters.push(i);
		}

		el.html("");			

		// Self executing named function expression:

		(function shuffle(start){

			// This code is run options.fps times per second
			// and updates the contents of the page element

			var i,
				len = letters.length,
				strCopy = str.slice(0);	// Fresh copy of the string

			if(start>len){
				return;
			}

			// All the work gets done here
			for(i=Math.max(start,0); i < len; i++){

				// The start argument and options.step limit
				// the characters we will be working on at once

				if( i < start+options.step){
					// Generate a random character at this position
					strCopy[letters[i]] = randomChar(types[letters[i]]);
				}
				else {
					strCopy[letters[i]] = "";
				}
			}

			el.text(strCopy.join(""));

			setTimeout(function(){

				shuffle(start+1);

			},1000/options.fps);

		})(-options.step);

	});
};

The plugin will take either the contents of the DOM element it was called on, or the text property of the object passed as an argument. It then splits the string into characters and determines the type of each one. The shuffle function then uses setTimeout() to call itself and randomize the string, updating the DOM element on each step.

When you head on to the demo you will see that you are able to type your own text and test it out. Here is how I did it:

assets/js/script.js

$(function(){

	// container is the DOM element;
	// userText is the textbox

	var container = $("#container")
		userText = $('#userText');

	// Shuffle the contents of container
	container.shuffleLetters();

	// Bind events
	userText.click(function () {

	  userText.val("");

	}).bind('keypress',function(e){

		if(e.keyCode == 13){

			// The return key was pressed

			container.shuffleLetters({
				"text": userText.val()
			});

			userText.val("");
		}

	}).hide();

	// Leave a 4 second pause

	setTimeout(function(){

		// Shuffle the container with custom text
		container.shuffleLetters({
			"text": "Test it for yourself!"
		});

		userText.val("type anything and hit return..").fadeIn();

	},4000);

});

The fragment above also shows how you can use the plugin and the custom text parameter.

Pop From Top Notification

Pop From Top Notification:

Have you seen that design pattern where a notification pops down from the top of the browser window, then slides away? We can rock that in pure CSS.

View Demo Download Files

We'll just make a div:

<div id="note">
  You smell good.
</div>

Then we'll style it and put it on the top of the screen:

#note {
  position: absolute;
  z-index: 101;
  top: 0;
  left: 0;
  right: 0;
  background: #fde073;
  text-align: center;
  line-height: 2.5;
  overflow: hidden;
  -webkit-box-shadow: 0 0 5px black;
  -moz-box-shadow:    0 0 5px black;
  box-shadow:         0 0 5px black;
}

Let's animate it

With a keyframe animation, we can "hide" it above the browser window and bring it down for a short while:

@-webkit-keyframes slideDown {
  0%, 100% { -webkit-transform: translateY(-50px); }
  10%, 90% { -webkit-transform: translateY(0px); }
}
@-moz-keyframes slideDown {
  0%, 100% { -moz-transform: translateY(-50px); }
  10%, 90% { -moz-transform: translateY(0px); }
}

Er... let's consider other browsers quick

But let's consider browsers that don't have transforms and animations for a second. For those, we'd want to default to just showing the notification bar at all times, with the ability to dismiss it.

So we'll make a custom build of Modernizr to test for transforms and animations, load that up, then we can write CSS to test for those features and only fire off the animations if we're in a browser that supports them.

.cssanimations.csstransforms #note {
  -webkit-transform: translateY(-50px);
  -webkit-animation: slideDown 2.5s 1.0s 1 ease forwards;
  -moz-transform:    translateY(-50px);
  -moz-animation:    slideDown 2.5s 1.0s 1 ease forwards;
}

The 1.0s in there is the delay before the animation runs. Best to wait a minute to make the notification more noticeable.

Now we'll add a close button into the HTML:

<div id="note">
  You smell good. <a id="close">[close]</a>
</div>

And a tiny bit of JavaScript at the bottom of the page so that the non-supporting browsers can close the notification.

<script>
close = document.getElementById("close");
close.addEventListener('click', function() {
 note = document.getElementById("note");
 note.style.display = 'none';
}, false);
</script>

Look ma, no libraries.

Since we don't need that close button in browsers that do support the animations, we'll hide it:

.cssanimations.csstransforms #close {
display: none;
}

For the record, this should work OK on mobile browsers (tested Mobile Safari). There is no fixed positioning used here, only absolute, and that's going to be less of a problem moving forward anyway (might want to consider making it fixed so even if the user is scrolled down the page they'll get it).

Enjoy

View Demo Download Files

Pop From Top Notification is a post from CSS-Tricks

Thursday, November 18, 2010

Signature Pad – A jQuery Plugin For Accepting Signatures Online

Signature Pad – A jQuery Plugin For Accepting Signatures Online:

Signature Pad is a jQuery plugin which transforms an HTML form into a canvas where users can draw their signatures.

It has 2 modes:

  • TypeIt mode where the user’s signature is automatically generated as HTML text and styled with @font-face from the input field where the name is typed.
  • DrawIt mode where the users can draw their signatures on the canvas element.

Signature Pad jQuery Plugin

The signature submitted is stored as a JSON array which makes re-generating it possible.

And, the plugin doesn't need to be used as its name suggests, you can ask users to draw anything and store it easily.

Special Downloads:

Related posts:

Parse RSS Feeds and Display Images with Lumebox

Parse RSS Feeds and Display Images with Lumebox:

The Lumebox is an Open-Source Lightbox clone written as a JavaScript jQuery plugin with a few added features. One of the main features is that it can parse RSS feeds just as easily as displaying images.

The Lumebox also searches the post or page for links leading to images (and RSS-feeds) and opens them in a popup instead of following them. The Lumebox was written using jQuery 1.4.3. The Lumebox plugin is released under the GNU GPL.

lumebox

Requirements: jQuery Framework Demo: http://anders.zakrisson.se/projects/lumebox/ License: GPL License

Related Posts

Wednesday, September 29, 2010

Ajax-Enable Standard Websites: jQuery Ajaxy

Ajax-Enable Standard Websites: jQuery Ajaxy

jQuery Ajaxy is a plugin which enables us to convert a standard website into an Ajaxed one with no hassles.

It has built-in support for URL hash changes, AJAX form submits or AJAX links.

jQuery Ajaxy

The usage of the plugin is so easy: the ordinary links and forms are upgraded into Ajax requests by just adding a CSS classname.

As the URL addresses change on every request, users can browse with browser back-forward buttons and URLs will stay SEO-friendly.

The plugin also gives the ability to control your web applications state manually through your code for advanced circumstances.

Special Downloads:

Related posts

Orbit – A Slick jQuery Image Slider Plugin

Orbit – A Slick jQuery Image Slider Plugin

Most jQuery image sliders hover at around 8 kbs for minified versions, and around 15kbs or more for uncompressed development files, but what if there was a way to keep the simple fades, slides, and a couple other nifty bits, but strip the bloated and corny diagonal-cross fades or spiral dissolves.

Orbit is a killer jQuery plugin that lets you create a simple, effective and beautiful slider for images of any size, and even includes some parameters for making awesome captions and a sweet timer.

slick-gallery

Requirements: jQuery Framework Demo: http://www.zurb.com/playground/jquery_image_slider_plugin License: MIT License

Friday, September 17, 2010

Easy jQuery Image Cropping with imgAreaSelect

Easy jQuery Image Cropping with imgAreaSelect

imgAreaSelect is a jQuery plugin for selecting a rectangular area of an image. It allows web developers to easily implement image cropping functionality, as well as other user interface features, such as photo notes like those on Flickr.

imgAreaSelect is highly configurable and customizable with CSS styling. Keyboard support for moving and resizing the selection. It works in all major browsers, including Firefox 2+, Opera 9.5+, Google Chrome, Safari 3+, and Internet Explorer 6+.

image-crop

Requirements: jQuery Framework Demo: http://odyniec.net/projects/imgareaselect/ License: MIT, GPL License

Google Powered Site Search with jQuery

Google Powered Site Search with jQuery

By far one of the most requested features by Tutorialzine’s readers, is building a site-wide search. One way to do it, is to build it yourself from the ground up. That is, to use a server-side language like PHP and run search queries on your database, displaying the results to the user.

Another way is to use the services of the one search engine that already knows everything about everyone. Yep, you guessed it. In this tutorial we are using Google’s AJAX Search API, to create a custom search engine, with which you can search for web results, images, video and news items on your site.

The HTML

Lets start with the HTML markup. From the new HTML5 doctype, we move on to defining the title of the document and including the stylesheet to the head section of the page.

search.html

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Google Powered Site Search | Tutorialzine Demo</title>

<link rel="stylesheet" type="text/css" href="styles.css" />

</head>
<body>

<div id="page">

  <h1>Google Powered Site Search</h1>

  <form id="searchForm" method="post">
      <fieldset>

          <input id="s" type="text" />

          <input type="submit" value="Submit" id="submitButton" />

          <div id="searchInContainer">
              <input type="radio" name="check" value="site" id="searchSite" checked />
              <label for="searchSite" id="siteNameLabel">Search</label>

              <input type="radio" name="check" value="web" id="searchWeb" />
              <label for="searchWeb">Search The Web</label>
          </div>

          <ul class="icons">
              <li class="web" title="Web Search" data-searchType="web">Web</li>
              <li class="images" title="Image Search" data-searchType="images">Images</li>
              <li class="news" title="News Search" data-searchType="news">News</li>
              <li class="videos" title="Video Search" data-searchType="video">Videos</li>
          </ul>

      </fieldset>
  </form>

  <div id="resultsDiv"></div>

</div>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script src="script.js"></script>
</body>
</html>

In the body section, we have the main container element – the #page div. The form inside it, acts not only as a search form, but as a container as well. It has CSS3 rounded corners and a darker background color applied to it, which makes it more easily distinguishable from the rest of the page.

Inside the form is the text input box, after which comes the radio group for searching on the current site / the web, and the four search type icons, organized as an unordered list. Lastly we include jQuery and our scripts.js, which is discussed in the last step of this tutorial.

Google Powered Site Search

Google Powered Site Search

The CSS

The CSS styles reside in styles.css. Only the more interesting parts are included here.

styles.css – Part 1

#searchForm{
/* The search form. */
background-color:#4C5A65;
padding:50px 50px 30px;
margin:80px 0;
position:relative;

-moz-border-radius:16px;
-webkit-border-radius:16px;
border-radius:16px;
}

fieldset{
border:none;
}

#s{
/* The search text box. */

border:none;
color:#888888;
background:url('img/searchBox.png') no-repeat;

float:left;
font-family:Arial,Helvetica,sans-serif;
font-size:15px;
height:36px;
line-height:36px;
margin-right:12px;
outline:medium none;
padding:0 0 0 35px;
text-shadow:1px 1px 0 white;
width:385px;
}

As mentioned above, the form’s functions are not limited to only submitting data, but also to act as a regular container element. This keeps the markup on the page to a minimum, while still providing rich functionality.

The text input box, #s, is styled with a background image and padding, so that the text does not cover the magnifying glass.

styles.css – Part 2

.icons{
list-style:none;
margin:10px 0 0 335px;
height:19px;
position:relative;
}

.icons li{
background:url('img/icons.png') no-repeat;
float:left;
height:19px;
text-indent:-999px;
cursor:pointer;
margin-right:5px;
}

/* Styling each icon */

li.web{ width:15px;}
li.web.active,
li.web:hover{ background-position:left bottom;}

li.images{ width:22px; background-position:-18px 0;}
li.images.active,
li.images:hover{ background-position:-18px bottom;}

li.news{ width:14px; background-position:-44px 0;}
li.news.active,
li.news:hover{ background-position:-44px bottom;}

li.videos{ width:17px; background-position:right 0;}
li.videos.active,
li.videos:hover{ background-position:right bottom;}

span.arrow{
/* The little arrow that moves below the icons */

width:11px;
height:6px;
margin:21px 0 0 5px;
position:absolute;
background:url('img/arrow.png') no-repeat;
left:0;
}

/* The submit button */

#submitButton{
background:url('img/buttons.png') no-repeat;
width:83px;
height:36px;
text-indent:-9999px;
overflow:hidden;
text-transform:uppercase;
border:none;
cursor:pointer;
}

#submitButton:hover{
background-position:left bottom;
}

In the fragment above, you can see that the search type icons all share a single background image. It is offset with background position so the appropriate part of it is shown, for both the default and the hover state.

The same technique is used for the submit button. Its text is hidden with a negative text-indent, and buttons.png is shown as its background, with the top part of the image visible by default and the bottom on hover.

styles.css – Part 3

/* Web & news results */

.webResult{ text-shadow:1px 1px 0 #586a75;margin-bottom:50px;}
.webResult h2{
background-color:#5D6F7B;
font-size:18px;
font-weight:normal;
padding:8px 20px;

/* Applying CSS3 rounded corners */
-moz-border-radius:18px;
-webkit-border-radius:18px;
border-radius:18px;
}
.webResult h2 b{ color:#fff; }
.webResult h2 a{ color:#eee;border:none;}
.webResult p{ line-height:1.5;padding:15px 20px;}
.webResult p b{ color:white;}
.webResult > a{ margin-left:20px;}

/* Image & video search results */

.imageResult{
float:left;
height:170px;
margin:0 0 20px 40px;
text-align:center;
width:150px;
}
.imageResult img{ display:block;border:none;}
.imageResult a.pic{
border:1px solid #fff;
outline:1px solid #777;
display:block;
margin:0 auto 15px;
}

/* The show more button */

#more{
width:83px;
height:24px;
background:url('img/more.png') no-repeat;
cursor:pointer;
margin:40px auto;
}

#more:hover{
background-position:left bottom;
}

In the last fragment, we style the results. Although we show four types of search results – web, news, images and video, these are only styled by the two classes above – .webResult and .imageResult. Lastly, we style the #more button, which is dynamically added to the page by jQuery depending on the results returned by Google.

jQuery & JSONp Google API Site Search

jQuery & JSONp Google API Site Search

The jQuery

As mentioned in the beginning, this app uses Google’s AJAX Search API. Google do provide their own JavaScript library, but if you choose to use it, you are constrained with their UI. While functional, it may not be what you want to offer your visitors. This is why, in this tutorial, we are using the “naked version” by issuing JSONp calls with jQuery directly to their API.

Before we start discussing the jQuery code, lets have a glimpse at what data Google makes available to us, after we run a search with the API.

Sample Result From Google’s API

{
  "GsearchResultClass": "GwebSearch",
  "unescapedUrl": "http://tutorialzine.com/2010/02/html5-css3-website-template/",
  "url": "http://tutorialzine.com/2010/02/html5-css3-website-template/",
  "visibleUrl": "tutorialzine.com",
  "cacheUrl": "http://www.google.com/search?q=cache:_NSLxH-cQMAJ:tutorialzine.com",
  "title": "Coding a <b>CSS3</b> & <b>HTML5</b> One-Page Website Template | Tutorialzine",
  "titleNoFormatting": "Coding a CSS3 & HTML5 One-Page Website Template | Tutorialzine",
  "content": "Feb 16, 2010 <b>...</b> Here we are using the new version of HTML.."
}

A search run through their API would return the same set of result that you’d normally get directly from their site. The difference is that here we get a JavaScript array populated with objects like the one above. Each of these objects holds the type of search, a title, a URL, and text from the page that contains the terms we are searching for.

Using the GsearchResultClass property, we can determine how to display the information, as you will see in a moment. This search app supports only web, image, news and video searches but you can see a complete list of the available types of searches in Google’s AJAX search documentation.

script.js – Part 1

$(document).ready(function(){

var config = {
 siteURL  : 'tutorialzine.com', // Change this to your site
 searchSite : true,
 type  : 'web',
 append  : false,
 perPage  : 8,   // A maximum of 8 is allowed by Google
 page  : 0    // The start page
}

// The small arrow that marks the active search icon:
var arrow = $('<span>',{className:'arrow'}).appendTo('ul.icons');

$('ul.icons li').click(function(){
 var el = $(this);

 if(el.hasClass('active')){
  // The icon is already active, exit
  return false;
 }

 el.siblings().removeClass('active');
 el.addClass('active');

 // Move the arrow below this icon
 arrow.stop().animate({
  left  : el.position().left,
  marginLeft : (el.width()/2)-4
 });

 // Set the search type
 config.type = el.attr('data-searchType');
 $('#more').fadeOut();
});

// Adding the site domain as a label for the first radio button:
$('#siteNameLabel').append(' '+config.siteURL);

// Marking the Search tutorialzine.com radio as active:
$('#searchSite').click();

// Marking the web search icon as active:
$('li.web').click();

// Focusing the input text box:
$('#s').focus();

$('#searchForm').submit(function(){
 googleSearch();
 return false;
});

$('#searchSite,#searchWeb').change(function(){
 // Listening for a click on one of the radio buttons.
 // config.searchSite is either true or false.

 config.searchSite = this.id == 'searchSite';
});

The config object holds general configuration options, such as the site URL, a start page (used in the pagination), and the default type of search (a web search). Google only allows us to select 8 results at a time, which is enough for web searches, but not so for images. Lets hope that Google will raise this limit in the future.

When the form is submitted, jQuery calls our googleSearch() function, which you can see below.

To integrate the search into your website, just replace the siteURL property of the config object, with that of your own site URL.

script.js – Part 2

 function googleSearch(settings){

 // If no parameters are supplied to the function,
 // it takes its defaults from the config object above:

 settings = $.extend({},config,settings);
 settings.term = settings.term || $('#s').val();

 if(settings.searchSite){
  // Using the Google site:example.com to limit the search to a
  // specific domain:
  settings.term = 'site:'+settings.siteURL+' '+settings.term;
 }

 // URL of Google's AJAX search API
 var apiURL = 'http://ajax.googleapis.com/ajax/services/search/'+settings.type+
     '?v=1.0&callback=?';
 var resultsDiv = $('#resultsDiv');

 $.getJSON(apiURL,{
  q : settings.term,
  rsz : settings.perPage,
  start : settings.page*settings.perPage
 },function(r){

  var results = r.responseData.results;
  $('#more').remove();

  if(results.length){

   // If results were returned, add them to a pageContainer div,
   // after which append them to the #resultsDiv:

   var pageContainer = $('<div>',{className:'pageContainer'});

   for(var i=0;i<results.length;i++){
    // Creating a new result object and firing its toString method:
    pageContainer.append(new result(results[i]) + '');
   }

   if(!settings.append){
    // This is executed when running a new search,
    // instead of clicking on the More button:
    resultsDiv.empty();
   }

   pageContainer.append('<div class="clear"></div>')
       .hide().appendTo(resultsDiv)
       .fadeIn('slow');

   var cursor = r.responseData.cursor;

   // Checking if there are more pages with results,
   // and deciding whether to show the More button:

   if( +cursor.estimatedResultCount > (settings.page+1)*settings.perPage){
    $('<div>',{id:'more'}).appendTo(resultsDiv).click(function(){
     googleSearch({append:true,page:settings.page+1});
     $(this).fadeOut();
    });
   }
  }
  else {

   // No results were found for this search.

   resultsDiv.empty();
   $('<p>',{
    className : 'notFound',
    html  : 'No Results Were Found!'
   }).hide().appendTo(resultsDiv).fadeIn();
  }
 });
}

The googleSearch() function sends a JSONp request to Google’s API, generates the markup of the results, and inserts it into the #resultsDiv div. It can either empty that div beforehand (if we are making a fresh search) or append the results (this happens when we click the “More” button).

Both paths follow the same logic – a new .pageContainer div is created for each set of results (this div has a bottom border, so it is easier to distinguish one page of results from the next) and an object of the result class (you can see this class below), is initialized and its markup is appended to the pageContainer.

Web Search Results

Web Search Results

script.js – Part 3

 function result(r){

 // This is class definition. Object of this class are created for
 // each result. The markup is generated by the .toString() method.

 var arr = [];

 // GsearchResultClass is passed by the google API
 switch(r.GsearchResultClass){

  case 'GwebSearch':
   arr = [
    '<div class="webResult">',
    '<h2><a href="',r.url,'">',r.title,'</a></h2>',
    '<p>',r.content,'</p>',
    '<a href="',r.url,'">',r.visibleUrl,'</a>',
    '</div>'
   ];
  break;
  case 'GimageSearch':
   arr = [
    '<div class="imageResult">',
    '<a href="',r.url,'" title="',r.titleNoFormatting,
    '" class="pic" style="width:',r.tbWidth,'px;height:',r.tbHeight,'px;">',
    '<img src="',r.tbUrl,'" width="',r.tbWidth,'" height="',
    r.tbHeight,'" /></a>','<div class="clear"></div>',
    '<a href="',r.originalContextUrl,'">',r.visibleUrl,'</a>',
    '</div>'
   ];
  break;
  case 'GvideoSearch':
   arr = [
    '<div class="imageResult">',
    '<a href="',r.url,'" title="',r.titleNoFormatting,'
    " class="pic" style="width:150px;height:auto;">',
    '<img src="',r.tbUrl,'" width="100%" /></a>',
    '<div class="clear"></div>','<a href="',
    r.originalContextUrl,'">',r.publisher,'</a>',
    '</div>'
   ];
  break;
  case 'GnewsSearch':
   arr = [
    '<div class="webResult">',
    '<h2><a href="',r.unescapedUrl,'">',r.title,'</a></h2>',
    '<p>',r.content,'</p>',
    '<a href="',r.unescapedUrl,'">',r.publisher,'</a>',
    '</div>'
   ];
  break;
 }

 // The toString method.
 this.toString = function(){
  return arr.join('');
 }
}
});

This function acts as the constructor of the result class. It takes the object which was returned from Google’s API (which you saw at the beginning of the jQuery step) and initializes arr according to the value of GsearchResultClass. Notice that arr is assigned an array instead of a string. This is a bit faster than multiple concatenations of a string together.

At the bottom of the class, we have the toString() method. It basically calls the array’s internal join method, turning it into a string. toString() is a magical method, which is implicitly called on line 38 of script.js – Part 2.

With this our own Google Powered Search Engine is complete!

Conclusion

Configuring this app to search your site is really simple. Just change the siteURL property of the config object in script.js. There are many ways how you can improve this example. Not all the data that comes from Google is currently displayed. You could also use the filetype: search modifier to look for specific types of files.

Introducing jQuery API Search

Introducing jQuery API Search

Half-baked tutorials and plugins have been stacking up for months in my virtual kitchen, waiting for me to fire up the oven, finish the cooking, and spread them out on the table. For some reason, though, I've become less and less sure about whether I've put all the right ingredients into the mix. It's irritating, to be sure, but I'm tired of fretting about it. I'm going to consider this the first of what I hope to be many 'taste tests' — experiments in various degrees of completion thrown against the wall to see what, if anything, sticks.

As some of you may know, the online jQuery documentation went through a major overhaul in January of this year, coinciding with the release of jQuery 1.4. Packt Publishing 'open sourced' the jQuery 1.4 Reference Guide that Jonathan Chaffer had been writing, allowing us to put its entire contents (and more) on api.jquery.com. Some of you may also know that the raw XML content of the site is available as a single file, which has allowed other sites such as jqapi.com and idocs.brandonaaron.net to provide alternative views of that content. But what most of you probably do not know is that the jQuery API has been available for quite some time as a searchable API that returns the results in JSON format.

Note: The reason you probably don't know about it is that it's half-baked. So, please go easy on it until some smart people have a chance to look under the hood at what I'm doing. Crazy abuse will surely bring it to its knees.

Motivation

I wanted to let people access the jQuery documentation via JavaScript from any other site and pull out exactly what is needed. I also wanted to play around with JSONP. This fits both of those desires.

URL

To access the searchable API, use the following URL:

http://api.jquery.com/jsonp/

Examples

You can tap into the API with one of jQuery's Ajax methods. If you use $.get() or $.getJSON(), you'll need to append '?callback=?' to the URL. With $.get(), you'll also need to set the dataType argument to 'jsonp'.

Find entries in the API that have 'class' in their name and then do something with them:

JavaScript:
  1. $.get('http://api.jquery.com/jsonp/?callback=?',
  2. {name: 'class'},
  3. function(data) {
  4. // do something with data
  5. },
  6. 'jsonp');

Find all effects-category entries and then do something with them:

JavaScript:
  1. $.getJSON('http://api.jquery.com/jsonp/?callback=?',
  2. {category: 'effects'},
  3. function(json) {
  4. // do something with json
  5. });

You can, of course, also use the low-level $.ajax() method.

Find entries with a title that ends in 'ajax'; append a link for each to the document body:

JavaScript:
  1. url: 'http://api.jquery.com/jsonp/',
  2. dataType: 'jsonp',
  3. data: {title: 'ajax', match: 'end'},
  4. success: function(json) {
  5. for (var i=0, len=json.length; i<len ; i++) {
  6. var entry = json[i];
  7. $('<a />', {
  8. href: entry.url,
  9. html: entry.title
  10. }).appendTo('body');
  11. }
  12. }
  13. });

Search Types

The JSONP API is searchable by name, category, and version. Searching by more than one criterion returns results that match all of the criteria. All searches are case-insensitive.

  • Search by name:
    • Key: title
    • Value: the name of any jQuery method, property, or selector
    • Searches in: post title and post slug
    • Substitutions: Before querying the database, all '$' are converted to 'jQuery' and each instance of one or more spaces is converted to a hyphen ('-') for both the search values and the the post title and slug.
    • Default: all titles
  • Search by category name
    • Key: category
    • Value: category name
    • Substitutions: Before querying the database, each instance of one or more spaces is converted to a hyphen ('-')
    • Searches in: category slug
    • Default: all categories
  • Search by version number
    • Key: version
    • Value: a jQuery version number
    • Searches in: category slug for all categories that are a child of the main 'version' category
    • Default: all versions

String Matching

The 'match' parameter lets you be confine the results to those that match the entire search term, or just the start or end of it.

  • Key: match
  • Value: one of 'start', 'end', or 'exact' (for search by version number, one of 'end' or 'exact')
  • Default: 'anywhere', except for version number, which has a default of 'start'

Returned Data

Data is returned as an array of objects. Each item in the array is an object representing a single method, property, or selector. For example, a result with one item would have the following structure:

JavaScript:
  1. [
  2. {
  3. "url": "...",
  4. "title": "...",
  5. "type": "...", // "method", "property", or "selector"
  6. "signatures": [
  7. {
  8. "added":"...",
  9. "params": [
  10. {
  11. "name": "...",
  12. "type": "...",
  13. "optional": "...", // either "true" or an empty string
  14. "desc": "..." // description of the parameter
  15. }
  16. ]
  17. }
  18. ],
  19. "desc": "...", // short description
  20. "longdesc": "...", // long description
  21. "return": "..." // type of return value
  22. }
  23. ]

Note that currently the examples/demos from each entry are not returned.

A (Fairly) Basic Demo

I put together a quick demo to give an idea of the API's flexibility. Type something into the 'Name' field in the form below—say, 'ajax'—and watch as the results come back. Inside the 'Advanced' area, choose the 'Matching... End' radio button and search again to see how the results differ.

✚ Search Again

jQuery API Search A demonstration

Name
Category
Version
Search

Advanced

Matching
Anywhere
Start
End
Exact
Include in Results
Version Added
Arguments
Short Description
Long Description

Clear Results

A Little Less Basic Demo

I replicated this search form on a test server and added back-button support with Ben Alman's crazy delicious BBQ Plugin. Try out the demo.

But wait! There's more!

I put the whole shebang (well, except for the server-side stuff) in a GitHub repo. Clone it, fork it, have your way with it.

But Wait! There's Less!

As I mentioned above, this little project is incomplete. If you peek at the scripts, you'll quickly spot some major chunks of code in need of refactoring. Also, had I but world enough and time, I'd use a nice templating system such as mustache.js or the jQuery Templates plugin to output the search results. But I'll leave all that for another day (or another developer).