Created
April 16, 2012 18:06
-
-
Save staylor/2400406 to your computer and use it in GitHub Desktop.
The old one
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Please do not edit this file directly (unless you intend to fork). | |
It's been open-sourced here: | |
http://github.com/dgouldin/django-hashsignal | |
Requires | |
* jQuery hashchange event - v1.2 - 2/11/2010 | |
* http://benalman.com/projects/jquery-hashchange-plugin/ | |
*/ | |
/*globals ActiveXObject, _gaq, window, jQuery */ | |
(function (window, $, undefined) { | |
"use strict"; | |
var ALWAYS_RELOAD = '__all__', | |
HASH_REPLACEMENT = ':', | |
CONTAINERPATH = '/listen/', | |
previousLocation = null, | |
upcomingLocation = null, | |
previousSubhash = null, | |
transitions = {}, | |
document = window.document, | |
location = window.location, | |
history = window.history, | |
insertId = 0, | |
activeOpts, | |
defaultOpts, | |
liveFormsSel, | |
referrer, | |
methods; | |
function isCached(url) { | |
var cache = -1 !== url.indexOf('.css') || | |
-1 !== url.indexOf('.js') || | |
-1 !== url.indexOf('/browse/') || | |
-1 !== url.indexOf('/charts/') || | |
-1 !== url.indexOf('/music-news/') || | |
-1 !== url.indexOf('/book-news/') || | |
-1 !== url.indexOf('/music-genres/') || | |
-1 !== url.indexOf('/book-genres/') || | |
-1 !== url.indexOf('/artist/') || | |
-1 !== url.indexOf('/search/') || | |
-1 !== url.indexOf('/radio/') || | |
(url.indexOf('/album/') === -1 && url.indexOf('/book/') === -1 && false !== pathOf(url)); | |
return cache; | |
} | |
// url helpers | |
function isCrossDomain(url) { | |
// taken straight from jQuery: | |
// https://github.com/jquery/jquery/blob/master/src/ajax.js | |
var ajaxLocation, | |
ajaxLocParts, | |
parts, | |
rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/; | |
try { | |
ajaxLocation = window.location.href; | |
} catch (e) { | |
ajaxLocation = window.document.createElement("a"); | |
ajaxLocation.href = ""; | |
ajaxLocation = ajaxLocation.href; | |
} | |
// Segment location into parts | |
ajaxLocParts = rurl.exec(ajaxLocation.toLowerCase()) || []; | |
parts = rurl.exec(url.toLowerCase()); | |
return !!(parts && | |
(parts[1] !== ajaxLocParts[1] || parts[2] !== ajaxLocParts[2] || | |
(parts[3] || (parts[1] === "http:" ? 80 : 443)) !== | |
(ajaxLocParts[3] || (ajaxLocParts[1] === "http:" ? 80 : 443)))); | |
} | |
function hrefToHash(href) { | |
var parts = href.split("#"), | |
subhash = parts[1] || ""; | |
return parts[0] + HASH_REPLACEMENT + encodeURIComponent(subhash); | |
} | |
function hashToHref(hash) { | |
var subhashIndex, | |
page, | |
subhash; | |
hash = (hash.charAt(0) === "#" ? hash.substr(1) : hash); | |
subhashIndex = hash.lastIndexOf(HASH_REPLACEMENT); | |
if (subhashIndex === -1) { | |
return hash; | |
} else { | |
page = hash.substr(0, subhashIndex); | |
subhash = decodeURIComponent(hash.substr(subhashIndex + 1)); | |
return page + (subhash ? "#" + subhash : ""); | |
} | |
} | |
function urlPrefix() { | |
return location.protocol + "//" + location.host; | |
} | |
function pathOf(absolute) { | |
var domain = urlPrefix() + "/"; | |
if (0 !== absolute.indexOf(domain)) { //off-site, or different protocol. | |
return false; | |
} | |
if (-1 !== absolute.indexOf(CONTAINERPATH + '#/')) { //handle links that have container path in the url, not for real hash | |
if (/:$/.test(absolute)) { | |
absolute = absolute.slice(0, -1); | |
return absolute.slice(domain.length + CONTAINERPATH.length); | |
} else { | |
return absolute.slice(domain.length + CONTAINERPATH.length); | |
} | |
} else { | |
return "/" + absolute.slice(domain.length); | |
} | |
} | |
function resolve(url) { | |
return $('<a href="' + url + '"></a>').get(0).href; | |
} | |
function log() { | |
var args; | |
if (!(activeOpts && activeOpts.debug)) { | |
return; | |
} | |
args = [new Date(), "hashsignal"].concat(Array.prototype.slice.apply(arguments)); | |
if (window.console) { | |
window.console.log(args); | |
} else { | |
window.alert(args.join(" ")); | |
} | |
} | |
defaultOpts = { | |
excludeSelector: '.no-ajax', | |
beforeUpdate: function () { log('beforeUpdate'); }, | |
afterUpdate: function () { log('afterUpdate'); }, | |
errorUpdate: function () { log('errorUpdate'); }, | |
onDocumentWrite: function (msg) { | |
$('.footer-wrapper').writeCapture().append(msg); | |
if (window.console) { | |
window.console.log("jQuery.hashsignal received document.write: " + msg); | |
} | |
}, | |
debug: false, | |
disabled: false, | |
resolverId: "hashsignal-abs", | |
inlineStylesheets: false, | |
replaceBlocksOnError: false | |
}; | |
function blockAction(actionName, blockName) { | |
/* DRYs up _unloadBlock and _loadBlock below */ | |
var transition = transitions[blockName], name; | |
if (!transition) { | |
return; | |
} | |
for (name in transition) { | |
if (transition.hasOwnProperty(name)) { | |
transition[name][actionName](); | |
/* Clean up old transitions which are no longer needed. */ | |
if (actionName === 'unload' && !transition[name].o.runOnce && blockName !== ALWAYS_RELOAD) { | |
delete transition[name]; | |
} | |
} | |
} | |
} | |
function getOldBlocks(doc) { | |
var blockRe = /^ (end)?block ([^ ]*) ([0-9a-f]{32} )?$/, | |
blocks = {}; | |
function walker(root, handle) { | |
var i, c; | |
handle(root); | |
for (i = 0, c = root.childNodes.length; i < c; i += 1) { | |
walker(root.childNodes[i], handle); | |
} | |
} | |
function blockWalker(root, handle) { //handle(name, isStart, node) | |
walker(root, function (node) { | |
var match; | |
if (node.nodeType === 8) { // comment node | |
match = blockRe.exec(node.nodeValue); | |
if (match) { | |
handle(match[2], match[3], !match[1], node); | |
} | |
} | |
}); | |
} | |
doc = doc || document; | |
blockWalker(doc, function (name, signature, isStart, node) { | |
if (blocks[name] === undefined) { | |
blocks[name] = { | |
nodes: [null, null], | |
signature: signature | |
}; | |
} | |
blocks[name].nodes[isStart ? 0 : 1] = node; | |
}); | |
return blocks; | |
} | |
function getNewBlocks(html, callback) { | |
var blocker = /<!-- (end)?block ([^ ]*) ([0123456789abcdef]{32} )?-->/gi, | |
stylesheet = /<link.+?(rel=["']?stylesheet["'\s])?.*?href=["']?(.+?)["'\s].*?(rel=["']?stylesheet["'\s])?.*?>/gi, | |
starts = [], //stack of {name:a, signature:x, start:y}; | |
closing, | |
blocks = {}, //name: {signature:x, html:z} | |
stylesheetPromises = []; | |
function last() { | |
return starts[starts.length - 1]; | |
} | |
html.replace(blocker, function (matched, ending, blockName, signatureMaybe, offset, fullString) { | |
if (ending && starts.length === 0) { | |
log("Unexpected block nesting on match: " + matched); | |
} | |
if (!ending && !signatureMaybe) { | |
log('WARNING: block found without signature', blockName); | |
} | |
if (ending) { | |
closing = last(); | |
blockName = closing.name; | |
starts.length = starts.length - 1; | |
blocks[blockName] = { | |
html: fullString.slice(closing.start, offset), | |
signature: closing.signature | |
}; | |
if (activeOpts.inlineStylesheets) { | |
// begin async loading stylesheets for inline replacement | |
blocks[blockName].html.replace(stylesheet, function (sMatched, preRel, href, postRel, offset, sFullString) { | |
if (!isCrossDomain(href) && ((preRel && (preRel.toLowerCase().indexOf('stylesheet') !== -1)) || (postRel && (postRel.toLowerCase().indexOf('stylesheet') !== -1)))) { | |
stylesheetPromises.push($.ajax({ | |
cache: isCached(href), | |
dataType: "text", | |
url: href | |
}).done(function (css) { | |
blocks[blockName].html = blocks[blockName].html.replace(sMatched, '<style type="text/css">' + css + '</style>'); | |
})); | |
} | |
}); | |
} | |
} else { | |
starts.push({ | |
name: blockName, | |
start: offset + matched.length, | |
signature: signatureMaybe | |
}); | |
} | |
}); | |
if (0 !== starts.length) { | |
log("Unclosed block: " + last().name); | |
} | |
if (stylesheetPromises.length > 0) { | |
$.when.apply($, stylesheetPromises).then(function () { | |
callback(blocks); | |
}, function () { | |
callback(blocks); | |
}); | |
} else { | |
callback(blocks); | |
} | |
} | |
function replaceBlocks(html, forceReload, callback) { | |
log('replaceBlocks'); | |
var oldBlocks = getOldBlocks(); | |
callback = callback || $.noop; | |
function siblingsBetween(start, end) { | |
var siblings = [], | |
current = start; | |
while (current && (current !== end)) { | |
if (current !== start) { | |
siblings.push(current); | |
} | |
current = current.nextSibling; | |
} | |
return siblings; | |
} | |
function getBodyAttrs(body) { | |
var bodyAttrs = {}, | |
// these are attrs which may be reported as present | |
// but cannot be modified, so we must skip. | |
blacklist = 'contentEditable'; | |
$.each(body.attributes, function (i, attr) { | |
// WARNING: attributes behavior is not very cross-browser friendly. | |
// see: http://www.quirksmode.org/dom/w3c_core.html#attributes | |
if (!(!!attr && attr.name) || blacklist.indexOf(attr.name) !== -1) { | |
return; | |
} | |
if (attr.value) { | |
bodyAttrs[attr.name] = attr.value; | |
} | |
}); | |
return bodyAttrs; | |
} | |
getNewBlocks(html, function (newBlocks) { | |
//update title | |
var titleRe = /<title>(.*)<\/title>/, | |
titleMatch = titleRe.exec(html), | |
oldBody = $('body'), | |
bodyRe = /<body([^>]*)>/, | |
bodyMatch = bodyRe.exec(html), | |
oldBodyAttrs, | |
newBodyAttrs, | |
fakeDoc, | |
namespaceURI, | |
fakeHtml, | |
newBody, | |
newValue, | |
blockName, | |
oldBlock, | |
newBlock; | |
if (titleMatch) { | |
document.title = titleMatch[1]; | |
} | |
// replace old body attributes with new ones | |
if (bodyMatch) { | |
if (window.ActiveXObject) { | |
// For IE | |
// NOTE: requires valid xml body attributes! | |
try { | |
fakeDoc = new ActiveXObject("Microsoft.XMLDOM"); | |
fakeDoc.async = false; | |
fakeDoc.loadXML('<body ' + bodyMatch[1] + '></body>'); | |
newBody = fakeDoc.documentElement; | |
} catch (e) {} | |
} else if (window.document.implementation && window.document.implementation.createDocument) { | |
namespaceURI = window.document.namespaceURI || 'http://www.w3.org/1999/xhtml'; | |
fakeDoc = window.document.implementation.createDocument(namespaceURI, 'html', null); | |
fakeHtml = fakeDoc.documentElement; | |
fakeHtml.innerHTML = '<body ' + bodyMatch[1] + '></body>'; | |
newBody = $('body', fakeHtml).get(0); | |
} | |
if (newBody) { | |
oldBodyAttrs = getBodyAttrs(oldBody.get(0)); | |
newBodyAttrs = getBodyAttrs(newBody); | |
$.each(oldBodyAttrs, function (key, oldValue) { | |
newValue = newBodyAttrs[key]; | |
if (newValue) { | |
if (newValue !== oldValue) { | |
oldBody.attr(key, newValue); | |
} | |
delete newBodyAttrs[key]; | |
} else { | |
if (oldBody.attr(key)) { | |
oldBody.removeAttr(key); | |
} | |
} | |
}); | |
oldBody.attr(newBodyAttrs); | |
} | |
} | |
methods._unloadBlock(ALWAYS_RELOAD); | |
for (blockName in newBlocks) { | |
if (newBlocks.hasOwnProperty(blockName)) { | |
if (oldBlocks.hasOwnProperty(blockName)) { // if (blockName in oldBlocks | |
oldBlock = oldBlocks[blockName]; | |
newBlock = newBlocks[blockName]; | |
if (oldBlock.signature && ((newBlock.signature && (oldBlock.signature === newBlock.signature)) && !forceReload)) { | |
log('Not replacing block, signatures match.', blockName, oldBlock.signature); | |
// The block is the same, no need to swap out the content. | |
continue; | |
} | |
methods._unloadBlock(blockName); | |
$(siblingsBetween(oldBlock.nodes[0], oldBlock.nodes[1])).remove(); | |
log('Replacing block', blockName, newBlock.html); | |
// methods._loadBlock must be called from inside newBlock.html so that mutations block as | |
//would normally happen with inline scripts. | |
$(oldBlock.nodes[0]).after( | |
newBlock.html + | |
'<script type="text/javascript">' + | |
'jQuery.hashsignal._loadBlock("' + | |
blockName.replace('"', '\\"') + '");' + | |
'</scr' + 'ipt>' | |
); | |
insertId += 1; | |
// update block signature | |
$(oldBlock.nodes[0]).replaceWith("<!-- block " + blockName + " " + (newBlock.signature || "") + "-->"); | |
} else { | |
log('WARNING: unmatched block', blockName); | |
} | |
} | |
} | |
methods._loadBlock(ALWAYS_RELOAD); | |
callback(); | |
}); | |
} | |
function updatePage(opts) { | |
var o, | |
callbacks, | |
urlParts, | |
expectedLocation, | |
subhash; | |
opts.url = opts.url + (opts.url.indexOf('?') < 0 ? '?' : '&') + 'hashsignal=true'; | |
o = $.extend({ | |
url: (previousLocation || '') + '#' + (previousSubhash || ''), | |
type: 'GET', | |
data: '', | |
cache: false, | |
forceReload: false | |
}, opts); | |
callbacks = $.extend({ | |
beforeUpdate: function () {}, | |
afterUpdate: function () {}, | |
errorUpdate: function () {} | |
}, activeOpts); | |
urlParts = o.url.split("#"); | |
expectedLocation = urlParts[0] || previousLocation; | |
subhash = urlParts[1] || ''; | |
if (expectedLocation === previousLocation && (subhash !== previousSubhash)) { | |
$(window).trigger('hashsignal.hashchange', [subhash]); | |
previousSubhash = subhash; | |
return; | |
} | |
if (!o.forceReload && (expectedLocation === previousLocation && ((o.type.toLowerCase() === 'get') && !o.data))) { | |
return; | |
} | |
//deal with multiple pending requests by always having the | |
// last-requested win, rather than last-responded. | |
upcomingLocation = expectedLocation; | |
function makeSuccessor(expectedLocation) { | |
return function (data, status, xhr) { | |
var jsonData; | |
if (expectedLocation !== upcomingLocation) { | |
log("Success for ", expectedLocation, " fired but last-requested was ", upcomingLocation, " - aborting"); | |
return; | |
} | |
try { | |
jsonData = $.parseJSON(data); | |
} catch (ex) {} | |
// If response body contains a redirect location, perform the redirect. | |
// This is an xhr-compatible proxy for 301/302 responses. | |
if (jsonData && jsonData.redirectLocation) { | |
log('redirecting page', jsonData.redirectLocation); | |
previousLocation = expectedLocation; | |
previousSubhash = subhash; | |
location.replace('#' + hrefToHash(jsonData.redirectLocation)); | |
return; | |
} | |
//setBase(urlPrefix() + expectedLocation); | |
replaceBlocks(data, o.forceReload, function () { | |
if (subhash) { | |
$(window).trigger('hashsignal.hashchange', [subhash]); | |
} | |
previousLocation = expectedLocation; | |
previousSubhash = subhash; | |
callbacks.afterUpdate(); | |
}); | |
}; | |
} | |
callbacks.beforeUpdate(); | |
$.ajax({ | |
dataType: "text", | |
data: o.data, | |
cache: isCached(expectedLocation), | |
error: function (xhr, status, error) { | |
log('updatePage error ' + status + " " + error); | |
callbacks.errorUpdate(xhr, status, error, previousLocation); | |
if (activeOpts.replaceBlocksOnError) { | |
makeSuccessor(expectedLocation)(xhr.responseText, status, xhr); | |
} else { | |
history.back(); | |
} | |
}, | |
success: makeSuccessor(expectedLocation), | |
beforeSend: function (xhr) { | |
xhr.setRequestHeader('X-Hashsignal', 'Hashsignal'); //Used to tell server to send Ajax-friendly redirects. | |
if (previousLocation) { | |
xhr.setRequestHeader('X-Hashsignal-Referer', resolve(previousLocation)); | |
} | |
}, | |
type: o.type, | |
url: expectedLocation | |
}); | |
} | |
function Transition(opts) { | |
var script, | |
that; | |
this.hasRun = false; | |
this.o = $.extend({ | |
load: function () {}, | |
unload: function () {}, | |
runOnce: false | |
}, opts); | |
this.events = []; | |
this.delegates = []; | |
this.timeouts = []; | |
this.intervals = []; | |
this.scripts = {}; | |
// shims | |
this.bind = function (obj, eventType, eventData, handler) { | |
this.events.push([obj, eventType, handler]); | |
return $(obj).bind(eventType, eventData, handler); | |
}; | |
this.delegate = function (obj, selector, eventType, eventData, handler) { | |
this.delegates.push([obj, selector, eventType, handler]); | |
return $(obj).delegate(selector, eventType, eventData, handler); | |
}; | |
this.setTimeout = function (callback, timeout) { | |
this.timeouts.push(window.setTimeout(callback, timeout)); | |
}; | |
this.setInterval = function (callback, timeout) { | |
this.intervals.push(window.setInterval(callback, timeout)); | |
}; | |
this.clearTimeout = window.clearTimeout; | |
this.clearInterval = window.clearInterval; | |
this.addScript = function (src, loadOnce) { | |
var parts; | |
loadOnce = loadOnce === undefined ? true : loadOnce; | |
if (!(loadOnce && this.scripts[src])) { | |
script = document.createElement('script'); | |
script.type = 'text/javascript'; | |
if (src.indexOf('?')) { | |
parts = src.split('?'); | |
src = parts[0]; | |
} | |
script.src = src; | |
script = $(script); | |
that = this; | |
script.load(function () { | |
that.scripts[src] = true; | |
$(this).unbind('load'); | |
}); | |
$('body').append(script); | |
} | |
}; | |
this.load = function () { | |
if (!(this.hasRun && this.runOnce)) { | |
this.o.load(this); | |
} | |
this.hasRun = true; | |
}; | |
this.unload = function () { | |
var i, e; | |
if (!this.runOnce) { | |
for (i = 0; i < this.events.length; i += 1) { | |
e = this.events[i]; | |
$(e[0]).unbind(e[1], e[2]); | |
} | |
for (i = 0; i < this.delegates.length; i += 1) { | |
e = this.delegates[i]; | |
$(e[0]).undelegate(e[1], e[2], e[3]); | |
} | |
for (i = 0; i < this.timeouts.length; i += 1) { | |
window.clearTimeout(this.timeouts[i]); | |
} | |
for (i = 0; i < this.intervals.length; i += 1) { | |
window.clearInterval(this.intervals[i]); | |
} | |
this.o.unload(this); | |
} | |
}; | |
} | |
function Location(url) { | |
var parts, | |
that, | |
partFunc, | |
k; | |
// parseUri 1.2.2 | |
// (c) Steven Levithan <stevenlevithan.com> | |
// MIT License | |
function parseUri(str) { | |
var o = parseUri.options, | |
m = o.parser[o.strictMode ? "strict" : "loose"].exec(str), | |
uri = {}, | |
i = 14; | |
while (i--) { uri[o.key[i]] = m[i] || ""; } | |
uri[o.q.name] = {}; | |
uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) { | |
if ($1) {uri[o.q.name][$1] = $2;} | |
}); | |
return uri; | |
} | |
parseUri.options = { | |
strictMode: false, | |
key: ["source", "protocol", "authority", "userInfo", "user", "password", "host", "port", "relative", "path", "directory", "file", "query", "anchor"], | |
q: { | |
name: "queryKey", | |
parser: /(?:^|&)([^&=]*)=?([^&]*)/g | |
}, | |
parser: { | |
strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/, | |
loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/ | |
} | |
}; | |
// end parseUri | |
parts = { | |
port: '', // 80 | |
protocol: '', // http: | |
hostname: '', // www.google.com | |
pathname: '', // /search | |
search: '' // ?q=devmo | |
}; | |
that = this; | |
partFunc = function (k) { | |
return function (value) { | |
if (value === undefined) { | |
return parts[k]; | |
} else { | |
parts[k] = value; | |
} | |
}; | |
}; | |
for (k in parts) { | |
if (parts.hasOwnProperty(k)) { | |
that[k] = partFunc(k); | |
} | |
} | |
parts.hash = ''; | |
this.hash = function (value) { // #test | |
if (value === undefined) { | |
return parts.hash; | |
} else { | |
if (value.length === 0) { | |
parts.hash = ''; | |
} else { | |
parts.hash = value[0] === '#' ? value : '#' + value; | |
} | |
return parts.hash; | |
} | |
}; | |
this.href = function (value) { | |
var obj; // http://www.google.com:80/search?q=devmo#test | |
if (value === undefined) { | |
return this.protocol() + '//' + this.host() + this.pathname() + this.search() + this.hash(); | |
} else { | |
obj = parseUri(value); | |
parts = { | |
port: obj.port, | |
protocol: obj.protocol + ':', | |
hostname: obj.host, | |
pathname: obj.path, | |
search: obj.query ? "?" + obj.query : "", | |
hash: obj.anchor ? "#" + obj.anchor : "" | |
}; | |
return this.href(); | |
} | |
}; | |
this.host = function (value) { | |
var obj; // www.google.com:80 | |
if (value === undefined) { | |
return this.hostname() + (this.port() === '' ? '' : ':' + this.port()); | |
} else { | |
obj = parseUri(value + this.pathname() + this.search() + this.hash()); | |
parts.port = obj.port; | |
parts.hostname = obj.host; | |
return this.host(); | |
} | |
}; | |
this.relativeHref = function () { | |
return this.pathname() + this.search() + this.hash(); | |
}; | |
this.href(url); // hook it up! | |
} | |
methods = { | |
init: function (explicitOpts) { | |
activeOpts = $.extend(defaultOpts, explicitOpts); | |
if (activeOpts.disabled) { | |
// shortcut event binding | |
return this; | |
} | |
document.write = activeOpts.onDocumentWrite; | |
$(window).bind('hashchange', function (e) { | |
log('hashchange', e); | |
updatePage({ | |
url: hashToHref(location.hash), | |
type: 'GET' | |
}); | |
}); | |
if (location.hash && location.hash !== '#') { | |
updatePage({ | |
url: hashToHref(location.hash), | |
type: 'GET' | |
}); | |
} | |
$('a:not(' + activeOpts.excludeSelector + ')').live('click', function () { | |
var href = resolve(this.getAttribute('href') || "."), | |
hash; | |
if (isCrossDomain(href)) { //off-site links act normally. | |
return true; | |
} | |
hash = hrefToHash(pathOf(href)); | |
if (hash === "/:" && ((window.location.hash === '#/' || window.location.hash === '#/:') && (!$.cookie('EMUSIC_REMEMBER_ME_COOKIE')))) { //we are at the home page and we might need to reload it to see a pitch page because we have no cookie, so force a reload here | |
window.location.href = "/"; | |
} | |
location.hash = hash; | |
return false; | |
}); | |
liveFormsSel = 'form:not(' + activeOpts.excludeSelector + ')'; | |
$(liveFormsSel).live('submit', function (event) { | |
var href = resolve($(this).attr('action') || "."), | |
path = pathOf(href), | |
type, | |
data, | |
submitter; | |
if (isCrossDomain(href) || path === false) { //off-site forms act normally. | |
return true; | |
} | |
if ($(this).has("input[type='file']").length) { | |
// we can't serialize files, so we have to do it the old-fashioned way | |
$(this).attr('action', path); | |
return true; | |
} | |
type = $(this).attr('method'); | |
data = $(this).serialize(); | |
if (!data) { //form might have no data | |
return false; | |
} | |
submitter = this.submitter; | |
if (submitter) { | |
data += (data.length === 0 ? "" : "&") + (encodeURIComponent($(submitter).attr("name")) + "=" + encodeURIComponent($(submitter).attr("value")) + ''); | |
} | |
if (type && type.toLowerCase() === 'get') { | |
//fix up the querystring. | |
path = path.substring(0, path.indexOf('?')) || path; | |
path += '?' + data; | |
location.hash = hrefToHash(path); | |
} else { | |
// TODO: how does a post affect the hash fragment? | |
activeOpts.beforeUpdate(); | |
updatePage({ | |
url: path, | |
type: type, | |
data: data | |
}); | |
} | |
return false; | |
}); | |
//make sure the submitting button is included in the form data. | |
$(liveFormsSel + " input[type=submit], " + liveFormsSel + " button[type=submit]").live('click', function (event) { | |
var form = $(this).closest("form").get(0); | |
if (form) { | |
form.submitter = this; | |
} | |
return true; | |
}); | |
return this; | |
}, | |
isEnabled: function () { | |
return activeOpts && activeOpts.hashsignalEnabled; | |
}, | |
hashchange: function (callback) { // callback = function(e, hash) { ... } | |
$(window).bind('hashsignal.hashchange', callback); | |
return this; | |
}, | |
location: (function (properties) { | |
var that = {}; | |
$(properties).each(function (i, property) { | |
that[property] = function (value) { | |
var href = resolve(hashToHref(location.hash)), | |
l = new Location(href); | |
if (!l) { | |
log("Could not parse current location! " + href); | |
} | |
if (value === undefined) { | |
return l[property](); | |
} else { | |
l[property](value); | |
location.hash = hrefToHash(l.relativeHref()); | |
} | |
}; | |
}); | |
that.assign = that.href; // alias to fully support window.location parity | |
that.reload = function () { | |
updatePage({ | |
forceReload: true | |
}); | |
}; | |
that.replace = function (url) { | |
var l = new Location(url); | |
location.replace('#' + hrefToHash(l.relativeHref())); | |
}; | |
return that; | |
}(['hash', 'href', 'pathname', 'search'])), | |
registerTransition: function (name, blockNames, opts) { | |
log('hashsignal.registerTransition', name, blockNames); | |
var transition = new Transition(opts), | |
i, | |
blockName; | |
if (!!opts.alwaysReload) { | |
blockNames = [ALWAYS_RELOAD]; | |
} | |
for (i = 0; i < blockNames.length; i += 1) { | |
blockName = blockNames[i]; | |
if (transitions[blockName] === undefined) { | |
transitions[blockName] = {}; | |
} | |
if (transitions[blockName][name] === undefined) { | |
transitions[blockName][name] = transition; | |
} | |
} | |
return this; | |
}, | |
_unloadBlock: function (blockName) { | |
log('hashsignal.unloadBlock', blockName); | |
blockAction('unload', blockName); | |
}, | |
_loadBlock: function (blockName) { | |
log('hashsignal.loadBlock', blockName); | |
blockAction('load', blockName); | |
} | |
}; | |
$.hashsignal = methods; | |
}(window, jQuery)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment