iFrame reloads when shown after being hidden in Firefox

This might be a bug or a feature (I am not sure) but if you hide an iframe and then show it again then it causes iframe to reload in FireFox.

$('#myIframe').css('display', 'none');

// some code ...

$('#myIframe').css('display', 'block');

The solution is to use visibility instead of display:

$('#myIframe').css('visibility', 'hidden');

// some code ...

$('#myIframe').css('visibility', 'visible');

Links in iOS web app open in new window

If you have ever tried creating a web app from your website (saving to Home Screen) with iPhone or iPad then you have probably noticed that all the links in your webapp open in the new Safari window.

The issue is explained and solved in this StackOverflow question.

I thought it’s also a good idea to check that we are actually inside the iOS app before running the code:

if (window.navigator && window.navigator.standalone) {
    var a = document.getElementsByTagName("a");
    for (var i = 0; i < a.length; i++) {
        a[i].onclick = function() {
            window.location = this.getAttribute("href");
            return false;
        };
    }
}

RaphaelJS rectangle shadow

I had to create a very basic shadow for a rectangle with rounded corners using RaphaelJS. Like this:

I used a shadow plugin from http://www.redbeard-tech.com for rectangles before but unfortunately it doesn’t work for rounded corners. So here is my extension to the plugin that solves rounded corners issue and adds a remove shadow functionality.

Raphael.el.shadow = function (x_offset, y_offset, size, color, radius) {
    if (typeof(this.shadowSet) == 'undefined') {
        this.shadowSet = this.paper.set();
    } else {
        while (this.shadowSet.length > 0) { this.shadowSet.pop().remove(); }
    }
    var width = this.attr('width'),
        height = this.attr('height'),
        left = this.attr('x'),
        top = this.attr('y');

    radius = radius + 8;
    for (i = size; i > 0; i--) {
        this.shadowSet.push(
            this.paper.rect(left - i + x_offset, top - i + y_offset, width + i*2, height + i*2, radius).attr({fill: color, stroke: 'none', opacity: 0.1 + i*0.02})
        );
    }

    this.onAnimation(function() {
        if (!this.hideShadow)
        {
    	    this.shadow(x_offset, y_offset, size, color, radius);
        }
    });

    this.removeShadow = function() {
        for (var i = 0; i < this.shadowSet.length; i++) {
            if (this.shadowSet[i]) {
                this.shadowSet[i].remove();
            }
        }
        this.hideShadow = true;
    };

    return this.shadowSet.insertBefore(this);
};

To apply the shadow to RaphaelJS object:

advertHolder.shadow(0, 0, 7, "#111", 10);

I can be used as a stand-alone extension to RaphaelJS (for rectangles only) or as an addition to the original plugin by copying and pasting the relevant code.

fb:comments iframe height

You can see the problem on the image below – the gap between the Facebook comments widget and the rest of the page is too big.

The reason for this is that Facebook explicitly sets the hight of iframe to 200px and increases it when new comment is added. Surprisingly if the comment was deleted the height stays the same as it was originally…

The best solution I could come up with was to get number of comments from Facebook as a separate fbml tag, parse it in javascript and then reduce the gap accordingly.

Here is my solution in action:

And this is the code:

var commentsCount = 0;

var resizeIframe = function(){
	if ((commentsCount == 0) && ($('.fbcomments iframe').height() > 200)) return false;

	switch (commentsCount)
	{
		case 0: $('.social').css('margin-bottom', '-100px'); break;
		case 1: $('.social').css('margin-bottom', '-30px'); break;
		default: $('.social').css('margin-bottom', '-10px');
	}
};

$(document).ready(function(){
	var e = document.createElement('script');
	e.src = 'http://connect.facebook.net/en_US/all.js#appId=XXXXXXXXXXXXX&xfbml=1';
	document.body.appendChild(e);

	window.fbAsyncInit = function() {
	       FB.init({status: true, cookie: true, xfbml: true});
	       FB.Event.subscribe("xfbml.render", function() {
	            setTimeout('resizeIframe()', 1000);
		    commentsCount = parseInt($('.fb-comments-count').text());

		    FB.Event.subscribe("comment.create", function() { commentsCount++; resizeIframe();});
	            FB.Event.subscribe("comment.remove", function() {
				commentsCount--;
				if ($('.fbcomments iframe').height() - 63 < 200) {
					$('.fbcomments iframe').height(200);
				} else {
					$('.fbcomments iframe').height($('.fbcomments iframe').height() - 63);
				}
				resizeIframe();
                	});
		});
	};
});
<!DOCTYPE html>

