Skip to content

Instantly share code, notes, and snippets.

@Hadryan
Created July 20, 2013 13:53
Show Gist options
  • Save Hadryan/6045111 to your computer and use it in GitHub Desktop.
Save Hadryan/6045111 to your computer and use it in GitHub Desktop.
a class of no-djax added to the original djax to have non-updatable internal links/elements. modification to have inline scripts at the end of updatable zone.
/*
* jQuery djax
*
* @version v0.122
*
* Copyright 2012, Brian Zeligson
* Released under the MIT license.
* http://www.opensource.org/licenses/mit-license.php
*
* Homepage:
* http://beezee.github.com/djax.html
*
* Authors:
* Brian Zeligson
*
* Contributors:
* Gary Jones @GaryJones
*
* Maintainer:
* Brian Zeligson github @beezee
*
*/
/*jslint browser: true, indent: 4, maxerr: 50, sub: true */
/*jshint bitwise:true, curly:true, eqeqeq:true, forin:true, immed:true, latedef:true, noarg:true, noempty:true, nomen:true, nonew:true, onevar:true, plusplus:true, regexp:true, smarttabs:true, strict:true, trailing:true, undef:true, white:true, browser:true, jquery:true, indent:4, maxerr:50, */
/*global jQuery */
// ==ClosureCompiler==
// @compilation_level ADVANCED_OPTIMIZATIONS
// @output_file_name jquery.djax.js
// @externs_url http://closure-compiler.googlecode.com/svn/trunk/contrib/externs/jquery-1.7.js
// ==/ClosureCompiler==
// http://closure-compiler.appspot.com/home
(function ($, exports) {
'use strict';
$.fn.djax = function (selector, exceptions, replaceBlockWithFunc) {
// If browser doesn't support pushState, abort now
if (!history.pushState) {
return $(this);
}
var self = this,
blockSelector = selector,
excludes = (exceptions && exceptions.length) ? exceptions : [],
replaceBlockWith = (replaceBlockWithFunc) ? replaceBlockWithFunc : $.fn.replaceWith,
djaxing = false;
// Ensure that the history is correct when going from 2nd page to 1st
window.history.replaceState(
{
'url' : window.location.href,
'title' : $('title').text()
},
$('title').text(),
window.location.href
);
self.clearDjaxing = function() {
self.djaxing = false;
}
// Exclude the link exceptions
self.attachClick = function (element, event) {
var link = $(element),
exception = false;
$.each(excludes, function (index, exclusion) {
if (link.attr('href').indexOf(exclusion) !== -1) {
exception = true;
}
if (window.location.href.indexOf(exclusion) !== -1) {
exception = true;
}
});
// If the link is one of the exceptions, return early so that
// the link can be clicked and a full page load as normal
if (exception) {
return $(element);
}
// From this point on, we handle the behaviour
event.preventDefault();
// If we're already doing djaxing, return now and silently fail
if (self.djaxing) {
setTimeout(self.clearDjaxing, 1000);
return $(element);
}
$(window).trigger('djaxClick', [element]);
self.reqUrl = link.attr('href');
self.triggered = false;
self.navigate(link.attr('href'), true);
};
// Handle the navigation
self.navigate = function (url, add) {
var blocks = $(blockSelector);
self.djaxing = true;
// Get the new page
$(window).trigger(
'djaxLoading',
[{
'url' : url
}]
);
var replaceBlocks = function (response) {
if (url !== self.reqUrl) {
self.navigate(self.reqUrl, false);
return true;
}
var result = $(response),
newBlocks = $(result).find(blockSelector);
if (add) {
window.history.pushState(
{
'url' : url,
'title' : $(result).filter('title').text()
},
$(result).filter('title').text(),
url
);
}
// Set page title as new page title
$('title').text($(result).filter('title').text());
//Remove element not done by other removes
$('.datepicker').remove();
var newStyle = $(result).filter('style'+blockSelector).text();
if($('style'+blockSelector).length)
{
$('style'+blockSelector).remove();
}
//Get all styles to add to the new page
var head = document.getElementsByTagName('head')[0];
var newStyles = $(result).filter('style'+blockSelector);
$.each(newStyles, function () {
var newStyle = $(this).text();
var style = document.createElement('style');
style.type = 'text/css';
style.className = blockSelector.replace('.', '');
if (style.styleSheet){
style.styleSheet.cssText = newStyle;
} else {
style.appendChild(document.createTextNode(newStyle));
}
head.appendChild(style);
});
// Loop through each block and find new page equivalent
blocks.each(function () {
var id = '#' + $(this).attr('id'),
newBlock = newBlocks.filter(id),
block = $(this);
//console.log(newBlock.html());
//console.log(block.html());
$('a', newBlock).not('.no-djax').filter(function () {
return this.hostname === location.hostname;
}).addClass('dJAX_internal').on('click', function (event) {
return self.attachClick(this, event);
});
if (newBlock.length) {
if (block.html() !== newBlock.html()) {
replaceBlockWith.call(block, newBlock);
}
} else {
block.remove();
}
});
// Loop through new page blocks and add in as needed
$.each(newBlocks, function () {
var newBlock = $(this),
id = '#' + $(this).attr('id'),
$previousSibling;
//console.log(newBlocks.html());
//console.log(newBlock.html());
// If there is a new page block without an equivalent block
// in the old page, we need to find out where to insert it
if (!$(id).length) {
// Find the previous sibling
$previousSibling = $(result).find(id).prev();
if ($previousSibling.length) {
// Insert after the previous element
newBlock.insertAfter('#' + $previousSibling.attr('id'));
} else {
// There's no previous sibling, so prepend to parent instead
newBlock.prependTo('#' + newBlock.parent().attr('id'));
}
}
// Only add a class to internal links
$('a', newBlock).not('.no-djax').filter(function () {
return this.hostname === location.hostname;
}).addClass('dJAX_internal').on('click', function (event) {
return self.attachClick(this, event);
});
});
var oldScripts = $('script.no-djax');
$.each(oldScripts, function () {
$(this).remove();
});
//Get all scripts to add to the new page
var newScripts = $(result).filter('script.no-djax');
$.each(newScripts, function () {
var newScript = $(this).text();
//console.log('error', newScript); //Debugging yo
//Create new script element and add it to the DOM corrently, that way it is executed :D
var script = document.createElement("script");
script.type = "text/javascript";
script.text = newScript; // use this for inline script
script.className = "no-djax";
var updateId = blockSelector.replace('#', '');
document.getElementById(updateId).appendChild(script);
});
// Trigger djaxLoad event as a pseudo ready()
if (!self.triggered) {
$(window).trigger(
'djaxLoad',
[{
'url' : url,
'title' : $(result).filter('title').text(),
'response' : response
}]
);
self.triggered = true;
self.djaxing = false;
}
};
$.get(url, function (response) {
replaceBlocks(response);
}).error(function (response) {
// handle error
console.log('error', response);
replaceBlocks(response['responseText']);
});
}; /* End self.navigate */
// Only add a class to internal links
$(this).find('a').not('.no-djax').filter(function () {
return this.hostname === location.hostname;
}).addClass('dJAX_internal').on('click', function (event) {
return self.attachClick(this, event);
});
// On new page load
$(window).bind('popstate', function (event) {
self.triggered = false;
if (event.originalEvent.state) {
self.reqUrl = event.originalEvent.state.url;
self.navigate(event.originalEvent.state.url, false);
}
});
};
}(jQuery, window));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment