There is a new shared block on Popfly called Locust IP Locator courtesy of mois. I thought I'd detail how I built it.
First thing to do is "declare your block class" which is also known as "declaring a function:"
this.__getLocationbyIP = new Location();
That wasn't so bad, right? The purpose of the one line of code there is to set the return type of a method called getLocationByIP to Location.
Next, let's declare a custom object (also known as "declaring a function"). This is the type of object that we'll return to the Popfly block.
function IPLocation(ip, cityState, country, latitude, longitude)
this.IPAddress = ip;
this.CityState = cityState;
this.Country = country;
this.Latitude = latitude;
this.Longitude = longitude;
Okay, moving on. Now we have to do some actual work! Let's write the function that goes to my Locust web service and parses the XML data it gets back (using the fancy-shmancy ternary operator):
LocustClass.prototype.getLocationByIP = function(ip)
var url = "http://locust.danwaters.com/locust.asmx/GetLocationByIP?ipAddress=" + ip;
var resultXml = environment.getXml(url);
var country = resultXml.getElementsByTagName("Country").length == 1 ? resultXml.getElementsByTagName("Country").text : "";
var cityState= resultXml.getElementsByTagName("CityState").length == 1 ? resultXml.getElementsByTagName("CityState").text : "";
var longitude= resultXml.getElementsByTagName("Longitude").length == 1 ? resultXml.getElementsByTagName("Longitude").text : "";
var latitude= resultXml.getElementsByTagName("Latitude").length == 1 ? resultXml.getElementsByTagName("Latitude").text : "";
var myIP= resultXml.getElementsByTagName("IPAddress").length == 1 ? resultXml.getElementsByTagName("IPAddress").text : "";
var resultLocation = new IPLocation(myIP, cityState, country, latitude, longitude);
Why did I declare that function as a prototype of LocustClass? Because I didn't want to declare it in the global namespace, which is not a good thing in the context of Popfly.
The environment.getXml command is used to navigate to an external URL that provides XML and load it into an XML object. From there, you can use the getElementsByTagName function to return a collection of elements matching that name. My object has no arrays (and is not an array) so I only have to check that the length is 1 before I reference the text insdie it.
I instantiate a new Location object and return it, and that is all.
There is one more function we need to look at: the toString function which is a prototype of the Location class. We do this because some other Popfly blocks will want to query it to get a description of its data, and if we don't implement this method we'll just get [object Object] or something else that's very nondescript.
Location.prototype.toString = function()
return "IP: " + this.IPAddress + "<br>" +
"Location: " + this.CityState + "<br>" +
"Country: " + this.Country + "<br>" +
"Lat/Long: " + this.Latitude + ", " + this.Longitude;
First element is the XML declaration.
Then comes the block element, the root of the document. block has one attribute, class, which is the same thing as your block class (LocustClass).
Under the block element are some block and provider metadata nodes: provderName, providerUrl, providerLogoUrl, blockIconUrl, and keys (keys is used when you need to identify yourself to the provider before using it). Then comes the operations node, which tells you what the block can do. Each subsequent operation node describes the inputs and outputs of a block operation.
<?xml version="1.0" encoding="UTF-8"?>
<providerName>Locust IP Geolocator</providerName>
<description>Returns location information for an IP address via the hostip.info project.</description>
<input name="ipAddress" required="true" type="ipAddress">
<description>Source IP address</description>
<output isArray="false" type="custom" object="Location"/>
<field name="IPAddress" type="ipAddress" isArray="false"/>
<field name="CityState" type="description" isArray="false"/>
<field name="Country" type="description" isArray="false"/>
<field name="Latitude" type="latitude" isArray="false"/>
<field name="Longitude" type="longitude" isArray="false"/>
I used this block immediately in a mashup that takes input from a User Input box, calls into the IP Locator to get latitude and longitude, and adds a pushpin to an instance of Live Maps!
That's the power and extensibility of Popfly, and we're only in Alpha. I can't wait to see what it's like down the road!