Plurk Rich Edit

By maxchu Last update Nov 1, 2009 — Installed 12,763 times. Daily Installs: 27, 20, 22, 15, 33, 14, 20, 10, 21, 14, 23, 24, 22, 14, 27, 26, 22, 15, 26, 21, 17, 20, 18, 20, 54, 39, 39, 43, 20, 27, 39, 20

There are 11 previous versions of this script.

Add Syntax Highlighting (this will take a few seconds, probably freezing your browser while it works)

// ==UserScript==
// @name           Plurk Rich Edit
// @namespace      http://maxchu.blogspot.com
// @description    Adds a simple rich edit interface on Plurk (version 0.7.1)
// @include        http://www.plurk.com/*
// @exclude        http://www.plurk.com/_comet/*
// @exclude        http://www.plurk.com/User/*
// @exclude        http://www.plurk.com/i18n/*
// ==/UserScript==

// Plurk Rich Edit (http://userscripts.org/scripts/show/28806)
// version 0.7.1
// modify from Flickr Rich Edit (http://userscripts.org/scripts/show/1419)
// Released under the GPL license
// http://www.gnu.org/copyleft/gpl.html

// == History ==
// 2009-11-01 V0.7.1: fix flikcr search
// 2009-10-31 V0.7: add interactive plurk bots
// 2009-07-16 V0.6.2: add some exclude URLs
// 2009-06-30 V0.6.1: fix cant work in FF3.5
// 2009-01-15 V0.6: use jquery 1.3 min version
// 2008-12-09 V0.5.1: fix jquery's conflict problem
// 2008-12-09 V0.5: use jquery
// 2008-12-03 v0.4.5: fix bug when it is not in English interface.
// 2008-11-17 v0.4.4: recorrect @include
// 2008-07-25 v0.4.3: 1) add more flickr search option : nsid/username/email, sort, remember account 2) link function: when there's no selected string, then popup prompt ask u enter description.
// 2008-07-12 v0.4.1: fix weird bug
// 2008-07-10 v0.4: add Flickr Search
// 2008-06-25 v0.3.x: normal rich edit function

// == Add jquery == //

var GM_JQ = document.createElement('script');
GM_JQ.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js';
GM_JQ.type = 'text/javascript';
document.getElementsByTagName('head')[0].appendChild(GM_JQ);

function GM_wait() {
	if(typeof unsafeWindow.jQuery == 'undefined') {
		window.setTimeout(GM_wait,100);
	} else {
		$ = unsafeWindow.jQuery.noConflict(true);
		window.setTimeout(doRTE, 2000);
	}
}

GM_wait();

// == CONSTANTS == //

var CONTROL_BAR_ITEM_COMMAND = {
	ITALICIZE: 1,
	EMBOLDEN: 2,
	UNDERLINE: 3,
	LINK: 4,
	FLICKR: 5,
	BOT: 6,
}

// == LIFECYCLE == //

var o_Plurks_editPlurk;
var o_Plurks__cancelOnClick;
var o_Plurks__saveOnClick;
var o_Plurks_removeExpand;

var o_Plurks_editPlurk_cb;

doRTE = function(){

	var input_big = $("#input_big")[0];
	if(input_big) {
			new ControlBar( true, true, true, true, true, true).inject(input_big);
	}
	
	var input_permalink = $("#input_permalink")[0];
	if(input_permalink) {
			new ControlBar( true, true, true, true, true, false).inject(input_permalink);
	}
	
	var p = unsafeWindow.Plurks;

	if(p) {
		o_Plurks_editPlurk = p._editPlurk;
		o_Plurks__cancelOnClick = p.__cancelOnClick;
		p.__cancelOnClick = function() {
			if(o_Plurks_editPlurk_cb) o_Plurks_editPlurk_cb.empty();
			o_Plurks__cancelOnClick();
		};
		o_Plurks_removeExpand = p._removeExpand;

		p._removeExpand = function(D) {
			if(o_Plurks_editPlurk_cb) o_Plurks_editPlurk_cb.empty();
			o_Plurks_removeExpand(D);
		};

		$dp = unsafeWindow.$dp;

		$($dp.man).children('.action').each(function(){
			$(this).unbind('click',p._editPlurk);
			$(this).click(function() {
				o_Plurks_editPlurk();
				o_Plurks_editPlurk_cb = new ControlBar( true, true, true, true, true, false ).inject($dp.ta);
				p.repositonCurrent();
				return false;
			});
		});

		$($dp.saver).children('.cancel').each(function(){
			$(this).unbind('click', o_Plurks__cancelOnClick);
			$(this).click(p.__cancelOnClick);
		});

		if(p.poster) {
			new ControlBar( true, true, true, true, true, false ).inject(p.poster.input);
		}
	}
};

// == CLASSES == //

function ControlBar( showItalic, showBold, showUnderline, showLink, showFlickr, showBot)
{
	this.showItalic = showItalic;
	this.showBold = showBold;
	this.showUnderline = showUnderline;
	this.showLink = showLink;
	this.showFlickr = showFlickr;
	this.showBot = showBot;

	this.inject = function( targetTextArea )
	{
		var controlBar = $("<span></span>").css('padding','1px').css('margin-bottom','1px').css('font-family','Georgia').css('font-size','11px').css('background','#000').css('opacity','0.75').css('-moz-border-radius','4px').css('display','table');

		if ( showItalic )
		{
			var item = new ControlBarItem( "<i>I</i>", CONTROL_BAR_ITEM_COMMAND.ITALICIZE, targetTextArea );

			controlBar.append( item.create() );
		}

		if ( showBold )
		{
			var item = new ControlBarItem( "<b>B</b>", CONTROL_BAR_ITEM_COMMAND.EMBOLDEN, targetTextArea );

			controlBar.append( item.create() );
		}

		if ( showUnderline )
		{
			var item = new ControlBarItem( "<u>U</u>", CONTROL_BAR_ITEM_COMMAND.UNDERLINE, targetTextArea );

			controlBar.append( item.create() );
		}

		if ( showLink )
		{
			var item = new ControlBarItem( "Link", CONTROL_BAR_ITEM_COMMAND.LINK, targetTextArea );

			controlBar.append( item.create() );
		}

		if ( showFlickr )
		{
			var item = new ControlBarItem( "Flickr", CONTROL_BAR_ITEM_COMMAND.FLICKR, targetTextArea );

			controlBar.append( item.create() );
		}
		
		if( showBot )
		{
      var item = new ControlBarItem( "Bot", CONTROL_BAR_ITEM_COMMAND.BOT, targetTextArea );
      
      controlBar.append( item.create() );
    }

		$(targetTextArea).before( controlBar );

		return controlBar;
	};
}

function ControlBarItem( label, editCommand, targetTextArea )
{
	this.label = label;
	this.editCommand = editCommand;
	this.targetTextArea = targetTextArea;

	this.create = function()
	{
		var link = document.createElement("a");
		link.href = "javascript:;";
		link.innerHTML = label;

		link.editCommand = this.editCommand;
		link.targetTextArea = this.targetTextArea;
		link.execute = this.execute;
		link.linkSelection = this.linkSelection;
		link.tagSelection = this.tagSelection;
		link.flickrSearch = this.flickrSearch;
		link.listBot = this.listBot;

		addEvent( link, "click", "execute" );

		return $(link).css('color','#fff').css('padding','4px').css('text-decoration','none');
	}

	this.execute = function(e)
	{
		switch( this.editCommand )
		{
			case CONTROL_BAR_ITEM_COMMAND.ITALICIZE:
				this.tagSelection( "*", "*" );
				break;
			case CONTROL_BAR_ITEM_COMMAND.EMBOLDEN:
				this.tagSelection( "**", "**" );
				break;
			case CONTROL_BAR_ITEM_COMMAND.UNDERLINE:
				this.tagSelection( "__", "__" );
				break;
			case CONTROL_BAR_ITEM_COMMAND.LINK:
				this.linkSelection();
				break;
			case CONTROL_BAR_ITEM_COMMAND.FLICKR:
				this.flickrSearch();
				break;
			case CONTROL_BAR_ITEM_COMMAND.BOT:
        this.listBot(e);
				break;
			default:
				throw "Unknown command encountered";
		}

		this.blur();
	}

	this.linkSelection = function()
	{
		var url = prompt( "Enter the URL:", "" );

		if (url && url != '' )
		{
			// work around Mozilla Bug #190382
			if ( this.targetTextArea.selectionEnd > this.targetTextArea.value.length )
			{
				this.targetTextArea.selectionEnd = this.targetTextArea.value.length;
			}
			//We will restore the selection later, so record the current selection.
			var selectionStart = this.targetTextArea.selectionStart;
			var selectionEnd = this.targetTextArea.selectionEnd;
			var desc = '';
			if(selectionStart == selectionEnd) {
				desc = prompt( "Enter the Description:", "" );
			}
			if(!desc) desc = '';

			this.tagSelection( url + ' (', desc + ')' );
		}
	}

	this.flickrSearch = function()
	{
		showFlickrBox(targetTextArea);
	}
	
	this.listBot = function(e)
	{

      showBotBox(e,targetTextArea);
  }

	this.tagSelection = function( tagOpen, tagClose )
	{
		if ( this.targetTextArea.selectionStart || this.targetTextArea.selectionStart == 0 ) //relies on this property.
		{
			//record scroll top to restore it later.
			var scrollTop = this.targetTextArea.scrollTop;

			// work around Mozilla Bug #190382
			if ( this.targetTextArea.selectionEnd > this.targetTextArea.value.length )
			{
				this.targetTextArea.selectionEnd = this.targetTextArea.value.length;
			}

			//We will restore the selection later, so record the current selection.
			var selectionStart = this.targetTextArea.selectionStart;
			var selectionEnd = this.targetTextArea.selectionEnd;

			this.targetTextArea.value =
				this.targetTextArea.value.substring( 0, selectionStart ) + //text leading up to the selection start
				tagOpen +
				this.targetTextArea.value.substring( selectionStart, selectionEnd ) + //selected text
				tagClose +
				this.targetTextArea.value.substring( selectionEnd ); //text after the selection end

			this.targetTextArea.selectionStart = selectionStart + tagOpen.length;
			this.targetTextArea.selectionEnd = selectionEnd + tagOpen.length;

			this.targetTextArea.scrollTop = scrollTop;

			this.targetTextArea.focus();
		}
	}
}

// == Bot List == //
var botBox;
var botWidth = 48;

function BotBox(targetTextArea) {
    this.targetTextArea = targetTextArea;
    this.container;
    this.itemList = new Array();

    this.move = function(e){
      offset = $(e.target).offset();
      this.container.css('top',offset.top - this.container.height()).css('left',offset.left);
    }
    
    this.toggle = function(e){
      if(this.container.css('display') == 'none'){
        this.container.fadeIn();
        this.move(e);
      }else{
        this.container.fadeOut();
      }
    }
    
    this.hide = function(){
      this.container.fadeOut();
    }
    
    this.append = function(item){
       this.itemList[this.itemList.length] = item;
    }
    
    this.create = function(){
      this.container = $('<div></div>').css('display','none').css('position','absolute')
                        .css('overflow','visible').css('border','2px solid #000').css('padding','1px')
                        .css('background','#fff').css('zIndex','999999999').css('color','#000')
                        .css('-moz-border-radius','4px');
      // item
      var size = this.itemList.length;
      var botCountPerRow = Math.sqrt(size);
      if(botCountPerRow > parseInt(botCountPerRow)) {
        botCountPerRow = parseInt(botCountPerRow) + 1;
      }
      this.container.css('width',(botCountPerRow*(botWidth+4+2))+'px');
      for(i=0;i<size;i++) {
        var item = this.itemList[i].create();
        this.container.append(item);
      }
      this.container.height();
      
      $('body').append(this.container);
    }

}

function BotItem(botBox,account,id,avatar,nickname,qualifer,callback) {
  this.botBox = botBox;
  this.account = account;
  this.id = id;
  this.avatar = avatar;
  this.nickname = nickname;
  this.container;
  this.callback = callback;

  this.create = function(){
    if(!this.container) {
      this.container = $('<span></span>').css('display','block').css('float','left')
                      .css('background','#fff').css('color','#000')
                      .css('border','1px solid #888').css('margin','1px').css('padding','1px').css('-moz-border-radius','2px')
                      .css('width',botWidth+'px').css('height',botWidth+'px');

      var avatarImg = $('<div><img src="http://avatars.plurk.com/'+id+'-medium'+avatar+'.gif"/></div>').css('text-align','center').css('width',botWidth+'px').css('height',botWidth+'px');
      this.container.append(avatarImg);

      var info = $('<div></div>')
                .css('width',botWidth+'px').css('height',botWidth+'px')
                .css('font-size','11px').css('text-align','center');
      var header = $('<div></div>').css('margin','0px').css('padding','0px')
                .css('background','#E2560B').css('display','block').css('font-size','11px');
      var link = $('<a href="http://plurk.com/'+account+'" target="_blank">Plurk</a>')
                .css('color','#fff').css('font-family','Ariel').css('font-weight','bold')
                .css('margin','0px').css('padding','0px').css('text-decoration','none');
      var desc = $('<div>'+nickname+'</div>').css('color','#fff').css('line-height','90%')
                 .css('margin-top','3px');
      header.append(link);
      info.append(header);
      info.append(desc);
      link.click(function(){
        botBox.hide();
      });
      desc.click(function(){
        botBox.hide();
        var result = callback();
        if(result && result != '') {
          $(botBox.targetTextArea).val(result);
          if(qualifer && qualifer != '') {
            unsafeWindow.main_poster.menu.updateQualifer(qualifer);
          }
        }
        return false;
      });
      
      this.container.mouseenter(function(){
        $(this).css('background','#000').css('color','#fff').html(info);
      });
      this.container.mouseleave(function(){
        $(this).css('background','#fff').css('color','#000').html(avatarImg);
      });
      
      $('body').append(this.container);
    }
    return this.container;
  }

}

