mike enriquez

Mac/iOS/Web Developer

Technical stuff

How to build a personal mashup page with jQuery

After finding out about GitHub pages, I decided to put mine to good use by building a mashup for my online content. Since we don’t have any control on the server side, we’re going to use only javascript to make it dynamic. This tutorial will show you how to use jQuery and JSONP to pull data from Twitter, GitHub, and an RSS Feed (without any server side magic). The techniques here can easily be used to interact with any other API.

For a demo, visit my personal mashup page hosted on GitHub. Get the code from GitHub

What is JSONP, and why do I need to use it?

JSONP is JSON with padding. For security reasons, browsers do not allow for scripts from a remote domain to run. This is known as the same origin policy. There a couple ways to get around this restriction, but we’re going to use JSONP in this tutorial because it is a purely javascript solution. Plus, jQuery 1.2 and greater makes it easy to work with JSONP.

jQuery and Twitter

First thing you need to do is get familiar with the Twitter API Documentation. Let’s list a user’s status updates using the statuses/user_timeline method.

This method is called with a GET request and does not require any authentication. It might not be a good idea to use a method that requires authentication using javascript. Try to stick with publicly available data or methods.

Twitter supports a couple different data formats. Since we want JSON, the URL to get a user’s timeline is http://twitter.com/statuses/user_timeline/<username>.json

Let’s build a wrapper for the Twitter API, and create a Statuses.user_timeline function. Let’s also create a Users.show function for kicks.

// Twitter API wrapper. http://apiwiki.twitter.com/Twitter-API-Documentation
function TwitterAPI(){}

TwitterAPI.Users = function Users(){}
TwitterAPI.Statuses = function Statuses(){}

// http://apiwiki.twitter.com/Twitter-REST-API-Method%3A-users%C2%A0show
TwitterAPI.Users.show = function(username, callback){
  requestURL = "http://twitter.com/users/show/" + username + ".json?callback=?";
  $.getJSON(requestURL, callback);
}

// http://apiwiki.twitter.com/Twitter-REST-API-Method%3A-statuses-user_timeline
TwitterAPI.Statuses.user_timeline = function(username, callback){
  requestURL = "http://twitter.com/statuses/user_timeline/" + username + ".json?callback=?";
  $.getJSON(requestURL, callback);
}

This wrapper simply takes a username and callback function, builds the URL, then passes it off to jQuery’s $.getJSON function. Notice in the requestURL that we had to add ?callback=?. Without it we would get a security error because of the same origin policy.

Let’s build a list of tweets for the Twitter user enriquez using the TwitterAPI wrapper:

TwitterAPI.Statuses.user_timeline("enriquez", function(json, status){
  var content = "";
  $.each(json, function(i){
    tweet = this['text'];
    content += "<li class=\"tweets\">" + tweet + "</li>";
  });
  $("ul#tweets").html(content);
})

You can see that our callback function is given a parameter called json. This is from jQuery’s $.getJSON, and it contains a collection of statuses. The above example loops through each status and places the text in a list. You can see what else is available in this object by studying the response structure from the Twitter API documentation for user_timeline. For example, if you want to get the “tweeted date” you would access the created_at attrbute and call it like this: this['created_at'].

jQuery and GitHub

The process for retrieving data from GitHub is similar to Twitter. The following is the GitHub API wrapper with a function for getting a user’s list of repos.

// http://develop.github.com/p/repo.html
GitHubAPI.Repos = function(username, callback){
  requestURL = "http://github.com/api/v2/json/repos/show/" + username + "?callback=?";
  $.getJSON(requestURL, function(json, status){
    callback(json.repositories, status);
  });
}

Notice that I’m passing in json.repositories, instead of just json. This is just for convenience. Building a list of a user’s repositories is accomplished like so:

GitHubAPI.Repos("enriquez", function(json, status){
  var content = "";
  $.each(json, function(i){
    projectName = this['name']
    content += "<li class=\"project\">" + projectName + "</li>";
  });
  $("ul#projects").html(content);
})

jQuery and an RSS Feed

An RSS Feed isn’t an API, but it is an XML file. Because it is an XML file, it takes a bit more work to read it in with jQuery. Not only do we need to work around the same origin policy, we need the data in JSON format… not XML. We could write a server side script to turn XML into JSON, but its easier to use

Yahoo! Pipes to do this for us. Yahoo! Pipes is great for building mashups. It allows you to work with API’s easily and better yet, it can expose an existing API with JSONP.

I’ve already created a Yahoo! Pipe that you can use to read an RSS Feed. Below is the wrapper for it.

// RSS Feed wrapper
function RSSFeed(){}

// Yahoo pipe for turning an RSS XML feed into JSONP
// http://pipes.yahoo.com/pipes/pipe.run?_id=NvfW_c9m3hGRjX4hoRWqPg
RSSFeed.Entries = function(feed_url, callback){
  requestURL = "http://pipes.yahoo.com/pipes/pipe.run?_id=NvfW_c9m3hGRjX4hoRWqPg&_render=json&_callback=?&feed=" + feed_url;
  $.getJSON(requestURL, function(json, status){
    callback(json.value.items, status);
  });
}

Just pass this your feed url, and you’ll be given an object containing a collection of “entries” or articles. Use the wrapper like this:

RSSFeed.Entries("http://feeds2.feedburner.com/theezpzway", function(json, status){
  var content = "";
  $.each(json, function(i){
    postTitle = "<a href=\"" + this['link'] + "\">" + this['title'] + "</a>";
    content += "<p class=\"posts\">" + postTitle + "</p>";
  })

  $("div#posts").html(content);
})

Conclusion

Using jQuery and some API’s you can build a dynamic mashup site without the need any server side logic. The code for my mashup is on GitHub. Bonus points to whoever finds the easter egg!

Resources


jQuery plugin EZPZ Hint

A simple jQuery plugin for showing a text field’s label inside the textbox itself. The hint disappears when it is given focus, and appears again if the inputted text is empty. Typically used for search and login forms.

This plugin works in all modern browsers, and it even works with password field hints.

Check out the demo here.

Features

How it works

The hint text is taken from the title attribute of the input. Sorry, no graceful degradation. Disabled javascript users will see a bunch of unlabeled text boxes. A future version will use a label tag to get the hint text.

Since IE doesn’t allow a password field to be changed into a text field, a dummy text field is dynamically created to hold the hint text. The dummy input and real input swap visibility on focus and blur to give the illusion that the hint text is appearing and disappearing. The only problem with this technique is that the dummy text field is not a direct copy of the real text field. The plugin only copies over the class and size attributes

This plugin disables the remember password feature of most browsers by setting autocomplete to “off”. The text hint gets confused with it on, and the browser actually remembers the dummy inputs instead of the real inputs. This can be fixed in the future to move all the dummy inputs to the top of the form, and the replacement would have to be done by absolutely positioning the dummys over the real text fields (that’s the theory anyway, I don’t know if it would work).

Download

As always, the code is available on GitHub. It can also be downloaded below.

jquery.ezpz_hint.js

jquery.ezpz_hint.min.js


jQuery plugin EZPZ Tooltip

UPDATE April 12, 2009. Added the showContent and hideContent callbacks. Use these for custom effects. Also updated the demo for examples.

There are a ton of tooltip plugins for jQuery out there, but I couldn’t find one that works with the way I think. To me, it’s a simple concept: You hover over a target element, then some content shows up. It should be flexible enough to customize the look and feel without requiring the bloat of any CSS or images. Hover targets should be mapped to their content counterparts by convention. I think I’ve built just that with the EZPZ Tooltip.

Check out the demo here.

Features

Basic Usage

The HTML

We need two elements, one for the target and one for the content. Take note of the id attribute.

<span id="example-target-1">Hover over me</span>
<div id="example-content-1">Tooltip content</div>

The content can be any block level element. We can easily use an image for the content by doing something like this:

<img id="example-content-1" width="276" height="110" src="http://google.com/intl/en_ALL/images/logo.gif" alt="Google"/>

The Javascript

Bind the hover event by calling ezpz_tooltip() on the target element on the document ready event. I’ll explain the naming convention for the target and content elements later.

$(document).ready(function(){
  $("#example-target-1").ezpz_tooltip();
});

The CSS

We need to hide the content of the tooltip and give it an absolute position (this may be done automatically in future versions of this plugin). This is where you can customize the look of the content by giving it a background image, borders, colors, etc…

#example-content-1 {
  display: none; /* required */
  position: absolute; /* required */
  padding: 10px; border: 1px solid black;
  background-color: white;
}

The Convention

By convention, the target and content elements are bound together by the name of their id attribute. The convention is this: (name)-target-(unique id) will be bound to (name)-content-(unique id). You can override this behavior by passing the id of the content to ezpz_tooltip() like so:

$("#target").ezpz_tooltip({contentId:"content"});
<div id="target">Hover over me</div>
<div id="content">I'm target's hover content</div>

Advanced Usage

Bind multiple tooltips

Typically, your page will have multiple tooltips on it.

<div class="tooltip-target" id="example-target-1">First Target</div>
<div class="tooltip-target" id="example-target-2">Second Target</div>
<div class="tooltip-target" id="example-target-3">Third Target</div>

<div class="tooltip-content" id="example-content-1">Content for first</div>
<div class="tooltip-content" id="example-content-2">Content for second</div>
<div class="tooltip-content" id="example-content-3">Content for third</div>

To bind all of the targets to their corresponding content, it takes only one line:

$(".tooltip-target").ezpz_tooltip();

Calling ezpz_tooltip() on a class will bind the hover event to each element, and because of the naming convention it will know which content to display.

Custom content position

Defining and using a position function is done like this:

$.fn.ezpz_tooltip.positions.topLeft = function(contentInfo, mouseX, mouseY, offset, targetInfo) {
  contentInfo['top'] = 0;
  contentInfo['left'] = 0;
  return contentInfo;
};

$("#tooltip-target-1").ezpz_tooltip({
  contentPosition: 'topLeft'
});

This topLeft example will position the content to the upper left corner of the window. You’ll probably need to use the parameters for your custom position, so here’s some detail on them:

For more examples of position functions, look towards the bottom of the jquery.ezpz_tooltip.js file.

Options and their defaults

Download

The code is available on GitHub. The master branch contains the code for development. The minified branch contains the compacted version that should be used in production. The latest stable version can be downloaded below:

jquery.ezpz_tooltip.js

jquery.ezpz_tooltip.min.js


How to integrate Ultraviolet into Mephisto

I couldn’t find a theme I liked for CodeRay, and I wasn’t up for creating/modifying my own. I ended up finding a different syntax highlighter called Ultraviolet. It uses TextMate’s syntax files which is pretty cool. The code in this article is highlighted using the “lazy” theme.

Integrating Ultraviolet into Mephisto (or more specifically the filtered_column_code_macro plugin) can be done in 3 steps.

Step 1: Install Ultraviolet

I won’t get into too much detail here. You can follow the directions here: http://ultraviolet.rubyforge.org/.

Step 2: Hack filtered_column_code_macro

I consider this a dirty hack. Ideally, filtered_column_code_macro would be written to give the user options to use either CodeRay or Ultraviolet. Kinda like how filtered_column supports Markdown and Textile. This works for now…

Modify code_macro.rb to look like the following:

# plugins/filtered_column_code_macro/lib/code_macro.rb

require 'uv'

