WordPress Simple Sharing Buttons

share-buttons

I recently needed to make some updates to this blog to fix some issues, update a few items and “get with the times” on a couple things… One of the things I wanted to make “fit” into the site a little better, or what I feel is a little better, is some more themed social icons.

Here’s what I did for these buttons.

Read more

Multiple Maps On a Single Page with jQuery

google-maps-example

I recently added a “locations” page to my website and was looking for a simple way to display multiple maps (Google Maps) on the page for the corresponding locations, without having to do a ton of coding or having to maintain a lot of JavaScript.

What I decided on was a simple jQuery implementation that uses data- elements to supply latitude (lat) and longitude (lng) vales for the map rendering.

Read more

Google Maps API Simple Async Loading

google-maps-example

In doing some page testing on my site using the Google PageSpeed Insights tool I found that on a couple of my pages, one of the things slowing my page loads down was the loading of the Google Maps API.

google-pagespeed

There are a lot of articles out there talking about a ton of different ways to load the Google Maps API in an asynchronous (async) manner, this basically sums up what I found… Basically the simplest way, that actually works (and a way that didn’t work).
Read more

No Such File or Directory: Exec of FILE Failed

I recently ran into the error “No Such File or Directory: Exec of FILE Failed” when trying to update a Perl script on a server running Apache.
 
The actual error message looked more like this.

No such file or directory: exec of 'script.cgi' failed
Premature end of script headers: script.cgi

 
A long story short, it turns out that the issue was line endings. Windows uses a standard CR+LF (Carriage Return + Line Feed) while Unix uses LF (Line Feed). We spotted this, after a lot of trying to figure what was going on, by running a “cat script.cgi” command on the server. When the content was displayed, every line was ended with a “^W”.
 
When using an application like WinSCP to copy the files to the server, the line endings are often converted during the copy process. But if you use an automated release process, or other process that doesn’t have the same features, you must manually convert the files to using Unix style line endings.
 
I converted the files using Notepad++. There are End-of-Line (EOL) conversion utilities built in. They can be accessed by going to Edit -> EOL Conversion after you have opened the offending file.
 
For some more information on how to convert the line endings in Unix, check out perltricks.com.
 
Once the line endings where converted from Windows to Unix style, everything worked as expected!
 
For some more information on line endings, check out Wikipedia, http://en.wikipedia.org/wiki/Newline.

Quest For A Simple Twitter Feed

I’ve always wanted to be able to just slap a quick and simple twitter feed on to a site and could never find the code to really do it (I mean really simple, just show some tweets and be done with it).

Here is the basic solution that I came up with (end result image on the right).

Basically this consists of 3 parts, jQuery, a jQuery extension that I wrote (jquery-twitterfeed) and some CSS. Other than that, you don’t need much to make this work; and that was the point.

With the jQuery extension installed, you can put a Twitter feed anywhere on your page using some simple code. Basically a container for the tweets and a call to the extension.

<div id="twitter-feed">
	<span class="twitter-loading">Loading...</span>
	<img src="/images/ajax-loader-arrows.gif" alt="" />
</div>
$('#twitter-feed').twitterfeed({
	'user': 'santsys', /* Your User Name Here */
	'num': 10
});

The look and feel is almost exactly the same as the Twitter embedded tweet samples, just simplified down. This layout supports a minimum width of 300px, and that could be lowered with some minor tweaks to the layout. If you want more information on the Twitter APIs, check out the documentation here, https://dev.twitter.com/docs.

Below is the full set of CSS and the jQuery extension used to generate the tweets in the image on the right. Now available on GitHub, https://github.com/santsys/jquery-twitterfeed.

The css used to style the tweets. This uses a background image set from twitter directly.

