diff --git a/module/VuFind/src/VuFind/Controller/AjaxController.php b/module/VuFind/src/VuFind/Controller/AjaxController.php
index 72ef9fbe439c3b2a68b94cfa056a68c44737696a..edcfa676c881eaec837ae0a378c3bf8e51a3c862 100644
--- a/module/VuFind/src/VuFind/Controller/AjaxController.php
+++ b/module/VuFind/src/VuFind/Controller/AjaxController.php
@@ -88,12 +88,13 @@ class AjaxController extends AbstractBase
                     ? ': ' . $e->getMessage() : '';
                 return $this->output(
                     $this->translate('An error has occurred') . $debugMsg,
-                    self::STATUS_ERROR
+                    self::STATUS_ERROR,
+                    500
                 );
             }
         } else {
             return $this->output(
-                $this->translate('Invalid Method'), self::STATUS_ERROR
+                $this->translate('Invalid Method'), self::STATUS_ERROR, 400
             );
         }
     }
@@ -478,7 +479,8 @@ class AjaxController extends AbstractBase
         if (!$user) {
             return $this->output(
                 $this->translate('You must be logged in first'),
-                self::STATUS_NEED_AUTH
+                self::STATUS_NEED_AUTH,
+                401
             );
         }
 
@@ -490,7 +492,8 @@ class AjaxController extends AbstractBase
         if (!is_array($ids) || !is_array($sources)) {
             return $this->output(
                 $this->translate('Argument must be array.'),
-                self::STATUS_ERROR
+                self::STATUS_ERROR,
+                400
             );
         }
         $result = [];
@@ -611,7 +614,8 @@ class AjaxController extends AbstractBase
         } catch (AuthException $e) {
             return $this->output(
                 $this->translate($e->getMessage()),
-                self::STATUS_ERROR
+                self::STATUS_ERROR,
+                401
             );
         }
 
@@ -629,7 +633,8 @@ class AjaxController extends AbstractBase
         if ($user === false) {
             return $this->output(
                 $this->translate('You must be logged in first'),
-                self::STATUS_NEED_AUTH
+                self::STATUS_NEED_AUTH,
+                401
             );
         }
         // empty tag
@@ -650,7 +655,8 @@ class AjaxController extends AbstractBase
         } catch (\Exception $e) {
             return $this->output(
                 ('development' == APPLICATION_ENV) ? $e->getMessage() : 'Failed',
-                self::STATUS_ERROR
+                self::STATUS_ERROR,
+                500
             );
         }
 
@@ -886,71 +892,56 @@ class AjaxController extends AbstractBase
         $id = $this->params()->fromQuery('id');
         $data = $this->params()->fromQuery('data');
         $requestType = $this->params()->fromQuery('requestType');
