/*global $, document, Event, VuFind, window */ VuFind.lightbox = (function() { // State var _originalUrl = false; var _currentUrl = false; var refreshOnClose = false; // Elements 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">' + VuFind.translate('close') + '</button>'); _modal.modal('show'); }; var flashMessage = function(message, type) { _modalBody.find('.alert,.fa.fa-spinner').remove(); _modalBody.find('h2:first-child') .after('<div class="alert alert-'+type+'">'+message+'</div>'); }; /** * Update content * * Form data options: * * data-lightbox-ignore = do not submit this form in lightbox */ var _update = function(html) { if (!html.match) return; // Isolate successes 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').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 $('#modal').find('.checkbox-select-all').change(function() { $(this).closest('.modal-body').find('.checkbox-select-item').prop('checked', this.checked); }); $('#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) { if (_xhr !== false) return; if (_originalUrl === false) { _originalUrl = obj.url; } // Add lightbox GET parameter if (!obj.url.match(/layout=lightbox/)) { var parts = obj.url.split('#'); obj.url = parts[0].indexOf('?') < 0 ? parts[0]+'?' : parts[0]+'&'; obj.url += 'layout=lightbox&lbreferer='+encodeURIComponent(_currentUrl); obj.url += parts.length < 2 ? '' : '#'+parts[1]; } _xhr = $.ajax(obj); _xhr.always(function() { _xhr = false; }) .done(function(html, status, jq_xhr) { if (jq_xhr.status == 205) { _refreshPage(); return; } if ( // Close the lightbox after deliberate login obj.method // is a form && !html.match(/alert alert-danger/) // skip failed logins && (obj.url.match(/MyResearch/) // that matches login/create account || obj.url.match(/catalogLogin/)) // catalog login for holds ) { if (_originalUrl.match(/UserLogin/) || obj.url.match(/catalogLogin/)) { 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; }; var reload = function() { ajax({url:_currentUrl || _originalUrl}); }; /** * Modal link data options * * data-lightbox-href = go to this url instead * data-lightbox-ignore = do not open this link in lightbox * data-lightbox-post = post data */ var _constrainLink = function(event) { if (typeof this.dataset.lightboxIgnore != 'undefined') { return true; } if (this.href.length > 1) { event.preventDefault(); var obj = {url: this.dataset.lightboxHref || this.href}; if("string" === typeof this.dataset.lightboxPost) { obj.type = 'POST'; obj.data = this.dataset.lightboxPost; } ajax(obj); _currentUrl = this.href; VuFind.modal('show'); return false; } }; /** * 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 var form = event.target; var dataset = form.dataset; var data = $(form).serializeArray(); data.push({'name':'layout', 'value':'lightbox'}); // Return in lightbox, please // Add submit button information var submit = $(_clickedButton); _clickedButton = null; var buttonData = {'name':name, 'value':1}; 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'); } buttonData.name = submit.attr('name') || 'submit'; buttonData.value = submit.attr('value') || 1; } data.push(buttonData); // Special handlers if ('undefined' !== typeof dataset) { // On submit behavior 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) { return ret; } } // onclose behavior if ('string' === typeof dataset.lightboxOnclose) { document.addEventListener('VuFind.lightbox.closed', function(event) { _evalCallback(dataset.lightboxOnclose, event); }, false); } } // Loading _modalBody.prepend('<i class="fa fa-spinner fa-spin pull-right"></i>'); // Get Lightbox content ajax({ url: form.action || _currentUrl, method: form.method || 'GET', data: data }); 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) { target = document; } $(target).find('a[data-lightbox]') .unbind('click', _constrainLink) .on('click', _constrainLink); $(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 return { // Properties refreshOnClose: refreshOnClose, // Methods ajax: ajax, alert: showAlert, bind: bind, flashMessage: flashMessage, reload: reload, reset: function() { _html(VuFind.translate('loading') + '...'); _originalUrl = false; _currentUrl = false; }, // Ready ready: function() { _modal = $('#modal'); _modalBody = _modal.find('.modal-body'); _modal.on('hide.bs.modal', function() { if (VuFind.lightbox.refreshOnClose) { _refreshPage(); } document.dispatchEvent(new Event('VuFind.lightbox.closing')); }); _modal.on('hidden.bs.modal', function() { document.dispatchEvent(new Event('VuFind.lightbox.closed')); VuFind.lightbox.reset(); }); VuFind.modal = function(cmd) { _modal.modal(cmd); }; bind(); } }; })(); $(document).ready(VuFind.lightbox.ready);