function showBotBox(e,targetTextArea) {
  if(!botBox) {
    botBox = new BotBox(targetTextArea);
    botBox.append(new BotItem(botBox,'song4u','4299622',2,'邦尼妹妹幫你呻吟','',function(){
      var singer = prompt("歌手是?", "");
      if(singer&&singer!=''){
        singer = ' ' + singer;
      }else {
        singer = '';
      }
      var songname = prompt("點播歌曲名稱是?", "");
      if(!songname||songname=='') {
        return;
      }
      return '幫我點播'+singer+' '+songname;
    }));
    botBox.append(new BotItem(botBox,'sheep_knowledge','3902175',4,'羊羊騎貘姿勢佳','asks',function(){
      var question = prompt("發問問題是?", "");
      if(!question || question == '') {
        return;
      }
      return question;
    }));
    botBox.append(new BotItem(botBox,'funkyou','4038751',2,'邦尼阿嬤幫你罵','',function(){
      var who = prompt("你要罵誰?", "");
      return '幫我罵' + who;
    }));
    botBox.append(new BotItem(botBox,'justitrip','3639166',2,'就是愛旅行','',function(){
      var where = prompt("想要去哪玩?", "");
      if(!where || where == '') {
        return;
      }
      return '教我玩' + where;
    }));
    botBox.append(new BotItem(botBox,'mining_tw','4021450',2,'無名挖挖挖','wonders',function(){
      var who = prompt("想挖那個正妹?", "");
      if(!who || who == '') {
        return;
      }
      return who;
    }));
    botBox.append(new BotItem(botBox,'lotteryu','4096250',4,'邦尼樂透幫你套弄','',function(){
      return '給我樂透';
    }));
    botBox.create();
    var src = e.target;
    $('body').click(function(e){
      if(e.target != src) botBox.hide();
    });
  }
  botBox.toggle(e);
}

// == Flickr Serach == //

var frAPIKey = '17f5005ce502a30e727c558a87cb8470';

var frVarWidth = 150;
var frKeyNSID = 'fr_key_nsid';
var frKeyRememberMe = 'fr_key_member_me';

var frBox;
var frResult;
var frCellNum;
var frRowNum;

var frOptUsername;
var frOptKeyword;
var frOptSort;
var frOptRememberMe;

var frSearchURL;

function showFlickrBox(targetTextArea) {

	unsafeWindow.frTargetTA = targetTextArea;

	if(!frBox) {

		frCellNum = parseInt((window.innerWidth - 150) / frVarWidth);
		frRowNum = parseInt((window.innerHeight - 200) / frVarWidth);
		var frBoxWidth = (frCellNum * frVarWidth);

		frBox = $('<div></div>').attr('id','frBox').css('position','absolute').css('overflow','visible').css('width',frBoxWidth + 'px').css('top','20px').css('padding','0px').css('margin','15px').css('left',(1*document.body.clientWidth-frBoxWidth)/2 + 'px').css('display','none').css('border','3px solid #F7861B').css('background','#ffffff').css('zIndex','999999999').css('font-family','Arial,Helvetica,sans-serif').css('-moz-border-radius','8px').css('color','#000');
		$('body').append(frBox);

		// title
		var titlebar = $('<div><span style="color:#0063DC">Flick</span><span style="color:#FF0084">r</span> Search</div>').css('text-align','center').css('font-size','14px').css('font-weight','bold').css('letter-spacing','2px').css('padding','5px');
		frBox.append(titlebar);

		// option
		var optionbar = $('<div></div>').css('padding','5px').css('background','#fefefe').css('border-top','1px dashed #000');
		frBox.append(optionbar);

		// Flickr Username or Email
		var op1 = $('<span>NSID/Username/Email : </span>').css('padding','5px');
		op1.append(frOptUsername = $('<input type="text" size="20"/>'));
		optionbar.append(op1);

		// retrieves
		setTimeout(function(){
			var nsid = GM_getValue(frKeyNSID);
			if(nsid) {
				frOptUsername.attr('value',nsid);
			}
		},0);

		// remember me
		var op4 = $('<span>Remember Account </span>').css('padding','5px');
		op4.append(frOptRememberMe = $('<input type="checkbox"/>'));
		optionbar.append(op4);

		// retrieves
		setTimeout(function(){
			var rememberMe = GM_getValue(frKeyRememberMe);
			if(rememberMe) {
				frOptRememberMe.attr('checked',rememberMe);
			}
		},0);

		optionbar.append('<br>');

		// keyword
		var op2 = $('<span>Keyword : </span>').css('padding','5px');
		op2.append(frOptKeyword = $('<input type="text" size="20"/>'));
		optionbar.append(op2);

		// sort
		var op3 = $('<span>Sort : </span>').css('padding','5px');
		op3.append(frOptSort = $('<select id="frOptSort"></select>').html(
		'<option value="interestingness-desc">Interestingness Desc</option>' +
		'<option value="interestingness-asc">Interestingness Asc</option>' +
		'<option value="date-posted-asc">Date Posted Asc</option>' +
		'<option value="date-posted-desc">Date Posted Desc</option>' +
		'<option value="date-taken-asc">Date Taken Asc</option>' +
		'<option value="date-taken-desc">Date Taken Desc</option>' +
		'<option value="relevance">relevance</option>'
		));
		optionbar.append(op3);

		var searchbtn;
		optionbar.append(searchbtn = $('<input type="button"/>').attr('value','Go'));
		searchbtn.click(function() {
			doFlickrURLAndSearch();
		});

		// result
		frResult = $('<div></div>').css('padding','5px').css('border-top','1px dashed #000').css('text-align','center');
		frBox.append(frResult);

		// close
		var closebar = $('<div></div>').css('text-align','right').css('background','#F7861B');
		var close = $('<span>Close</span>').css('cursor','point').css('color','#fff').css('background','#F7861B').css('padding','2px').css('font-weight','bold');
		close.click(function() {
			frBox.fadeOut();
		});
		closebar.append(close);
		frBox.append(closebar);
	}

	frBox.fadeIn();

}

function getFlickrURI(method, param) {
	return 'http://api.flickr.com/services/rest/?method=' + method + '&format=json&jsoncallback=?&api_key=' + frAPIKey + '&' + param;
}

function doFlickrURLAndSearch() {

	if(frOptUsername.val() == '') {
		_doFlickrURLAndSearch('');
	}else {
		// by name
		$.getJSON(getFlickrURI('flickr.people.findByUsername','username=' + frOptUsername.val()), function(rsp){
			if(rsp.stat == 'ok') {
				_doFlickrURLAndSearch(rsp.user.nsid);
			}else {
				// by email
				$.getJSON(getFlickrURI('flickr.people.findByEmail','find_email=' + frOptUsername.val()), function(rsp) {
					if(rsp.stat == 'ok') {
						_doFlickrURLAndSearch(rsp.user.nsid);
					}else {
						_doFlickrURLAndSearch(frOptUsername.val());
					}
				});
			}
		});
	}

	// store
	setTimeout(function() {
		var frOptRememberMeisCheck = eval(frOptRememberMe.attr('checked'));
		if(frOptRememberMeisCheck) {
			GM_setValue(frKeyNSID, frOptUsername.attr('value'));
			GM_setValue(frKeyRememberMe, frOptRememberMeisCheck);
		}else {
			GM_setValue(frKeyNSID, '');
			GM_setValue(frKeyRememberMe, false);
		}
	},0);

}

function _doFlickrURLAndSearch(nsid) {

	frSearchURL = getFlickrURI(
		'flickr.photos.search',
		'privacy_filter=1' +
		'&per_page=' + (frCellNum * frRowNum) +
		'&sort=' + $('#frOptSort option:selected')[0].value +
		'&text=' + encodeURIComponent(frOptKeyword.val()) +
		((nsid == '') ? '' : ('&user_id=' + nsid))
		);

	doFlickrSearch();
}

