Skip to content
Snippets Groups Projects
Commit f384d4e9 authored by Brian Canini's avatar Brian Canini
Browse files

Merge branch 'views_infinite_scroll' into module-updates-rc

parents 6b7356d2 1162e4d5
No related branches found
No related tags found
No related merge requests found
Showing
with 138 additions and 47 deletions
...@@ -8649,17 +8649,17 @@ ...@@ -8649,17 +8649,17 @@
}, },
{ {
"name": "drupal/views_infinite_scroll", "name": "drupal/views_infinite_scroll",
"version": "1.7.0", "version": "1.8.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://git.drupalcode.org/project/views_infinite_scroll.git", "url": "https://git.drupalcode.org/project/views_infinite_scroll.git",
"reference": "8.x-1.7" "reference": "8.x-1.8"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://ftp.drupal.org/files/projects/views_infinite_scroll-8.x-1.7.zip", "url": "https://ftp.drupal.org/files/projects/views_infinite_scroll-8.x-1.8.zip",
"reference": "8.x-1.7", "reference": "8.x-1.8",
"shasum": "42ff1b7c835a2cb0755425999bb8251f19c62fac" "shasum": "b9fceb24184792fb81c4e2ff1bf7f18fd8e50674"
}, },
"require": { "require": {
"drupal/core": "^8.8 || ^9" "drupal/core": "^8.8 || ^9"
...@@ -8667,8 +8667,8 @@ ...@@ -8667,8 +8667,8 @@
"type": "drupal-module", "type": "drupal-module",
"extra": { "extra": {
"drupal": { "drupal": {
"version": "8.x-1.7", "version": "8.x-1.8",
"datestamp": "1584489857", "datestamp": "1614959012",
"security-coverage": { "security-coverage": {
"status": "covered", "status": "covered",
"message": "Covered by Drupal's security advisory policy" "message": "Covered by Drupal's security advisory policy"
......
...@@ -11,7 +11,8 @@ CONTENTS OF THIS FILE ...@@ -11,7 +11,8 @@ CONTENTS OF THIS FILE
INTRODUCTION INTRODUCTION
------------ ------------
The Views Infinite Scroll module provides a pager, which allows an infinite scroll effect for views. It can work on any view: block, page, etc. The Views Infinite Scroll module provides a pager, which allows an infinite
scroll effect for views. It can work on any view: block, page, etc.
* For a full description of the module visit https://www.drupal.org/project/views_infinite_scroll * For a full description of the module visit https://www.drupal.org/project/views_infinite_scroll
...@@ -33,13 +34,18 @@ INSTALLATION ...@@ -33,13 +34,18 @@ INSTALLATION
CONFIGURATION CONFIGURATION
------------- -------------
1. Navigate to Administration > Extend and enable the Views Infinite Scroll module. 1. Navigate to Administration > Extend and enable the Views Infinite Scroll
2. Navigate to Administration > Structure > Views and click + Add view to create a new view, when done creating the new view, click Save and edit. module.
3. In the "Page Settings" fieldset, enable "Use a page" by checking the appropriate box. Select "Save and edit". 2. Navigate to Administration > Structure > Views and click + Add view to
4. In the "Pager" fieldset, click on the link after "Use pager", which defaults to Mini. create a new view, when done creating the new view, click Save and edit.
3. In the "Page Settings" fieldset, enable "Use a page" by checking the
appropriate box. Select "Save and edit".
4. In the "Pager" fieldset, click on the link after "Use pager", which defaults
to Mini.
5. Select "Infinite Scroll". Apply the changes. 5. Select "Infinite Scroll". Apply the changes.
6. In the field set "Infinite Scroll Options" edit the button text. 6. In the field set "Infinite Scroll Options" edit the button text.
7. Check the "Automatically Load Content" box if the functionality of automatically loading subsequent pages as the user scrolls is desired. 7. Check the "Automatically Load Content" box if the functionality of
automatically loading subsequent pages as the user scrolls is desired.
8. Select and amount of Items to display. Apply changes. 8. Select and amount of Items to display. Apply changes.
9. Save the view. 9. Save the view.
...@@ -47,6 +53,7 @@ CONFIGURATION ...@@ -47,6 +53,7 @@ CONFIGURATION
MAINTAINERS MAINTAINERS
----------- -----------
* Neslee Canil Pinto - https://www.drupal.org/u/neslee-canil-pinto
* Sam Becker (Sam152) - https://www.drupal.org/u/sam152 * Sam Becker (Sam152) - https://www.drupal.org/u/sam152
* Remon Georgy (Remon) - https://www.drupal.org/u/remon * Remon Georgy (Remon) - https://www.drupal.org/u/remon
......
...@@ -11,3 +11,6 @@ views.pager.infinite_scroll: ...@@ -11,3 +11,6 @@ views.pager.infinite_scroll:
automatically_load_content: automatically_load_content:
type: boolean type: boolean
label: 'Automatically Load Content' label: 'Automatically Load Content'
initially_load_all_pages:
type: boolean
label: 'Initially load all pages'
/**
* @file
* Infinite Scroll JS.
*/
(function ($, Drupal, debounce) { (function ($, Drupal, debounce) {
"use strict"; "use strict";
...@@ -43,8 +48,13 @@ ...@@ -43,8 +48,13 @@
var $newRows = $newView.find(contentWrapperSelector).children(); var $newRows = $newView.find(contentWrapperSelector).children();
var $newPager = $newView.find(pagerSelector); var $newPager = $newView.find(pagerSelector);
// Add the new rows to existing view. view.$view.find(contentWrapperSelector)
view.$view.find(contentWrapperSelector).append($newRows); // Trigger a jQuery event on the wrapper to inform that new content was
// loaded and allow other scripts to respond to the event.
.trigger('views_infinite_scroll.new_content', $newRows.clone())
// Add the new rows to existing view.
.append($newRows);
// Replace the pager link with the new link and ajaxPageState values. // Replace the pager link with the new link and ajaxPageState values.
$existingPager.replaceWith($newPager); $existingPager.replaceWith($newPager);
...@@ -63,16 +73,22 @@ ...@@ -63,16 +73,22 @@
* During `unload` remove the scroll event binding. * During `unload` remove the scroll event binding.
*/ */
Drupal.behaviors.views_infinite_scroll_automatic = { Drupal.behaviors.views_infinite_scroll_automatic = {
attach : function(context, settings) { attach : function (context, settings) {
$(context).find(automaticPagerSelector).once('infinite-scroll').each(function() { $(context).find(automaticPagerSelector).once('infinite-scroll').each(function () {
var $pager = $(this); var $pager = $(this);
$pager.addClass('visually-hidden'); $pager.addClass('visually-hidden');
$window.on(scrollEvent, debounce(function() { var isLoadNeeded = function () {
if (window.innerHeight + window.pageYOffset > $pager.offset().top - scrollThreshold) { return window.innerHeight + window.pageYOffset > $pager.offset().top - scrollThreshold;
};
$window.on(scrollEvent, debounce(function () {
if (isLoadNeeded()) {
$pager.find('[rel=next]').click(); $pager.find('[rel=next]').click();
$window.off(scrollEvent); $window.off(scrollEvent);
} }
}, 200)); }, 200));
if (isLoadNeeded()) {
$window.trigger(scrollEvent);
}
}); });
}, },
detach: function (context, settings, trigger) { detach: function (context, settings, trigger) {
......
...@@ -18,9 +18,9 @@ class AjaxResponseSubscriber implements EventSubscriberInterface { ...@@ -18,9 +18,9 @@ class AjaxResponseSubscriber implements EventSubscriberInterface {
* @param array $commands * @param array $commands
* An array of commands to alter. * An array of commands to alter.
*/ */
protected function alterPaginationCommands(&$commands) { protected function alterPaginationCommands(array &$commands) {
foreach ($commands as $delta => &$command) { foreach ($commands as $delta => &$command) {
// Substitute the 'replace' method without our custom jQuery method which // Substitute the 'replace' method with our custom jQuery method which
// will allow views content to be injected one after the other. // will allow views content to be injected one after the other.
if (isset($command['method']) && $command['method'] === 'replaceWith') { if (isset($command['method']) && $command['method'] === 'replaceWith') {
$command['method'] = 'infiniteScrollInsertView'; $command['method'] = 'infiniteScrollInsertView';
...@@ -49,7 +49,9 @@ public function onResponse(FilterResponseEvent $event) { ...@@ -49,7 +49,9 @@ public function onResponse(FilterResponseEvent $event) {
$view = $response->getView(); $view = $response->getView();
// Only alter commands if the user has selected our pager and it attempting // Only alter commands if the user has selected our pager and it attempting
// to move beyond page 0. // to move beyond page 0.
if ($view->getPager()->getPluginId() !== 'infinite_scroll' || $view->getCurrentPage() === 0) { if ($view->getPager()->getPluginId() !== 'infinite_scroll' || $event->getRequest()->query->get('page') == 0) {
// When the current page is 0 it might be the case that there where no
// additional items in this case we want to still append the empty result.
return; return;
} }
......
<?php <?php
namespace Drupal\views_infinite_scroll\Plugin\views\pager; namespace Drupal\views_infinite_scroll\Plugin\views\pager;
use Drupal\views\Plugin\views\pager\SqlBase; use Drupal\views\Plugin\views\pager\SqlBase;
...@@ -23,11 +22,13 @@ class InfiniteScroll extends SqlBase { ...@@ -23,11 +22,13 @@ class InfiniteScroll extends SqlBase {
* {@inheritdoc} * {@inheritdoc}
*/ */
public function render($input) { public function render($input) {
$this->updatePageInfo();
// Replace tokens in the button text. // Replace tokens in the button text.
$text = $this->options['views_infinite_scroll']['button_text']; $text = $this->options['views_infinite_scroll']['button_text'];
if (!empty($text) && strpos($text, '@') !== FALSE) { if (!empty($text) && strpos($text, '@') !== FALSE) {
$replacements = [ $replacements = [
'@next_page_count' => $this->getNumberItemsLeft(), '@next_page_count' => $this->getNumberItemsLeft(),
'@remaining_items_count' => $this->getRemainingNumberItems(),
'@total' => (int) $this->getTotalItems(), '@total' => (int) $this->getTotalItems(),
]; ];
$this->options['views_infinite_scroll']['button_text'] = strtr($text, $replacements); $this->options['views_infinite_scroll']['button_text'] = strtr($text, $replacements);
...@@ -36,6 +37,7 @@ public function render($input) { ...@@ -36,6 +37,7 @@ public function render($input) {
return [ return [
'#theme' => $this->themeFunctions(), '#theme' => $this->themeFunctions(),
'#options' => $this->options['views_infinite_scroll'], '#options' => $this->options['views_infinite_scroll'],
'#view' => $this->view,
'#attached' => [ '#attached' => [
'library' => ['views_infinite_scroll/views-infinite-scroll'], 'library' => ['views_infinite_scroll/views-infinite-scroll'],
], ],
...@@ -57,6 +59,9 @@ public function defineOptions() { ...@@ -57,6 +59,9 @@ public function defineOptions() {
'automatically_load_content' => [ 'automatically_load_content' => [
'default' => FALSE, 'default' => FALSE,
], ],
'initially_load_all_pages' => [
'default' => FALSE,
],
], ],
]; ];
return $options; return $options;
...@@ -67,7 +72,14 @@ public function defineOptions() { ...@@ -67,7 +72,14 @@ public function defineOptions() {
*/ */
public function summaryTitle() { public function summaryTitle() {
$action = $this->options['views_infinite_scroll']['automatically_load_content'] ? $this->t('Automatic infinite scroll') : $this->t('Click to load'); $action = $this->options['views_infinite_scroll']['automatically_load_content'] ? $this->t('Automatic infinite scroll') : $this->t('Click to load');
return $this->formatPlural($this->options['items_per_page'], '@action, @count item', '@action, @count items', ['@action' => $action, '@count' => $this->options['items_per_page']]); $pages = $this->options['views_infinite_scroll']['initially_load_all_pages'] ? $this->t('Initially load all pages') : $this->t('Initially load one page');
return $this->formatPlural($this->options['items_per_page'], '@action, @count item', '@action, @count items, @pages',
[
'@action' => $action,
'@count' => $this->options['items_per_page'],
'@pages' => $pages,
]
);
} }
/** /**
...@@ -94,6 +106,7 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) { ...@@ -94,6 +106,7 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
'#theme' => 'item_list', '#theme' => 'item_list',
'#items' => [ '#items' => [
'@next_page_count -- the next page record count', '@next_page_count -- the next page record count',
'@remaining_items_count -- the remaining amount of results',
'@total -- the total amount of results returned from the view', '@total -- the total amount of results returned from the view',
], ],
'#prefix' => $this->t('The following tokens are supported:'), '#prefix' => $this->t('The following tokens are supported:'),
...@@ -105,9 +118,31 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) { ...@@ -105,9 +118,31 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
'#description' => $this->t('Automatically load subsequent pages as the user scrolls.'), '#description' => $this->t('Automatically load subsequent pages as the user scrolls.'),
'#default_value' => $options['automatically_load_content'], '#default_value' => $options['automatically_load_content'],
], ],
'initially_load_all_pages' => [
'#type' => 'checkbox',
'#title' => $this->t('Initially load all pages up to the requested page'),
'#description' => $this->t('When initially loading a page beyond the first, this option will load all pages up to the requested page instead of just the requested page. So, if you have the pager set to 10 items per page, and you load the page with ?page=2 in the url, you will get page 0, 1 and 2 loaded for a total of 30 items. <em>Note that this could cause some long page load times when loading many pages.</em>'),
'#default_value' => $options['initially_load_all_pages'],
],
]; ];
} }
/**
* {@inheritdoc}
*/
public function query() {
// Run the pant method which is sufficient if we're on the first page.
parent::query();
// If configured, for pages beyond the first, we want to show all items up
// to the current page.
if ($this->options['views_infinite_scroll']['initially_load_all_pages'] && !\Drupal::request()->isXmlHttpRequest() && $this->current_page > 0) {
$limit = ($this->current_page + 1) * $this->options['items_per_page'];
$offset = $this->options['offset'];
$this->view->query->setLimit($limit);
$this->view->query->setOffset($offset);
}
}
/** /**
* Returns the number of items in the next page. * Returns the number of items in the next page.
* *
...@@ -129,4 +164,18 @@ protected function getNumberItemsLeft() { ...@@ -129,4 +164,18 @@ protected function getNumberItemsLeft() {
return $next_page_count; return $next_page_count;
} }
/**
* Returns the number of items remaining over the next pages.
*
* @return int
* The number of items over the remaining pages.
*/
protected function getRemainingNumberItems() {
$items_per_page = (int) $this->view->getItemsPerPage();
$total = (int) $this->getTotalItems();
$current_page = (int) $this->getCurrentPage() + 1;
return $total - ($current_page * $items_per_page);
}
} }
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
{% if items.next %} {% if items.next %}
<ul{{ attributes }}> <ul{{ attributes }}>
<li class="pager__item"> <li class="pager__item">
<a class="button" href="{{ items.next.href }}" title="{{ 'Go to next page'|t }}" rel="next">{{ options.button_text }}</a> <a class="button" href="{{ items.next.href }}" title="{{ 'Load more items'|t }}" rel="next">{{ options.button_text }}</a>
</li> </li>
</ul> </ul>
{% endif %} {% endif %}
...@@ -36,7 +36,8 @@ protected function setUp() { ...@@ -36,7 +36,8 @@ protected function setUp() {
*/ */
public function testPlugin() { public function testPlugin() {
// Create a view with the pager plugin enabled. // Create a view with the pager plugin enabled.
$this->drupalPostForm('admin/structure/views/add', [ $this->drupalGet('admin/structure/views/add');
$this->submitForm([
'label' => 'Test Plugin', 'label' => 'Test Plugin',
'id' => 'test_plugin', 'id' => 'test_plugin',
'page[create]' => '1', 'page[create]' => '1',
...@@ -44,23 +45,23 @@ public function testPlugin() { ...@@ -44,23 +45,23 @@ public function testPlugin() {
'page[path]' => 'test-plugin', 'page[path]' => 'test-plugin',
], 'Save and edit'); ], 'Save and edit');
$this->clickLink('Mini'); $this->clickLink('Mini');
$this->drupalPostForm(NULL, [ $this->submitForm([
'pager[type]' => 'infinite_scroll', 'pager[type]' => 'infinite_scroll',
], 'Apply'); ], 'Apply');
$this->drupalPostForm(NULL, [ $this->submitForm([
'pager_options[views_infinite_scroll][button_text]' => 'More Please', 'pager_options[views_infinite_scroll][button_text]' => 'More Please',
'pager_options[views_infinite_scroll][automatically_load_content]' => '', 'pager_options[views_infinite_scroll][automatically_load_content]' => '',
], 'Apply'); ], 'Apply');
$this->assertSession()->linkExists('Infinite Scroll'); $this->assertSession()->linkExists('Infinite Scroll');
$this->assertSession()->pageTextContains('Click to load, 10 items'); $this->assertSession()->pageTextContains('Click to load, 10 items');
$this->drupalPostForm(NULL, [], 'Save'); $this->submitForm([], 'Save');
// Open the permissions to view the page. // Open the permissions to view the page.
$this->clickLink('Permission'); $this->clickLink('Permission');
$this->drupalPostForm(NULL, [ $this->submitForm([
'access[type]' => 'none', 'access[type]' => 'none',
], 'Apply'); ], 'Apply');
$this->drupalPostForm(NULL, [], 'Save'); $this->submitForm([], 'Save');
// Ensure the wrapper div appears on the page. // Ensure the wrapper div appears on the page.
$this->drupalGet('test-plugin'); $this->drupalGet('test-plugin');
......
...@@ -64,6 +64,15 @@ public function testInfiniteScroll() { ...@@ -64,6 +64,15 @@ public function testInfiniteScroll() {
$this->assertSession()->waitForElement('css', '.node--type-page:nth-child(4)'); $this->assertSession()->waitForElement('css', '.node--type-page:nth-child(4)');
$this->assertTotalNodes(6); $this->assertTotalNodes(6);
// Test loading a page past the first.
$this->createView('initially-load-all', [
'button_text' => 'Load More',
'automatically_load_content' => FALSE,
'initially_load_all_pages' => TRUE,
]);
$this->drupalGet('initially-load-all', ['query' => ['page' => 1]]);
$this->assertTotalNodes(6);
// Test the view automatically loading. // Test the view automatically loading.
$this->createView('automatic-load', [ $this->createView('automatic-load', [
'button_text' => 'Load More', 'button_text' => 'Load More',
...@@ -96,6 +105,16 @@ public function testInfiniteScroll() { ...@@ -96,6 +105,16 @@ public function testInfiniteScroll() {
$this->getSession()->getPage()->clickLink('Load 5 more of 11'); $this->getSession()->getPage()->clickLink('Load 5 more of 11');
$this->assertSession()->waitForElement('css', '.node--type-page:nth-child(7)'); $this->assertSession()->waitForElement('css', '.node--type-page:nth-child(7)');
$this->assertTotalNodes(11); $this->assertTotalNodes(11);
// Test @remaining_items_count token.
$this->createView('remaining-items-count', [
'button_text' => 'Load @next_page_count more of @remaining_items_count remaining',
'automatically_load_content' => FALSE,
]);
$this->drupalGet('remaining-items-count');
$this->getSession()->getPage()->clickLink('Load 3 more of 8 remaining');
$this->assertSession()->waitForElement('css', '.node--type-page:nth-child(7)');
$this->assertTotalNodes(6);
} }
/** /**
...@@ -128,7 +147,7 @@ protected function scrollTo($pixels) { ...@@ -128,7 +147,7 @@ protected function scrollTo($pixels) {
* @param int $items_per_page * @param int $items_per_page
* The number of items per page to display. * The number of items per page to display.
*/ */
protected function createView($path, $settings, $items_per_page = 3) { protected function createView($path, array $settings, $items_per_page = 3) {
View::create([ View::create([
'label' => 'VIS Test', 'label' => 'VIS Test',
'id' => $this->randomMachineName(), 'id' => $this->randomMachineName(),
......
...@@ -7,7 +7,7 @@ core_version_requirement: ^8.8 || ^9 ...@@ -7,7 +7,7 @@ core_version_requirement: ^8.8 || ^9
dependencies: dependencies:
- drupal:views - drupal:views
# Information added by Drupal.org packaging script on 2020-03-18 # Information added by Drupal.org packaging script on 2021-03-05
version: '8.x-1.7' version: '8.x-1.8'
project: 'views_infinite_scroll' project: 'views_infinite_scroll'
datestamp: 1584489859 datestamp: 1614959014
...@@ -22,9 +22,9 @@ function views_infinite_scroll_preprocess_views_infinite_scroll_pager(&$vars) { ...@@ -22,9 +22,9 @@ function views_infinite_scroll_preprocess_views_infinite_scroll_pager(&$vars) {
$pager = $pager_manager->getPager($element); $pager = $pager_manager->getPager($element);
if (isset($pager) && $pager->getCurrentPage() < ($pager->getTotalPages() - 1)) { if (isset($pager) && $pager->getCurrentPage() < ($pager->getTotalPages() - 1)) {
$options = array( $options = [
'query' => $pager_manager->getUpdatedParameters($parameters, $element, $pager->getCurrentPage() + 1), 'query' => $pager_manager->getUpdatedParameters($parameters, $element, $pager->getCurrentPage() + 1),
); ];
$vars['items']['next']['href'] = Url::fromRoute('<none>', [], $options); $vars['items']['next']['href'] = Url::fromRoute('<none>', [], $options);
} }
$vars['#cache']['contexts'][] = 'url.query_args'; $vars['#cache']['contexts'][] = 'url.query_args';
...@@ -46,15 +46,9 @@ function views_infinite_scroll_preprocess_views_view(&$vars) { ...@@ -46,15 +46,9 @@ function views_infinite_scroll_preprocess_views_view(&$vars) {
if (!isset($vars['rows']['#theme_wrappers'])) { if (!isset($vars['rows']['#theme_wrappers'])) {
$vars['rows']['#theme_wrappers'] = []; $vars['rows']['#theme_wrappers'] = [];
} }
$vars['rows']['#theme_wrappers']['container'] = [ $vars['rows']['#theme_wrappers']['container']['#attributes']['data-drupal-views-infinite-scroll-content-wrapper'] = TRUE;
'#attributes' => [ $vars['rows']['#theme_wrappers']['container']['#attributes']['class'][] = 'views-infinite-scroll-content-wrapper';
'data-drupal-views-infinite-scroll-content-wrapper' => TRUE, $vars['rows']['#theme_wrappers']['container']['#attributes']['class'][] = 'clearfix';
'class' => [
'views-infinite-scroll-content-wrapper',
'clearfix',
],
],
];
} }
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment