').parent().html(),
+ newblock_html = newBlock.clone().wrap('
').parent().html();
+
+ if (block_html !== newblock_html) {
+ replacements_config.push({
+ 'type': 'replace',
+ 'new_block' : newBlock,
+ 'target' : $currentBlock
+ });
+ }
+ else {
+ // get rid of the new block if the html of the old
+ // block is exactly the same!
+ replacements_config.push({
+ 'type': 'remove',
+ 'new_block': newBlock,
+ 'target' : undefined
+ });
+ }
+ }
+ });
+
+
+ //
+ // Case in which blocks need to be added/appended
+ //
+ var $previousBlock;
+
+ $.each($newBlocks, function () {
+
+ var $newBlock = $(this),
+ id = '#' + $(this).attr('id'),
+ $previousSibling;
+
+ // 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
+ replacements_config.push({
+ 'type' : 'insertAfter',
+ 'target' : $('#' + $previousSibling.attr('id')),
+ 'new_block' : $newBlock
+ });
+ } else {
+ // There's no previous sibling, so prepend to parent instead
+ var parent_id = $newBlock.parent().attr('id');
+ if (parent_id === undefined && $previousBlock !== undefined) {
+ replacements_config.push({
+ 'type' : 'insertAfter',
+ 'target' : $('#' + $previousBlock.attr('id')),
+ 'new_block' : $newBlock
+ });
+ }
+ else {
+ replacements_config.push({
+ 'type' : 'prependTo',
+ 'target' : $('#' + parent_id),
+ 'new_block' : $newBlock
+ });
+ }
+ }
+ }
+
+ // Keep the previous block
+ $previousBlock = $newBlock;
+
+ // Only add a class to internal links
+ // TODO: Remove this
+ // $('a:not(.' + settings.ignoreClass + ')', $newBlock).filter(function () {
+ // return this.hostname === location.hostname;
+ // }).addClass('dJAX_internal').on('click.djax', function (event) {
+ // return _methods.attachClick.call($this, this, event);
+ // });
+
+ var replace_fn = function ($newBlock) {
+ $('a:not(.' + settings.ignoreClass + ')', $newBlock).filter(function () {
+ return this.hostname === location.hostname;
+ }).addClass('dJAX_internal').on('click.djax', function (event) {
+ return _methods.attachClick.call($this, this, event);
+ });
+ }
+
+ replacements_config.push({
+ 'type' : 'function',
+ 'target': replace_fn,
+ 'args' : [$newBlock]
+ });
+
+ });
+
+ // Delegate block replacement
+
+ var done_fn = function () {
+ // Trigger djaxLoad event as a pseudo ready()
+ if (!triggered) {
+ $(window).trigger(
+ 'djaxLoad',
+ [{
+ 'url' : url,
+ 'title' : $result.filter('title').text(),
+ 'response' : response
+ }]
+ );
+ triggered = true;
+ djaxing = false;
+ }
+ }
+
+ replacements_config.push({
+ 'type' : 'function',
+ 'target': done_fn,
+ 'args' : []
+ });
+
+ $(window).trigger(
+ 'djaxDeferReplacements',
+ [ replacements_config ]
+ );
+ }
+ };
+
+ var methods = {
+ 'init' : function (options) {
+
+ var settings = $.extend({
+ 'selector' : undefined,
+ 'ignoreClass' : '',
+ 'exceptions' : [],
+ 'urlDataAttribute' : undefined,
+ 'replaceBlockFunction' : undefined,
+ 'ajax_data_parameter' : { },
+ 'ajax_timeout': undefined,
+ 'ajax_timeout_callback' : undefined,
+ /*
+ * Called synchronously before ajax call starts.
+ *
+ * - djaxClickData: element or identifier of element the
+ * user interacted with;
+ *
+ * - requestParameters: parameters that will be included in the
+ * ajax call. This is an object.
+ */
+ 'onDjaxClickCallback' : function (djaxClickData, requestParameters) { return; },
+ 'onHistoryPopStateCallback' : function () { return; }
+ }, options);
+
+ return this.each(function() {
+ var $this = $(this);
+
+ // save settings
+ $this.data('settings', settings);
+
+ // If browser doesn't support pushState, abort now
+ if (!history.pushState) {
+ return $(this);
+ }
+
+ var excludes = settings.exceptions,
+ ignoreClass = settings.ignoreClass,
+ replaceBlockWith = (settings.replaceBlockFunction) ? settings.replaceBlockFunction: $.fn.replaceWith;
+
+ djaxing = false;
+
+ var blockSelector = settings.selector;
+
+ // Save block selector internally so that we can use it in later calls
+ $this.data('djaxBlockSelector', blockSelector);
+
+ // Save the replaceBlockWith function internally too...
+ $this.data('djaxReplaceBlockWith', replaceBlockWith);
+
+ // Save excludes so that we can use them later...
+ $this.data('djaxUserExcludes', excludes);
+
+ // 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
+ );
+
+ // Exclude the link exceptions
+ // Only add a class to internal links
+ $this.find('a:not(.' + ignoreClass + ')').filter(function () {
+ return this.hostname === location.hostname;
+ }).addClass('dJAX_internal').on('click.djax', function (event) {
+ return _methods.attachClick.call($this, this, event);
+ });
+
+ // On new page load
+ $(window).bind('popstate', function (event) {
+ triggered = false;
+
+ if (event.originalEvent.state) {
+ var targetUrl = event.originalEvent.state.url;
+
+ // prevent IE <= 9 to navigate repeatedly to the current url
+ var url_parts = targetUrl.split("#");
+ if (url_parts.length === 2) {
+ if (url_parts[0].indexOf(url_parts[1]) >= 0) {
+ popstateUrl = '';
+ return;
+ }
+ }
+
+ if (popstateUrl != targetUrl) {
+ settings.onHistoryPopStateCallback();
+ reqUrl = targetUrl;
+ popstateUrl = targetUrl;
+
+ _methods.navigate.call($this, {
+ url: popstateUrl,
+ add_to_history: false,
+ method: 'GET'
+ });
+ }
+ else {
+ // second time just reset the popstate url.
+ popstateUrl = '';
+ }
+ }
+ });
+ });
+ },
+ 'is_djaxing' : function () {
+ return djaxing;
+ },
+ 'navigate' : function (url, add_to_history, data, method, requestParameters) {
+ var $this = this;
+
+ if (typeof data === 'undefined') {
+ data = [];
+ }
+
+ if (djaxing) {
+ // push url in the queue and handle once the previous ajax
+ // request has completed
+ url_queue.push([url, add_to_history, data, method, requestParameters]);
+
+ // handle queue
+ setTimeout(function () { _methods.clearDjaxing.call($this)} , 1000);
+ return $this;
+ }
+ else {
+ triggered = false;
+ $(window).trigger('djaxClick', data);
+
+ // call blocking callback
+ var settings = $this.data('settings');
+ settings.onDjaxClickCallback.call($this, data, requestParameters);
+
+ reqUrl = url;
+ _methods.navigate.call($this, {
+ url: url,
+ add_to_history: add_to_history,
+ method: method
+ });
+ }
+ },
+ 'set_ajax_data_parameter' : function (ajax_parameters_func_or_obj) {
+ var $this = this;
+ var settings = $this.data('settings');
+
+ // if function: will be called when needed; if object: will be
+ // passed straight away to the $.ajax call.
+ settings.ajax_data_parameter = ajax_parameters_func_or_obj;
+
+ // save parameters
+ $this.data('settings', settings);
+ }
+ };
+
+ $.fn.djax = function(method) {
+ /*
+ * Just a router for method calls
+ */
+ if (methods[method]) {
+ // call a method
+ return methods[method].apply(this,
+ Array.prototype.slice.call(arguments, 1)
+ );
+ }
+ else if (typeof method == 'object' || !method) {
+ // call init, user passed the settings as parameters
+ return methods.init.apply(this, arguments);
+ }
+ else {
+ $.error('Cannot call method ' + method);
+ }
+
+ };
+
+}(jQuery, window));
diff --git a/readme.md b/readme.md
index 8897db5..c17ab54 100644
--- a/readme.md
+++ b/readme.md
@@ -1,139 +1,5 @@
#djax: Dynamic pjax
-##Basic usage
+This project is not maintained. It was diverging too much from the original project, that ended up as another project: DDJAX.
-djax is very quick to set up, with a few markup requirements to let it work smoothly.
-
-First include it in your header after jquery:
-
-
-
-
-Then instantiate on the largest page element where you will have updating content. 'body' is typically the way to go with this:
-
-
-
-Congrats, you're done! Well mostly...
-
-##Markup
-
-djax will track elements with the class you pass it as a first argument. In the above example I've passed the class 'updatable,' so my markup would look something like this:
-
-
-
-
- Here's a div that will be monitored for changes by djax.
-
-
- Here's another
-
-
-
-
-Your markup can be laid out however you like, and your trackable sections can be anywhere in relation to one another. It's best to keep them top level (nesting is unnecessary and unsupported,) and
-there are a few requirements that allow the plugin to function properly.
-
-###IDs
-
-Trackable elements must all have IDs. This is how the requested page is matched up with the current page. Only trackable elements that differ between the two pages will be loaded.
-Trackable elements that do not exist on the requested page will be removed, and trackable elements that do not exist on the current page will be added. In order to support this, it
-is also necessary to ensure the *parent* elements of every trackable element has an ID, as well as the sibling element immediately *prior* to each trackable element (if one exists).
-
-These ID's are used to add elements when necessary. If an element exists in a requested page, but not the current page, it will be inserted after the prior sibling (by ID,) or prepended to
-the parent element (by ID.)
-
-##Parameters
-
-The plugin accepts only two parameters, and only one is required.
-
-###Tracking Class
-
-The first and only required parameter is the class you will use to identify trackable elements. If my code looks like the below sample, every dynamic element in my markup should have a class
-of djaxable
-
-
-
-###Exceptions
-
-By default djax works on any internal links, but sometimes you may want to exclude certain URLs on your site. The second parameter allows you to pass an array of URL fragments to exclude from djax
-loading. This is performed with a simple Javascript 'indexOf,' so the more of the URL you provide, the more specifically your exclusions will be matched. The below example will djax any internal links
-that do not contain admin, resources, or ?s= in the url.
-
-
-
-##DOM Replacement Callbacks (optional)
-
-Pass in a reference to a function that will handle the DOM replacement logic. The default djax replacement uses the standard jQuery `replaceWith` and does an immediate replace. For transitions, fade in/outs etc, you can control when and how the new content displays on
-the page. The following example fades out the old content, and fades in the new content.
-
-
-
-
-##Events
-
-###djaxLoad
-
-By loading new content via ajax, your visitors will only encounter $('document').ready() the first time they land on your site, and any time they manually perform a hard refresh. To help address this,
-djax triggers a window level event on each partial load it performs. Here's an example of enabling pageview tracking with Google Analytics on a djax enabled site:
-
- $(window).bind('djaxLoad', function(e, data) {
- _gaq.push(['_trackPageview']);
- });
-
-As a convenience, the data object passed with the event contains the requested url, the page title for the requested page, and the contents of the requested page as a string. Use something like the following
-code to work with the response as a jQuery object
-
- $(window).bind('djaxLoad', function(e, data) {
- var responseObj = $('
'+data.response+'
');
- //do stuff here
- });
-
-###djaxClick
-
-This event is triggered when a djax'ed link is clicked. Use something like the code below to scroll top before loading in new content with ajax:
-
- $(window).bind('djaxClick', function(e, data) {
- var bodyelem = ($.browser.safari) ? bodyelem = $("body") : bodyelem = $("html,body");
- bodyelem.scrollTop(0);
- });
-
-##Live Demo
-
-djax arose out of a desire to use [pjax](https://github.com/defunkt/jquery-pjax) with complicated and varied layouts. See [here](http://brianzeligson.com/djax) for a WordPress site using a modified version
-of the [bones](http://themble.com/bones/) WordPress theme. djax enabling this theme took about [28 lines of code](https://github.com/beezee/bones-responsive/commit/58aadde224d74f8aaa3266a4bd76e961f2888ada)
-(if you count adding a class to an element as a line of code.)
-
-There is also a small working example in the github repository. Feel free to load up any of the included html files in your browser to see how it works.
+See DDJAX at https://github.com/lokku/jquery-ddjax