<html lang="en" xmlns:fb="https://www.facebook.com/2008/fbml">
<head>
	<meta charset="utf-8">
	<title>untitled</title>
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
	<style>
		.fbcomments iframe {position:relative; z-index:100;}
	</style>
</head>
<body>
	<div id="fb-root"></div>

	<a style="display: none" href="http://dashasalo.com" class="fb-comments-count">0</a>

	<div class="social">
		<div class="fbcomments" id="fbcomments">
			<fb:comments href="http://dashasalo.com" num_posts="3" width="500"></fb:comments>
		</div>
	</div>

	<p>The current situation where we are today, there’s a clear distinction between the Open Web and native APIs and how things have to be built. As many developers are aware of, we need consistent APIs across web browsers, operating systems and devices to be able to build something for the world, not just a specific device or vendor. We need a way to take the web to the next step. What is WebAPI?</p>
</body>
</html>

New night theme

night theme

Finally found some time to create a night theme for this blog. You can see it every day after 10pm – just visit the blog.

Theme is now weather aware as well. You will most probably see either a cloud (on a cloudy day) or rain drops (on a rainy day). Weather doesn’t vary much here in Newcastle :)

More exciting stuff to follow!

Google Weather API

I have recently discovered a very simple and powerful (and seems like secret) weather service from Google. It has been covered in details in this old post by Adam DuVander.

Great thing about it is that you don’t have to do much work to get the basic weather details and images – it’s all included in the returned XML. All you need to do is append your location name or post code to the url and parse the XML.

The simple example I used for this blog:

$requestAddress = "http://www.google.com/ig/api?weather=Newcastle+Upon+Tyne&hl=en";

$xml_str = file_get_contents($requestAddress, 0);
$xml = new SimplexmlElement($xml_str);

XML you should get back get back looks like this:

    <xml_api_reply version="1">
        <weather module_id="0" tab_id="0" mobile_row="0" mobile_zipped="1" row="0" section="0">
            <forecast_information>
                <city data="Newcastle Upon Tyne, Tyne And Wear"/>
                <postal_code data="ne46at"/>
                <latitude_e6 data=""/>
                <longitude_e6 data=""/>
                <forecast_date data="2011-09-22"/>
                <current_date_time data="2011-09-22 09:20:00 +0000"/>
                <unit_system data="US"/>
            </forecast_information>
            <current_conditions>
                <condition data="Partly Cloudy"/>
                <temp_f data="55"/>
                <temp_c data="13"/>
                <humidity data="Humidity: 67%"/>
                <icon data="/ig/images/weather/partly_cloudy.gif"/>
                <wind_condition data="Wind: W at 23 mph"/>
            </current_conditions>
            <forecast_conditions>
                <day_of_week data="Thu"/>
                <low data="50"/>
                <high data="57"/>
                <icon data="/ig/images/weather/mostly_sunny.gif"/>
                <condition data="Mostly Sunny"/>
            </forecast_conditions>
            <forecast_conditions>
                <day_of_week data="Fri"/>
                <low data="48"/>
                <high data="61"/>
                <icon data="/ig/images/weather/chance_of_rain.gif"/>
                <condition data="Chance of Rain"/>
            </forecast_conditions>
            <forecast_conditions>
                <day_of_week data="Sat"/>
                <low data="52"/>
                <high data="61"/>
                <icon data="/ig/images/weather/mostly_sunny.gif"/>
                <condition data="Mostly Sunny"/>
            </forecast_conditions>
            <forecast_conditions>
                <day_of_week data="Sun"/>
                <low data="55"/>
                <high data="64"/>
                <icon data="/ig/images/weather/mostly_sunny.gif"/>
                <condition data="Partly Sunny"/>
            </forecast_conditions>
        </weather>
    </xml_api_reply>

To get the particular node use SimpleXML syntax. For example, to get current weather condition:

$weather = $xml->weather->current_conditions->condition['data'];

List of conditions can be found in this StackOverflow question feed. But as there is no official documentation from Google the list might be incomplete.