diff --git a/modules/overlay/overlay-parent.js b/modules/overlay/overlay-parent.js index 8f11df6..131ad25 100644 --- a/modules/overlay/overlay-parent.js +++ b/modules/overlay/overlay-parent.js @@ -46,6 +46,10 @@ Drupal.behaviors.overlayParent = { * child document is fully loaded. * - drupalOverlayLoad: This event is triggered when the overlay is finished * loading. + * - drupalOverlayStoreFormData: This event is triggered when the overlay is + * saving form data for possible restoration. + * - drupalOverlayRestoreFormData: This event is triggered when the overlay is + * restoring form data back into the form. * - drupalOverlayResize: This event is triggered when the overlay is being * resized to match the parent window. */ @@ -53,7 +57,8 @@ Drupal.overlay = Drupal.overlay || { isOpen: false, isOpening: false, isClosing: false, - isLoading: false + isLoading: false, + formData: {} }; Drupal.overlay.prototype = {}; @@ -123,6 +128,9 @@ Drupal.overlay.create = function () { .bind('drupalOverlayReady' + eventClass + ' drupalOverlayClose' + eventClass, $.proxy(this, 'eventhandlerSyncURLFragment')) .bind('drupalOverlayClose' + eventClass, $.proxy(this, 'eventhandlerRefreshPage')) + .bind('drupalOverlayBeforeLoad' + eventClass + + ' drupalOverlayBeforeClose' + eventClass, $.proxy(this, 'eventhandlerStoreFormData')) + .bind('drupalOverlayReady' + eventClass, $.proxy(this, 'eventhandlerRestoreFormData')) .bind('drupalOverlayBeforeClose' + eventClass + ' drupalOverlayBeforeLoad' + eventClass + ' drupalOverlayResize' + eventClass, $.proxy(this, 'eventhandlerDispatchEvent')); @@ -237,6 +245,110 @@ Drupal.overlay.redirect = function (url) { }; /** + * Saves form data of any form within the overlay for possible restoration. + * + * The form data is being stored in a JavaScript variable so forms can be + * restored if the overlay was closed accidentally and browser's back-button + * is being used. + */ +Drupal.overlay.storeFormData = function() { + if (!this.isOpen || !this.iframeWindow || !this.iframeWindow.document) { + return; + } + + var self = this; + $('form', this.iframeWindow.document).each(function() { + var $form = $(this); + var formId = $form.attr('id'); + // Overwrite any old data, replace it with the newer data. If we eventually + // do come back to this form, we'll want to re-populate it with the most up + // to date data available to us. + self.formData[formId] = {}; + $form.find(':input').each(function() { + var $input = $(this); + var name = $input.attr('name'); + // Basic validation: make sure the name is a non-empty string, and bypass + // input fields that aren't worth storing. + if (typeof name == 'string' && name.length && name != 'form_build_id' && name != 'form_token' && name != 'form_id' && name != 'op') { + // For checkboxes, store whether or not it's checked instead of storing + // an arbitrary value. + if ($input.is(':checkbox')) { + self.formData[formId][name] = $input.is(':checked'); + } + // For radio buttons, only store the value if this specific radio button + // is currently selected. + else if ($input.is(':radio')) { + if ($input.is(':checked')) { + self.formData[formId][name] = $input.val(); + } + } + // For everything else, just store the value. + else { + self.formData[formId][name] = $input.val(); + } + } + }); + }); + + // Allow other scripts to respond to this event. + $(document).trigger('drupalOverlaySaveFormData'); +}; + +/** + * Restores previously stored form data of any form within the overlay. + * + * @see Drupal.overlay.storeFormData() + */ +Drupal.overlay.restoreFormData = function() { + if (!this.isOpen || !this.iframeWindow || !this.iframeWindow.document) { + return; + } + + var self = this; + $('form', this.iframeWindow.document).each(function() { + var $form = $(this); + var formId = $form.attr('id'); + if (typeof self.formData[formId] == 'object') { + $form.find(':input').each(function() { + var $input = $(this); + var name = $input.attr('name'); + // Basic validation: make sure the name is a non-empty string. + if (typeof name == 'string' && name.length && typeof self.formData[formId][name] != 'undefined') { + // With checkboxes, we don't change the value; instead, we change + // the "checked" attribute. + if ($input.is(':checkbox')) { + if (self.formData[formId][name]) { + $input.attr('checked', 'checked').change(); + } + else { + $input.removeAttr('checked').change(); + } + } + // With radios, we also don't change the value; instead, we alter + // the "checked" attribute, checking it only if its value matches + // the value stored. + else if ($input.is(':radio')) { + if ($input.val() == self.formData[formId][name]) { + $input.attr('checked', 'checked').change(); + } + else { + $input.removeAttr('checked').change(); + } + } + // For all other elements, just set the value to the stored data. + else { + $input.val(self.formData[formId][name]); + } + } + }); + + // Allow other scripts to respond to this event. + $(document).trigger('drupalOverlayRestoreFormData'); + } + }); +}; + +/** * Bind the child window. * * Note that this function is fired earlier than Drupal.overlay.loadChild. @@ -646,6 +758,26 @@ Drupal.overlay.eventhandlerSyncURLFragment = function (event) { }; /** + * Event handler: stores form data of any form within the overlay. + * + * @param event + * Event being triggered + */ +Drupal.overlay.eventhandlerStoreFormData = function (event) { + this.storeFormData(); +}; + +/** + * Event handler: restores form data of any form within the overlay. + * + * @param event + * Event being triggered + */ +Drupal.overlay.eventhandlerRestoreFormData = function (event) { + this.restoreFormData(); +}; + +/** * Event handler: if the child window suggested that the parent refresh on * close, force a page refresh. *