Search code examples
phpjqueryajaxjquery-address

jquery address crawling - logic issues


I'm using the jquery address plugin to build an ajax driven site, and i've got it working! Yay! For the purposes of this question we can use the test site:

http://www.asual.com/jquery/address/samples/crawling
http://www.asual.com/download/jquery/address
(I had to remove two calls to urlencode() to make the crawling example work.)

I'm encountering a problem with the $crawling->nav() call. It basically uses js and php to load parts of an xml file into the dom. I (mostly) understand how it works, and I would like to modify the example code to include sub pages.

For example, I would like to show 'subnav-project.html' at '/!#/project' and '/!#/project/blue', but not at '/!#/contact'. To do this, I figure php should 'know' what page the user is on, that way I can base my logic off of that.

Is this crazy? Can php ever know the current state of the site if I'm building it this way? If not, how does one selectively load html snippets, or modify what links are shown in navigation menus?

I've never gotten too crazy with ajax before, so any feedback at all would be helpful.

EDIT

This is the crawling class.

class Crawling { 

    const fragment = '_escaped_fragment_';

    function Crawling(){ 

        // Initializes the fragment value
        $fragment = (!isset($_REQUEST[self::fragment]) || $_REQUEST[self::fragment] == '') ? '/' : $_REQUEST[self::fragment];

        // Parses parameters if any
        $this->parameters = array();
        $arr = explode('?', $fragment);
        if (count($arr) > 1) {
            parse_str($arr[1], $this->parameters);
        }

        // Adds support for both /name and /?page=name
        if (isset($this->parameters['page'])) {
            $this->page = '/?page=' . $this->parameters['page'];
        } else {
            $this->page = $arr[0];
        }

        // Loads the data file
        $this->doc = new DOMDocument();
        $this->doc->load('data.xml');
        $this->xp = new DOMXPath($this->doc);
        $this->nodes = $this->xp->query('/data/page');
        $this->node = $this->xp->query('/data/page[@href="' . $this->page . '"]')->item(0);

        if (!isset($this->node)) {
            header("HTTP/1.0 404 Not Found");
        }
    }

    function base() {
        $arr = explode('?', $_SERVER['REQUEST_URI']);
        return $arr[0] != '/' ? preg_replace('/\/$/', '', $arr[0]) : $arr[0];
    }

    function title() {
        if (isset($this->node)) {
            $title = $this->node->getAttribute('title');
        } else {
            $title = 'Page not found';
        }
        echo($title);
    }

    function nav() {
        $str = '';

        // Prepares the navigation links
        foreach ($this->nodes as $node) {
            $href = $node->getAttribute('href');
            $title = $node->getAttribute('title');
            $str .= '<li><a href="' . $this->base() . ($href == '/' ? '' : '?' . self::fragment . '=' .html_entity_decode($href)) . '"' 
                . ($this->page == $href ? ' class="selected"' : '') . '>' 
                . $title . '</a></li>';
        }
        echo($str);
    }

    function content() {
        $str = '';

        // Prepares the content with support for a simple "More..." link
        if (isset($this->node)) {
            foreach ($this->node->childNodes as $node) {
                if (!isset($this->parameters['more']) && $node->nodeType == XML_COMMENT_NODE && $node->nodeValue == ' page break ') {
                    $str .= '<p><a href="' . $this->page . 
                        (count($this->parameters) == 0 ? '?' : '&') . 'more=true' . '">More...</a></p>';
                    break;
                } else {
                    $str .= $this->doc->saveXML($node);
                }
            }
        } else {
            $str .= '<p>Page not found.</p>';
        }

        echo(preg_replace_callback('/href="(\/[^"]+|\/)"/', array(get_class($this), 'callback'), $str));
    }

    private function callback($m) {
        return 'href="' . ($m[1] == '/' ? $this->base() : ($this->base() . '?' . self::fragment . '=' .$m[1])) . '"';
    }
}

$crawling = new Crawling();

Solution

  • You won't be able to make server-side decisions using the fragment-identifier (i.e., everything to the right of the # character). This is because browsers don't send fragment-identifiers to the server. If you're going to want to make server-side decisions, you'll need to use some JavaScript assistance (including AJAX) to communicate what the current fragment-identifier is.