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())?>" />