Showing posts with label Blogger. Show all posts
Showing posts with label Blogger. Show all posts

Sunday, January 25, 2009

Blog Flower Code

This article is the second in a two part series on the Blog Flower Gadget. In the previous post I described how I created the artwork using InkScape. In this post I will describe the programming behind the gadget.

There are two parts to the gadget. The first part which is the gadget itself is contained in a JavaScript file, the second part contains all of the 'Add to Blogger' submission functionality, it is a combination of an html form and another JavaScript file.

The gadget is built using the Google Data API, which provides the content of a blog as either an XML feed or a JSON feed. I primarily work on a Windows Forms application using the .NET Framework, so this was the first time I had even heard of JSON. It is a data format somewhat like XML, except that it is much more compact, and is built specifically for JavaScript. In fact the Google API returns it as an already parsed collection of JavaScript obejcts, which couldn't be easier to work with.

Here is the first JavaScript file, BlogFlower.js which is the gadget.

BlogFlower.js

// (C)2009 by Peter Noyes
function blogFlower(root)
{
var feed = root.feed;
var entries = feed.entry;
if (entries.length == 0)
return;

var entry = entries[0];
var ds = entry.published.$t;
var d = new Date(ds.substring(0,4), ds.substring(5,7) - 1, ds.substring(8,10));
var days = Math.floor((new Date() - d) / 86400000);
document.write('<div class="blogFlower">');

var flower;
if (days < 5)
flower = 'http://www.geeklounge.org/script/Flower1.png';
else if (days < 10)
flower = 'http://www.geeklounge.org/script/Flower2.png';
else
flower = 'http://www.geeklounge.org/script/Flower3.png';

document.write('<img src="' + flower + '">');
document.write('<br>');

switch (days)
{
case 0:
document.write('updated today');
break;
case 1:
document.write('updated yesterday');
break;
default:
document.write('updated ' + days + ' days ago');
}

document.write('</div>');
}


The blogFlower function is called by the Google API, and the root variable is the JSON object that the API constructs. The blog post is retrieved from root.feed.entry, which is an array of all the entries. Google has a good description of this here. The only real trouble I had with JSON was compatibility with the date format. I did find a Google Date API that may have helped, but it added a tremendous amount of JavaScript to this project, which seemed overkill. In the end I used substrings to pluck the year, month, and day from the JSON date. To find the number of days since the last posting, I subtracted the parsed date from the current date, which returns the time span in milliseconds. The conversion factor of 86,400,000 is built up by 1000ms * 60s * 60m * 24h. The corresponding image and text is then written to the document as HTML.

The submission code uses the syntax described here, in order to add the gadget to Blogger. It also sets up the API call to the Google Data API and provides the callback to the blogFlower function.

First is the submission HTML that I placed in the blog post, it is followed by SubmitBlogFlower.js which is referenced by the HTML. I first wanted the submission code to be in the blog post as well, however the syntax checker in the blog post editor barfed on the JavaScript and wouldn't let me post it.

HTML in Blog Post

<script src="http://www.geeklounge.org/script/SubmitBlogFlower.js"></script>
<form name="blogFlowerForm" method="post" action="http://www.blogger.com/add-widget">
<span>http://<input type="text" name="blogName" onkeypress="return noEnter()">.blogspot.com</span><br><a href="javascript: submitForm()"><img src="http://www.blogger.com/img/add/add2blogger_sm_w.gif" style="border:0px"/></a>
<input type="hidden" name="infoUrl" value="http://peternoyes.blogspot.com"/>
<input type="hidden" name="widget.title" value="Blog Flower"/>
<textarea name="widget.content" style="display:none;"></textarea>
</form>


SubmitBlogFlower.js

// (C)2009 by Peter Noyes
function submitForm()
{
var content1 = '\<script type="text/javascript" src="http://www.geeklounge.org/script/BlogFlower.js"\>\</script\>';
var content2 = '\<script type="text/javascript" src="http://';
var content3 = document.blogFlowerForm.blogName.value;
var content4 = '.blogspot.com/feeds/posts/default?orderby=published&max-results=1&alt=json-in-script&callback=blogFlower"\>/</script\>';
document.blogFlowerForm['widget.content'].value = content1 + content2 + content3 + content4;
document.blogFlowerForm.submit();
}

function noEnter(evt)
{
var evt = (evt) ? evt : ((event) ? event : null);
var node = (evt.target) ? evt.target : ((evt.srcElement) ? evt.srcElement : null);
if ((evt.keyCode == 13) && (node.type=="text")) {return false;}
}

document.onkeypress = noEnter;


The gadget is added to Blogger using an html form. I used all hidden form fields except for a visible text field for the user to enter the name of their blog. When the user clicks the submit button it calls the function submitForm, which dynamically constructs code for the widget.content field. This code first references the BlogFlower.js, and then it references the Google Data API. It builds up the feed URL using the blogName text field. I send the following parameters to recover the JSON feed:

  • orderby=published, This ensures that I will be returned the latest posts.

  • max-results=1, This instructs Google to only send back a single post. When doing research I came across a popular Blogger gadget that shows a list of recent posts. Even though they only consumed a few posts, they omitted this parameter which causes Google to return a feed containing every single blog post. This is a complete waste of bandwidth.

  • alt=json-in-script, This instructs Google to return the feed as JSON instead of XML, and to use a callback.

  • callback=blogFlower, This is the callback function implemented in BlogFlower.js


