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