.clear { clear: both; }
.tweet, .tweet a, .tweet span, .tweet div { font: normal normal normal 12px/16px "Helvetica Neue",Arial,sans-serif; color: #777; }
.tweet { padding: .25em; border: 1px solid #EEE; border-radius: 5px; max-width:500px; margin-bottom: .25em; min-width: 300px; }
.tweet .t-head a, .tweet .t-head a span { text-decoration: none; color: #333; line-height: 18px; }
.tweet .t-head .t-avatar { position: absolute; }
.tweet .t-head .t-avatar img { border-radius: 4px; }
.tweet .t-head .t-name { margin-left: 53px; margin-top: 8px; float: left; font-size: 16px; font-weight: bold; }
.tweet .t-head a:hover span.t-name { text-decoration: underline; }
.tweet .t-head .t-nickname { margin-left: 53px; float: left; clear: both; color: #999; font-size: 11px; }
.tweet .t-body { clear: both; margin-top: 55px; }
.tweet .t-content { color: #333; line-height: 18px; font-size: 14px; }
.tweet .t-content a { line-height: 18px; font-size: 14px; color: #2FC2EF; text-decoration: none; }
.tweet .t-content a:hover { text-decoration: underline; }
.tweet .t-foot { margin-top: 6px; }
.tweet .t-foot a.t-details { color: #777; text-decoration: none; }
.tweet .t-foot a:hover.t-details { color: #999; text-decoration: underline; }
.tweet .t-foot .t-actions { clear: both; float: right; margin: 0; padding: 0; }
.tweet .t-foot .t-actions li { float: left; list-style-type: none; list-style-position: outside; margin-left: .2em;}
.tweet .t-foot .t-actions li * { float: left; font-weight: normal; }
.tweet .t-foot .t-actions i { background: transparent url(https://platform.twitter.com/embed/sprite.png) no-repeat 0px 0px; } 
.tweet .t-foot .t-actions a, .tweet .t-foot .t-actions a b { color: #999; text-decoration: none; }
.tweet .t-foot .t-actions a:hover, .tweet .t-foot .t-actions a:hover b { color: #777; text-decoration: underline; }
.tweet .t-foot .t-actions a.t-reply i { background-position: 0 -30px; height: 13px; width: 18px; margin: 1px 5px 0 8px; } 
.tweet .t-foot .t-actions a.t-retweet i { background-position: 0 -48px; height: 13px; width: 22px; margin: 1px 5px 0 8px; } 
.tweet .t-foot .t-actions a.t-favorite i { background-position: 0 -66px; height: 15px; width: 16px; margin: 0 5px 0 8px; }
.tweet .t-foot .t-actions a:hover.t-reply i { background-position: -23px -30px; } 
.tweet .t-foot .t-actions a:hover.t-retweet i { background-position: -27px -48px; } 
.tweet .t-foot .t-actions a:hover.t-favorite i { background-position: -21px -66px; }

The jquery-twitterfeed.js jQuery extension that actually does the rendering, etc.

/*
	Twitter jQuery Feed
	Version 1.0
	By: Josh Santomieri (http://www.santsys.com/)

	Options:
		user - The twitter user
		num - The number of tweets to display

	Documentaion on the twitter feeds here:
	https://dev.twitter.com/docs/api/1/get/statuses/user_timeline
*/

(function ($) {
	jQuery.fn.twitterfeed = function (options) {
		var settings = $.extend({
			'user': '',
			'num': 10
		}, options);

		if (this.length <= 0) return;

		var _this = this;
		var _url = 'http://api.twitter.com/1/statuses/user_timeline.json';
		_url += '?screen_name=' + escape(settings.user);
		_url += '&count=' + settings.num;
		_url += '&exclude_replies=true';
		_url += '&callback=?';
		
		$.ajax({
			url: _url,
			type: 'GET',
			dataType: 'jsonp',
			crossDomain: true,
			cache: false,
			contentType: 'application/javascript',
			jsonpCallback: 'parseTwitterFeed',
			success: function (json) {
				if (json == null) {
					_this.text('No response from feed!');
				}
				else {

					if (json instanceof Array) {
						var html = '';
						var months = [
							"JAN", "FEB", "MAR",
							"APR", "MAY", "JUN",
							"JUL", "AUG", "SEP",
							"OCT", "NOV", "DEC"
						];

						for (var i = 0; i < json.length; i++) {
							var tweet = json[i];
							
							var date = new Date(tweet.created_at);
							var replyLink = 'https://twitter.com/intent/tweet';
							replyLink += '?in_reply_to=' + tweet.id;
							replyLink += '&tw_i=' + tweet.id;
							replyLink += '&tw_e=reply';
							replyLink += '&tw_p=tweetembed';
							replyLink += '&source=tweetembed';

							html += '<div class="tweet">';
							html += '<div class="t-head">';
							html += '<a href="https://twitter.com/' + tweet.user.screen_name + '">';
							html += '<span class="t-avatar"><img src="' + tweet.user.profile_image_url_https + '" alt="">';
							html += '<span class="t-name">' + tweet.user.name + '';
							html += '<span class="t-nickname">@<b>' + tweet.user.screen_name + '</b>';
							html += '';
							html += '';
							html += '<div class="t-body">';
							html += '<div class="t-content">' + parseTweet(tweet.text) + '</div>';
							html += '</div>';
							html += '<div class="t-foot">';
							html += '<a class="t-details" href="https://twitter.com/twitterapi/statuses/' + tweet.id + '">';
							html += '<span class="t-updated " title="' + date.toLocaleDateString() + '">';
							html += date.getDate() + ' ' + months[date.getMonth()] + ' ' + date.getFullYear().toString().substr(2, 2);
							html += '</span>' + result[0] + '');
			}

			rx = new RegExp("#[a-zA-Z0-9]+", "gi");
			while (result = rx.exec(text)) {
				out = out.replace(result[0], '<a href="https://twitter.com/search/?src=hash&q=' + escape(result[0]) + '">' + result[0] + '</a>');
			}

			return out;
		}
	};
})(jQuery);

Update – 9/5/2012
Twitter just released an updated set of code for embedded timelines, check it out here, https://dev.twitter.com/docs/embedded-timelines.

Public Link Feed: bitly + feedburner

I’ve been wanting a quick and simple way to get my public links from bitly to my site… something automatic that I wouldn’t have to mess with. 

I’ve done some searching, but couldn’t find anything that worked how I wanted it.

Bitly’s APIs offer a lot of basic options, but they are mostly around authenticated processes for users to login and see their content but there are not many ways for me to stream my content.

Bitly offers some basic methods such as http://bitly.com/u/santsys.json and http://bitly.com/u/santsys.rss to see my feed in JSON and RSS formats. The only problem is this causes a lot of JavaScript cross-site scripting issues if you want to integrate the information on your site. Especially because they don’t seem to support any JSONP functionality.

So the quick and dirty workaround I found was to load up the RSS feed into feedburner (http://feedburner.google.com) and use their JSONP API to load the data on my site.

There are some interesting lag times due to caching within feedburner. At the time of writing this, FeedBurner updates every 30 minutes. I have noticed it often takes much longer for the actual page feed to update. Possibly there are some other systems out there that might update more frequently?

Here is the basic code, and some simple usage samples (also in use on this blog, on the right side of the page titled “Links”).

/*
	Feedburner jQuery Feed
	Version 1.0
	By: Josh Santomieri (http://www.santsys.com/)

	Options:
		feedUrl 
			- The URL to your feed on feedburner, for example
			  http://feeds.feedburner.com/RecentBookmarksFromSantsysOnBitly.
		numLinks 
			- The number of links you want to be displayed.
		feedBurnerUrl 
			- The url for the feedburner API, currently
			  https://ajax.googleapis.com/ajax/services/feed/load.
		removeBitlyPlus 
			- If your feed pulls from Bitly, there will be '+' at the end of
			  the shortened URLs; set this to true to remove them.
		userIP 
			- If you want to set the user ip to send to feedburner, go for it.
			"Google is less likely to mistake requests for abuse when they include userip"

	Most of the documentation on the feedburner/Google APIs can be found here, 
	https://developers.google.com/feed/v1/jsondevguide
*/

(function ($) {
	jQuery.fn.feedBurn = function (options) {
		try {

			var settings = $.extend({
				'feedUrl' : 'http://feeds.feedburner.com/RecentBookmarksFromSantsysOnBitly',
				'numLinks': 10,
				'feedBurnerUrl': 'https://ajax.googleapis.com/ajax/services/feed/load',
				'removeBitlyPlus': true,
				'userIP' : ''
			}, options);

			var _feedUrl = settings.feedBurnerUrl;
			_feedUrl += '?q=' + settings.feedUrl;
			_feedUrl += '&amp;v=1.0';
			_feedUrl += '&amp;num=' + settings.numLinks;
			if (settings.userIP != null &amp;&amp; settings.userIP != '') {
				_feedUrl += '&amp;userip=' + settings.userIP;
			}
			_feedUrl += '&amp;callback=?';
			var container = this;

			$.ajax({
				url: _feedUrl,
				type: 'GET',
				dataType: 'jsonp',
				crossDomain: true,
				cache: false,
				jsonpCallback: 'parseFeed',
				success: function(json) {
					if (json == null) {
						container.text('Invalid response from server.');
					} else if (json.responseData == null) {
						container.text('Status Code: ' + json.responseStatus + '; Status: ' + json.responseDetails);
					}
					else {
						var links = json.responseData.feed.entries;
						var html = '';

						for (var i = 0; i &lt; links.length; i++) {
							var link = links[i];
							var linkHref = link.link;

							// Bitly adds a '+' to the end of the links so they open in a Bitly UI
							if (settings.removeBitlyPlus) {
								if (linkHref.charAt(linkHref.length - 1) == '+') {
									linkHref = linkHref.substring(0, linkHref.length - 1);
								}
							}

							html += '&lt;div class="feed-history"&gt;';
							html += '&lt;div class="feed-link"&gt;';
							html += '&lt;a href="' + linkHref + '" title="' + link.title + '"&gt;' + link.title + '&lt;/a>';
							html += '&lt;/div&gt;';
							html += '&lt;/div&gt;';
						}

						container.html(html);
					}
				}
			});
		}
		catch (e) { container.text(e); }
	};
})(jQuery);

And here is some sample usage code.

(function ($) {
	$(document).ready(function () {
		try {
			var options = {
				'numLinks': 6,
				'feedUrl': 'http://feeds.feedburner.com/RecentBookmarksFromSantsysOnBitly'
			};
			$("#bitly-feed div.side").feedBurn(options);
		}
		catch (e) { }
	});
})(jQuery);