function doFlickrSearch(page) {

	frResult.html('<img src="data:image/gif;base64,R0lGODlhKwALAPEAAP////eGG/rDj/eGGyH+GkNyZWF0ZWQgd2l0aCBhamF4bG9hZC5pbmZvACH5BAAKAAAAIf8LTkVUU0NBUEUyLjADAQAAACwAAAAAKwALAAACMoSOCMuW2diD88UKG95W88uF4DaGWFmhZid93pq+pwxnLUnXh8ou+sSz+T64oCAyTBUAACH5BAAKAAEALAAAAAArAAsAAAI9xI4IyyAPYWOxmoTHrHzzmGHe94xkmJifyqFKQ0pwLLgHa82xrekkDrIBZRQab1jyfY7KTtPimixiUsevAAAh+QQACgACACwAAAAAKwALAAACPYSOCMswD2FjqZpqW9xv4g8KE7d54XmMpNSgqLoOpgvC60xjNonnyc7p+VKamKw1zDCMR8rp8pksYlKorgAAIfkEAAoAAwAsAAAAACsACwAAAkCEjgjLltnYmJS6Bxt+sfq5ZUyoNJ9HHlEqdCfFrqn7DrE2m7Wdj/2y45FkQ13t5itKdshFExC8YCLOEBX6AhQAADsAAAAAAAAAAAA%3D">');

	setTimeout(function(){
		$.getJSON(frSearchURL + ((page) ? "&page=" + page : ""),function(rsp) {
			generateFlickrResult(rsp);
		});
	}, 500);

}

function generateFlickrResult(rsp) {

	frResult.html('');

	if (rsp.stat != "ok"){
		frResult.html('<b>' + rsp.message + '</b>');
		return;
	}

	if(rsp.photos.total == 0) {
		frResult.html('<b>No Match !</b>');
		return;
	}

	var photo = rsp.photos.photo;

	var table = $('<table></table>').css('width','100%');
	frResult.append(table);

	var tr;

	for(i in photo) {

		if(i % frCellNum == 0) {
			tr = $('<tr></tr>');
			table.append(tr);
		}

		var td = $('<td></td>').css('text-align','center').css('vertical-align','top').css('width',frVarWidth + 'px');
		tr.append(td);
		var p = photo[i];
		var imgUrl = 'http://farm' + p.farm + '.static.flickr.com/' + p.server + '/' + p.id + '_' + p.secret + '_t.jpg';

		var img = $('<img/>').attr('src',imgUrl).css('padding','5px');
		td.append(img);

		var title = $('<div>' + ((p.title.length > 30) ? (p.title.substr(0,30) + '...') : p.title) + '</div>');
		td.append(title);

		var imgLink = 'http://www.flickr.com/photos/' + p.owner + '/' + p.id + '/';
		var append = $('<span><a href="#" style="color:#fff;font-weight:bold;text-decoration:none;" onclick="javascript:frTargetTA.value += \'' + imgLink + ' \';return false;">+</a></span>').css('background','red').css('-moz-border-radius','2px').css('margin-right','5px').css('padding','0px 2px').css('cursor','pointer');
		title.prepend(append);

	}

	var pagebar = $('<div></div>').css('text-align','center').css('padding','5px').css('border-top','1px dashed #000');
	frResult.append(pagebar);

	var prev;
	if(rsp.photos.page > 1) {
		prev = $('<a/>').css('cursor','pointer').css('color','#0063DC');
		prev.click(function(e) {
			doFlickrSearch(rsp.photos.page-1);
		});
	}else {
		prev = $('<span></span>');
	}
	prev.html('&#9668; Prev');
	pagebar.append(prev);

	var pages = $('<span>&nbsp;&nbsp;&nbsp;<span style="color:#FF0084">' + rsp.photos.page + '</span> / ' + rsp.photos.pages + '&nbsp;&nbsp;&nbsp;</span>').css('color','#0063DC');
	pagebar.append(pages);

	var next;
	if(rsp.photos.page < rsp.photos.pages) {
		next = $('<a/>').css('cursor','pointer').css('color','#0063DC');
		next.click(function(e) {
			doFlickrSearch(rsp.photos.page+1);
		});
	}else {
		next = $('<span></span>');
	}
	next.html('Next &#9658;');
	pagebar.append(next);
}

//Delegated event wire-up utitlity. Using this allows you to use the "this" keyword in a delegated function.
function addEvent( target, eventName, handlerName )
{
	target.addEventListener(eventName, function(e){target[handlerName](e);}, false);
}