-        if (!empty($id) && !empty($data)) {
-            // check if user is logged in
-            $user = $this->getUser();
-            if (!$user) {
-                return $this->output(
-                    [
-                        'status' => false,
-                        'msg' => $this->translate('You must be logged in first')
-                    ],
-                    self::STATUS_NEED_AUTH
-                );
-            }
-
-            try {
-                $catalog = $this->getILS();
-                $patron = $this->getILSAuthenticator()->storedCatalogLogin();
-                if ($patron) {
-                    switch ($requestType) {
-                    case 'ILLRequest':
-                        $results = $catalog->checkILLRequestIsValid(
-                            $id, $data, $patron
-                        );
-
-                        $msg = $results
-                            ? $this->translate(
-                                'ill_request_place_text'
-                            )
-                            : $this->translate(
-                                'ill_request_error_blocked'
-                            );
-                        break;
-                    case 'StorageRetrievalRequest':
-                        $results = $catalog->checkStorageRetrievalRequestIsValid(
-                            $id, $data, $patron
-                        );
-
-                        $msg = $results
-                            ? $this->translate(
-                                'storage_retrieval_request_place_text'
-                            )
-                            : $this->translate(
-                                'storage_retrieval_request_error_blocked'
-                            );
-                        break;
-                    default:
-                        $results = $catalog->checkRequestIsValid(
-                            $id, $data, $patron
-                        );
+        if (empty($id) || empty($data)) {
+            return $this->output(
+                $this->translate('bulk_error_missing'),
+                self::STATUS_ERROR,
+                400
+            );
+        }
+        // check if user is logged in
+        $user = $this->getUser();
+        if (!$user) {
+            return $this->output(
+                $this->translate('You must be logged in first'),
+                self::STATUS_NEED_AUTH,
+                401
+            );
+        }
 
-                        $msg = $results
-                            ? $this->translate('request_place_text')
-                            : $this->translate('hold_error_blocked');
-                        break;
-                    }
-                    return $this->output(
-                        ['status' => $results, 'msg' => $msg], self::STATUS_OK
+        try {
+            $catalog = $this->getILS();
+            $patron = $this->getILSAuthenticator()->storedCatalogLogin();
+            if ($patron) {
+                switch ($requestType) {
+                case 'ILLRequest':
+                    $results = $catalog->checkILLRequestIsValid($id, $data, $patron);
+                    $msg = $results
+                        ? 'ill_request_place_text' : 'ill_request_error_blocked';
+                    break;
+                case 'StorageRetrievalRequest':
+                    $results = $catalog->checkStorageRetrievalRequestIsValid(
+                        $id, $data, $patron
                     );
+                    $msg = $results ? 'storage_retrieval_request_place_text'
+                        : 'storage_retrieval_request_error_blocked';
+                    break;
+                default:
+                    $results = $catalog->checkRequestIsValid($id, $data, $patron);
+                    $msg = $results ? 'request_place_text' : 'hold_error_blocked';
+                    break;
                 }
-            } catch (\Exception $e) {
-                // Do nothing -- just fail through to the error message below.
+                return $this->output(
+                    ['status' => $results, 'msg' => $this->translate($msg)],
+                    self::STATUS_OK
+                );
             }
+        } catch (\Exception $e) {
+            // Do nothing -- just fail through to the error message below.
         }
 
         return $this->output(
-            $this->translate('An error has occurred'), self::STATUS_ERROR
+            $this->translate('An error has occurred'), self::STATUS_ERROR, 500
         );
     }
 
@@ -965,7 +956,8 @@ class AjaxController extends AbstractBase
         if ($user === false) {
             return $this->output(
                 $this->translate('You must be logged in first'),
-                self::STATUS_NEED_AUTH
+                self::STATUS_NEED_AUTH,
+                401
             );
         }
 
@@ -973,7 +965,9 @@ class AjaxController extends AbstractBase
         $comment = $this->params()->fromPost('comment');
         if (empty($id) || empty($comment)) {
             return $this->output(
-                $this->translate('An error has occurred'), self::STATUS_ERROR
+                $this->translate('bulk_error_missing'),
+                self::STATUS_ERROR,
+                400
             );
         }
 
@@ -997,15 +991,25 @@ class AjaxController extends AbstractBase
         if ($user === false) {
             return $this->output(
                 $this->translate('You must be logged in first'),
-                self::STATUS_NEED_AUTH
+                self::STATUS_NEED_AUTH,
+                401
             );
         }
 
         $id = $this->params()->fromQuery('id');
+        if (empty($id)) {
+            return $this->output(
+                $this->translate('bulk_error_missing'),
+                self::STATUS_ERROR,
+                400
+            );
+        }
         $table = $this->getTable('Comments');
-        if (empty($id) || !$table->deleteIfOwnedByUser($id, $user)) {
+        if (!$table->deleteIfOwnedByUser($id, $user)) {
             return $this->output(
-                $this->translate('An error has occurred'), self::STATUS_ERROR
+                $this->translate('edit_list_fail'),
+                self::STATUS_ERROR,
+                403
             );
         }
 
@@ -1076,7 +1080,8 @@ class AjaxController extends AbstractBase
         if (!$pluginManager->has($resolverType)) {
             return $this->output(
                 $this->translate("Could not load driver for $resolverType"),
-                self::STATUS_ERROR
+                self::STATUS_ERROR,
+                500
             );
         }
         $resolver = new \VuFind\Resolver\Connection(
@@ -1151,46 +1156,45 @@ class AjaxController extends AbstractBase
         $this->writeSession();  // avoid session write timing bug
         $id = $this->params()->fromQuery('id');
         $pickupLib = $this->params()->fromQuery('pickupLib');
-        if (!empty($id) && !empty($pickupLib)) {
-            // check if user is logged in
-            $user = $this->getUser();
-            if (!$user) {
-                return $this->output(
-                    [
-                        'status' => false,
-                        'msg' => $this->translate('You must be logged in first')
-                    ],
-                    self::STATUS_NEED_AUTH
-                );
-            }
+        if (empty($id) || empty($pickupLib)) {
+            return $this->output(
+                $this->translate('bulk_error_missing'),
+                self::STATUS_ERROR,
+                400
+            );
+        }
+        // check if user is logged in
+        $user = $this->getUser();
+        if (!$user) {
+            return $this->output(
+                $this->translate('You must be logged in first'),
+                self::STATUS_NEED_AUTH,
+                401
+            );
+        }
 
-            try {
-                $catalog = $this->getILS();
-                $patron = $this->getILSAuthenticator()->storedCatalogLogin();
-                if ($patron) {
-                    $results = $catalog->getILLPickupLocations(
-                        $id, $pickupLib, $patron
-                    );
-                    foreach ($results as &$result) {
-                        if (isset($result['name'])) {
-                            $result['name'] = $this->translate(
-                                'location_' . $result['name'],
-                                [],
-                                $result['name']
-                            );
-                        }
+        try {
+            $catalog = $this->getILS();
+            $patron = $this->getILSAuthenticator()->storedCatalogLogin();
+            if ($patron) {
+                $results = $catalog->getILLPickupLocations($id, $pickupLib, $patron);
+                foreach ($results as &$result) {
+                    if (isset($result['name'])) {
+                        $result['name'] = $this->translate(
+                            'location_' . $result['name'],
+                            [],
+                            $result['name']
+                        );
                     }
-                    return $this->output(
-                        ['locations' => $results], self::STATUS_OK
-                    );
                 }
-            } catch (\Exception $e) {
-                // Do nothing -- just fail through to the error message below.
+                return $this->output(['locations' => $results], self::STATUS_OK);
             }
+        } catch (\Exception $e) {
+            // Do nothing -- just fail through to the error message below.
         }
 
         return $this->output(
-            $this->translate('An error has occurred'), self::STATUS_ERROR
+            $this->translate('An error has occurred'), self::STATUS_ERROR, 500
         );
     }
 
@@ -1204,50 +1208,49 @@ class AjaxController extends AbstractBase
         $this->writeSession();  // avoid session write timing bug
         $id = $this->params()->fromQuery('id');
         $requestGroupId = $this->params()->fromQuery('requestGroupId');
-        if (!empty($id) && !empty($requestGroupId)) {
-            // check if user is logged in
-            $user = $this->getUser();
-            if (!$user) {
-                return $this->output(
-                    [
-                        'status' => false,
-                        'msg' => $this->translate('You must be logged in first')
-                    ],
-                    self::STATUS_NEED_AUTH
-                );
-            }
+        if (empty($id) || empty($requestGroupId)) {
+            return $this->output(
+                $this->translate('bulk_error_missing'),
+                self::STATUS_ERROR,
+                400
+            );
+        }
+        // check if user is logged in
+        $user = $this->getUser();
+        if (!$user) {
+            return $this->output(
+                $this->translate('You must be logged in first'),
+                self::STATUS_NEED_AUTH,
+                401
+            );
+        }
 
-            try {
-                $catalog = $this->getILS();
-                $patron = $this->getILSAuthenticator()->storedCatalogLogin();
-                if ($patron) {
-                    $details = [
-                        'id' => $id,
-                        'requestGroupId' => $requestGroupId
-                    ];
-                    $results = $catalog->getPickupLocations(
-                        $patron, $details
-                    );
-                    foreach ($results as &$result) {
-                        if (isset($result['locationDisplay'])) {
-                            $result['locationDisplay'] = $this->translate(
-                                'location_' . $result['locationDisplay'],
-                                [],
-                                $result['locationDisplay']
-                            );
-                        }
+        try {
+            $catalog = $this->getILS();
+            $patron = $this->getILSAuthenticator()->storedCatalogLogin();
+            if ($patron) {
+                $details = [
+                    'id' => $id,
+                    'requestGroupId' => $requestGroupId
+                ];
+                $results = $catalog->getPickupLocations($patron, $details);
+                foreach ($results as &$result) {
+                    if (isset($result['locationDisplay'])) {
+                        $result['locationDisplay'] = $this->translate(
+                            'location_' . $result['locationDisplay'],
+                            [],
+                            $result['locationDisplay']
+                        );
                     }
-                    return $this->output(
-                        ['locations' => $results], self::STATUS_OK
-                    );
                 }
-            } catch (\Exception $e) {
-                // Do nothing -- just fail through to the error message below.
+                return $this->output(['locations' => $results], self::STATUS_OK);
             }
+        } catch (\Exception $e) {
+            // Do nothing -- just fail through to the error message below.
         }
 
         return $this->output(
-            $this->translate('An error has occurred'), self::STATUS_ERROR
+            $this->translate('An error has occurred'), self::STATUS_ERROR, 500
         );
     }
 
diff --git a/themes/bootstrap3/js/check_item_statuses.js b/themes/bootstrap3/js/check_item_statuses.js
index 45ba11f6f39716cfad2f775356da060c86abad20..0aeec0d860ad510de4fcb9fed2fdeee818c723a5 100644
--- a/themes/bootstrap3/js/check_item_statuses.js
+++ b/themes/bootstrap3/js/check_item_statuses.js
@@ -13,75 +13,76 @@ function checkItemStatuses() {
     dataType: 'json',
     method: 'POST',
     url: VuFind.getPath() + '/AJAX/JSON?method=getItemStatuses',
-    data: {id:id},
-    success: function(response) {
-      if(response.status == 'OK') {
-        $.each(response.data, function(i, result) {
-          var item = $($('.ajaxItem')[result.record_number]);
+    data: {id:id}
+  })
+  .done(function(response) {
+    $.each(response.data, function(i, result) {
+      var item = $($('.ajaxItem')[result.record_number]);
 
-          item.find('.status').empty().append(result.availability_message);
-          if (typeof(result.full_status) != 'undefined'
-            && result.full_status.length > 0
-            && item.find('.callnumAndLocation').length > 0
+      item.find('.status').empty().append(result.availability_message);
+      if (typeof(result.full_status) != 'undefined'
+        && result.full_status.length > 0
+        && item.find('.callnumAndLocation').length > 0
+      ) {
+        // Full status mode is on -- display the HTML and hide extraneous junk:
+        item.find('.callnumAndLocation').empty().append(result.full_status);
+        item.find('.callnumber').addClass('hidden');
+        item.find('.location').addClass('hidden');
+        item.find('.hideIfDetailed').addClass('hidden');
+        item.find('.status').addClass('hidden');
+      } else if (typeof(result.missing_data) != 'undefined'
+        && result.missing_data
+      ) {
+        // No data is available -- hide the entire status area:
+        item.find('.callnumAndLocation').addClass('hidden');
+        item.find('.status').addClass('hidden');
+      } else if (result.locationList) {
+        // We have multiple locations -- build appropriate HTML and hide unwanted labels:
+        item.find('.callnumber').addClass('hidden');
+        item.find('.hideIfDetailed').addClass('hidden');
+        item.find('.location').addClass('hidden');
+        var locationListHTML = "";
+        for (var x=0; x<result.locationList.length; x++) {
+          locationListHTML += '<div class="groupLocation">';
+          if (result.locationList[x].availability) {
+            locationListHTML += '<i class="fa fa-ok text-success"></i> <span class="text-success">'
+              + result.locationList[x].location + '</span> ';
+          } else if (typeof(result.locationList[x].status_unknown) !== 'undefined'
+              && result.locationList[x].status_unknown
           ) {
-            // Full status mode is on -- display the HTML and hide extraneous junk:
-            item.find('.callnumAndLocation').empty().append(result.full_status);
-            item.find('.callnumber').addClass('hidden');
-            item.find('.location').addClass('hidden');
-            item.find('.hideIfDetailed').addClass('hidden');
-            item.find('.status').addClass('hidden');
-          } else if (typeof(result.missing_data) != 'undefined'
-            && result.missing_data
-          ) {
-            // No data is available -- hide the entire status area:
-            item.find('.callnumAndLocation').addClass('hidden');
-            item.find('.status').addClass('hidden');
-          } else if (result.locationList) {
-            // We have multiple locations -- build appropriate HTML and hide unwanted labels:
-            item.find('.callnumber').addClass('hidden');
-            item.find('.hideIfDetailed').addClass('hidden');
-            item.find('.location').addClass('hidden');
-            var locationListHTML = "";
-            for (var x=0; x<result.locationList.length; x++) {
-              locationListHTML += '<div class="groupLocation">';
-              if (result.locationList[x].availability) {
-                locationListHTML += '<i class="fa fa-ok text-success"></i> <span class="text-success">'
-                  + result.locationList[x].location + '</span> ';
-              } else if (typeof(result.locationList[x].status_unknown) !== 'undefined'
-                  && result.locationList[x].status_unknown
-              ) {
-                if (result.locationList[x].location) {
-                  locationListHTML += '<i class="fa fa-status-unknown text-warning"></i> <span class="text-warning">' 
-                    + result.locationList[x].location + '</span> ';
-                }
-              } else {
-                locationListHTML += '<i class="fa fa-remove text-error"></i> <span class="text-error"">'
-                  + result.locationList[x].location + '</span> ';
-              }
-              locationListHTML += '</div>';
-              locationListHTML += '<div class="groupCallnumber">';
-              locationListHTML += (result.locationList[x].callnumbers)
-                   ?  result.locationList[x].callnumbers : '';
-              locationListHTML += '</div>';
+            if (result.locationList[x].location) {
+              locationListHTML += '<i class="fa fa-status-unknown text-warning"></i> <span class="text-warning">'
+                + result.locationList[x].location + '</span> ';
             }
-            item.find('.locationDetails').removeClass('hidden');
-            item.find('.locationDetails').empty().append(locationListHTML);
           } else {
-            // Default case -- load call number and location into appropriate containers:
-            item.find('.callnumber').empty().append(result.callnumber+'<br/>');
-            item.find('.location').empty().append(
-              result.reserve == 'true'
-              ? result.reserve_message
-              : result.location
-            );
+            locationListHTML += '<i class="fa fa-remove text-danger"></i> <span class="text-danger"">'
+              + result.locationList[x].location + '</span> ';
           }
-        });
+          locationListHTML += '</div>';
+          locationListHTML += '<div class="groupCallnumber">';
+          locationListHTML += (result.locationList[x].callnumbers)
+               ?  result.locationList[x].callnumbers : '';
+          locationListHTML += '</div>';
+        }
+        item.find('.locationDetails').removeClass('hidden');
+        item.find('.locationDetails').empty().append(locationListHTML);
       } else {
-        // display the error message on each of the ajax status place holder
-        $(".ajax-availability").empty().append(response.data);
+        // Default case -- load call number and location into appropriate containers:
+        item.find('.callnumber').empty().append(result.callnumber+'<br/>');
+        item.find('.location').empty().append(
+          result.reserve == 'true'
+          ? result.reserve_message
+          : result.location
+        );
       }
-      $(".ajax-availability").removeClass('ajax-availability');
-    }
+    });
+
+    $(".ajax-availability").removeClass('ajax-availability');
+  })
+  .fail(function(response, textStatus) {
+    if (textStatus == "abort") { return; }
+    // display the error message on each of the ajax status place holder
+    $(".ajax-availability").empty().append(response.responseJSON.data).addClass('text-danger');
   });
 }
 
diff --git a/themes/bootstrap3/js/check_save_statuses.js b/themes/bootstrap3/js/check_save_statuses.js
index a7259a62c8421ebffe9eb49d7892146732d46312..032c7eda006a563e225f76ef173146fd08ddd11c 100644
--- a/themes/bootstrap3/js/check_save_statuses.js
+++ b/themes/bootstrap3/js/check_save_statuses.js
@@ -18,23 +18,21 @@ function checkSaveStatuses() {
       dataType: 'json',
       method: 'POST',
       url: VuFind.getPath() + '/AJAX/JSON?method=getSaveStatuses',
-      data: {id:ids, 'source':srcs},
-      success: function(response) {
-        if(response.status == 'OK') {
-          for (var rn in response.data) {
-            var list = $('#result'+rn).find('.savedLists')
-            if (list.length == 0) {
-              list = $('.savedLists');
-            }
-            var html = list.find('strong')[0].outerHTML+'<ul>';
-            for (var i=0; i<response.data[rn].length; i++) {
-              html += '<li><a href="' + VuFind.getPath() + '/MyResearch/MyList/' + response.data[rn][i].list_id + '">'
-                       + response.data[rn][i].list_title + '</a></li>';
-            }
-            html += '</ul>';
-            list.html(html).removeClass('hidden');
-          }
+      data: {id:ids, 'source':srcs}
+    })
+    .done(function(response) {
+      for (var rn in response.data) {
+        var list = $('#result'+rn).find('.savedLists')
+        if (list.length == 0) {
+          list = $('.savedLists');
         }
+        var html = list.find('strong')[0].outerHTML+'<ul>';
+        for (var i=0; i<response.data[rn].length; i++) {
+          html += '<li><a href="' + VuFind.getPath() + '/MyResearch/MyList/' + response.data[rn][i].list_id + '">'
+                   + response.data[rn][i].list_title + '</a></li>';
+        }
+        html += '</ul>';
+        list.html(html).removeClass('hidden');
       }
     });
   }
diff --git a/themes/bootstrap3/js/common.js b/themes/bootstrap3/js/common.js
index 9528b20897e4bb544ae99dea97cdddfd4ab52694..de3aa0505695d1a05a593d76756c19b8f1a9f3f5 100644
--- a/themes/bootstrap3/js/common.js
+++ b/themes/bootstrap3/js/common.js
@@ -1,5 +1,8 @@
 /*global btoa, console, hexEncode, isPhoneNumberValid, Lightbox, rc4Encrypt, unescape, VuFind */
 
+// IE 9< console polyfill
+window.console = window.console || {log: function () {}};
+
 function VuFindNamespace(p, s, dsb) {
   var defaultSearchBackend = dsb;
   var path = p;
@@ -196,57 +199,49 @@ function newAccountHandler(html) {
 function ajaxLogin(form) {
   Lightbox.ajax({
     url: VuFind.getPath() + '/AJAX/JSON?method=getSalt',
-    dataType: 'json',
-    success: function(response) {
-      if (response.status == 'OK') {
-        var salt = response.data;
-
-        // extract form values
-        var params = {};
-        for (var i = 0; i < form.length; i++) {
-          // special handling for password
-          if (form.elements[i].name == 'password') {
-            // base-64 encode the password (to allow support for Unicode)
-            // and then encrypt the password with the salt
-            var password = rc4Encrypt(
-                salt, btoa(unescape(encodeURIComponent(form.elements[i].value)))
-            );
-            // hex encode the encrypted password
-            params[form.elements[i].name] = hexEncode(password);
-          } else {
-            params[form.elements[i].name] = form.elements[i].value;
-          }
-        }
+    dataType: 'json'
+  })
+  .done(function(response) {
+    var salt = response.data;
 
-        // login via ajax
-        Lightbox.ajax({
-          type: 'POST',
-          url: VuFind.getPath() + '/AJAX/JSON?method=login',
-          dataType: 'json',
-          data: params,
-          success: function(response) {
-            if (response.status == 'OK') {
-              Lightbox.addCloseAction(refreshPageForLogin);
-              // and we update the modal
-              var params = deparam(Lightbox.lastURL);
-              if (params['subaction'] == 'UserLogin') {
-                Lightbox.close();
-              } else {
-                Lightbox.getByUrl(
-                  Lightbox.lastURL,
-                  Lightbox.lastPOST,
-                  Lightbox.changeContent
-                );
-              }
-            } else {
-              Lightbox.displayError(response.data);
-            }
-          }
-        });
+    // extract form values
+    var params = {};
+    for (var i = 0; i < form.length; i++) {
+      // special handling for password
+      if (form.elements[i].name == 'password') {
+        // base-64 encode the password (to allow support for Unicode)
+        // and then encrypt the password with the salt
+        var password = rc4Encrypt(
+            salt, btoa(unescape(encodeURIComponent(form.elements[i].value)))
+        );
+        // hex encode the encrypted password
+        params[form.elements[i].name] = hexEncode(password);
       } else {
-        Lightbox.displayError(response.data);
+        params[form.elements[i].name] = form.elements[i].value;
       }
     }
+
+    // login via ajax
+    Lightbox.ajax({
+      type: 'POST',
+      url: VuFind.getPath() + '/AJAX/JSON?method=login',
+      dataType: 'json',
+      data: params
+    })
+    .done(function(response) {
+      Lightbox.addCloseAction(refreshPageForLogin);
+      // and we update the modal
+      var params = deparam(Lightbox.lastURL);
+      if (params['subaction'] == 'UserLogin') {
+        Lightbox.close();
+      } else {
+        Lightbox.getByUrl(
+          Lightbox.lastURL,
+          Lightbox.lastPOST,
+          Lightbox.changeContent
+        );
+      }
+    });
   });
 }
 
@@ -325,7 +320,7 @@ function setupAutocomplete() {
           },
           dataType:'json',
           success: function(json) {
-            if (json.status == 'OK' && json.data.length > 0) {
+            if (json.data.length > 0) {
               var datums = [];
               for (var i=0;i<json.data.length;i++) {
                 datums.push(json.data[i]);
diff --git a/themes/bootstrap3/js/hierarchyTree.js b/themes/bootstrap3/js/hierarchyTree.js
index 20b906b56c95dc7040214d6bb28f35aa770d368f..a4f24c9de44058c5eeb5aacac0a940cb1abf12cf 100644
--- a/themes/bootstrap3/js/hierarchyTree.js
+++ b/themes/bootstrap3/js/hierarchyTree.js
@@ -27,18 +27,16 @@ function html_entity_decode(string, quote_style) {
 function getRecord(recordID) {
   $.ajax({
     url: VuFind.getPath() + '/Hierarchy/GetRecord?' + $.param({id: recordID}),
-    dataType: 'html',
-    success: function(response) {
-      if (response) {
-        $('#hierarchyRecord').html(html_entity_decode(response));
-        // Remove the old path highlighting
-        $('#hierarchyTree a').removeClass("jstree-highlight");
-        // Add Current path highlighting
-        var jsTreeNode = $(":input[value='"+recordID+"']").parent();
-        jsTreeNode.children("a").addClass("jstree-highlight");
-        jsTreeNode.parents("li").children("a").addClass("jstree-highlight");
-      }
-    }
+    dataType: 'html'
+  })
+  .done(function(response) {
+    $('#hierarchyRecord').html(html_entity_decode(response));
+    // Remove the old path highlighting
+    $('#hierarchyTree a').removeClass("jstree-highlight");
+    // Add Current path highlighting
+    var jsTreeNode = $(":input[value='"+recordID+"']").parent();
+    jsTreeNode.children("a").addClass("jstree-highlight");
+    jsTreeNode.parents("li").children("a").addClass("jstree-highlight");
   });
 }
 
@@ -78,27 +76,27 @@ function doTreeSearch() {
         'lookfor': keyword,
         'hierarchyID': hierarchyID,
         'type': $("#treeSearchType").val()
-      }) + "&format=true",
-      'success': function(data) {
-        if(data.results.length > 0) {
-          $('#hierarchyTree').find('.jstree-search').removeClass('jstree-search');
-          var tree = $('#hierarchyTree').jstree(true);
-          tree.close_all();
-          for(var i=data.results.length;i--;) {
-            var id = htmlEncodeId(data.results[i]);
-            tree._open_to(id);
-          }
-          for(i=data.results.length;i--;) {
-            var tid = htmlEncodeId(data.results[i]);
-            $('#hierarchyTree').find('#'+tid).addClass('jstree-search');
-          }
-          changeNoResultLabel(false);
-          changeLimitReachedLabel(data.limitReached);
-        } else {
-          changeNoResultLabel(true);
+      }) + "&format=true"
+    })
+    .done(function(data) {
+      if(data.results.length > 0) {
+        $('#hierarchyTree').find('.jstree-search').removeClass('jstree-search');
+        var tree = $('#hierarchyTree').jstree(true);
+        tree.close_all();
+        for(var i=data.results.length;i--;) {
+          var id = htmlEncodeId(data.results[i]);
+          tree._open_to(id);
         }
-        $('#treeSearchLoadingImg').addClass('hidden');
+        for(i=data.results.length;i--;) {
+          var tid = htmlEncodeId(data.results[i]);
+          $('#hierarchyTree').find('#'+tid).addClass('jstree-search');
+        }
+        changeNoResultLabel(false);
+        changeLimitReachedLabel(data.limitReached);
+      } else {
+        changeNoResultLabel(true);
       }
+      $('#treeSearchLoadingImg').addClass('hidden');
     });
   }
 }
@@ -127,17 +125,18 @@ function buildJSONNodes(xml) {
 }
 
 function buildTreeWithXml(cb) {
-  $.ajax({'url': VuFind.getPath() + '/Hierarchy/GetTree',
+  $.ajax({
+    'url': VuFind.getPath() + '/Hierarchy/GetTree',
     'data': {
       'hierarchyID': hierarchyID,
       'id': recordID,
       'context': hierarchyContext,
       'mode': 'Tree'
-    },
-    'success': function(xml) {
-      var nodes = buildJSONNodes($(xml).find('root'));
-      cb.call(this, nodes);
     }
+  })
+  .done(function(xml) {
+    var nodes = buildJSONNodes($(xml).find('root'));
+    cb.call(this, nodes);
   });
 }
 
diff --git a/themes/bootstrap3/js/hold.js b/themes/bootstrap3/js/hold.js
index 4895a5ab3447543c44999d7cd34d1adfc5056a0e..a34780b1ba58309e7f4afe229bcca6c69294080c 100644
--- a/themes/bootstrap3/js/hold.js
+++ b/themes/bootstrap3/js/hold.js
@@ -17,25 +17,24 @@ function setUpHoldRequestForm(recordId) {
       data: params,
       dataType: 'json',
       cache: false,
-      url: VuFind.getPath() + '/AJAX/JSON',
-      success: function(response) {
-        if (response.status == 'OK') {
-          var defaultValue = $('#pickUpLocation').data('default');
-          $.each(response.data.locations, function() {
-            var option = $('<option></option>').attr('value', this.locationID).text(this.locationDisplay);
-            if (this.locationID == defaultValue || (defaultValue == '' && this.isDefault && $emptyOption.length == 0)) {
-              option.attr('selected', 'selected');
-            }
-            $('#pickUpLocation').append(option);
-          });
+      url: VuFind.getPath() + '/AJAX/JSON'
+    })
+    .done(function(response) {
+      var defaultValue = $('#pickUpLocation').data('default');
+      $.each(response.data.locations, function() {
+        var option = $('<option></option>').attr('value', this.locationID).text(this.locationDisplay);
+        if (this.locationID == defaultValue || (defaultValue == '' && this.isDefault && $emptyOption.length == 0)) {
+          option.attr('selected', 'selected');
         }
-        $('#pickUpLocationLabel i').removeClass("fa fa-spinner icon-spin");
-        $('#pickUpLocation').removeAttr('disabled');
-      },
-      fail: function() {
-        $('#pickUpLocationLabel i').removeClass("fa fa-spinner icon-spin");
-        $('#pickUpLocation').removeAttr('disabled');
-      }
+        $('#pickUpLocation').append(option);
+      });
+
+      $('#pickUpLocationLabel i').removeClass("fa fa-spinner icon-spin");
+      $('#pickUpLocation').removeAttr('disabled');
+    })
+    .fail(function(response) {
+      $('#pickUpLocationLabel i').removeClass("fa fa-spinner icon-spin");
+      $('#pickUpLocation').removeAttr('disabled');
     });
   });
   $('#requestGroupId').change();
diff --git a/themes/bootstrap3/js/ill.js b/themes/bootstrap3/js/ill.js
index e9033271d002878188f8cec5774cb8800d0e467d..cdef12d3c19d6a396b1d9843e11c2650bbd9f4de 100644
--- a/themes/bootstrap3/js/ill.js
+++ b/themes/bootstrap3/js/ill.js
@@ -11,22 +11,20 @@ function setUpILLRequestForm(recordId) {
     $.ajax({
       dataType: 'json',
       cache: false,
-      url: url,
-      success: function(response) {
-        if (response.status == 'OK') {
-          $.each(response.data.locations, function() {
-            var option = $("<option></option>").attr("value", this.id).text(this.name);
-            if (this.isDefault) {
-              option.attr("selected", "selected");
-            }
-            $("#ILLRequestForm #pickupLibraryLocation").append(option);
-          });
+      url: url
+    })
+    .done(function(response) {
+      $.each(response.data.locations, function() {
+        var option = $("<option></option>").attr("value", this.id).text(this.name);
+        if (this.isDefault) {
+          option.attr("selected", "selected");
         }
-        $("#ILLRequestForm #pickupLibraryLocationLabel i").removeClass("fa fa-spinner icon-spin");
-      },
-      fail: function() {
-        $("#ILLRequestForm #pickupLibraryLocationLabel i").removeClass("fa fa-spinner icon-spin");
-      }
+        $("#ILLRequestForm #pickupLibraryLocation").append(option);
+      });
+      $("#ILLRequestForm #pickupLibraryLocationLabel i").removeClass("fa fa-spinner icon-spin");
+    })
+    .fail(function(response) {
+      $("#ILLRequestForm #pickupLibraryLocationLabel i").removeClass("fa fa-spinner icon-spin");
     });
   });
   $("#ILLRequestForm #pickupLibrary").change();
diff --git a/themes/bootstrap3/js/lightbox.js b/themes/bootstrap3/js/lightbox.js
index 531dc25b2edb29bc9685cbb747ba030423050119..5ac629f9c6ed3749c0db388763623ebc19583891 100644
--- a/themes/bootstrap3/js/lightbox.js
+++ b/themes/bootstrap3/js/lightbox.js
@@ -75,11 +75,25 @@ var Lightbox = {
    * We store all the ajax calls in case we need to cancel.
    * This function cancels the previous call and creates a new one.
    */
-  ajax: function(obj) {
+  ajax: function(obj) {
     if(this.XHR) {
       this.XHR.abort();
     }
-    this.XHR = $.ajax(obj);
+    this.XHR = $.ajax(obj)
+    this.XHR.then().fail(function(response, textStatus) {
+      if (textStatus == "abort") { return; }
+      if (response.responseJSON) {
+        Lightbox.displayError(response.responseJSON.data);
+      } else {
+        var json = JSON.parse(response.responseText);
+        if (json.data) {
+          Lightbox.displayError(json.data);
+        } else {
+          Lightbox.displayError(response.responseText);
+        }
+      }
+    });
+    return this.XHR;
   },
   /**********************************/
   /* ====== LIGHTBOX ACTIONS ====== */
@@ -227,24 +241,12 @@ var Lightbox = {
     this.ajax({
       type:'POST',
       url:url,
-      data:post,
-      success:function(html) { // Success!
-        callback(html);
-      },
-      error:function(d,e) {
-        if (d.status == 200) {
-          try {
-            var data = JSON.parse(d.responseText);
-            Lightbox.changeContent('<p class="alert alert-danger">'+data.data+'</p>');
-          } catch(error) {
-            Lightbox.changeContent('<p class="alert alert-danger">'+d.responseText+'</p>');
-          }
-        } else if(d.status > 0) {
-          Lightbox.changeContent('<p class="alert alert-danger">'+d.statusText+' ('+d.status+')</p>');
-        }
-        console.log(e,d); // Error reporting
-        console.log(url,post);
-      }
+      data:post
+    })
+    .done(callback)
+    .fail(function(response, textStatus) {
+      console.log(response, textStatus); // Error reporting
+      console.log(url, post);
     });
     // Store current "page" context for empty targets
     if(this.openingURL === false) {
@@ -474,22 +476,19 @@ $(document).ready(function() {
   });
 
   Lightbox.addFormHandler('exportForm', function(evt) {
-    $.ajax({
+    Lightbox.ajax({
       url: VuFind.getPath() + '/AJAX/JSON?' + $.param({method:'exportFavorites'}),
       type:'POST',
       dataType:'json',
-      data:Lightbox.getFormData($(evt.target)),
-      success:function(data) {
-        if(data.data.export_type == 'download' || data.data.needs_redirect) {
-          document.location.href = data.data.result_url;
-          Lightbox.close();
-          return false;
-        } else {
-          Lightbox.changeContent(data.data.result_additional);
-        }
-      },
-      error:function(d,e) {
-        //console.log(d,e); // Error reporting
+      data:Lightbox.getFormData($(evt.target))
+    })
+    .done(function(data) {
+      if(data.data.export_type == 'download' || data.data.needs_redirect) {
+        document.location.href = data.data.result_url;
+        Lightbox.close();
+        return false;
+      } else {
+        Lightbox.changeContent(data.data.result_additional);
       }
     });
     return false;
diff --git a/themes/bootstrap3/js/openurl.js b/themes/bootstrap3/js/openurl.js
index 7d9f4432e2c6fb9415700db59675baecca2f9d86..3594d138048f2cf20c8e807549b1594ae58fa32b 100644
--- a/themes/bootstrap3/js/openurl.js
+++ b/themes/bootstrap3/js/openurl.js
@@ -5,16 +5,15 @@ function loadResolverLinks($target, openUrl) {
   var url = VuFind.getPath() + '/AJAX/JSON?' + $.param({method:'getResolverLinks',openurl:openUrl});
   $.ajax({
     dataType: 'json',
-    url: url,
-    success: function(response) {
-      if (response.status == 'OK') {
-        $target.removeClass('ajax_availability')
-          .empty().append(response.data);
-      } else {
-        $target.removeClass('ajax_availability').addClass('error')
-          .empty().append(response.data);
-      }
-    }
+    url: url
+  })
+  .done(function(response) {
+    $target.removeClass('ajax_availability').empty().append(response.data);
+  })
+  .fail(function(response, textStatus) {
+    if (textStatus == "abort") { return; }
+    $target.removeClass('ajax_availability').addClass('text-danger')
+      .empty().append(response.responseJSON.data);
   });
 }
 
diff --git a/themes/bootstrap3/js/pubdate_vis.js b/themes/bootstrap3/js/pubdate_vis.js
index 2d0915b062b6e038715d343d09b5588bce60addd..ef7721426c11e3a4e7b6fe90e4ce0c2c0694e172 100644
--- a/themes/bootstrap3/js/pubdate_vis.js
+++ b/themes/bootstrap3/js/pubdate_vis.js
@@ -54,81 +54,79 @@ function loadVis(facetFields, searchParams, baseURL, zooming) {
   // AJAX call
   var url = baseURL + '/AJAX/json?method=getVisData&facetFields=' + encodeURIComponent(facetFields) + '&' + searchParams;
   $.getJSON(url, function (data) {
-    if (data.status == 'OK') {
-      $.each(data['data'], function(key, val) {
-        //check if there is data to display, if there isn't hide the box
-        if (val['data'] == undefined || val['data'].length == 0) {
-          return;
-        }
-        $("#datevis" + key + "xWrapper").removeClass('hidden');
+    $.each(data['data'], function(key, val) {
+      //check if there is data to display, if there isn't hide the box
+      if (val['data'] == undefined || val['data'].length == 0) {
+        return;
+      }
+      $("#datevis" + key + "xWrapper").removeClass('hidden');
 
-        // plot graph
-        var placeholder = $("#datevis" + key + "x");
+      // plot graph
+      var placeholder = $("#datevis" + key + "x");
 
-        //set up the hasFilter variable
-        var hasFilter = true;
+      //set up the hasFilter variable
+      var hasFilter = true;
 
-        //set the has filter
-        if (val['min'] == 0 && val['max']== 0) {
-          hasFilter = false;
-        }
+      //set the has filter
+      if (val['min'] == 0 && val['max']== 0) {
+        hasFilter = false;
+      }
 
-        //check if the min and max value have been set otherwise set them to the ends of the graph
-        if (val['min'] == 0) {
-          val['min'] = val['data'][0][0] - 5;
+      //check if the min and max value have been set otherwise set them to the ends of the graph
+      if (val['min'] == 0) {
+        val['min'] = val['data'][0][0] - 5;
+      }
+      if (val['max']== 0) {
+        val['max'] =  parseInt(val['data'][val['data'].length - 1][0], 10) + 5;
+      }
+
+      if (zooming) {
+        //check the first and last elements of the data array against min and max value (+padding)
+        //if the element exists leave it, otherwise create a new marker with a minus one value
+        if (val['data'][val['data'].length - 1][0] != parseInt(val['max'], 10) + 5) {
+          val['data'].push([parseInt(val['max'], 10) + 5, -1]);
         }
-        if (val['max']== 0) {
-          val['max'] =  parseInt(val['data'][val['data'].length - 1][0], 10) + 5;
+        if (val['data'][0][0] != val['min'] - 5) {
+          val['data'].push([val['min'] - 5, -1]);
         }
-
-        if (zooming) {
-          //check the first and last elements of the data array against min and max value (+padding)
-          //if the element exists leave it, otherwise create a new marker with a minus one value
-          if (val['data'][val['data'].length - 1][0] != parseInt(val['max'], 10) + 5) {
-            val['data'].push([parseInt(val['max'], 10) + 5, -1]);
-          }
-          if (val['data'][0][0] != val['min'] - 5) {
-            val['data'].push([val['min'] - 5, -1]);
+        //check for values outside the selected range and remove them by setting them to null
+        for (var i=0; i<val['data'].length; i++) {
+          if (val['data'][i][0] < val['min'] -5 || val['data'][i][0] > parseInt(val['max'], 10) + 5) {
+            //remove this
+            val['data'].splice(i,1);
+            i--;
           }
-          //check for values outside the selected range and remove them by setting them to null
-          for (var i=0; i<val['data'].length; i++) {
-            if (val['data'][i][0] < val['min'] -5 || val['data'][i][0] > parseInt(val['max'], 10) + 5) {
-              //remove this
-              val['data'].splice(i,1);
-              i--;
-            }
-          }
-
-        } else {
-          //no zooming means that we need to specifically set the margins
-          //do the last one first to avoid getting the new last element
-          val['data'].push([parseInt(val['data'][val['data'].length - 1][0], 10) + 5, -1]);
-          //now get the first element
-          val['data'].push([val['data'][0][0] - 5, -1]);
         }
 
+      } else {
+        //no zooming means that we need to specifically set the margins
+        //do the last one first to avoid getting the new last element
+        val['data'].push([parseInt(val['data'][val['data'].length - 1][0], 10) + 5, -1]);
+        //now get the first element
+        val['data'].push([val['data'][0][0] - 5, -1]);
+      }
 
-        var plot = $.plot(placeholder, [val], options);
-        if (hasFilter) {
-          // mark pre-selected area
-          plot.setSelection({ x1: val['min'] , x2: val['max']});
-        }
-        // selection handler
-        placeholder.bind("plotselected", function (event, ranges) {
-          var from = Math.floor(ranges.xaxis.from);
-          var to = Math.ceil(ranges.xaxis.to);
-          location.href = val['removalURL'] + '&daterange[]=' + key + '&' + key + 'to=' + PadDigits(to,4) + '&' + key + 'from=' + PadDigits(from,4);
-        });
 
-        if (hasFilter) {
-          var newdiv = document.createElement('span');
-          var text = document.getElementById("clearButtonText").innerHTML;
-          newdiv.setAttribute('id', 'clearButton' + key);
-          newdiv.innerHTML = '<a href="' + htmlEncode(val['removalURL']) + '">' + text + '</a>';
-          newdiv.className += "dateVisClear";
-          placeholder.before(newdiv);
-        }
+      var plot = $.plot(placeholder, [val], options);
+      if (hasFilter) {
+        // mark pre-selected area
+        plot.setSelection({ x1: val['min'] , x2: val['max']});
+      }
+      // selection handler
+      placeholder.bind("plotselected", function (event, ranges) {
+        var from = Math.floor(ranges.xaxis.from);
+        var to = Math.ceil(ranges.xaxis.to);
+        location.href = val['removalURL'] + '&daterange[]=' + key + '&' + key + 'to=' + PadDigits(to,4) + '&' + key + 'from=' + PadDigits(from,4);
       });
-    }
+
+      if (hasFilter) {
+        var newdiv = document.createElement('span');
+        var text = document.getElementById("clearButtonText").innerHTML;
+        newdiv.setAttribute('id', 'clearButton' + key);
+        newdiv.innerHTML = '<a href="' + htmlEncode(val['removalURL']) + '">' + text + '</a>';
+        newdiv.className += "dateVisClear";
+        placeholder.before(newdiv);
+      }
+    });
   });
 }
\ No newline at end of file
diff --git a/themes/bootstrap3/js/record.js b/themes/bootstrap3/js/record.js
index deed2b2c01cd2c5987467a34fa9b5569bf32ccf9..c3ea5fc2e5638efeb9dce06c66d91135c488bdd9 100644
--- a/themes/bootstrap3/js/record.js
+++ b/themes/bootstrap3/js/record.js
@@ -12,19 +12,19 @@ function checkRequestIsValid(element, requestType, blockedClass) {
   $.ajax({
     dataType: 'json',
     cache: false,
-    url: url,
-    success: function(response) {
-      if (response.data.status) {
-        $(element).removeClass('disabled')
-          .attr('title', response.data.msg)
-          .html('<i class="fa fa-flag"></i>&nbsp;'+response.data.msg);
-      } else {
-        $(element).remove();
-      }
-    },
-    error: function(response) {
+    url: url
+  })
+  .done(function(response) {
+    if (response.data.status) {
+      $(element).removeClass('disabled')
+        .attr('title', response.data.msg)
+        .html('<i class="fa fa-flag"></i>&nbsp;'+response.data.msg);
+    } else {
       $(element).remove();
     }
+  })
+  .fail(function(response) {
+    $(element).remove();
   });
 }
 
@@ -44,12 +44,10 @@ function deleteRecordComment(element, recordId, recordSource, commentId) {
   var url = VuFind.getPath() + '/AJAX/JSON?' + $.param({method:'deleteRecordComment',id:commentId});
   $.ajax({
     dataType: 'json',
-    url: url,
-    success: function(response) {
-      if (response.status == 'OK') {
-        $($(element).closest('.comment')[0]).remove();
-      }
-    }
+    url: url
+  })
+  .done(function(response) {
+    $($(element).closest('.comment')[0]).remove();
   });
 }
 
@@ -57,21 +55,19 @@ function refreshCommentList($target, recordId, recordSource) {
   var url = VuFind.getPath() + '/AJAX/JSON?' + $.param({method:'getRecordCommentsAsHTML',id:recordId,'source':recordSource});
   $.ajax({
     dataType: 'json',
-    url: url,
-    success: function(response) {
-      // Update HTML
-      if (response.status == 'OK') {
-        var $commentList = $target.find('.comment-list');
-        $commentList.empty();
-        $commentList.append(response.data);
-        $commentList.find('.delete').unbind('click').click(function() {
-          var commentId = $(this).attr('id').substr('recordComment'.length);
-          deleteRecordComment(this, recordId, recordSource, commentId);
-          return false;
-        });
-        $target.find('.comment-form input[type="submit"]').button('reset');
-      }
-    }
+    url: url
+  })
+  .done(function(response) {
+    // Update HTML
+    var $commentList = $target.find('.comment-list');
+    $commentList.empty();
+    $commentList.append(response.data);
+    $commentList.find('.delete').unbind('click').click(function() {
+      var commentId = $(this).attr('id').substr('recordComment'.length);
+      deleteRecordComment(this, recordId, recordSource, commentId);
+      return false;
+    });
+    $target.find('.comment-form input[type="submit"]').button('reset');
   });
 }
 
@@ -91,17 +87,17 @@ function registerAjaxCommentRecord() {
       type: 'POST',
       url:  url,
       data: data,
-      dataType: 'json',
-      success: function(response) {
-        if (response.status == 'OK') {
-          var $tab = $(form).closest('.tab-pane');
-          refreshCommentList($tab, id, recordSource);
-          $(form).find('textarea[name="comment"]').val('');
-          $(form).find('input[type="submit"]').button('loading');
-        } else {
-          Lightbox.displayError(response.data);
-        }
-      }
+      dataType: 'json'
+    })
+    .done(function(response) {
+      var $tab = $(form).closest('.tab-pane');
+      refreshCommentList($tab, id, recordSource);
+      $(form).find('textarea[name="comment"]').val('');
+      $(form).find('input[type="submit"]').button('loading');
+    })
+    .fail(function(response, textStatus) {
+      if (textStatus == "abort") { return; }
+      Lightbox.displayError(response.responseJSON.data);
     });
     return false;
   });
@@ -156,15 +152,15 @@ function ajaxLoadTab($newTab, tabid, setHash) {
     url: path + urlroot + '/AjaxTab',
     type: 'POST',
     data: {tab: tabid},
-    success: function(data) {
-      $newTab.html(data);
-      registerTabEvents();
-      if(typeof syn_get_widget === "function") {
-        syn_get_widget();
-      }
-      if (typeof setHash == 'undefined' || setHash) {
-        window.location.hash = tabid;
-      }
+  })
+  .done(function(data) {
+    $newTab.html(data);
+    registerTabEvents();
+    if(typeof syn_get_widget === "function") {
+      syn_get_widget();
+    }
+    if (typeof setHash == 'undefined' || setHash) {
+      window.location.hash = tabid;
     }
   });
   return false;
@@ -179,20 +175,18 @@ function refreshTagList(target, loggedin) {
   var recordSource = $(target).find('.hiddenSource').val();
   var $tagList = $(target).find('.tagList');
   if ($tagList.length > 0) {
-    $tagList.empty();
     var url = VuFind.getPath() + '/AJAX/JSON?' + $.param({method:'getRecordTags',id:recordId,'source':recordSource});
     $.ajax({
-      dataType: 'json',
-      url: url,
-      complete: function(response) {
-        if(response.status == 200) {
-          $tagList.replaceWith(response.responseText);
-          if(loggedin) {
-            $tagList.addClass('loggedin');
-          } else {
-            $tagList.removeClass('loggedin');
-          }
-        }
+      dataType: 'html',
+      url: url
+    })
+    .done(function(response) {
+      $tagList.empty();
+      $tagList.replaceWith(response);
+      if(loggedin) {
+        $tagList.addClass('loggedin');
+      } else {
+        $tagList.removeClass('loggedin');
       }
     });
   }
@@ -216,10 +210,10 @@ function ajaxTagUpdate(link, tag, remove) {
       id:recordId,
       source:recordSource,
       remove:remove
-    },
-    complete: function() {
-      refreshTagList($target, false);
     }
+  })
+  .always(function() {
+    refreshTagList($target, false);
   });
 }
 
@@ -330,7 +324,7 @@ function recordDocReady() {
   });
   // Tag lightbox
   Lightbox.addFormCallback('tagRecord', function(html) {
-    refreshTagList(true);
+    refreshTagList(document, true);
     Lightbox.confirm(VuFind.translate('add_tag_success'));
   });
 }
\ No newline at end of file
diff --git a/themes/bootstrap3/js/vudl/record.js b/themes/bootstrap3/js/vudl/record.js
index 3e40714ad6fdfad419a737e8b47682564b89e72c..9e62e5ab5cbeaa6eddbc5d37e1ad6c54f7a6001f 100644
--- a/themes/bootstrap3/js/vudl/record.js
+++ b/themes/bootstrap3/js/vudl/record.js
@@ -17,21 +17,20 @@ function ajaxGetView(pageObject) {
       type: 'POST',
       url : '../VuDL/ajax?method=viewLoad',
       data: pageObject,
-      success: function(e) {
-        $('#view').html(e.data);
-        currentType = pageObject['filetype'];
-        var tab = $('#'+currentTab, e.data);
-        if(tab.length > 0) {
-          tab.click();
-        } else {
-          currentTab = $('.nav-tabs li a:eq(0)')[0].id;
-        }
-      },
-      error: function(d,e){
-        console.log(d.responseText);
-        console.log(e);
-      },
       dataType: 'json'
+    })
+    .done(function(e) {
+      $('#view').html(e.data);
+      currentType = pageObject['filetype'];
+      var tab = $('#'+currentTab, e.data);
+      if(tab.length > 0) {
+        tab.click();
+      } else {
+        currentTab = $('.nav-tabs li a:eq(0)')[0].id;
+      }
+    })
+    .fail(function(response, textStatus) {
+      console.log(response, textStatus);
     });
   } else {
     updateFunction(pageObject, currentTab);
@@ -43,19 +42,18 @@ function updateTechInfo(record) {
   $.ajax({dataType:'json',
     type:'post',
     url:path+'/VuDL/ajax?method=getTechInfo',
-    data:record,
-    success:function(d) {
-      $('#techinfo').html(d.data.div);
-      var downloadSrc = 'MASTER';
-      if(typeof d.data.type !== "undefined") {
-        $('#download-button .details').html(d.data.type+' ~ '+d.data.size);
-      }
-      $('#file-download').attr('action', VuFind.getPath()+'/files/'+record.id+'/'+downloadSrc+'?download=true');
-    },
-    error:function(d,e) {
-      console.log(d.responseText);
-      console.log(e);
+    data:record
+  })
+  .done(function(d) {
+    $('#techinfo').html(d.data.div);
+    var downloadSrc = 'MASTER';
+    if(typeof d.data.type !== "undefined") {
+      $('#download-button .details').html(d.data.type+' ~ '+d.data.size);
     }
+    $('#file-download').attr('action', VuFind.getPath()+'/files/'+record.id+'/'+downloadSrc+'?download=true');
+  })
+  .fail(function(response, textStatus) {
+    console.log(response, textStatus);
   });
 }
 // ====== GET MORE THUMBNAILS ====== //
@@ -85,32 +83,31 @@ function ajaxLoadPages(min, max) {
   //console.log('ajax', min, max, counts);
   $.ajax({
     url:path+'/VuDL/ajax?method=pageAjax&record='+documentID+'&start='+min+'&end='+max,
-    dataType:'json',
-    success : function(response) {
-      loadWait = false;
-      // For each page
-      for(var i=0;i<response.data.length;i++) {
-        var page = response.data.outline[response.data.start];
-        if(page == undefined) continue;
-        var img = $('<img src="'+page.thumbnail+'"/>');
-        $('.page-link#item'+response.data.start)
-          .attr('onClick','ajaxGetView('+JSON.stringify(page).replace(/"/g, "'")+', this)')
-          .attr('title',page.id)
-          .attr('alt',page.label)
-          .attr('id', 'item'+response.data.start)
-          .html('<br/>'+page.label)
-          .prepend(img)
-          .addClass('active')
-          .removeClass('loading')
-          .removeClass('unloaded');
-        response.data.start++;
-      }
-      findVisible();
-    },
-    error : function(d,e){
-      console.log(d.responseText);
-      console.log(e);
+    dataType:'json'
+  })
+  .done(function(response) {
+    loadWait = false;
+    // For each page
+    for(var i=0;i<response.data.length;i++) {
+      var page = response.data.outline[response.data.start];
+      if(page == undefined) continue;
+      var img = $('<img src="'+page.thumbnail+'"/>');
+      $('.page-link#item'+response.data.start)
+        .attr('onClick','ajaxGetView('+JSON.stringify(page).replace(/"/g, "'")+', this)')
+        .attr('title',page.id)
+        .attr('alt',page.label)
+        .attr('id', 'item'+response.data.start)
+        .html('<br/>'+page.label)
+        .prepend(img)
+        .addClass('active')
+        .removeClass('loading')
+        .removeClass('unloaded');
+      response.data.start++;
     }
+    findVisible();
+  }
+  .fail(function(response, textStatus) {
+    console.log(response, textStatus);
   });
 }
 // Pages