Tidbits @ Kassemi

A collection of opinions, thoughts, tricks and misc. information.

Tuesday, September 06, 2005

 

AJAX in-page browser

Before you get into this post, if you don't know how to program with javascript and HTTPRequestObjects, you should look at my tutorial on PHPBuilder.com:

http://www.phpbuilder.com/columns/kassemi20050606.php3 (part 1)
http://www.phpbuilder.com/columns/kassemi20050613.php3 (part 2)

Yep. I wrote it. From what I gather, you either love it or hate it. It's been pretty popular (links to it show up when you google AJAX tutorial... :) )

So I needed to allow a user to select from a number of options while in page form. There are many such options available... The closest example I can think about are school codes. For every school there is an assigned school code. To find the one that applies to you, you need to be able to search through a number of schools. This information is not easily accessible from a dropdown box. The solution? Have you seen those pages that have a calendar icon you can click on to get a calendar next to the form input (I have one of these on the page, as well)? Why not offer a way to let users browse information next to the form, much in the same way they can browse through the months in the calendars? An iframe would do the trick, but in order to keep away from frames entirely, we'll use a div and some AJAX... Here's the PHP back-end to the whole thing. You can add security restrictions, as I have done:


span style="color: #000000">
<?php

/* PHP backend for AJAX browser */

    
$data = file_get_contents($_GET['to']);

    if(
stripos($data, '<body') !== true){


        
$start = stripos($data, '<body');

        
$end = stripos($data, '>', $start);


        
$data = substr($data, $end + 1);     

    }

    if(
stripos($data, '</body>') !== false){


        
$data = substr($data, 0, stripos($data, '</body>'));

    }


    echo
$_GET['div_id'].','.$data;

?>



All it does is return the data from a page (anything within the body element, if it exists), and the id that we pass to it... Here's the js... Everything is extremely simple:


/* (Copyright 2005 James Kassemi) */

function getHTTPObject() {
var xmlhttp;
/*@cc_on
@if (@_jscript_version >= 5)
try {
xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
} catch (E) {
xmlhttp = false;
}
}

@else
xmlhttp = false;
@end @*/
if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
try {
xmlhttp = new XMLHttpRequest();
} catch (e) {
xmlhttp = false;
}
}
return xmlhttp;
}
var http = getHTTPObject();

function request_o(http_object, method, url, capture_function, post_args){
http_object.abort();
http_object.open(method, url);
if(method=='post'){
http_object.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
http_object.onreadystatechange = eval(capture_function);
http_object.send(post_args);
}
if(method != 'post'){
http_object.onreadystatechange = eval(capture_function);
http_object.send(null);
}
}

function navigate(to, div_id){
request_o(http, 'GET', './div_browser.php?to=' + escape(to) + '&div_id=' + escape(div_id), 'handle_navigate');
}

function handle_navigate(){
if(http.readyState == 4){
/* This could be done using XML and certain procedures I've used before, but in this case this will work just fine... */
var response = http.responseText;
/* Instead of using split, we'll use our own procedure that should be a little faster. */
for(i=0;i<response.length;i++){
if(response.charAt(i) == ','){
var div_id = response.substring(0,i);
var content = response.substring(i+1);
break;
}
}
/* We now have the content for the div, and we have the div's id... Let's replace with content. */
document.getElementById(div_id).innerHTML = content;
/* Now we should convert the links inside to open in the same box... */
convert_links(div_id);
}
}

function convert_links(div){
/* Convert all anchor links to navigate() links... */
div_box = document.getElementById(div);
var links = div_box.getElementsByTagName('a');
for(i=0;i<links.length;i++){
var value = links.item(i).getAttribute('href');
if(value){
links.item(i).setAttribute('href', "javascript:navigate('" + escape(value) + "', '" + div + "');");
}
}
}


And that's pretty much the entire thing! A call to navigate(to, div_id) will replace the contents of div_id with the page, to. I added a few more options more specific to my site (including a little icon that can be clicked next to the form field, as I was talking about), and grabbed the obligatory slashdot.org screenshot:



I'm not saying this is a full solution for anything, but it could easily become one. You could add your own back, forward, and home buttons, and could even insert a navigation bar, where the person can enter whatever URL they want to have loaded.

One thing that would need some serious work, however, would be the convert_links function. It currently just takes anything that is in the href attribute of a link and adds the navigate event to it, so it will load in the current div... The problem with this is that it will not render relative links in functional format...

If you are going to expand this, be sure you're careful about security. Make certain no administrator-like page on your server or anything checks authenticity only by whether or not you're on localhost... There are quite a few things somebody could easily do with this technology if they wanted to. You may wish to consider adding a check that only loads pages that are on your own server, and further, only pages that you want accessed...

Until next time,
James

Comments: Post a Comment



<< Home

Archives

August 2005   September 2005   October 2005   November 2005   December 2005   January 2006   February 2006   March 2006   April 2006   June 2006   July 2006   August 2006   September 2006   October 2006   November 2006  

This page is powered by Blogger. Isn't yours?