Archive for the 'JSON' Category

My online footprint lately

Wednesday, July 23rd, 2008

This is a sort of a catch-up post for listing what I've been up to lately.

  • YUI Blog just published my first article, I'm so proud. It's about loading JavaScript in non-blocking fashion, because JavaScripts, they, you know, like, block downloads. Luckily, there's an easy fix - DOM includes, which I've previously discussed, discussed and discussed.
  • SitePoint published an update to my older article that introduces AJAX, ok, Ajax, by creating a command-line-like interface with PHP on the server side. The updated article features improved code, jQuery example, YUI example, JSON discussion and example. Check it out, bookmark and recommend to your friends that keep asking you "What's this AJAX (they are new, don't know it's now spelled "Ajax") thing? Do you know of a good article?"
  • YDN (developer.yahoo.com) published a video presentation of me and my lovely teammate Nicole Sullivan where we talk about some new and cool front-end performance techniques. So if you wandered how I look and are eager to hear my fabulous Balkan peninsula accent, give it a shot. The talk is called "After YSlow 'A'" and is targeted at those of you who have reached performance nirvana, but are still hungry for more. We talk about preloading components, post-loading, javascript, images, using flush() in PHP to send first byte early on and other fun stuff.
  • Last, not least, I decided to try and find some time to update my JavaScript patterns site. Unfortunately I got sidetracked (yep, I'm easily distracted by shiny objects) and played with a not-so-javascript pattern. The post I published (includes a pretty lame screencast! and) demonstrates how you can use animated background position to indicate loading progress.

Whew, c'est tout pout ce moment, expect a lot more now that the JavaScript book is out of the way. Ah, yep, if you feel like it, join me on Facebook, I created a JS book page.

 

JSON data island

Monday, February 12th, 2007

Here's a hacky thing, I called it JSON data island, referencing the XML data island, that MS came up with for their IE browser. The idea is to use a comment in your HTML that holds some data in JSON format. Then using DOM, you access the comment, eval()-uate it and there you go - you have the data as a Javascript object.

» Here's a little proof of concept.

What we have in the HTML is:

<div id="some-div"><!--
    {prop:'value', prop2:['value1','value2','value3']}
-->
    Some stuff in div
</div>

Then the JavaScript that will process the JSON data in the comment:

var island = document.getElementById('some-div').firstChild;
var the_data = eval('(' + island.data + ')');
alert(the_data.prop2);

In this case I added the comment island as the firstChild of some div, but it could be anywhere, as long as you know how to access it with DOM methods.

Q&A

OK, why?
Well, I need some data that comes from the database, so it needs some server-side processing before it appears in the JavaScript code.

Can't it simply be in an inline <script>?
Inline scripts are bad, they mix behaviour (JS) with content (HTML). Also, imagine how your client runs some SEO tool that reports inline scripts in the content, the client goes: "You used an inline script!? Gimme my money back this instant!"

In your external .js then?
I'd like to have external .js simple, with no server-side scripting involved. I don't want to make my beautiful, big, long script appear as something like script.js.php

One small additional little .js.php only for the data you need?
Look, I said "no"! .js.php will require a new database connection, since it's a seperate request. Performance will suffer. In addition it's a new HTTP request and those are expensive.

An AJAX request fired from your beloved clean external .js that will only return the JSON data you hacked into your island thing of yours?
Same as above. New HTTP request, new DB connection.

OK then, I give up!
It was about time!

Thanks: to Phil Renaud for the inspirational idea of making conversational posts, his are hysterical.

 

JSON renderer for Text_Highlight

Friday, October 27th, 2006

Text_Highlighter is one of my favourite PEAR packages, seems like I'm addicted to highlighting source code. After adding BB code and simple HTML renderers and an ABAP code syntax definition, today I played with adding a JSON renderer. Useful in case you want to get highlighted source code in your new shiny AJAX app.

Array renderer

After I did the JSON renderer, I said, OK, what if I want to tweak the JSON output just a bit (or the output from any renderer for that matter)? Add more options? Nah, I had a better idea, I scrapped the whole thing and did an Array renderer first. If you have the array output from the renderer, it's trivial to format it as JSON, or XML, or HTML, or anything. I believe even the exisitng Text_Highlighter renderers should be rewritten, to extend an Array renderer. Anyway, back to JSON.

Demo

To see the JSON renderer in action, you can go to my hiliteme.com site and check the JSON tab.

Source

The source code is available here - JSON.phps which extends Array.phps. To test, you need to add the two renderers to your PEAR repository under Text/Highlighter/Renderer

Example

So let's say you need to highlight the PHP code

<?php 
    echo "Hello Highlighted World!"; 
?>

You create an instance of Text_Highlighter and Text_Highlighter_Renderer_JSON and call the highlight() method, assuming that the code you need highlighted is in $source

<?php
// dependencies
require_once 'Text/Highlighter.php';
require_once 'Text/Highlighter/Renderer/JSON.php';
 
// instance
$json_options = array();
$json_options['tabsize'] = 4;
$json_options['enumerated'] = true;
$renderer =& new Text_Highlighter_Renderer_JSON($json_options);
$highlighter =& Text_Highlighter::factory($_POST['language']);
$highlighter->setRenderer($renderer);
 
// do the highlighting
$json_result = $highlighter->highlight($source);
?>

Now $json_result will look like:

[["inlinetags","&lt;?php"],["code"," \\n    "],["reserved","echo"],["code"," "],["quotes","&quot;"],["string","Hello Highlighted World!"],["quotes","&quot;"],["code","; \\n"],["inlinetags","?&gt;"]]

As you see the JSON output is an array, one element per highlighted keyword, and in this array there is a sub array - class/keyword. If you want to display this in your page (let's say you got it from an AJAX call), you can do a loop through the array and surround the keywords with span tags of the selected style:

// say your ajax call returned var src 
// var src = xmlhttp.responseText;
var data = eval(src); 
 
var res = ''; 
for (var i in data) {
    res += '<span class="hl-' + data[i][0] + '">';
    res += data[i][1];
    res += '</span>';
}
 
var el = document.getElementById('some-div').
el.innerHTML = '<pre>' + res + '</pre>';

Here I used innerHTML, you can also use DOM, but in this case you need a special case for the "\n" so that you can create a br element to address IE's habit of ignoring line feeds in a DOM-generated pre tag.

BTW, if you don't set the enumerated option to true, you'll get objects inside the main array, check hiliteme.com's JSON tab for an idea of how this would look like.

 

Yahoo API search with JavaScript alone

Thursday, October 12th, 2006

Previously I've mentioned how I do image searches with my bigger daughter, hunting for images of Cinderella, Ariel the little mermaid, and other equally beautiful princesses. So I thought why not build a custom little app for the little kid to do this, I mean, her, being the good (and beautiful) girl that she is, totally deserves it. Here are the very basics of such an app, my idea was to do a little demo how you can consume Y! services to do web and image searches, using nothing but JavaScript. Look ma, no server! ;)

» demo

JS alone

The cool think about Y! web services is that they provide you different options for the output format of the results they return. You can get XML, php serialized string or JSON. (No SOAP, thank you very much!). I think more companies should consider such an offer, I mean since you get your service to work, the output format is just a ... a format, nothing special.

How do you make the request? With JavaScript includes, meaning you use DOM methods to sreate a new <script> tag and add it to the head of your page. The src attribute of the new script tag points to the Y! service, a longish kind of URL with a bunch of parameters.

When making your request, you say that the output format should be JSON. Then you provide a callback function name. What Y! service does is it calls the function you gave, passing the JSON output as a parameter. Let's say you made a request to:

http://..../...&output=json&callback=myfunction

and we assume the result of your request is an array:
[1,2,3]
The Y! service will write out:
myfunction([1,2,3])
At the end, your function gets called, receiving the response from the call to the Y! service. It's now up to this function to decide what to do with the result.

Implementation

It all starts with a simple form and a placeholder for the result:

<body>
<form
    action=""
    method="get"
    onsubmit="ysearch.doSearch(
                this[0].value, 
                'content', 
                this[1].checked
              ); 
              return false;">
  <input />
  <input type="checkbox" />Image search
  <input type="submit" value="go!"/>
</form>
<div id="content">&nbsp; </div>
</body>

Submitting this form calls the doSearch() method of the ysearch class.

ysearch class has a few properties:

// url of the image search service
this.image_url = "http://api.search.yahoo.com/ImageSearchService/V1/imageSearch?";
// url of the web search service
this.web_url = "http://api.search.yahoo.com/WebSearchService/V1/webSearch?";
 
// ID of element that will
// display the result
this.where = '';
// is this an image search?
this.image_search = false;
 
// parameters for the search
this.url = "output=json"+
           "&callback=ysearch.process" +
           "&appid=YahooDemo" +
           "&start=1" +
           "&results=5" +
           "&query=";
 
// reference to the last included script
this.last_include = false;

Then comes the doSearch method. It does the following:

  1. Checks input parameters to see if this is a request for a web search or an image search. The two types af searches use a different web service with a different URL
  2. Appends the search query to the URL
  3. Creates a new script tag with SRC that was just figured out
  4. Saves a reference to the new script tag, so that it can be cleaned up with the next search

Here's the actual code for the doSearch() method:

this.doSearch = function(q, where, web_image) {
 
  this.where = where;
 
  var script_filename = "";
  if (web_image) {
      script_filename = this.image_url;
      this.image_search = true;
  } else {
      script_filename = this.web_url;
      this.image_search = false;
  }
 
  script_filename += this.url + escape(q);
  var html_doc = document.getElementsByTagName('head').item(0);
  // remove the last included script, we don't need it anymore
  if (this.last_include) {
      html_doc.removeChild(this.last_include);
  }
  var js = document.createElement('script');
  js.setAttribute('type', 'text/javascript');
  js.setAttribute('src', script_filename);
  html_doc.appendChild(js);
 
  // set the pointer to the last include
  this.last_include = js;
 
};

Becuase we passed the callback function name ysearch.process to the service, the new Y! script will call it, passing the search results as an object. Let's see what process() does, really nothing but looping through the results object (description of the object here and here) and spitting out HTML using the politically incorrect innerHTML. Here's the code:

this.process = function(resp) {
 
  if (resp.ResultSet && resp.ResultSet.totalResultsReturned > 0) {
    // loop through the results
    var out = '';
    for (var i = 0,
     max = resp.ResultSet.Result.length;
     i < max;
     i++) {
 
    var item = resp.ResultSet.Result[i];
    if (this.image_search) {
      out += '<p><a href="' + item.Url + '">'
      out += '<img src="' + item.Thumbnail.Url + '" /><\/a>';
      out += '<br />' + item.Summary + '<\/p>';
    } else {
      out += '<p><a href="' + item.Url + '">' + item.Title + '<\/a>';
      out += '<br />' + item.Summary + '<\/p>';
    }
 
    }
    document.getElementById(this.where).innerHTML = out;
  } else {
    alert('no results');
  }
}
 

JSON JavaScript cookies

Wednesday, September 27th, 2006

Here's a little thing I came up with, which hopefully can make reading/writing cookies with JavaScript easier.

The big idea

The idea is to keep a JavaScript object (a hash array) of all little variable things you want to store in a cookie. Then, once ready, you encode the object into a JSON string and save it to a cookie. To load the data from a previously saved cookie, you decode the JSON string back into an object.

The tiny implementation

Having the little JSON lib from json.org, it's very easy. The solution was to have an object called prefs (the idea initially came when I wanted to save user preferences), which has:

  • data attribute - stores the data you want to save,
  • save() method, and
  • load() method.

The code is as follows:

var prefs = {
 
    data: {},
 
    load: function () {
        var the_cookie = document.cookie.split(';');
        if (the_cookie[0]) {
            this.data = unescape(the_cookie[0]).parseJSON();
        }
        return this.data;
    },
 
    save: function (expires, path) {
        var d = expires || new Date(2020, 02, 02);
        var p = path || '/';
        document.cookie = escape(this.data.toJSONString())
                          + ';path=' + p
                          + ';expires=' + d.toUTCString();
    }
 
}

Using the prefs object

In order to use this you need to satisfy dependencies first, including json.js and prefs.js:

<script type="text/javascript" src="json.js"></script>
<script type="text/javascript" src="prefs.js"></script>

Then you're ready to do save()s and load()s. If you need to delete a cookie, you call save() with date in the past. Here are some examples:

// save
prefs.data.something = "one"; // save one
// ... do other stuff ...
prefs.data.another = "two";
// ready to store?
prefs.save();
 
 
// another syntax
var to_save = {
    one: 1,
    two: 2,
}
prefs.data = to_save;
prefs.save();
 
 
// delete
var date_in_the_past = new Date(2000,02,02);
prefs.save(date_in_the_past);
 
 
// read
var what = prefs.load();
// load populates prefs.data and also returns
alert(what.something);
// or ...
alert(prefs.data.something);

Thanks

Thank you for reading! As always, any comments are appreciated.

 

JavaScript to find your Yahoo! ranking

Wednesday, April 19th, 2006

Motivation

Inspired by this article on SitePoint that shows how to find the Google ranking for a specific page and a search query, I decided to do the same, but for the Yahoo! ranking. The fun part is that my script is a JavaScript and requires nothing but a browser in order to run.

How mine is different

In the article above you need to use Google's SOAP service, so if you're not lucky enough to be running PHP5, you'll probably need something along the lines of PEAR SOAP or NuSOAP. That implies you also need a web server, running PHP. Then you need a Google API key and you need to download stuff and upload it to your server.

Nothing even close to that in terms of requirements if you opt in for the Yahoo! web service. All you need is a browser and JavaScript enabled, which shouldn't be a big deal, I don't think ;)

About the Yahoo! JSON web service

Yahoo's web service can return XML as everybody else, but it can also return serialized PHP and also JSON. Using the JSON option you can make a simple XMLHTTPRequest and get all the content JavaScript-ready, without the headaches of getELementsByTagName() or other DOMmy methods to wrestle that XML tree. The problem here is that you're requesting a file from a different domain, so the browser won't allow it. Workaround - a simple PHP script to serve as a proxy. Oooor (as we said we don't need no stinkin' server) you can use the dynamic JavaScript includes (discussed here) to do the request. As a result you get a working solution with JS only.

By the way, if you're wondering about the beauty of JSON, try this eye-opener.

Demo

Ah, yes, the demo is here.

Enter a/ your URL, or part of it, and b/ a search query. Then the script will tell you where in the first 1000 results is your URL to be found. If it is found.

How it works

Check the source for the details, it's reasonably well commented, but the big picture:

  • You make a request (in yjsonrank.makeRequest()) by appending a new SCRIPT element to the HEAD of your HTML. The URL of the script element (the SRC attribute) points to the Y! web service and also passes the search query and a function to be called once the script is included. This function happens to be yjsonrank.process()
  • The yjsonrank.process() function receives JSON data returned by the service, assigned to the resp variable.
  • We loop through resp.ResultSet, checking every resp.ResultSet.Result if its Url property contains our URL. If yes - we're done! If not, we make another request this time for the next 50 results. (50 is randomly chosen, feel free to modify). We continue until we reach 1000th result, which is the max that Y! will be willing to give.

And that's pretty much it, the rest is just fluff and beautifications ;)

More Y! info

Thanks for reading!