Gi11i4m
Gi11i4m

Reputation: 15

Load the html head from an unloaded document with jquery / javascript

I'm re-writing a website for my father's driving school, changing the unnecessary iframes and images to html5 and css3 markup, and improving the functionality trough javascript and jquery.

Now, I have a full page for every menu-item (for the search crawlers), while the header and the menu mostly stay the same. That's why I want to use the history api and change the content and the document title and description when a link gets clicked on a device with javascript enabled, so there doesn't have to be a full page refresh.

What works: - getting the #content div of the target page and loading it into the current page - using the history api to show a new url and the popstate event to return to previous states - changing the content of the html head from the current document

What doesn't work: - getting the html head from the target document

There should be a simple function for this, right? Or a good way to do this?

Upvotes: 1

Views: 208

Answers (2)

greim
greim

Reputation: 9437

See my comments under the accepted answer. Basically, there are some performance concerns using that approach, which made me look for a better approach. To that end, I adapted an approach found in the rails turbolinks project, which is MIT licensed and written coffeescript. Credit goes to them for working around some of the browser compatibility issues.

https://github.com/rails/turbolinks

/*
 * A function that takes a string of HTML and returns a document object.
 */
var parseDocument = (function() {
    function createDocumentUsingParser(html) {
        return (new DOMParser()).parseFromString(html, 'text/html');
    }
    function createDocumentUsingDOM(html) {
        var doc = document.implementation.createHTMLDocument('');
        doc.documentElement.innerHTML = html;
        return doc;
    }
    function createDocumentUsingWrite(html) {
        var doc = document.implementation.createHTMLDocument('');
        doc.open('replace');
        doc.write(html);
        doc.close();
        return doc;
    }
    /*
     * Use createDocumentUsingParser if DOMParser is defined and natively
     * supports 'text/html' parsing (Firefox 12+, IE 10)
     * 
     * Use createDocumentUsingDOM if createDocumentUsingParser throws an exception
     * due to unsupported type 'text/html' (Firefox < 12, Opera)
     * 
     * Use createDocumentUsingWrite if:
     *  - DOMParser isn't defined
     *  - createDocumentUsingParser returns null due to unsupported type 'text/html' (Chrome, Safari)
     *  - createDocumentUsingDOM doesn't create a valid HTML document (safeguarding against potential edge cases)
     */
    var parser;
    if (window.DOMParser) {
        try {
            var testDoc = createDocumentUsingParser('<html><body><p>test');
            if (testDoc && testDoc.body && testDoc.body.childNodes.length === 1) {
                parser = createDocumentUsingParser;
            }
        } catch(ex) {
            parser = createDocumentUsingDOM;
        }
    }
    if (!parser) {
        parser = createDocumentUsingWrite;
    }
    return parser;
})();

Then presumably for example you could do something like:

var doc = parseDocument(wadOfHtml);
var title = doc.title;
var $content = $(doc).find('#content');

Be warned, I haven't verified for myself whether this code works, I'm going off of the reputability of the rails project. I also haven't verified whether my adaptation from coffeescript didn't introduce syntax or other errors. I literally haven't even run it yet; I'm merely optimistic.

Upvotes: 0

T.J. Crowder
T.J. Crowder

Reputation: 1074505

Since it's on the same origin, you can do that. It's a bit awkward, though it's not a million miles off what jQuery does behind-the-scenes when you use its ajax load (I expect jQuery uses a document fragment rather than an iframe).

Basically, you can create an off-page iframe, load the content page into there, and then extract whatever you need from it, something like this (completely unoptimized):

// I'm assuming you have a variable containing the content URL; I'll use `page`
var page = "/ocazuc/2";

// Create the iframe, put it off-page, and put it in the DOM
var iframe = $('<iframe>');
iframe.css({
  position: "absolute",
  left: -10000
}).appendTo(document.body);

// Hook the load event on it
iframe.load(function() {
  // Get the document
  var $doc = $(iframe[0].contentDocument.documentElement);

  // Steal its content
  $doc.find("body").contents().appendTo(document.body);

  // And use its title or whatever else you want from the `head`
  document.title = $doc.find('title').text();

  // Done with it
  iframe.remove();
});

// Start loading it
iframe[0].src = page;

Live Example | Source

Upvotes: 1

Related Questions