class CodeMacro < FilteredColumn::Macros::Base
  DEFAULT_OPTIONS = {:wrap => :div, :line_numbers => :table, :tab_width => 2, :bold_every => 5, :hint => false, :line_number_start => 1}
  def self.filter(attributes, inner_text = '', text = '')
    # It's a whole lot easier to just set your attributes statically
    # I think for most of us the only option we're gonna change is 'lang'
    # refer to http://rd.cycnus.de/coderay/doc/classes/CodeRay/Encoders/HTML.html for more info
    # use code_highlighter.css to change highlighting
    # don't change, formats code so code_highlighter.css can be used

    lang    = attributes[:lang].blank? ? nil : attributes[:lang].to_sym
    options = DEFAULT_OPTIONS.dup
    # type of line number to print options: :inline, :table, :list, nil [default = :table]
    # you can change the line_numbers default value but you will probably have to change the css too
    options[:line_numbers]      = attributes[:line_numbers].to_sym    unless attributes[:line_numbers].blank?
    # changes tab spacing [default = 2]
    options[:tab_width]         = attributes[:tab_width].to_i         unless attributes[:tab_width].blank?
    # bolds every 'X' line number
    options[:bold_every]        = attributes[:bold_every].to_i        unless attributes[:bold_every].blank?
    # use it if you want to can be :info, :info_long, :debug just debugging info in the tags
    options[:hint]              = attributes[:hint].to_sym            unless attributes[:hint].blank?
    # start with line number
    options[:line_number_start] = attributes[:line_number_start].to_i unless attributes[:line_number_start].blank?

    inner_text = inner_text.gsub(/\A\r?\n/, '').chomp
    html = ""

    begin
      html = Uv.parse(inner_text, "xhtml", lang.to_s, false, "lazy")
    rescue
      unless lang.blank?
        RAILS_DEFAULT_LOGGER.warn "UltraViolet Error: #{$!.message}"
        RAILS_DEFAULT_LOGGER.debug $!.backtrace.join("\n")
      end
      html = "<pre><code>#{CGI.escapeHTML(inner_text)}</code></pre>"
    end
    "<div class=\"ultraviolet\">\n#{html}</div>\n"
  end
end

Two things to note here:

  1. Don’t forget to require 'uv' at the top. We won’t be needing CodeRay here anymore.
  2. Pay attention to the parameters passed to Uv.parse towards the bottom.

If you want to turn on line numbers, set the 4th parameter for Uv.parse to true. If you want to use a different theme, place it’s name in the 5th parameter. Again, a dirty hack that should be configured by the user of this library, but this isn’t an article about best practices.

Step 3: Generate and include the CSS

Fire up irb and run the following:

>> require 'uv'
>> Uv.copy_files "xhtml", "PATH_TO_GENERATE_FILES"

This will create a css directory containing all of the TextMate themes. Copy the theme you want and include it in your layout.liquid:

<!-- layout.liquid -->
{{ 'lazy' | stylesheet : 'screen, projection' }}

That’s it! Using it works the same way as before by using the <macro:code lang="ruby"> tags. A list of supported languages can be found by running puts Uv.syntaxes.join( ", " ) in irb.


Chocolate Meat Mephisto Theme

Photo by flickr user bigberto

What is chocolate meat? Not only is it a delicious Filipino dish it is now also a Mephisto theme! For blogging developers, it uses a modified version of the “lazy” TextMate syntax highlighting theme (via Ultraviolet). Check out my last post to see the syntax highlighting in action (this blog is using Chocolate Meat)

Tried and tested on Mephisto 0.8. Anything else is unknown territory.

Chocolate Meat AKA Dinuguan

Features

Download

chocolate_meat-1.0.zip

Install

Log into your Mephisto site, then navigate to Design → Manage Themes → Import New Theme. Browse to the zip file and activate the theme.

The “lazy” syntax highlighting theme relies on Ultraviolet. If you want this feature, read my last post for directions for integrating it into Mephisto.

Contribute

The latest version of chocolate meat is on github. Fork it, fix it, change it, whatever… Please share.

Note: This blog no longer uses this theme. You can see it at the Mephisto Themes Gallery by selecting “chocolate meat” from the menu at the top.