From 88951879460802675ec26082ca0d73379be23772 Mon Sep 17 00:00:00 2001 From: gloas <gloas@afi-sa.fr> Date: Wed, 15 Sep 2021 13:41:38 +0200 Subject: [PATCH] hotline MT #134907 fix list with tools --- VERSIONS_HOTLINE/134907 | 1 + .../Assets/js/truncate_list_tools.js | 51 ++++++++ .../templates/Intonation/Library/Settings.php | 8 ++ .../View/RenderAjaxPaginatedList.php | 16 +-- .../Intonation/View/RenderTruncateList.php | 121 ++++++++---------- .../View/RenderTruncateList/Tools.php | 44 +++++++ .../Polygone/Assets/js/scroll_search.js | 3 + public/opac/java/search_input/search_input.js | 3 + .../TemplatesAbonneSelectionsTest.php | 6 + .../Templates/TemplatesAbonneTest.php | 52 ++++++-- .../Templates/TemplatesWidgetTest.php | 7 + 11 files changed, 226 insertions(+), 86 deletions(-) create mode 100644 VERSIONS_HOTLINE/134907 create mode 100644 library/templates/Intonation/Assets/js/truncate_list_tools.js create mode 100644 library/templates/Intonation/View/RenderTruncateList/Tools.php diff --git a/VERSIONS_HOTLINE/134907 b/VERSIONS_HOTLINE/134907 new file mode 100644 index 00000000000..c3ac6076cbc --- /dev/null +++ b/VERSIONS_HOTLINE/134907 @@ -0,0 +1 @@ + - ticket #134907 : Magasin de thèmes : Correction du composant liste avec interaction. Le mot élément est accordé en fonction du nombre d'éléments. La barre d'outils en bas de la liste est maintenant fonctionnelle. \ No newline at end of file diff --git a/library/templates/Intonation/Assets/js/truncate_list_tools.js b/library/templates/Intonation/Assets/js/truncate_list_tools.js new file mode 100644 index 00000000000..4ea25b177f9 --- /dev/null +++ b/library/templates/Intonation/Assets/js/truncate_list_tools.js @@ -0,0 +1,51 @@ +(function ( $ ) { + $.fn.truncate_list_tools = function (params) { + var widget = $(this); + var container = widget.find('.truncate_list_wrapper'); + + var page_size = params['page_size']; + container.children().slice(0, page_size).show(); + + widget.find('select.select_size_tool') + .change(function() + { + container.children().hide(); + var size = $(this).val(); + widget.find('select.select_size_tool').not(this).val(size); + container.children().not('.search_input_not_found').slice(0, size).show(); + }); + + widget.find('input.input_search_tool') + .removeAttr('onkeypress') + .keypress(function(event) + { + return event.which != 13; + }) + .keyup(function() + { + widget.find('select.select_size_tool').val(10000); + + var html_size = widget.find('.truncate_list_size').first().html(); + + var single = params['single'] + '$'; + var single_reg_exp = new RegExp(single, 'gi'); + var html_size_plural = html_size.replace(single_reg_exp, params['plural']); + + var plural = params['plural'] + '$'; + var plural_reg_exp = new RegExp(plural, 'gi'); + var html_size_single = html_size.replace(plural_reg_exp, params['single']); + + var list_size = container.children(':visible').length; + + widget.find('.truncate_list_size').html(1 >= list_size ? html_size_single : html_size_plural); + widget.find('.truncate_list_size_number').text(list_size); + + var searchText = $(this).val(); + + if (!searchText || searchText == '' || searchText == '*') + widget.find('select.select_size_tool').val(params['page_size']).change(); + + widget.find('input.input_search_tool').not(this).val(searchText); + }); + }; +} (jQuery)); diff --git a/library/templates/Intonation/Library/Settings.php b/library/templates/Intonation/Library/Settings.php index e9e4ee3d2b3..a24a301b81c 100644 --- a/library/templates/Intonation/Library/Settings.php +++ b/library/templates/Intonation/Library/Settings.php @@ -312,6 +312,14 @@ class Intonation_Library_Settings extends Intonation_System_Abstract { 'a class account-disconnect' => 'btn btn-sm btn-secondary', 'span class user_notifications' => 'btn btn-sm list-group-item-danger', 'div class babeltheque_reviews' => 'mt-3 mb-3', + 'span class truncate_list_size' => 'btn btn-sm btn-info', + 'div class truncate_list_size_wrapper' => 'col-12 col-sm-3', + 'div class truncate_list_form_wrapper' => 'col-12 col-sm-9', + 'div class truncate_list_container' => 'container my-2', + 'div class truncate_list_row' => 'justify-content-start', + 'div class truncate_list_wrapper' => 'col-12 list-group bg-transparent no_border', + 'div class truncate_list_top_tools' => 'col-12', + 'div class truncate_list_bottom_tools' => 'col-12', ], 'icons_map_doc_types' => [], diff --git a/library/templates/Intonation/View/RenderAjaxPaginatedList.php b/library/templates/Intonation/View/RenderAjaxPaginatedList.php index a4aaef34739..8e86884d5ce 100644 --- a/library/templates/Intonation/View/RenderAjaxPaginatedList.php +++ b/library/templates/Intonation/View/RenderAjaxPaginatedList.php @@ -161,17 +161,9 @@ class Intonation_View_RenderAjaxPaginatedList extends ZendAfi_View_Helper_BaseHe 'submit_' . $this->_id, ['class' => 'd-none']); - $html = [$this->_tag('div', - $this->_tag('span' , - $this->_('%s éléments', $this->_tag('span', - $helper->getSize())), - ['class' => 'btn btn-sm btn-info']), - ['class' => 'col-12 col-sm-3']), - - $this->_tag('div', - $this->view->renderInlineForm($form), - ['class' => 'ajax_paginated_form col-12 col-sm-9'])]; - - return $this->view->grid($html, ['class' => 'container my-2'], ['class' => 'justify-content-start']); + return + $this->view->RenderTruncateList_Tools($form, + $helper->getSize(), + 'ajax_paginated_form'); } } diff --git a/library/templates/Intonation/View/RenderTruncateList.php b/library/templates/Intonation/View/RenderTruncateList.php index bda4d5e242f..68a195ae590 100644 --- a/library/templates/Intonation/View/RenderTruncateList.php +++ b/library/templates/Intonation/View/RenderTruncateList.php @@ -27,64 +27,64 @@ class Intonation_View_RenderTruncateList extends ZendAfi_View_Helper_BaseHelper $_page_size = 3, $_ajax_size = 20, $_container_id, - $_input_id, + $_widget_id, + $_top_tools_id, + $_bottom_tools_id, $_carousel_context; public function renderTruncateList($collection, $callback, $page_size = 3) { - $this->_container_id = $id = uniqid(); - $this->_input_id = 'input_' . $this->_container_id; - if ($collection->isEmpty()) return ''; - $this->_page_size = $page_size; - $size = $collection->count(); if ($this->_ajax_size < $size) return $this->_ajaxifyList($collection); - if ($this->_page_size >= $size && $this->_page_size <= $this->_min_size_for_tools) - return $this->view->renderList($collection, $callback); + $this->_page_size = $page_size; - $html = $collection - ->injectInto('', function($html, $element) use ($callback) - { - return $html . $this->_tag('div', - $callback($element->inJsSearch()), - ['style' => 'display: none', - 'class' => 'list-group-item bg-transparent px-0']); - }); - - $tools = $this->_renderTools($size); - - return - $tools - . $this->_tag('div', - $html, - ['id' => $this->_container_id, - 'class' => 'list-group bg-transparent no_border']) - . $tools; + return ($this->_page_size >= $size && $this->_page_size <= $this->_min_size_for_tools) + ? $this->view->renderList($collection, $callback) + : $this->_truncateListWithTools($collection, $callback, $size); } - protected function _renderTools($size) { - $size_id = uniqid(); - $id = uniqid(); + protected function _truncateListWithTools($collection, $callback, $size) { + $this->_container_id = uniqid(); + $this->_widget_id = 'truncate_list_widget_id_' . $this->_container_id; + $this->_top_tools_id = 'top_tools_' . $this->_container_id; + $this->_bottom_tools_id = 'bottom_tools_' . $this->_container_id; + + $html = $collection + ->injectInto('', function($html, $element) use ($callback) + { + return $html . $this->_tag('div', + $callback($element->inJsSearch()), + ['style' => 'display: none', + 'class' => 'list-group-item bg-transparent px-0']); + }); $this->renderHeadScriptsOn(Class_ScriptLoader::getInstance()); - $onchange = - "var container = $('#" . $this->_container_id . "');" - . "container.children().hide();" - . "var value=$('#" . $id . "').val();" - . "container.children().not('.search_input_not_found').slice(0, value).show();"; + $top_tools = $this->_div(['class' => 'truncate_list_top_tools'], + $this->_renderTools($size, $this->_top_tools_id)); - $input_keyup = - "$('#" . $id . "').val(10000).change();" - . "setTimeout(function() { $('#" . $size_id . "').text($('#" . $this->_container_id . "').children(':visible').length); var searchText = $('#" . $this->_input_id . "').val(); if (!searchText || searchText == '' || searchText == '*') $('#" . $id . "').val(" . $this->_page_size . ").change();}, 10);"; + $list_html = $this->_tag('div', + $html, + ['id' => $this->_container_id, + 'class' => 'truncate_list_wrapper']); + $bottom_tools = $this->_div(['class' => 'truncate_list_bottom_tools'], + $this->_renderTools($size, $this->_bottom_tools_id)); + + return $this->_div(['class' => 'truncate_list_widget', + 'id' => $this->_widget_id], + $this->view->grid($top_tools . $list_html . $bottom_tools)); + } + + + protected function _renderTools($size, $tools_id) { $multi_options = $this->_getTruncateOptions($size); $form = new ZendAfi_Form; @@ -92,57 +92,46 @@ class Intonation_View_RenderTruncateList extends ZendAfi_View_Helper_BaseHelper $form ->setAction('GET') ->addElement('select', - $id, + 'select_' . $tools_id, ['label' => $this->_('Afficher'), 'title' => $this->_('Limiter le nombre d\'éléments à afficher'), - 'onchange' => $onchange, - 'multiOptions' => $multi_options]) + 'multiOptions' => $multi_options, + 'class' => 'select_size_tool']) ->addElement('text', - $this->_input_id, + 'input_' . $tools_id, ['label' => $this->_('Filtrer'), 'placeholder' => $this->_('Filtrer avec un nom, un mot, une date'), 'title' => $this->_('Filtrer la liste avec des noms, des mots, des dates'), - 'onkeyup' => $input_keyup]) + 'class' => 'input_search_tool']) ->addElement('submit', - md5($id), + 'submit_' . $tools_id, ['class' => 'd-none']); - return $this->view->grid($this->_tag('div', - $this->_tag('span' , - $this->_tag('span', - $size, - ['id' => $size_id]) - . $this->_(' éléments'), - ['class' => 'btn btn-sm btn-info']), - ['class' => 'col-12 col-sm-3']) - - . $this->_tag('div', - $this->view->renderInlineForm($form), - ['class' => 'col-12 col-sm-9']), - ['class' => 'container my-2'], - ['class' => 'justify-content-start']); + return $this->view->RenderTruncateList_Tools($form, $size, 'paginated_form'); } protected function _getTruncateOptions($size) { - return [$this->_page_size => $this->_page_size, - $this->_page_size * 2 => $this->_page_size * 2, - $this->_page_size * 5 => $this->_page_size * 5, - '10000' => $this->_('Tout')]; + return [$this->_page_size => $this->_page_size, + $this->_page_size * 2 => $this->_page_size * 2, + $this->_page_size * 5 => $this->_page_size * 5, + '10000' => $this->_('Tout')]; } public function renderHeadScriptsOn($script_loader) { $script_loader ->addSearchInputToContainer('#' . $this->_container_id, - '#' . $this->_input_id, + '#input_' . $this->_top_tools_id . ', #input_' . $this->_bottom_tools_id, '#' . $this->_container_id . ' div.card *, .dropdown, .dropdown-menu') - - ->addJQueryReady("var container = $('#" . $this->_container_id . "');" - . "setTimeout(function() {container.children().slice(0, " . $this->_page_size . ").show();" - . "$('#" . $this->_input_id . "').attr('onkeypress', 'return event.keyCode != 13;');}, 10);"); + ->addScripts([Class_Url::absolute('/library/templates/Intonation/Assets/js/truncate_list_tools.js')]) + ->addJQueryReady(sprintf('$("#%s").truncate_list_tools({page_size: "%s", single: "%s", plural: "%s"});', + $this->_widget_id, + $this->_page_size, + $this->_('élément'), + $this->_('éléments'))); return $this; } diff --git a/library/templates/Intonation/View/RenderTruncateList/Tools.php b/library/templates/Intonation/View/RenderTruncateList/Tools.php new file mode 100644 index 00000000000..37596b95e04 --- /dev/null +++ b/library/templates/Intonation/View/RenderTruncateList/Tools.php @@ -0,0 +1,44 @@ +<?php +/** + * Copyright (c) 2012-2021, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH is free software; you can redistribute it and/or modify + * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE + * along with BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +class Intonation_View_RenderTruncateList_Tools extends ZendAfi_View_Helper_BaseHelper { + public function RenderTruncateList_Tools($form, $size, $form_class) { + $size_html = $this->_div(['class' => 'truncate_list_size_wrapper'], + $this->_tag('span' , + $this->_plural($size, + 'Pas d\'élément', + '%s élément', + '%s éléments', + $this->_tag('span', + $size, + ['class' => 'truncate_list_size_number'])), + ['class' => 'truncate_list_size'])); + + $form_html = $this->_div(['class' => 'truncate_list_form_wrapper ' . $form_class], + $this->view->renderInlineForm($form)); + + return + $this->view->grid( $size_html . $form_html, + ['class' => 'truncate_list_container'], + ['class' => 'justify-content-start']); + } +} diff --git a/library/templates/Polygone/Assets/js/scroll_search.js b/library/templates/Polygone/Assets/js/scroll_search.js index 648afb2dc90..5ad5ef6943d 100644 --- a/library/templates/Polygone/Assets/js/scroll_search.js +++ b/library/templates/Polygone/Assets/js/scroll_search.js @@ -23,6 +23,9 @@ var search_widget = $(this); var visible = function(element) { + if ( ! element) + return; + var rect = element.getBoundingClientRect(), top = rect.top, height = rect.height; diff --git a/public/opac/java/search_input/search_input.js b/public/opac/java/search_input/search_input.js index 9dc4cf2ddd8..c9fcc3407d2 100644 --- a/public/opac/java/search_input/search_input.js +++ b/public/opac/java/search_input/search_input.js @@ -110,6 +110,9 @@ var checkRegex = function (reg_exps, value) { var check = true; + if ( ! reg_exps) + return check; + reg_exps.forEach(function (regexp) { check &= regexp.test(accentsTidy(value)); }); diff --git a/tests/scenarios/Templates/TemplatesAbonneSelectionsTest.php b/tests/scenarios/Templates/TemplatesAbonneSelectionsTest.php index 5e702dbf00b..981b59de19a 100644 --- a/tests/scenarios/Templates/TemplatesAbonneSelectionsTest.php +++ b/tests/scenarios/Templates/TemplatesAbonneSelectionsTest.php @@ -181,6 +181,12 @@ class TemplatesAbonneSelectionsAsAbonneTest extends TemplatesAbonneSelectionsTes public function linkToFollowASearchShouldBePresent() { $this->assertXPathContentContains('//div[@class = "collection_action alone_in_the_list btn btn-sm btn-success col mr-3 col-3"]//a', 'Suivre'); } + + + /** @test */ + public function scriptTruncateListToolsShouldBeLoaded() { + $this->assertXPath('//script[contains(@src, "/library/templates/Intonation/Assets/js/truncate_list_tools.js")]'); + } } diff --git a/tests/scenarios/Templates/TemplatesAbonneTest.php b/tests/scenarios/Templates/TemplatesAbonneTest.php index ad0acdd389c..49db660f4f8 100644 --- a/tests/scenarios/Templates/TemplatesAbonneTest.php +++ b/tests/scenarios/Templates/TemplatesAbonneTest.php @@ -397,6 +397,36 @@ class TemplatesDispatchAbonneLoansPaginatedTest extends TemplatesIntonationAccou $this->assertXPathContentContains('//div//a[contains(@href, "/bib-numerique/return-pnb-loan/id/38bcd646a69f4da7fce8921d4cf762ad/page/1/id_profil/72/search/house/size/10/loan_id/666_3")]', 'Retour anticip'); $this->assertXPathContentContains('//div//a[contains(@href, "/bib-numerique/extends-pnb-loan/id/38bcd646a69f4da7fce8921d4cf762ad/page/1/id_profil/72/search/house/size/10/loan_id/666_3")]', 'Prolonger'); } + + + /** @test */ + public function loansListShouldCountShouldBeNoElement() { + Storm_Cache::beVolatile(); + + $cards = new Class_User_Cards(Class_Users::getIdentity()); + + $loans = $cards->getPNBLoans([]); + + $loans = array_map(function($loan) + { + return (new Intonation_Library_View_Wrapper_PNBLoan) + ->setModel($loan) + ->setView($this->view); + }, $loans->getArrayCopy()); + + $collection = new Storm_Collection($loans); + + $helper = (new Intonation_Library_AjaxPaginatedListHelper) + ->setCollection($collection) + ->setRendering('cardifyHorizontal'); + + + $id = $helper->getId(); + + $this->dispatch('/opac/index/ajax-paginated-list/id/' . $id . '/page/1/id_profil/72/search/no+data/size/1'); + $this->assertXPathContentContains('//div[@class="truncate_list_size_wrapper col-12 col-sm-3"]//span[@class="truncate_list_size btn btn-sm btn-info"]', + utf8_encode('Pas d\'élément')); + } } @@ -678,12 +708,6 @@ class TemplatesDispatchAbonneLargeNumberOfHoldsTest extends TemplatesIntonationA } - /** @test */ - public function selectOnChangeShouldBePresent() { - $this->assertXPath('//select[contains(@onchange,"var container = $(")][contains(@onchange, "container.children().hide();var value=$(")][contains(@onchange, "val();container.children().not(\'.search_input_not_found\').slice(0, value).show()")]'); - } - - /** @test */ public function holdsShouldBeDisplaydInListGroup() { $this->assertXPath('//div[contains(@class, "list-group")]//div[contains(@class, "list-group-item")]//div[contains(@class, "card")]'); @@ -697,8 +721,20 @@ class TemplatesDispatchAbonneLargeNumberOfHoldsTest extends TemplatesIntonationA /** @test */ - public function scriptShouldContainsChildrenSliceShow() { - $this->assertXPathContentContains('//script', 'setTimeout(function() {container.children().slice(0, 20).show();'); + public function truncateListSizeShouldBe20Elements() { + $this->assertXPathContentContains('//div[@class="truncate_list_size_wrapper col-12 col-sm-3"]//span[@class="truncate_list_size btn btn-sm btn-info"]', '20 éléments'); + } + + + /** @test */ + public function scriptTruncateListToolsShouldBeLoaded() { + $this->assertXPath('//script[contains(@src, "/library/templates/Intonation/Assets/js/truncate_list_tools.js")]'); + } + + + /** @test */ + public function pageShouldBeHTML5Valid() { + $this->assertHTML5(); } } diff --git a/tests/scenarios/Templates/TemplatesWidgetTest.php b/tests/scenarios/Templates/TemplatesWidgetTest.php index 6e1c8964cc7..8adc46b325f 100644 --- a/tests/scenarios/Templates/TemplatesWidgetTest.php +++ b/tests/scenarios/Templates/TemplatesWidgetTest.php @@ -1547,6 +1547,13 @@ class TemplatesWidgetWithPaginatedListTest extends AbstractControllerTestCase { public function nextButtonShouldNotHaveDataDisabled() { $this->assertXPath('//a[contains(@class, "btn btn-sm btn-secondary ajax_anchor next_ajax_anchor")][not(@data-disabled)]'); } + + + /** @test */ + public function truncateListSizeShouldBe10Elements() { + $this->assertXPathContentContains('//div[@class="truncate_list_size_wrapper col-12 col-sm-3"]//span[@class="truncate_list_size btn btn-sm btn-info"]', + utf8_encode('10 éléments')); + } } -- GitLab