From 94703e23a117c58a34df0966b267d0da419fc3d4 Mon Sep 17 00:00:00 2001 From: Chris Hallberg <crhallberg@gmail.com> Date: Thu, 15 Dec 2016 15:42:53 -0500 Subject: [PATCH] Form attribute support (#802) - Use form="id" attribute to simplify form markup - Includes polyfill for legacy browsers --- .../VuFind/src/VuFind/Service/ReCaptcha.php | 2 +- .../src/VuFind/View/Helper/Root/Record.php | 6 +- .../View/Helper/Root/RecordTest.php | 4 +- themes/bootstrap3/js/cart.js | 84 ++++++++++--------- themes/bootstrap3/js/common.js | 26 +++++- .../bootstrap3/js/lib/form-attr-polyfill.js | 68 +++++++++++++++ themes/bootstrap3/js/lightbox.js | 11 +-- themes/bootstrap3/js/record.js | 19 ++--- .../templates/RecordTab/usercomments.phtml | 2 - .../templates/record/checkbox.phtml | 4 +- .../search/bulk-action-buttons.phtml | 12 +-- .../templates/search/list-list.phtml | 4 +- .../bootstrap3/templates/search/results.phtml | 8 +- themes/bootstrap3/theme.config.php | 1 + 14 files changed, 171 insertions(+), 80 deletions(-) create mode 100644 themes/bootstrap3/js/lib/form-attr-polyfill.js diff --git a/module/VuFind/src/VuFind/Service/ReCaptcha.php b/module/VuFind/src/VuFind/Service/ReCaptcha.php index 2a8ff092584..a8152779436 100644 --- a/module/VuFind/src/VuFind/Service/ReCaptcha.php +++ b/module/VuFind/src/VuFind/Service/ReCaptcha.php @@ -66,7 +66,7 @@ class ReCaptcha extends \LosReCaptcha\Service\ReCaptcha $divregex = '/<div[^>]*id=[\'"]recaptcha_widget[\'"][^>]*>/'; $scriptRegex = '|<script[^>]*></script>|'; - $scriptReplacement = '<script>/*form magic*/</script>'; + $scriptReplacement = ''; // remove return preg_replace( [$divregex, $scriptRegex], diff --git a/module/VuFind/src/VuFind/View/Helper/Root/Record.php b/module/VuFind/src/VuFind/View/Helper/Root/Record.php index 1054069909e..7dd53c668dd 100644 --- a/module/VuFind/src/VuFind/View/Helper/Root/Record.php +++ b/module/VuFind/src/VuFind/View/Helper/Root/Record.php @@ -410,16 +410,20 @@ class Record extends AbstractHelper * Render an HTML checkbox control for the current record. * * @param string $idPrefix Prefix for checkbox HTML ids + * @param string $formAttr ID of form for [form] attribute * * @return string */ - public function getCheckbox($idPrefix = '') + public function getCheckbox($idPrefix = '', $formAttr = false) { static $checkboxCount = 0; $id = $this->driver->getSourceIdentifier() . '|' . $this->driver->getUniqueId(); $context = ['id' => $id, 'count' => $checkboxCount++, 'prefix' => $idPrefix]; + if ($formAttr) { + $context['formAttr'] = $formAttr; + } return $this->contextHelper->renderInContext( 'record/checkbox.phtml', $context ); diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/View/Helper/Root/RecordTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/View/Helper/Root/RecordTest.php index 32434ba4980..33121548b7d 100644 --- a/module/VuFind/tests/unit-tests/src/VuFindTest/View/Helper/Root/RecordTest.php +++ b/module/VuFind/tests/unit-tests/src/VuFindTest/View/Helper/Root/RecordTest.php @@ -271,10 +271,10 @@ class RecordTest extends \PHPUnit_Framework_TestCase { $context = $this->getMockContext(); $context->expects($this->at(1))->method('renderInContext') - ->with($this->equalTo('record/checkbox.phtml'), $this->equalTo(['id' => 'Solr|000105196', 'count' => 0, 'prefix' => 'bar'])) + ->with($this->equalTo('record/checkbox.phtml'), $this->equalTo(['id' => 'Solr|000105196', 'count' => 0, 'prefix' => 'bar', 'formAttr' => 'foo'])) ->will($this->returnValue('success')); $context->expects($this->at(2))->method('renderInContext') - ->with($this->equalTo('record/checkbox.phtml'), $this->equalTo(['id' => 'Solr|000105196', 'count' => 1, 'prefix' => 'bar'])) + ->with($this->equalTo('record/checkbox.phtml'), $this->equalTo(['id' => 'Solr|000105196', 'count' => 1, 'prefix' => 'bar', 'formAttr' => 'foo'])) ->will($this->returnValue('success')); $record = $this->getRecord( $this->loadRecordFixture('testbug1.json'), [], $context diff --git a/themes/bootstrap3/js/cart.js b/themes/bootstrap3/js/cart.js index 5cd0bdeb604..3d2474241b6 100644 --- a/themes/bootstrap3/js/cart.js +++ b/themes/bootstrap3/js/cart.js @@ -122,47 +122,52 @@ VuFind.register('cart', function Cart() { } var _cartNotificationTimeout = false; - function _registerUpdate($form) { - if ($form) { - $("#updateCart, #bottom_updateCart").unbind('click').click(function cartUpdate() { - var elId = this.id; - var selectedBoxes = $("input[name='ids[]']:checked", $form); - var selected = []; - $(selectedBoxes).each(function cartCheckboxValues(i) { - selected[i] = this.value; + function _registerUpdate(_form) { + var $form = typeof _form === 'undefined' + ? $('form[name="bulkActionForm"]') + : $(_form); + $("#updateCart, #bottom_updateCart").unbind('click').click(function cartUpdate() { + var elId = this.id; + var selected = []; + var selectedInForm = $form.find('input[name="ids[]"]:checked'); + var selectedFormAttr = $('input[form="' + $form.attr('id') + '"][name="ids[]"]:checked'); + $(selectedInForm).each(function cartFormCheckboxValues() { + selected.push(this.value); + }); + $(selectedFormAttr).each(function cartAttrCheckboxValues() { + selected.push(this.value); + }); + if (selected.length > 0) { + var msg = ""; + var orig = getFullItems(); + $(selected).each(function cartCheckedItemsAdd() { + var data = this.split('|'); + addItem(data[1], data[0]); }); - if (selected.length > 0) { - var msg = ""; - var orig = getFullItems(); - $(selected).each(function cartCheckedItemsAdd() { - var data = this.split('|'); - addItem(data[1], data[0]); - }); - var updated = getFullItems(); - var added = updated.length - orig.length; - var inCart = selected.length - added; - msg += added + " " + VuFind.translate('itemsAddBag'); - if (updated.length >= parseInt(VuFind.translate('bookbagMax'), 10)) { - msg += "<br/>" + VuFind.translate('bookbagFull'); - } - if (inCart > 0 && orig.length > 0) { - msg += "<br/>" + inCart + " " + VuFind.translate('itemsInBag'); - } - $('#' + elId).data('bs.popover').options.content = msg; - $('#cartItems strong').html(updated.length); - } else { - $('#' + elId).data('bs.popover').options.content = VuFind.translate('bulk_noitems_advice'); + var updated = getFullItems(); + var added = updated.length - orig.length; + var inCart = selected.length - added; + msg += added + " " + VuFind.translate('itemsAddBag'); + if (updated.length >= parseInt(VuFind.translate('bookbagMax'), 10)) { + msg += "<br/>" + VuFind.translate('bookbagFull'); } - $('#' + elId).popover('show'); - if (_cartNotificationTimeout !== false) { - clearTimeout(_cartNotificationTimeout); + if (inCart > 0 && orig.length > 0) { + msg += "<br/>" + inCart + " " + VuFind.translate('itemsInBag'); } - _cartNotificationTimeout = setTimeout(function notificationHide() { - $('#' + elId).popover('hide'); - }, 5000); - return false; - }); - } + $('#' + elId).data('bs.popover').options.content = msg; + $('#cartItems strong').html(updated.length); + } else { + $('#' + elId).data('bs.popover').options.content = VuFind.translate('bulk_noitems_advice'); + } + $('#' + elId).popover('show'); + if (_cartNotificationTimeout !== false) { + clearTimeout(_cartNotificationTimeout); + } + _cartNotificationTimeout = setTimeout(function notificationHide() { + $('#' + elId).popover('hide'); + }, 5000); + return false; + }); } function init() { @@ -192,8 +197,7 @@ VuFind.register('cart', function Cart() { }); } else { // Search results - var $form = $('form[name="bulkActionForm"]'); - _registerUpdate($form); + _registerUpdate(); } $("#updateCart, #bottom_updateCart").popover({content: '', html: true, trigger: 'manual'}); updateCount(); diff --git a/themes/bootstrap3/js/common.js b/themes/bootstrap3/js/common.js index 1b4551ecf1e..fcd3fe6fb54 100644 --- a/themes/bootstrap3/js/common.js +++ b/themes/bootstrap3/js/common.js @@ -1,5 +1,5 @@ /*global grecaptcha, isPhoneNumberValid */ -/*exported VuFind, htmlEncode, deparam, moreFacets, lessFacets, phoneNumberFormHandler, recaptchaOnLoad, bulkFormHandler */ +/*exported VuFind, htmlEncode, deparam, moreFacets, lessFacets, phoneNumberFormHandler, recaptchaOnLoad, resetCaptcha, bulkFormHandler */ // IE 9< console polyfill window.console = window.console || {log: function polyfillLog() {}}; @@ -170,6 +170,14 @@ function recaptchaOnLoad() { } } } +function resetCaptcha($form) { + if (typeof grecaptcha !== 'undefined') { + var captcha = $form.find('.g-recaptcha'); + if (captcha.length > 0) { + grecaptcha.reset(captcha.data('captchaId')); + } + } +} function bulkFormHandler(event, data) { if ($('.checkbox-select-item:checked,checkbox-select-all:checked').length === 0) { @@ -310,7 +318,7 @@ function setupFacets() { $(item).collapse('hide'); } } finally { - $.support.transition = saveTransition; + $.support.transition = saveTransition; } } }); @@ -343,10 +351,20 @@ $(document).ready(function commonDocReady() { // Checkbox select all $('.checkbox-select-all').change(function selectAllCheckboxes() { - $(this).closest('form').find('.checkbox-select-item').prop('checked', this.checked); + var $form = $(this).closest('form') + $form.find('.checkbox-select-item').prop('checked', this.checked); + $('[form="' + $form.attr('id') + '"]').prop('checked', this.checked); }); $('.checkbox-select-item').change(function selectAllDisable() { - $(this).closest('form').find('.checkbox-select-all').prop('checked', false); + var $form = $(this).closest('form'); + if ($form.length === 0 && this.form) { + $form = $(this.form); + } + if ($form.length === 0) { + return; + } + $form.find('.checkbox-select-all').prop('checked', false); + $('.checkbox-select-all[form="' + $form.attr('id') + '"]').prop('checked', false); }); // handle QR code links diff --git a/themes/bootstrap3/js/lib/form-attr-polyfill.js b/themes/bootstrap3/js/lib/form-attr-polyfill.js new file mode 100644 index 00000000000..000a63e44a5 --- /dev/null +++ b/themes/bootstrap3/js/lib/form-attr-polyfill.js @@ -0,0 +1,68 @@ +/** + * From http://stackoverflow.com/questions/17742275/polyfill-html5-input-form-attribute/26696165#26696165 + * Recommended by https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-browser-Polyfills + * Adapted to eslint styling and updated detection by Chris Hallberg (@crhallberg) for VuFind + */ +(function formAttrPolyfill($) { + /** + * polyfill for html5 form attr + */ + + // every browser supports except IE + if (typeof document.documentMode == 'undefined') { + // any other browser? skip + return; + } + + function resetFormAttr(form) { + var $form = $(form); + $form.find('.js-form-attr').remove(); + return $form; + } + function makeFieldElement(data) { + return $('<input/>', data) + .addClass('js-form-attr') + .attr('type', 'hidden'); + } + + $(document).ready(function formAttrReady() { + /** + * Find all input fields with form attribute point to jQuery object + * + */ + $('form[id]').submit(function locateFormAttr(/*e*/) { + // serialize data + var data = $('[form=' + this.id + ']').serializeArray(); + // append data to form + var $form = resetFormAttr(this); + for (var i=0; i<data.length; i++) { + $form.append(makeFieldElement(data[i])); + } + return true; + }).each(function locateFormAttrEach() { + var form = this, + $fields = $('[form=' + this.id + ']'); + + $fields.filter('button, input').filter('[type=reset],[type=submit]').click(function formAttrButtonSubmit() { + var type = this.type.toLowerCase(); + if (type === 'reset') { + // reset form + form.reset(); + // for elements outside form + $fields.each(function formAttrGatherFieldData() { + this.value = this.defaultValue; + this.checked = this.defaultChecked; + }).filter('select').each(function formAttrGatherSelectData() { + $(this).find('option').each(function formAttrGatherOptionData() { + this.selected = this.defaultSelected; + }); + }); + } else if (type.match(/^submit|image$/i)) { + var $form = resetFormAttr(form); + $form.append( makeFieldElement({name: this.name, value: this.value}) ).submit(); + } + }); + }); + }); + +})(jQuery); diff --git a/themes/bootstrap3/js/lightbox.js b/themes/bootstrap3/js/lightbox.js index 37a5a9352b1..a1e11f4b65a 100644 --- a/themes/bootstrap3/js/lightbox.js +++ b/themes/bootstrap3/js/lightbox.js @@ -1,4 +1,4 @@ -/*global grecaptcha, recaptchaOnLoad, VuFind */ +/*global grecaptcha, recaptchaOnLoad, resetCaptcha, VuFind */ VuFind.register('lightbox', function Lightbox() { // State var _originalUrl = false; @@ -279,9 +279,7 @@ VuFind.register('lightbox', function Lightbox() { method: $(form).attr('method') || 'GET', data: data }).done(function recaptchaReset() { - if (typeof grecaptcha !== 'undefined') { - grecaptcha.reset($(form).find('.g-recaptcha').data('captchaId')); - } + resetCaptcha($(form)); }); VuFind.modal('show'); @@ -301,7 +299,10 @@ VuFind.register('lightbox', function Lightbox() { // 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); + $('form[data-lightbox]').each(function bindFormSubmitsLightbox(i, form) { + $(form).find('[type=submit]').click(_storeClickedStatus); + $('[type="submit"][form="' + form.id + '"]').click(_storeClickedStatus); + }); } function reset() { diff --git a/themes/bootstrap3/js/record.js b/themes/bootstrap3/js/record.js index e090e917889..63900a8571f 100644 --- a/themes/bootstrap3/js/record.js +++ b/themes/bootstrap3/js/record.js @@ -1,4 +1,4 @@ -/*global deparam, grecaptcha, recaptchaOnLoad, syn_get_widget, userIsLoggedIn, VuFind */ +/*global deparam, grecaptcha, recaptchaOnLoad, resetCaptcha, syn_get_widget, userIsLoggedIn, VuFind */ /*exported ajaxTagUpdate, recordDocReady */ /** @@ -78,9 +78,7 @@ function refreshCommentList($target, recordId, recordSource) { return false; }); $target.find('.comment-form input[type="submit"]').button('reset'); - if (typeof grecaptcha !== 'undefined') { - grecaptcha.reset(); - } + resetCaptcha($target); }); } @@ -109,16 +107,15 @@ function registerAjaxCommentRecord() { dataType: 'json' }) .done(function addCommentDone(/*response, textStatus*/) { - var $tab = $(form).closest('.list-tab-content'); + var $form = $(form); + var $tab = $form.closest('.list-tab-content'); if (!$tab.length) { - $tab = $(form).closest('.tab-pane'); + $tab = $form.closest('.tab-pane'); } refreshCommentList($tab, id, recordSource); - $(form).find('textarea[name="comment"]').val(''); - $(form).find('input[type="submit"]').button('loading'); - if (typeof grecaptcha !== 'undefined') { - grecaptcha.reset($(form).find('.g-recaptcha').data('captchaId')); - } + $form.find('textarea[name="comment"]').val(''); + $form.find('input[type="submit"]').button('loading'); + resetCaptcha($form); }) .fail(function addCommentFail(response, textStatus) { if (textStatus === 'abort' || typeof response.responseJSON === 'undefined') { return; } diff --git a/themes/bootstrap3/templates/RecordTab/usercomments.phtml b/themes/bootstrap3/templates/RecordTab/usercomments.phtml index e00d5eaaffc..4bd7cb6e88b 100644 --- a/themes/bootstrap3/templates/RecordTab/usercomments.phtml +++ b/themes/bootstrap3/templates/RecordTab/usercomments.phtml @@ -19,8 +19,6 @@ <textarea name="comment" class="form-control" rows="3" required></textarea><br/> <? if ($this->tab->isRecaptchaActive()): ?> <?=$this->recaptcha()->html(true, false) ?><br/> - <? else: ?> - <script>/* workaround for nested form bug */</script> <? endif; ?> <input class="btn btn-primary" data-loading-text="<?=$this->transEsc('Submitting') ?>..." type="submit" value="<?=$this->transEsc("Add your comment")?>"/> <? else: ?> diff --git a/themes/bootstrap3/templates/record/checkbox.phtml b/themes/bootstrap3/templates/record/checkbox.phtml index e6cba3addf1..f889038dbba 100644 --- a/themes/bootstrap3/templates/record/checkbox.phtml +++ b/themes/bootstrap3/templates/record/checkbox.phtml @@ -1,2 +1,2 @@ -<input class="checkbox-select-item" type="checkbox" name="ids[]" value="<?=$this->escapeHtmlAttr($this->id) ?>"/> -<input type="hidden" name="idsAll[]" value="<?=$this->escapeHtmlAttr($this->id) ?>"/> +<input class="checkbox-select-item" type="checkbox" name="ids[]" value="<?=$this->escapeHtmlAttr($this->id) ?>"<? if(isset($this->formAttr)): ?> form="<?=$this->formAttr ?>"<? endif; ?>/> +<input type="hidden" name="idsAll[]" value="<?=$this->escapeHtmlAttr($this->id) ?>"<? if(isset($this->formAttr)): ?> form="<?=$this->formAttr ?>"<? endif; ?>/> diff --git a/themes/bootstrap3/templates/search/bulk-action-buttons.phtml b/themes/bootstrap3/templates/search/bulk-action-buttons.phtml index 7122165f7c6..9c3edeca19b 100644 --- a/themes/bootstrap3/templates/search/bulk-action-buttons.phtml +++ b/themes/bootstrap3/templates/search/bulk-action-buttons.phtml @@ -3,23 +3,23 @@ <div class="bulkActionButtons hidden-print"> <div class="checkbox"> <label> - <input type="checkbox" class="checkbox-select-all" name="selectAll" id="<?=$this->idPrefix?>addFormCheckboxSelectAll"/> <?=$this->transEsc('select_page')?> + <input type="checkbox" class="checkbox-select-all" name="selectAll" id="<?=$this->idPrefix?>addFormCheckboxSelectAll"<?if($this->formAttr):?> form="<?=$this->escapeHtmlAttr($this->formAttr) ?>"<? endif; ?>/> <?=$this->transEsc('select_page')?> | <?=$this->transEsc('with_selected')?>: </label> </div> <div class="btn-group"> <? if (isset($this->showBulkOptions) && $this->showBulkOptions): ?> - <input id="ribbon-email" class="btn btn-default" type="submit" name="email" title="<?=$this->transEsc('bookbag_email_selected')?>" value="<?=$this->transEsc('Email')?>"/> + <input id="ribbon-email" class="btn btn-default" type="submit" name="email" title="<?=$this->transEsc('bookbag_email_selected')?>" value="<?=$this->transEsc('Email')?>"<?if($this->formAttr):?> form="<?=$this->escapeHtmlAttr($this->formAttr) ?>"<? endif; ?>/> <? $exportOptions = $this->export()->getBulkOptions(); if (count($exportOptions) > 0): ?> - <input id="ribbon-export" class="btn btn-default" type="submit" name="export" title="<?=$this->transEsc('bookbag_export_selected')?>" value="<?=$this->transEsc('Export')?>"/> + <input id="ribbon-export" class="btn btn-default" type="submit" name="export" title="<?=$this->transEsc('bookbag_export_selected')?>" value="<?=$this->transEsc('Export')?>"<?if($this->formAttr):?> form="<?=$this->escapeHtmlAttr($this->formAttr) ?>"<? endif; ?>/> <? endif; ?> - <input id="ribbon-print" class="btn btn-default" type="submit" name="print" title="<?=$this->transEsc('bookbag_print_selected')?>" value="<?=$this->transEsc('Print')?>"/> + <input id="ribbon-print" class="btn btn-default" type="submit" name="print" title="<?=$this->transEsc('bookbag_print_selected')?>" value="<?=$this->transEsc('Print')?>"<?if($this->formAttr):?> form="<?=$this->escapeHtmlAttr($this->formAttr) ?>"<? endif; ?>/> <? if ($this->userlist()->getMode() !== 'disabled'): ?> - <input id="ribbon-save" class="btn btn-default" type="submit" name="saveCart" title="<?=$this->transEsc('bookbag_save_selected')?>" value="<?=$this->transEsc('Save')?>"/> + <input id="ribbon-save" class="btn btn-default" type="submit" name="saveCart" title="<?=$this->transEsc('bookbag_save_selected')?>" value="<?=$this->transEsc('Save')?>"<?if($this->formAttr):?> form="<?=$this->escapeHtmlAttr($this->formAttr) ?>"<? endif; ?>/> <? endif; ?> <? endif; ?> <? if (isset($this->showCartControls) && $this->showCartControls): ?> - <input id="<?=$this->idPrefix?>updateCart" type="submit" class="btn btn-default" name="add" value="<?=$this->transEsc('Add to Book Bag')?>"/> + <input id="<?=$this->idPrefix?>updateCart" type="submit" class="btn btn-default" name="add" value="<?=$this->transEsc('Add to Book Bag')?>"<?if($this->formAttr):?> form="<?=$this->escapeHtmlAttr($this->formAttr) ?>"<? endif; ?>/> <? endif; ?> </div> </div> diff --git a/themes/bootstrap3/templates/search/list-list.phtml b/themes/bootstrap3/templates/search/list-list.phtml index b6adf0cd9e9..a01cfdd9541 100644 --- a/themes/bootstrap3/templates/search/list-list.phtml +++ b/themes/bootstrap3/templates/search/list-list.phtml @@ -7,7 +7,7 @@ <div class="checkbox hidden-print"> <? if ($showCheckboxes): ?> <label> - <?=$this->record($current)->getCheckbox()?> + <?=$this->record($current)->getCheckbox('', 'search-cart-form')?> <?=$recordNumber ?> </label> <? else: ?> @@ -16,4 +16,4 @@ </div> <?=$this->record($current)->getSearchResult('list')?> </div> -<? endforeach; ?> \ No newline at end of file +<? endforeach; ?> diff --git a/themes/bootstrap3/templates/search/results.phtml b/themes/bootstrap3/templates/search/results.phtml index 36b8ebffcfe..77e3a907557 100644 --- a/themes/bootstrap3/templates/search/results.phtml +++ b/themes/bootstrap3/templates/search/results.phtml @@ -109,12 +109,12 @@ <? endif; ?> <? endforeach; ?> <? else: ?> - <form class="form-inline" method="post" name="bulkActionForm" action="<?=$this->url('cart-searchresultsbulk')?>" data-lightbox data-lightbox-onsubmit="bulkFormHandler"> + <form id="search-cart-form" class="form-inline" method="post" name="bulkActionForm" action="<?=$this->url('cart-searchresultsbulk')?>" data-lightbox data-lightbox-onsubmit="bulkFormHandler"> <?=$this->context($this)->renderInContext('search/bulk-action-buttons.phtml', ['idPrefix' => ''])?> - <?=$this->render('search/list-' . $this->params->getView() . '.phtml')?> - <?=$this->context($this)->renderInContext('search/bulk-action-buttons.phtml', ['idPrefix' => 'bottom_'])?> - <?=$this->paginationControl($this->results->getPaginator(), 'Sliding', 'search/pagination.phtml', ['results' => $this->results, 'options' => isset($this->paginationOptions) ? $this->paginationOptions : []])?> </form> + <?=$this->render('search/list-' . $this->params->getView() . '.phtml')?> + <?=$this->context($this)->renderInContext('search/bulk-action-buttons.phtml', ['idPrefix' => 'bottom_', 'formAttr' => 'search-cart-form'])?> + <?=$this->paginationControl($this->results->getPaginator(), 'Sliding', 'search/pagination.phtml', ['results' => $this->results, 'options' => isset($this->paginationOptions) ? $this->paginationOptions : []])?> <div class="searchtools hidden-print"> <strong><?=$this->transEsc('Search Tools')?>:</strong> diff --git a/themes/bootstrap3/theme.config.php b/themes/bootstrap3/theme.config.php index 45b2f9d805e..37804a60d1e 100644 --- a/themes/bootstrap3/theme.config.php +++ b/themes/bootstrap3/theme.config.php @@ -15,6 +15,7 @@ return array( 'vendor/bootstrap.min.js', 'vendor/bootstrap-accessibility.min.js', 'vendor/validator.min.js', + 'lib/form-attr-polyfill.js', // input[form] polyfill, cannot load conditionally, since we need all versions of IE 'lib/autocomplete.js', 'common.js', 'lightbox.js', -- GitLab