diff --git a/js/ajax_view.js b/js/ajax_view.js
index d7fa0d7e..8a65ea25 100644
--- a/js/ajax_view.js
+++ b/js/ajax_view.js
@@ -8,45 +8,69 @@
* Attaches the AJAX behavior to Views exposed filter forms and key View links.
*/
Drupal.behaviors.ViewsAjaxView = {};
-Drupal.behaviors.ViewsAjaxView.attach = function() {
+Drupal.behaviors.ViewsAjaxView.attach = function(context, settings) {
if (Drupal.settings && Drupal.settings.views && Drupal.settings.views.ajaxViews) {
- $.each(Drupal.settings.views.ajaxViews, function(i, settings) {
- Drupal.views.instances[i] = new Drupal.views.ajaxView(settings);
+ $.each(Drupal.settings.views.ajaxViews, function(i, viewSettings) {
+ Drupal.views.instances[i] = new Drupal.views.ajaxView(viewSettings);
});
- if (window.location.hash) {
- hash = Drupal.Views.getLocationHash();
-
- // Do we have a hash that corresponds to an auto-submit form?
- $exposed_form_submitted = $('form#views-exposed-form-'+ hash.f);
+ // This attach function is invoked by two or more events:
+ // 1) First page load (context == document)
+ // 2) AJAX response (context == modified content)
+ //
+ // The views-auto-submit-processed class is applied by the $('body').once
+ // call in the submitExposedForm method, and should be cleared on every
+ // attach to prepare the environment for the user navigating back in
+ // history.
+ $('body').removeClass('views-auto-submit-processed');
+ if (context == document) {
+ this.submitExposedForm();
+ $(window).bind('popstate', jQuery.proxy(this.viewsHistoryCallback, this));
+ }
+ }
+};
- $lastLinkEvent = location.hash;
+Drupal.behaviors.ViewsAjaxView.viewsHistoryCallback = function(event) {
+ this.submitExposedForm();
+}
+
+Drupal.behaviors.ViewsAjaxView.submitExposedForm = function() {
+ var curFormState = history.state;
+ if (!$.isEmptyObject(curFormState)) {
+ // Was an exposed form submitted?
+ exposedFormSubmitted = $('form#views-exposed-form-' + curFormState.f);
+
+ // Ensure that the form is re-submitted once
+ $('body').once('views-auto-submit', function() {
+ if (Drupal.Views.isNumeric(curFormState.p)) {
+ var page = $('').val(curFormState.p);
+ exposedFormSubmitted.prepend(page);
+ }
- $('body').once('views-hash', function() {
- if (Drupal.Views.isNumeric(hash.p)) {
- var pageValue = $('').val(hash.p);
- $exposed_form_submitted.prepend(pageValue);
- }
- for (var v in hash) {
- if (hash.hasOwnProperty(v)) {
- // Set the form element to the value from the hash.
- if (hash[v] == 'true') {
- $exposed_form_submitted.find(('[id='+ v +']')).prop('checked', true);
+ for (var v in curFormState) {
+ if (curFormState.hasOwnProperty(v)) {
+ // Set the form element to the value from the query string
+ if (curFormState[v] == 'true') {
+ exposedFormSubmitted.find(('[id=' + v + ']')).prop('checked', true);
+ }
+ else {
+ if (curFormState[v] == 'false') {
+ exposedFormSubmitted.find(('[id=' + v + ']')).prop('checked', false);
}
else {
- $exposed_form_submitted.find(('[id='+ v +']')).prop('value', hash[v]);
+ exposedFormSubmitted.find(('[id=' + v + ']')).prop('value', curFormState[v]);
}
}
}
+ }
- if ($exposed_form_submitted.hasClass('ctools-auto-submit-full-form')) {
- $exposed_form_submitted.find('input, select').first().change();
- }
- else {
- $exposed_form_submitted.find(':submit').click();
- }
- });
- } // End if hash.
+ if (exposedFormSubmitted.hasClass('ctools-auto-submit-full-form')) {
+ exposedFormSubmitted.find('input, select').first().change();
+ }
+ else {
+ exposedFormSubmitted.find('#' + curFormState.submit).click();
+ }
+ });
}
};
@@ -118,44 +142,65 @@ Drupal.views.ajaxView = function(settings) {
};
/**
- * Exposed forms use this to append their id as a URL hash so we can esubmit the
- * form when the browser's "Back" button is used.
+ * Store the current form state into the History queue, so that it is
+ * retrievable when interacting with the Browser's history.
*/
Drupal.views.ajaxView.prototype.ajaxCompleteExposedCallback = function(event, request, options) {
if (options.url === this.element_settings.url) {
- var data = Drupal.Views.parseQueryString(options.data);
- hash = Drupal.Views.getLocationHash();
-
- var val = {};
- var changed_exposed_filter = false;
- this.$exposed_form.find('select, input').each(function(i, element) {
- if ((this.name !== "" && this.type == 'select-one') || (this.type == 'checkbox')) {
- changed_exposed_filter = true;
- if (this.type == 'checkbox') {
- if (this.checked) {
- val[this.id] = 'true';
- }
- else {
- if (hash[this.id] == 'true') {
- val[this.id] = 'false';
- }
- }
- }
- else {
- val[this.id] = this.value;
- }
+ // WARNING: This method will be invoked by all ajaxView instances on a page,
+ // and we only want to store history for the submitted exposed form of a
+ // single view. The submitted exposed form ID and related information is
+ // extracted from the AJAX request.
+ var requestParams = Drupal.Views.parseQueryString(options.data);
+ var formState = $.isEmptyObject(history.state) ? {} : history.state;
+ var formStateChanged = false;
+ var page = requestParams.hasOwnProperty('page') ? requestParams.page : 0;
+ var formId = requestParams.view_name.replace(/_/g, '-')
+ + '-'
+ + requestParams.view_display_id.replace(/_/g, '-');
+ var exposedForm = $('form#views-exposed-form-' + formId);
+ var submitId = 'edit-submit-' + requestParams.view_name.replace(/_/g, '-');
+
+ // When a View filter is updated, multiple Ajax requests are sent, and
+ // we cannot be sure that the View HTML is in sync with the final result of
+ // the Ajax request. Since the request parameters store the form values
+ // submitted in the Ajax request but *not* the HTML form element IDs, and
+ // retrieving the Ajax request parameters is more reliable than retrieving
+ // the HTML form values, the Ajax request parameters will be auto-associated
+ // with the HTML form values.
+ $(exposedForm).find('select, input').each(function(i, element) {
+ if (!this.hasAttribute('id') || this.id == '') {
+ return;
}
- else {
- val[this.id] = this.value;
+
+ var requestParamId = this.id.replace(/^edit-/, '').replace(/-/g, '_');
+ if (requestParams.hasOwnProperty(requestParamId)) {
+ if (!formState.hasOwnProperty(this.id) || formState[this.id] != requestParams[requestParamId]) {
+ formState[this.id] = requestParams[requestParamId];
+ formStateChanged = true;
+ }
}
});
- if (changed_exposed_filter) {
- val['p'] = 0;
+ if (!formState.hasOwnProperty('p') || formState['p'] != page) {
+ formState['p'] = page;
+ formStateChanged = true;
+ }
+
+ if (!formState.hasOwnProperty('f') || formState['f'] != formId) {
+ formState['f'] = formId;
+ formStateChanged = true;
+ }
+
+ if (!formState.hasOwnProperty('submit') || formState['submit'] != submitId) {
+ formState['submit'] = submitId;
+ formStateChanged = true;
+ }
+
+ if (formStateChanged) {
+ history.pushState(formState, '');
}
- Drupal.Views.updateLocationHash(val);
- Drupal.Views.updateLocationHash({ f: this.settings.view_name.replace(/_/g, '-') + '-' + this.settings.view_display_id.replace(/_/g, '-'), p: data.page});
this.$exposed_form.find('input[name=page]').remove();
}
};
@@ -205,20 +250,6 @@ Drupal.views.ajaxView.prototype.attachPagerLinkAjax = function(id, link) {
this.element_settings.submit = viewData;
this.pagerAjax = new Drupal.ajax(false, $link, this.element_settings);
this.links.push(this.pagerAjax);
-
- // Attach click handler to update hash.
- $link.click(this.pagerHandler);
-};
-
-/**
- * Click handler updates the location hash based on pager.
- */
-Drupal.views.ajaxView.prototype.pagerHandler = function(event) {
- var args = Drupal.Views.parseQueryString(event.target.href);
- if (typeof args.page === "undefined") {
- args.page = 0;
- }
- Drupal.Views.updateLocationHash({ p: args.page });
};
Drupal.ajax.prototype.commands.viewsScrollTop = function (ajax, response, status) {
diff --git a/js/base.js b/js/base.js
index ac149235..5220b7ef 100644
--- a/js/base.js
+++ b/js/base.js
@@ -113,26 +113,6 @@ Drupal.Views.getPath = function (href) {
};
/**
- * Helper function updates window.location.hash data from a javascript object.
- *
- * We provide for multiple arbitrary values to be stored in the hash by using a
- * urlencoded string.
- */
-Drupal.Views.updateLocationHash = function (data) {
- hash = Drupal.Views.getLocationHash();
- $.extend(hash, data);
- window.location.hash = decodeURIComponent($.param(hash));
-};
-
-/**
- * Helper function to get the window.location.hash data.
- */
-Drupal.Views.getLocationHash = function () {
- hashStr = window.location.hash.substr(1); // Strips the # itself.
- return Drupal.Views.parseQueryString(hashStr);
-};
-
-/**
* Determines whether its argument represents a Javascript number (This is
* provided in jQuery 1.7, but we're not there yet).
*/