diff --git a/productcomments.php b/productcomments.php index fb9ee754..99a505b7 100644 --- a/productcomments.php +++ b/productcomments.php @@ -898,7 +898,6 @@ public function hookDisplayHeader() if ($this->context->controller instanceof ProductControllerCore) { $jsList[] = '/modules/productcomments/views/js/post-comment.js'; $jsList[] = '/modules/productcomments/views/js/list-comments.js'; - $jsList[] = '/modules/productcomments/views/js/jquery.simplePagination.js'; } foreach ($cssList as $cssUrl) { $this->context->controller->registerStylesheet(sha1($cssUrl), $cssUrl, ['media' => 'all', 'priority' => 80]); @@ -969,6 +968,13 @@ private function renderProductCommentsList($product) $commentsNb = $productCommentRepository->getCommentsNumber($product->id, (bool) Configuration::get('PRODUCT_COMMENTS_MODERATE')); $isPostAllowed = $productCommentRepository->isPostAllowed($product->id, (int) $this->context->cookie->id_customer, (int) $this->context->cookie->id_guest); + /* configure pagination */ + $commentsTotalPages = 0; + $commentsPerPage = (int) Configuration::get('PRODUCT_COMMENTS_COMMENTS_PER_PAGE'); + if ($commentsNb > 0) { + $commentsTotalPages = ceil($commentsNb / $commentsPerPage); + } + $this->context->smarty->assign([ 'post_allowed' => $isPostAllowed, 'usefulness_enabled' => Configuration::get('PRODUCT_COMMENTS_USEFULNESS'), @@ -987,6 +993,7 @@ private function renderProductCommentsList($product) 'productcomments', 'ReportComment' ), + 'list_total_pages' => $commentsTotalPages, ]); return $this->context->smarty->fetch('module:productcomments/views/templates/hook/product-comments-list.tpl'); diff --git a/views/css/productcomments.css b/views/css/productcomments.css index ab40df51..106d2808 100644 --- a/views/css/productcomments.css +++ b/views/css/productcomments.css @@ -589,7 +589,7 @@ font-size: 13px; } -@media (min-width: 768px) { +@media (min-width: 960px) { #product-comments-list-footer { position: relative; min-height: 45px; @@ -607,7 +607,7 @@ } } -@media (max-width: 768px) { +@media (max-width: 960px) { #product-comments-list-footer { display: flex; flex-direction: row-reverse; @@ -616,7 +616,7 @@ } } -@media (max-width: 576px) { +@media (max-width: 768px) { #product-comments-list-footer { display: flex; flex-direction: column; @@ -665,3 +665,7 @@ #product-comments-list-pagination ul li.active span { cursor: not-allowed; } + +#product-comments-list-pagination ul li.hidden { + display: none; +} diff --git a/views/js/jquery.simplePagination.js b/views/js/jquery.simplePagination.js deleted file mode 100644 index 1108cdc6..00000000 --- a/views/js/jquery.simplePagination.js +++ /dev/null @@ -1,398 +0,0 @@ -/** -* simplePagination.js v1.6 -* A simple jQuery pagination plugin. -* http://flaviusmatis.github.com/simplePagination.js/ -* -* Copyright 2012, Flavius Matis -* Released under the MIT license. -* http://flaviusmatis.github.com/license.html -*/ - -(function($){ - - var methods = { - init: function(options) { - var o = $.extend({ - items: 1, - itemsOnPage: 1, - pages: 0, - displayedPages: 5, - edges: 2, - currentPage: 0, - useAnchors: true, - hrefTextPrefix: '#page-', - hrefTextSuffix: '', - prevText: 'Prev', - nextText: 'Next', - ellipseText: '…', - ellipsePageSet: true, - cssStyle: 'light-theme', - listStyle: '', - labelMap: [], - selectOnClick: true, - nextAtFront: false, - invertPageOrder: false, - useStartEdge : true, - useEndEdge : true, - onPageClick: function(pageNumber, event) { - // Callback triggered when a page is clicked - // Page number is given as an optional parameter - }, - onInit: function() { - // Callback triggered immediately after initialization - } - }, options || {}); - - var self = this; - - o.pages = o.pages ? o.pages : Math.ceil(o.items / o.itemsOnPage) ? Math.ceil(o.items / o.itemsOnPage) : 1; - if (o.currentPage) - o.currentPage = o.currentPage - 1; - else - o.currentPage = !o.invertPageOrder ? 0 : o.pages - 1; - o.halfDisplayed = o.displayedPages / 2; - - this.each(function() { - self.addClass(o.cssStyle + ' simple-pagination').data('pagination', o); - methods._draw.call(self); - }); - - o.onInit(); - - return this; - }, - - selectPage: function(page) { - methods._selectPage.call(this, page - 1); - return this; - }, - - prevPage: function() { - var o = this.data('pagination'); - if (!o.invertPageOrder) { - if (o.currentPage > 0) { - methods._selectPage.call(this, o.currentPage - 1); - } - } else { - if (o.currentPage < o.pages - 1) { - methods._selectPage.call(this, o.currentPage + 1); - } - } - return this; - }, - - nextPage: function() { - var o = this.data('pagination'); - if (!o.invertPageOrder) { - if (o.currentPage < o.pages - 1) { - methods._selectPage.call(this, o.currentPage + 1); - } - } else { - if (o.currentPage > 0) { - methods._selectPage.call(this, o.currentPage - 1); - } - } - return this; - }, - - getPagesCount: function() { - return this.data('pagination').pages; - }, - - setPagesCount: function(count) { - this.data('pagination').pages = count; - }, - - getCurrentPage: function () { - return this.data('pagination').currentPage + 1; - }, - - destroy: function(){ - this.empty(); - return this; - }, - - drawPage: function (page) { - var o = this.data('pagination'); - o.currentPage = page - 1; - this.data('pagination', o); - methods._draw.call(this); - return this; - }, - - redraw: function(){ - methods._draw.call(this); - return this; - }, - - disable: function(){ - var o = this.data('pagination'); - o.disabled = true; - this.data('pagination', o); - methods._draw.call(this); - return this; - }, - - enable: function(){ - var o = this.data('pagination'); - o.disabled = false; - this.data('pagination', o); - methods._draw.call(this); - return this; - }, - - updateItems: function (newItems) { - var o = this.data('pagination'); - o.items = newItems; - o.pages = methods._getPages(o); - this.data('pagination', o); - methods._draw.call(this); - }, - - updateItemsOnPage: function (itemsOnPage) { - var o = this.data('pagination'); - o.itemsOnPage = itemsOnPage; - o.pages = methods._getPages(o); - this.data('pagination', o); - methods._selectPage.call(this, 0); - return this; - }, - - getItemsOnPage: function() { - return this.data('pagination').itemsOnPage; - }, - - _draw: function() { - var o = this.data('pagination'), - interval = methods._getInterval(o), - i, - tagName; - - methods.destroy.call(this); - - tagName = (typeof this.prop === 'function') ? this.prop('tagName') : this.attr('tagName'); - - var $panel = tagName === 'UL' ? this : $('').appendTo(this); - - // Generate Prev link - if (o.prevText) { - methods._appendItem.call(this, !o.invertPageOrder ? o.currentPage - 1 : o.currentPage + 1, {text: o.prevText, classes: 'prev'}); - } - - // Generate Next link (if option set for at front) - if (o.nextText && o.nextAtFront) { - methods._appendItem.call(this, !o.invertPageOrder ? o.currentPage + 1 : o.currentPage - 1, {text: o.nextText, classes: 'next'}); - } - - // Generate start edges - if (!o.invertPageOrder) { - if (interval.start > 0 && o.edges > 0) { - if(o.useStartEdge) { - var end = Math.min(o.edges, interval.start); - for (i = 0; i < end; i++) { - methods._appendItem.call(this, i); - } - } - if (o.edges < interval.start && (interval.start - o.edges != 1)) { - $panel.append('
  • ' + o.ellipseText + '
  • '); - } else if (interval.start - o.edges == 1) { - methods._appendItem.call(this, o.edges); - } - } - } else { - if (interval.end < o.pages && o.edges > 0) { - if(o.useStartEdge) { - var begin = Math.max(o.pages - o.edges, interval.end); - for (i = o.pages - 1; i >= begin; i--) { - methods._appendItem.call(this, i); - } - } - - if (o.pages - o.edges > interval.end && (o.pages - o.edges - interval.end != 1)) { - $panel.append('
  • ' + o.ellipseText + '
  • '); - } else if (o.pages - o.edges - interval.end == 1) { - methods._appendItem.call(this, interval.end); - } - } - } - - // Generate interval links - if (!o.invertPageOrder) { - for (i = interval.start; i < interval.end; i++) { - methods._appendItem.call(this, i); - } - } else { - for (i = interval.end - 1; i >= interval.start; i--) { - methods._appendItem.call(this, i); - } - } - - // Generate end edges - if (!o.invertPageOrder) { - if (interval.end < o.pages && o.edges > 0) { - if (o.pages - o.edges > interval.end && (o.pages - o.edges - interval.end != 1)) { - $panel.append('
  • ' + o.ellipseText + '
  • '); - } else if (o.pages - o.edges - interval.end == 1) { - methods._appendItem.call(this, interval.end); - } - if(o.useEndEdge) { - var begin = Math.max(o.pages - o.edges, interval.end); - for (i = begin; i < o.pages; i++) { - methods._appendItem.call(this, i); - } - } - } - } else { - if (interval.start > 0 && o.edges > 0) { - if (o.edges < interval.start && (interval.start - o.edges != 1)) { - $panel.append('
  • ' + o.ellipseText + '
  • '); - } else if (interval.start - o.edges == 1) { - methods._appendItem.call(this, o.edges); - } - - if(o.useEndEdge) { - var end = Math.min(o.edges, interval.start); - for (i = end - 1; i >= 0; i--) { - methods._appendItem.call(this, i); - } - } - } - } - - // Generate Next link (unless option is set for at front) - if (o.nextText && !o.nextAtFront) { - methods._appendItem.call(this, !o.invertPageOrder ? o.currentPage + 1 : o.currentPage - 1, {text: o.nextText, classes: 'next'}); - } - - if (o.ellipsePageSet && !o.disabled) { - methods._ellipseClick.call(this, $panel); - } - - }, - - _getPages: function(o) { - var pages = Math.ceil(o.items / o.itemsOnPage); - return pages || 1; - }, - - _getInterval: function(o) { - return { - start: Math.ceil(o.currentPage > o.halfDisplayed ? Math.max(Math.min(o.currentPage - o.halfDisplayed, (o.pages - o.displayedPages)), 0) : 0), - end: Math.ceil(o.currentPage > o.halfDisplayed ? Math.min(o.currentPage + o.halfDisplayed, o.pages) : Math.min(o.displayedPages, o.pages)) - }; - }, - - _appendItem: function(pageIndex, opts) { - var self = this, options, $link, o = self.data('pagination'), $linkWrapper = $('
  • '), $ul = self.find('ul'); - - pageIndex = pageIndex < 0 ? 0 : (pageIndex < o.pages ? pageIndex : o.pages - 1); - - options = { - text: pageIndex + 1, - classes: '' - }; - - if (o.labelMap.length && o.labelMap[pageIndex]) { - options.text = o.labelMap[pageIndex]; - } - - options = $.extend(options, opts || {}); - - if (pageIndex == o.currentPage || o.disabled) { - if (o.disabled || options.classes === 'prev' || options.classes === 'next') { - $linkWrapper.addClass('disabled'); - } else { - $linkWrapper.addClass('active'); - } - $link = $('' + (options.text) + ''); - } else { - if (o.useAnchors) { - $link = $('' + (options.text) + ''); - } else { - $link = $('' + (options.text) + ''); - } - $link.click(function(event){ - return methods._selectPage.call(self, pageIndex, event); - }); - } - - if (options.classes) { - $link.addClass(options.classes); - } - - $linkWrapper.append($link); - - if ($ul.length) { - $ul.append($linkWrapper); - } else { - self.append($linkWrapper); - } - }, - - _selectPage: function(pageIndex, event) { - var o = this.data('pagination'); - o.currentPage = pageIndex; - if (o.selectOnClick) { - methods._draw.call(this); - } - return o.onPageClick(pageIndex + 1, event); - }, - - - _ellipseClick: function($panel) { - var self = this, - o = this.data('pagination'), - $ellip = $panel.find('.ellipse'); - $ellip.addClass('clickable').parent().removeClass('disabled'); - $ellip.click(function(event) { - if (!o.disable) { - var $this = $(this), - val = (parseInt($this.parent().prev().text(), 10) || 0) + 1; - $this - .html('') - .find('input') - .focus() - .click(function(event) { - // prevent input number arrows from bubbling a click event on $ellip - event.stopPropagation(); - }) - .keyup(function(event) { - var val = $(this).val(); - if (event.which === 13 && val !== '') { - // enter to accept - if ((val>0)&&(val<=o.pages)) - methods._selectPage.call(self, val - 1); - } else if (event.which === 27) { - // escape to cancel - $ellip.empty().html(o.ellipseText); - } - }) - .bind('blur', function(event) { - var val = $(this).val(); - if (val !== '') { - methods._selectPage.call(self, val - 1); - } - $ellip.empty().html(o.ellipseText); - return false; - }); - } - return false; - }); - } - - }; - - $.fn.pagination = function(method) { - - // Method calling logic - if (methods[method] && method.charAt(0) != '_') { - return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); - } else if (typeof method === 'object' || !method) { - return methods.init.apply(this, arguments); - } else { - $.error('Method ' + method + ' does not exist on jQuery.pagination'); - } - - }; - -})(jQuery); diff --git a/views/js/list-comments.js b/views/js/list-comments.js index 697c9ec6..89bc6c40 100644 --- a/views/js/list-comments.js +++ b/views/js/list-comments.js @@ -32,7 +32,13 @@ jQuery(document).ready(function () { const reportCommentUrl = commentsList.data('report-comment-url'); const commentPrototype = commentsList.data('comment-item-prototype'); - emptyProductComment.hide(); + const pagesListId = '#product-comments-list-pagination'; + const pageIdPrefix = '#pcl_page_'; + const totalPages = commentsList.data('total-pages'); + const prevCount = 0; + const nextCount = totalPages + 1; + const gapText = '…'; + $('.grade-stars').rating(); prestashop.on('updatedProduct', function() { @@ -59,31 +65,80 @@ jQuery(document).ready(function () { reportCommentPostErrorModal.modal('show'); } - function paginateComments(page) { - $.get(commentsListUrl, {page: page}, function(jsonResponse) { - if (jsonResponse.comments && jsonResponse.comments.length > 0) { - populateComments(jsonResponse.comments); - if (jsonResponse.comments_nb > jsonResponse.comments_per_page) { - $('#product-comments-list-pagination').pagination({ - currentPage: page, - items: jsonResponse.comments_nb, - itemsOnPage: jsonResponse.comments_per_page, - cssStyle: '', - prevText: '', - nextText: '', - useAnchors: false, - displayedPages: 2, - onPageClick: paginateComments - }); - } else { - $('#product-comments-list-pagination').hide(); - } - } else { - commentsList.html(''); - emptyProductComment.show(); - commentsList.append(emptyProductComment); + async function fetchComments(page) { + let response = await fetch(commentsListUrl + "&page=" + page); + + if (response.status === 200) { + let data = await response.text(); + populateComments((JSON.parse(data)).comments); + } + } + + $(pagesListId + ' li').on('click', + function() { + let oldCount = commentsList.data('current-page'); + let newCount = $(this).index(); + + if (newCount === prevCount) { // click prev + newCount = oldCount - 1; + if (newCount <= 0) return; } - }); + if (newCount === nextCount) { // click next + newCount = oldCount + 1; + if (newCount >= nextCount) return; + } + + $(`${pageIdPrefix}${oldCount} span`).removeClass('current'); + $(`${pageIdPrefix}${oldCount}`).removeClass('active'); + + fetchComments(newCount); // fetch new page's comments + + $(`${pageIdPrefix}${newCount}`).addClass('active'); + $(`${pageIdPrefix}${newCount} span`).addClass('current'); + + $(`${pageIdPrefix}${newCount} span`).html(newCount); + commentsList.data('current-page', newCount); + + if (newCount === 1) // disable prev + $(`${pageIdPrefix}${prevCount}`).addClass('disabled'); + else + $(`${pageIdPrefix}${prevCount}`).removeClass('disabled'); + + if (newCount === totalPages) // disable next + $(`${pageIdPrefix}${nextCount}`).addClass('disabled'); + else + $(`${pageIdPrefix}${nextCount}`).removeClass('disabled'); + + // long list with over 9 pages + if (9 <= totalPages) { + generateGap(newCount, prevCount); + generateGap(newCount, nextCount); + } + } + ) + + function generateGap(start, stop) { + if (start == stop) + return 0; + let step = (start < stop) ? +1 : -1; + let i = start + step; + if (4 < Math.abs(stop - start)) { + $(`${pageIdPrefix}${i}`).removeClass('hidden').removeClass('disabled'); + $(`${pageIdPrefix}${i} span`).html(i); + i = i + step; + $(`${pageIdPrefix}${i}`).removeClass('hidden').removeClass('disabled'); + $(`${pageIdPrefix}${i} span`).html(gapText); + i = i + step; + for (; i != stop - 2*step; i = i + step) { + $(`${pageIdPrefix}${i}`).addClass('hidden'); + } + } + else { + for (; i != stop; i = i + step) { + $(`${pageIdPrefix}${i}`).removeClass('hidden').removeClass('disabled'); + $(`${pageIdPrefix}${i} span`).html(i); + } + } } function populateComments(comments) { @@ -165,5 +220,11 @@ jQuery(document).ready(function () { }) } - paginateComments(1); + if (totalPages <= 1) + $(pagesListId).hide(); + + if (totalPages > 0) { + emptyProductComment.hide(); + $(`${pageIdPrefix}1`).trigger('click'); + } }); diff --git a/views/templates/hook/product-comments-list.tpl b/views/templates/hook/product-comments-list.tpl index 3d07c5ee..1f353544 100644 --- a/views/templates/hook/product-comments-list.tpl +++ b/views/templates/hook/product-comments-list.tpl @@ -42,11 +42,25 @@ data-list-comments-url="{$list_comments_url nofilter}" data-update-comment-usefulness-url="{$update_comment_usefulness_url nofilter}" data-report-comment-url="{$report_comment_url nofilter}" - data-comment-item-prototype="{$comment_prototype|escape:'html'}"> + data-comment-item-prototype="{$comment_prototype|escape:'html'}" + data-current-page="1" + data-total-pages="{$list_total_pages}">