The noEnter function is used to prevent the user from being able to submit the form by pressing 'Enter' in the blogName text field, because doing so would submit the gadget incorrectly.

To get this to all to work took a decent amount of research. At first I kept stumbling across the Widget Tags for Layouts which is the syntax used to create a Blogger Layout. Some gadgets are written using this API, however I couldn't find a way to create the Blog Flower this way. Once I found the Google Data API the implementation went pretty quickly. Creating the artwork actually took up most of the time.

Thursday, January 22, 2009

Blog Flower Art







In a previous post I introduced the Blog Flower Gadget. I have decided to go into some detail about how I created the gadget, and I will split the information into two posts. In this first post I will talk about how I created the artwork. In the second post I will describe the programming implementation.

First of all, part of the inspiration for creating this gadget is that I am currently doing some work involving bezier curves, and as part of my research I downloaded and played with Inkscape. Inkscape is an open source vector graphics editor. I decided to try and trace something using the Bezier curve feature.

I started by sketching the three stages of the flower on paper. I then took a picture of the sketch using my digital camera and imported it into Inkscape. Once in Inkscape I turned the opacity of the image way down so that I could see what I was doing. The actual tracing using the bezier curve tool was pretty easy. Basiclly single-clicking will place corners, and a drag-click will create control points for a curve. It takes a minute to get the hang of it. For each shape I would create a rough outline, and then I would clean it up by moving the points around. It is also possible to add or remove points.

Once I had completed each stage of the flower, I copied and pasted it into a new document and shrunk it down to a smaller size. I first tried actually using .svg files as the final output format for the gadget. It seemed to work best using the <object> tag in the HTML. However, after I finally got it working in Firefox and Internet Explorer I realized that Chrome doesn't support SVG at all, so I decided to fall back to using PNG files instead. It is not a total loss because in the end the .png files were about half the size of the .svg files, even though logically one would think a vector format should end up smaller than a raster version. Although SVG is vector, it uses a very verbose XML syntax and is uncompressed, which explains the difference in file size.

Anyway, I had fun working on this project. It is my first attempt at doing vector based artwork so I am considering it a success.

Saturday, January 17, 2009

Blog Flower Gadget





Part of the reason I started this blog was to motivate myself to finish projects. In fact, at one time, a project of mine was to program a blog from scratch as a way to learn ASP.NET. Unfortunately that project didn't get too far. I think that part of my problem with finishing these side projects is that I have always chosen projects with too large of a scope, and I just don't have the extra time. I have many of these projects left unfinished.

However, I am proud to be able to post an actual completed project. I decided to create a Blogger Gadget and the result is the 'Blog Flower'. The gadget is pretty simple, I was able to complete it in about half a day or so. Most of the work was actually creating the graphics. As you might guess the gadget adds a flower to a blog, and it will start to wilt and die if a new post isn't added frequently enough. It can be thought of as a motivator to post regularly, because who wants to see a dead flower on their blog?

To add this to your own blog simply enter in your blog name and click the add to blogger link.



http://.blogspot.com




Sunday, January 11, 2009

Blogger Image Bug

There is a very frustrating "bug" with Blogger and Picassa. Some images when uploaded get rotated by 90 degrees and cannot be fixed. This only happens with images wider than they are tall. It also only happens with images that contain digital camera metadata. Furthermore it only happens with images that have oval like characteristics. From my previous post the Man o' war and Stone Crab images came in rotated incorrectly. My theory is that Google has a "feature" where it attempts to identify images of a face taken with a digital camera on its side and auto correct the rotation. I am sure that this is a great feature for some users, but it is an absolute hindrance for others. The Picassa Web Album allows users to rotate images once uploaded, and furthermore Blogger images now show up as a hidden album in Picassa, but for whatever reason you can't rotate images in the Blogger album! There is absolutely no way to fix the image once uploaded! When uploading an image from Blogger there is a confirmation screen with a preview of the image, they really need to add some rotate buttons to this screen. For now my workaround is to first open the picture in Paint and then save it as a .png which strips the metadata.

Update
I discovered the source of the problem. My camera is storing camera orientation information in the EXIF data of the jpeg files. Right clicking a jpeg in Windows Vista doesn't show the orientation field, which is why I didn't discover this earlier. Picasa is rotating the image when uploaded based on the stored orientation. This doesn't seem like the correct behavior, especially because the behavior is not consistent across browsers. I am hoping Google fixes this, or at least provides a way to change the rotation once uploaded.

Update #2
I have been involved in a discussion about this issue in the Blogger help groups. A Blogger employee just followed up on that discussion hinting that they are hopefully going resolve this issue!

Peter Noyes,

Thanks a lot for investigating; it looks like you have stumbled into a solution for some of the photo issues that have arisen in the past here. I'll pass your feedback along to the rest of the team and we'll see if we can make this better.

And thanks to Mishka for the heads up!

Gatsby
The Blogger Team