/* innerShiv: makes HTML5shim work on innerHTML & jQuery
 * http://jdbartlett.github.com/innershiv
 *
 * This program is free software. It comes without any warranty, to
 * the extent permitted by applicable law. You can redistribute it
 * and/or modify it under the terms of the Do What The Fuck You Want
 * To Public License, Version 2, as published by Sam Hocevar. See
 * http://sam.zoy.org/wtfpl/COPYING for more details.
 */
window.innerShiv = (function () {
	var div;
	var doc = document;
	var needsShiv;
	
	// Array of elements that are new in HTML5
	var html5 = 'abbr article aside audio canvas datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video'.split(' ');
	
	// Used to idiot-proof self-closing tags
	function fcloseTag(all, front, tag) {
		return (/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i).test(tag) ? all : front + '></' + tag + '>';
	}
	
	return function (
		html, /* string */
		returnFrag /* optional false bool */
	) {
		if (!div) {
			div = doc.createElement('div');
			
			// needsShiv if can't use HTML5 elements with innerHTML outside the DOM
			div.innerHTML = '<nav></nav>';
			needsShiv = div.childNodes.length !== 1;
			
			if (needsShiv) {
				// MSIE allows you to create elements in the context of a document
				// fragment. Jon Neal first discovered this trick and used it in his
				// own shimprove: http://www.iecss.com/shimprove/
				var shimmedFrag = doc.createDocumentFragment();
				var i = html5.length;
				while (i--) {
					shimmedFrag.createElement(html5[i]);
				}
				
				shimmedFrag.appendChild(div);
			}
		}
		
		html = html
			// Trim whitespace to avoid unexpected text nodes in return data:
			.replace(/^\s\s*/, '').replace(/\s\s*$/, '')
			// Strip any scripts:
			.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
			// Fix misuses of self-closing tags:
			.replace(/(<([\w:]+)[^>]*?)\/>/g, fcloseTag)
			;
		
		// Fix for using innerHTML in a table
		var tabled;
		if (tabled = html.match(/^<(tbody|tr|td|th|col|colgroup|thead|tfoot)[\s\/>]/i)) {
			div.innerHTML = '<table>' + html + '</table>';
		} else {
			div.innerHTML = html;
		}
		
		// Avoid returning the tbody or tr when fixing for table use
		var scope;
		if (tabled) {
			scope = div.getElementsByTagName(tabled[1])[0].parentNode;
		} else {
			scope = div;
		}
		
		// If not in jQuery return mode, return child nodes array
		if (returnFrag === false) {
			return scope.childNodes;
		}
		
		// …otherwise, build a fragment to return
		var returnedFrag = doc.createDocumentFragment();
		var j = scope.childNodes.length;
		while (j--) {
			returnedFrag.appendChild(scope.firstChild);
		}
		
		return returnedFrag;
	};
}());

// jQuery plugin based on .load() for use with innerShiv
// http://jdbartlett.github.com/innershiv for more info
// $('selector').loadShiv('example.html selector');
jQuery.fn.loadShiv = function (url, params, callback) {
	var off, selector, self, type;

	if (!this.length || typeof url !== 'string') {
		return this;
	}

	off = url.indexOf(' ');
	if (off >= 0) {
		selector = url.slice(off, url.length);
		url = url.slice(0, off);
	}

	type = 'GET';

	if (params) {
		if (jQuery.isFunction(params)) {
			callback = params;
			params = null;
		} else if (typeof params === 'object') {
			params = jQuery.param(params, jQuery.ajaxSettings.traditional);
			type = 'POST';
		}
	}

	self = this;

	jQuery.ajax({
		url: url,
		type: type,
		dataType: 'html',
		data: params,
		complete: function (res, status) {
			var shivved;

			if (status === 'success' || status === 'notmodified') {
				shivved = jQuery(innerShiv((selector ? '<div>' : '') + res.responseText, false));

				if (selector) {
					shivved = shivved.find(selector);
				}

				self.empty().append(shivved);
			}

			if (callback) {
				self.each(callback, [res.responseText, status, res]);
			}
		}
	});

	return this;
}
