diff --git a/themes/bootstrap3/js/lightbox.js b/themes/bootstrap3/js/lightbox.js
index 164e496a9ace40c1e8416d9ddddf4246380ae439..516984a823ac03056295958a761acd5deb537c7f 100644
--- a/themes/bootstrap3/js/lightbox.js
+++ b/themes/bootstrap3/js/lightbox.js
@@ -5,19 +5,19 @@ VuFind.lightbox = (function() {
   var _currentUrl = false;
   var refreshOnClose = false;
   // Elements
-  var _modal, _modalBody;
+  var _modal, _modalBody, _clickedButton = null;
   // Utilities
   var _html = function(html) {
     _modalBody.html(html);
     _modal.modal('handleUpdate');
-  }
+  };
   // Public: Present an alert
   var showAlert = function(message, type) {
     if ('undefined' == typeof type) {
       type = 'info';
     }
     _html('<div class="alert alert-'+type+'">'+message+'</div>\
-    <button class="btn btn-default" data-dismiss="modal">close</button>');
+    <button class="btn btn-default" data-dismiss="modal">' + VuFind.translate('close') + '</button>');
     _modal.modal('show');
   };
   var flashMessage = function(message, type) {
@@ -26,27 +26,38 @@ VuFind.lightbox = (function() {
       .after('<div class="alert alert-'+type+'">'+message+'</div>');
   };
 
-  // Update content
+  /**
+   * Update content
+   * 
+   * Form data options:
+   *
+   * data-lightbox-ignore = do not submit this form in lightbox
+   */
   var _update = function(html) {
     if (!html.match) return;
-    // Deframe HTML
-    if(html.match('<!DOCTYPE html>')) {
-      html = $('<div>'+html+'</div>').find('.main > .container').html();
-    }
     // Isolate successes
-    var testDiv = $('<div>'+html+'</div>');
-    var alerts = testDiv.find('.alert-success');
+    var htmlDiv = $('<div>'+html+'</div>');
+    var alerts = htmlDiv.find('.alert-success');
     if (alerts.length > 0) {
       showAlert(alerts[0].innerHTML, 'success');
       return;
     }
+    // Deframe HTML
+    if (html.match('<!DOCTYPE html>')) {
+      html = htmlDiv.find('.main > .container').html();
+    }
     // Fill HTML
     _html(html);
     _modal.modal('show');
     // Attach capturing events
-    _modalBody.find('a').on('click', _constrainLink);
-    var forms = _modalBody.find('form');
-    for(var i=0;i<forms.length;i++) {
+    _modalBody.find('a').click(_constrainLink);
+    // Handle submit buttons attached to a form as well as those in a form. Store 
+    // information about which button was clicked here as checking focused button 
+    // doesn't work on all browsers and platforms.
+    _modalBody.find('[type=submit]').click(_storeClickedStatus);
+    
+    var forms = _modalBody.find('form:not([data-lightbox-ignore])');
+    for (var i=0;i<forms.length;i++) {
       $(forms[i]).on('submit', _formSubmit);
     }
     // Select all checkboxes
@@ -56,8 +67,12 @@ VuFind.lightbox = (function() {
     $('#modal').find('.checkbox-select-item').change(function() {
       $(this).closest('.modal-body').find('.checkbox-select-all').prop('checked', false);
     });
-  }
+  };
 
+  var _storeClickedStatus = function() {
+    _clickedButton = this;
+  };    
+  
   var _xhr = false;
   // Public: Handle AJAX in the Lightbox
   var ajax = function(obj) {
@@ -78,8 +93,7 @@ VuFind.lightbox = (function() {
     _xhr.always(function() { _xhr = false; })
       .done(function(html, status, jq_xhr) {
         if (jq_xhr.status == 205) {
-          // No reload since any post params would cause a prompt
-          window.location.href = window.location.href;
+          _refreshPage();
           return;
         }
         if ( // Close the lightbox after deliberate login
@@ -89,13 +103,26 @@ VuFind.lightbox = (function() {
           || obj.url.match(/catalogLogin/))    // catalog login for holds
         ) {
           if (_originalUrl.match(/UserLogin/) || obj.url.match(/catalogLogin/)) {
-            window.location.reload();
+            var event = new CustomEvent('VuFind.lightbox.login', {
+              detail: {
+                originalUrl: _originalUrl,
+                formUrl: obj.url
+              },
+              bubbles: true,
+              cancelable: true
+            });
+            if (document.dispatchEvent(event)) {
+              _refreshPage();
+            }
             return false;
           } else {
             VuFind.lightbox.refreshOnClose = true;
           }
         }
         _update(html);
+      })
+      .fail(function() {
+        showAlert(VuFind.translate('error_occurred'), 'danger');  
       });
     return _xhr;
   };
@@ -126,13 +153,19 @@ VuFind.lightbox = (function() {
       VuFind.modal('show');
       return false;
     }
-  }
+  };
 
   /**
-   * Form data options
+   * Handle form submission.
+   * 
+   * Form data options:
    *
    * data-lightbox-onsubmit = on submit, run named function
    * data-lightbox-onclose  = on close, run named function
+   * 
+   * Submit button data options:
+   * 
+   * data-lightbox-ignore = do not handle clicking this button in lightbox
    */
   var _formSubmit = function(event) {
     // Gather data
@@ -141,21 +174,24 @@ VuFind.lightbox = (function() {
     var data = $(form).serializeArray();
     data.push({'name':'layout', 'value':'lightbox'}); // Return in lightbox, please
     // Add submit button information
-    var clicked = $(form).find('[type=submit]:focus');
-    if(clicked.length > 0) {
-      var name = clicked.attr('name') ? clicked.attr('name') : 'submit';
-      data.push({'name':name, 'value':clicked.attr('value') || 1});
+    var submit = $(_clickedButton);
+    _clickedButton = null;
+    if (submit.length > 0) {
+      if (typeof submit.data('lightbox-ignore') !== 'undefined') {
+        return true;  
+      }
+      // Prevent multiple submission of submit button in lightbox
+      if (submit.closest(_modal).length > 0) {
+        submit.attr('disabled', 'disabled');
+      }
+      var name = submit.attr('name') ? submit.attr('name') : 'submit';
+      data.push({'name':name, 'value':submit.attr('value') || 1});
     }
     // Special handlers
     if ('undefined' !== typeof dataset) {
       // On submit behavior
-      if("string" === typeof dataset.lightboxOnsubmit) {
-        var ret = null;
-        if ("function" === typeof window[dataset.lightboxOnsubmit]) {
-          ret = window[dataset.lightboxOnsubmit](event, data);
-        } else {
-          ret = eval('(function(event, data) {' + dataset.lightboxOnsubmit + '}())'); // inline code
-        }
+      if ('string' === typeof dataset.lightboxOnsubmit) {
+        var ret = _evalCallback(dataset.lightboxOnsubmit, event, data);
         // return true or false to send that to the form
         // return null or anything else to continue to the ajax
         if (ret === false || ret === true) {
@@ -163,9 +199,9 @@ VuFind.lightbox = (function() {
         }
       }
       // onclose behavior
-      if("string" === typeof dataset.lightboxOnclose && "function" === typeof window[dataset.lightboxOnclose]) {
-        document.addEventListener('VuFind.lightbox.closed', function() {
-          window[dataset.lightboxOnclose]();
+      if ('string' === typeof dataset.lightboxOnclose) {
+        document.addEventListener('VuFind.lightbox.closed', function(event) {
+          _evalCallback(dataset.lightboxOnclose, event);  
         }, false);
       }
     }
@@ -180,8 +216,35 @@ VuFind.lightbox = (function() {
 
     VuFind.modal('show');
     return false;
-  }
+  };
 
+  /**
+   * Evaluate a callback 
+   */
+  var _evalCallback = function(callback, event, data) {
+    if ('function' === typeof window[callback]) {
+      return window[callback](event, data);
+    } else {
+      return eval('(function(event, data) {' + callback + '}())'); // inline code  
+    }
+  };
+  
+  /**
+   * Reload the page without causing trouble with POST parameters while keeping hash
+   */
+  var _refreshPage = function() {
+    var parts = window.location.href.split('#');
+    if (typeof parts[1] === 'undefined') {
+      window.location.href = window.location.href;  
+    } else {
+      var href = parts[0];
+      // Force reload with a timestamp
+      href += href.indexOf('?') == -1 ? '?_=' : '&_=';
+      href += new Date().getTime() + '#' + parts[1];
+      window.location.href = href;
+    }
+  };
+  
   // Public: Attach listeners to the page
   var bind = function(target) {
     if ('undefined' === typeof target) {
@@ -193,6 +256,11 @@ VuFind.lightbox = (function() {
     $(target).find('form[data-lightbox]')
       .unbind('submit', _formSubmit)
       .on('submit', _formSubmit);
+    
+    // Handle submit buttons attached to a form as well as those in a form. Store 
+    // information about which button was clicked here as checking focused button 
+    // doesn't work on all browsers and platforms.
+    $('form[data-lightbox] [type=submit]').click(_storeClickedStatus);
   };
 
   // Reveal
@@ -218,7 +286,7 @@ VuFind.lightbox = (function() {
       _modalBody = _modal.find('.modal-body');
       _modal.on('hide.bs.modal', function() {
         if (VuFind.lightbox.refreshOnClose) {
-          window.location.reload();
+          _refreshPage();
         }
         document.dispatchEvent(new Event('VuFind.lightbox.closing'));
       });
@@ -227,7 +295,7 @@ VuFind.lightbox = (function() {
         VuFind.lightbox.reset();
       });
 
-      VuFind.modal = function(cmd) { _modal.modal(cmd); }
+      VuFind.modal = function(cmd) { _modal.modal(cmd); };
       bind();
     }
   };
diff --git a/themes/bootstrap3/templates/layout/layout.phtml b/themes/bootstrap3/templates/layout/layout.phtml
index 6853101137494ef0c1550b70a35d908a352b24cb..25ab54c4eabf813b2b6faf5e11d1114658feeb1c 100644
--- a/themes/bootstrap3/templates/layout/layout.phtml
+++ b/themes/bootstrap3/templates/layout/layout.phtml
@@ -34,6 +34,7 @@
             'bulk_noitems_advice' => 'bulk_noitems_advice',
             'bulk_save_success' => 'bulk_save_success',
             'close' => 'close',
+            'error_occurred' => 'An error has occurred',
             'go_to_list' => 'go_to_list',
             'libphonenumber_invalid' => 'libphonenumber_invalid',
             'libphonenumber_invalidcountry' => 'libphonenumber_invalidcountry',
diff --git a/themes/bootstrap3/templates/record/addtag.phtml b/themes/bootstrap3/templates/record/addtag.phtml
index 563cda1b8e130f6ce2d16482b42e28762cfeff16..2d0ea2f33ac535fcf9c6dabc0a04cc0fc871ce08 100644
--- a/themes/bootstrap3/templates/record/addtag.phtml
+++ b/themes/bootstrap3/templates/record/addtag.phtml
@@ -9,7 +9,7 @@
 ?>
 <div class="record">
   <h2><?=$this->transEsc('Add Tags') ?></h2>
-  <form method="post" name="tagRecord" class="form-horizontal" data-lightbox-onclose="refreshTagList">
+  <form method="post" name="tagRecord" class="form-horizontal" data-lightbox-onclose="refreshTagList();">
     <input type="hidden" name="submit" value="1" />
     <input type="hidden" name="id" value="<?=$this->escapeHtmlAttr($this->driver->getUniqueId())?>" />
     <input type="hidden" name="source" value="<?=$this->escapeHtmlAttr($this->driver->getSourceIdentifier())?>" />
diff --git a/themes/bootstrap3/templates/record/save.phtml b/themes/bootstrap3/templates/record/save.phtml
index febb5b1783eaa52229e5e415fa946b4e0cec1eb4..d53c1bb5f55a3c016116d6cfed7772acc722ddb2 100644
--- a/themes/bootstrap3/templates/record/save.phtml
+++ b/themes/bootstrap3/templates/record/save.phtml
@@ -8,7 +8,7 @@
     . '<li class="active">' . $this->transEsc('Save') . '</li>';
 ?>
 <h2><?=$this->transEsc("add_favorite_prefix") ?> <span class="title-in-heading"><?=$this->escapeHtml($this->driver->getBreadcrumb())?></span> <?=$this->transEsc("add_favorite_suffix") ?></h2>
-<form id="edit-save-form" class="form-horizontal" method="post" action="<?=$this->recordLink()->getActionUrl($this->driver, 'Save')?>" name="saveRecord" data-lightbox-onsubmit="VuFind.lightbox.refreshOnClose=true">
+<form id="edit-save-form" class="form-horizontal" method="post" action="<?=$this->recordLink()->getActionUrl($this->driver, 'Save')?>" name="saveRecord" data-lightbox-onclose="checkSaveStatuses();">
   <input type="hidden" name="submit" value="1" />
   <input type="hidden" name="id" value="<?=$this->escapeHtmlAttr($this->driver->getUniqueId()) ?>" />
   <input type="hidden" name="source" value="<?=$this->escapeHtmlAttr($this->driver->getSourceIdentifier())?>" />