Problem/Motivation

Not sure if this is feasible or even a useful user experience, but if you scroll to page 10, click an item and then click back, you will loose your state. This is probably the expected behavior, but it might be possible to automatically open N pages worth of content based on how far the user got.

Proposed resolution

See if this is worth solving.

Remaining tasks

  • Come up with some possible solutions.
  • Write a patch.
  • Make sure it's tested.

User interface changes

None.

API changes

None.

Data model changes

None yet...

CommentFileSizeAuthor
#78 use-page-parameter-when-not-ajax-2667516-77.patch2.2 KBgeophysicist
#76 2667516-76.patch13.18 KBolivier.br
#73 interdiff-2667516-72-73.txt3.14 KBYurkinPark
#73 2667516-73.patch13.31 KBYurkinPark
#72 2667516-72.patch13.45 KBsuresh prabhu parkala
#66 2667516-66.patch13.3 KBYurkinPark
#63 interdiff_62-63.txt1.25 KBolivier.br
#63 2667516-63.patch12.72 KBolivier.br
#62 interdiff_60-62.txt4.13 KBlammensj
#62 2667516-62.patch12.78 KBlammensj
#61 interdiff_56-60.txt890 bytesAnonymous (not verified)
#60 2667516-60.patch12.63 KBAnonymous (not verified)
#59 interdiff_56-59.txt792 bytesAnonymous (not verified)
#59 2667516_59.patch12.53 KBAnonymous (not verified)
#56 interdiff_2667516_52_56.txt670 bytesYurkinPark
#56 2667516_56.patch12.41 KBYurkinPark
#52 interdiff_2667516_50_52.txt4.21 KBYurkinPark
#52 2667516_52.patch12.5 KBYurkinPark
#50 views_infinite_scroll_history_2667516_50.patch9.82 KBnimoatwoodway
#49 interdiff_2667516_48_49.txt8.49 KBYurkinPark
#49 2667516_49.patch21.61 KBYurkinPark
#48 interdiff_2667516_47_48.txt2.36 KBYurkinPark
#48 2667516_48.patch12.57 KBYurkinPark
#47 2667516_47.patch10 KBYurkinPark
#45 use-page-parameter-when-not-ajax-2667516-39.patch1.15 KBgfed
#44 login_redirect_to_front-3021203-1.diff914 bytesgfed
#38 2667516-38.patch6.69 KBtimwood
#37 interdiff_29-37.txt7.39 KBfinnsky
#37 2667516-37.patch6.7 KBfinnsky
#35 interdiff_2667516-29-35.txt396 bytesfinnsky
#35 views_infinite_scroll_history_2667516_35.patch10 KBfinnsky
#33 interdiff_2667516_9_10.txt3.93 KBYurkinPark
#29 views_infinite_scroll_history_2667516_10.patch9.95 KBYurkinPark
#28 views_infinite_scroll_history_2667516_9.patch10.94 KBdexterns88
#25 views_infinite_scroll_history_2667516_8.patch10.06 KBYurkinPark
#24 views_infinite_scroll_history_2667516_7.patch9.97 KBYurkinPark
#19 views_infinite_scroll_history_2667516_6.patch10.29 KBvinlaurens
#16 views_infinite_scroll_history_2667516_5.patch10.29 KBvinlaurens
#13 views_infinite_scroll_history_2667516_4.patch9.62 KBvinlaurens
#10 views_infinite_scroll_history_2667516_3.patch7.01 KBvinlaurens
#7 views_infinite_scroll_history_2667516_2.patch20.58 KBvinlaurens
#6 views_infinite_scroll_history_2667516_1.patch9.76 KBvinlaurens

Comments

Sam152 created an issue. See original summary.

david.gil’s picture

This could help, interested in this issue...

https://css-tricks.com/rethinking-dynamic-page-replacing-content/

best
David

david.gil’s picture

Hi,

i have a solution for this problem using an external library:

https://github.com/highrisehq/snapback_cache.

For those of you that need something similar i just created a custom JS function in my theme:

(function ($) {
  'use strict';

  if ($('.js-infinite-scroll').length) {
    var snapbackCache = SnapbackCache({ bodySelector: "body", });
    $(document).ajaxComplete(function (e, xhr, settings) {
      snapbackCache.cachePage();
    });
  }

})(jQuery);

In my views-infinite-scroll-pager.html.twig i have added a class to views-infinite-scroll : js-infinite-scroll

Works perfect!

david.gil’s picture

Here is my last version of this:


(function ($) {
  'use strict';

  var snapbackCache = SnapbackCache({ bodySelector: "#main-content" });

  if ($('.js-infinite-scroll').length) {
    var $mainContent = $("#main-content");

    $mainContent.on("snapback-cache:loaded", function(e, cachedPage) {
      //console.log("snapback-cache:loaded");
      Drupal.attachBehaviors();
    });
    //$mainContent.on("snapback-cache:cached", function(e, cachedPage) {
    //  console.log("snapback-cache:cached");
    //});

    $(document).on("click", "a", function (e) {
      //console.log("snapback-cache: click en link, meto en la cache.");
      snapbackCache.cachePage();
    });
  }
})(jQuery);

vinlaurens’s picture

I am proposing a patch for this issue to incorporate this functionality into views_infinite_scroll. A patch is attached.

The patch offers an extra option in views_infinite_scroll settings interface where one can select to "preserve history" on a per view/per display basis when using the back button. It also works with views in blocks.

The solution works with sessionStorage to save the current status of the view. window.performance.navigation is used to determine if the user used the back button functionality. This methodology appears supported by all major browsers.

Any feedback is appreciated.

vinlaurens’s picture

Whoops. Seems something went wrong with attaching the patch.

vinlaurens’s picture

Fixing schema.

vinlaurens’s picture

Status: Active » Needs review
legolasbo’s picture

Status: Needs review » Needs work
  1. +++ b/js/infinite-scroll.behaviors.js
    @@ -0,0 +1,67 @@
    +    sessionStorage.removeItem("previousItems_"+viewIdentifier);
    +    sessionStorage.removeItem("previousPager_"+viewIdentifier);
    

    Wouldn't it be possible to store a single object containing both the previousItems (content?) and the previousPager? That would make checking for presence of data and clearing data from session storage a lot more straight forward.

  2. +++ b/js/infinite-scroll.behaviors.js
    @@ -0,0 +1,67 @@
    +  function issetSessionStorageData(viewIdentifier) {
    +    return (sessionStorage["previousPager_"+viewIdentifier] || sessionStorage["previousItems_"+viewIdentifier]);
    +  }
    

    Wouldn't 'hasDataInSessionStorage' be more descriptive for this method?

  3. +++ b/js/infinite-scroll.behaviors.js
    @@ -0,0 +1,67 @@
    +  function getContent(viewIdentifier) {
    +    var content = JSON.parse(sessionStorage.getItem("previousItems_"+viewIdentifier));
    +    if (typeof content !== 'undefined') {
    +      return htmlDecode(content);
    +    }
    +    return '';
    +  }
    

    'getContentFromSessionStorage' would better describe this method.

  4. +++ b/js/infinite-scroll.behaviors.js
    @@ -0,0 +1,67 @@
    +  function getPager(viewIdentifier) {
    +    var pager = JSON.parse(sessionStorage.getItem("previousPager_"+viewIdentifier));
    +    if (typeof pager !== 'undefined') {
    +      return htmlDecode(pager);
    +    }
    +    return '';
    +  }
    

    Same here, this gets a pager from session storage, so 'getPagerFromSessionStorage' would be more appropriate.

    I also noticed that getContent and getPager both have the same code, differing only in the item they get from session storage. This duplication should be removed.

  5. +++ b/js/infinite-scroll.behaviors.js
    @@ -0,0 +1,67 @@
    +      $('body', context).children().find("div[class*=view-id-]").once('attachBehaviors').each(function () {
    +        if (!window.performance) return;
    +        var pagerSelector = '[data-drupal-views-infinite-scroll-pager]';
    +        var viewId = /view-id-(\w+)/.exec($(this).attr('class'))[1];
    +        var viewDisplay = /view-display-id-(\w+)/.exec($(this).attr('class'))[1];
    +        var domViewId = getDomViewIdFromDom(viewId, viewDisplay);
    +        var view = Drupal.views.instances[domViewId];
    +        var viewIdentifier = viewId+"_"+viewDisplay+"_"+domViewId;
    +        if (!issetSessionStorageData(viewIdentifier)) return;
    +        if (performance.navigation.type !== performance.navigation.TYPE_BACK_FORWARD) {
    +          emptySessionStorage(viewIdentifier);
    +          return;
    +        }
    +        var $existingPager = view.$view.find(pagerSelector);
    +        var content = getContent(viewIdentifier);
    ...
    +        var pager = getPager(viewIdentifier);
    +        $existingPager.remove();
    +        $existingPager.once('pagerReplaced').each(function(){
    +          $existingPager.html(pager);
    +          view.$view.removeOnce('ajax-pager');
    +          view.$exposed_form.removeOnce('exposed-form');
    +          $existingPager.removeOnce('infinite-scroll');
    +        });
    

    This could do with some blank lines to improve readability.

    Besides that, I'm wondering what $('.view-id-'+viewId+'.view-display-id-'+viewDisplay+'.js-view-dom-id-'+domViewId.replace('views_dom_id:', '')+' > .view-content > .views-infinite-scroll-content-wrapper', context).append(content); does, it's one excessively long line. Can't that be broken up into several more descriptive statements?

  6. +++ b/js/infinite-scroll.js
    @@ -19,21 +22,49 @@
    +  var entityMap = {
    +    '&': '&',
    +    '<': '&lt;',
    +    '>': '&gt;',
    +    '"': '&quot;',
    +    "'": '&#39;',
    +    '/': '&#x2F;',
    +    '`': '&#x60;',
    +    '=': '&#x3D;'
    +  };
    +
       /**
    -   * Insert a views infinite scroll view into the document.
    -   *
    -   * @param {jQuery} $newView
    -   *   New content detached from the DOM.
    +   * Escapes HTML for sessionStorage as JSON string
    +   * @param string
    +   * @returns {string}
        */
    +  function escapeHtml (string) {
    +    return String(string).replace(/[&<>"'`=\/]/g, function (s) {
    +      return entityMap[s];
    +    });
    +  }
    +
    +  String.prototype.escapeSpecialChars = function() {
    +    return this.replace(/\\n/g, "\\n")
    +        .replace(/\\'/g, "\\'")
    +        .replace(/\\"/g, '\\"')
    +        .replace(/\\&/g, "\\&")
    +        .replace(/\\r/g, "\\r")
    +        .replace(/\\t/g, "\\t")
    +        .replace(/\\b/g, "\\b")
    +        .replace(/\\f/g, "\\f");
    +  };
    

    Do we really need to manually escape HTML? Can't we use some built in HTMLEncode function?

    We're bound to have forgotten a symbol which someone surely is going to have inserted into the content being displayed in a view, which would then break everything. So let's try to not re-invent the wheel.

  7. +++ b/js/infinite-scroll.js
    @@ -19,21 +22,49 @@
    -    // Remove once so that the exposed form and pager are processed on
    -    // behavior attach.
    +
    

    Why was this comment removed?

  8. +++ b/src/Plugin/views/pager/InfiniteScroll.php
    @@ -47,6 +47,9 @@ class InfiniteScroll extends SqlBase {
    +        'preserve_history' => [
    +          'default' => FALSE,
    +        ],
    

    I like how you've made this option opt-in so it doesn't affect existing sites unless they want it to.

  9. +++ b/src/Plugin/views/pager/InfiniteScroll.php
    @@ -87,7 +90,13 @@ class InfiniteScroll extends SqlBase {
       }
    -
     }
    +
    

    These changes are unrelated.

  10. +++ b/views_infinite_scroll.info.yml
    @@ -1,3 +1,4 @@
    +
     name: Views Infinite Scroll
     type: module
    

    This newline is unrelated.

  11. +++ b/views_infinite_scroll.module
    @@ -28,6 +28,7 @@ function views_infinite_scroll_preprocess_views_infinite_scroll_pager(&$vars) {
         'data-drupal-views-infinite-scroll-pager' => $vars['options']['automatically_load_content'] ? 'automatic' : TRUE,
    +    'data-drupal-views-infinite-scroll-history' => $vars['options']['preserve_history'] ? 'preserve-history' : TRUE,
       ]);
    

    So the default setting is to have history preservation turned off, but if the option hasn't been set yet we're turning it on? Seems like an error to me.

  12. +++ b/views_infinite_scroll.module
    @@ -40,6 +41,7 @@ function views_infinite_scroll_preprocess_views_view(&$vars) {
    diff --git a/views_infinite_scroll_history_2667516_1.patch b/views_infinite_scroll_history_2667516_1.patch
    
    diff --git a/views_infinite_scroll_history_2667516_1.patch b/views_infinite_scroll_history_2667516_1.patch
    new file mode 100644
    
    new file mode 100644
    index 0000000..538193f
    
    index 0000000..538193f
    --- /dev/null
    
    --- /dev/null
    +++ b/views_infinite_scroll_history_2667516_1.patch
    
    +++ b/views_infinite_scroll_history_2667516_1.patch
    +++ b/views_infinite_scroll_history_2667516_1.patch
    @@ -0,0 +1,264 @@
    
    @@ -0,0 +1,264 @@
    +diff --git a/js/infinite-scroll.behaviors.js b/js/infinite-scroll.behaviors.js
    +new file mode 100644
    +index 0000000..3abf6bf
    +--- /dev/null
    

    Oops. patchception. (in other words, you've added a patch to your patch)

vinlaurens’s picture

StatusFileSize
new7.01 KB

Thanks @legolasbo for your comments. I looked into them and provide the following patch. I agree with a lot of your points and they have been reflected in this new patch.

Besides that, I'm wondering what $('.view-id-'+viewId+'.view-display-id-'+viewDisplay+'.js-view-dom-id-'+domViewId.replace('views_dom_id:', '')+' > .view-content > .views-infinite-scroll-content-wrapper', context).append(content); does, it's one excessively long line. Can't that be broken up into several more descriptive statements?

The line is long because the content has to be appended in the exact right spot (children of certain identifiers, these identifiers include the view id, display id and dom id). This is to ensure we are really replacing the content of the right view. If you have suggestions on how to make this shorter without losing it's specificness, I'm open to ideas.

Do we really need to manually escape HTML? Can't we use some built in HTMLEncode function?

We're bound to have forgotten a symbol which someone surely is going to have inserted into the content being displayed in a view, which would then break everything. So let's try to not re-invent the wheel.

There doesn't appear to be a good solution for this in javascript (as far as I know). The developers of mustache.js apparently had the same problem (https://github.com/janl/mustache.js/blob/master/mustache.js#L60) and this is where I took this code excerpt from.

The patchception has been removed in the latest patch. ;)

vinlaurens’s picture

Status: Needs work » Needs review
legolasbo’s picture

Status: Needs review » Needs work
+++ b/js/infinite-scroll.js
@@ -19,13 +22,42 @@
+   * Escapes HTML for sessionStorage as JSON string
+   * @param string
+   * @returns {string}
    */
+  function escapeHtml (string) {
+    return String(string).replace(/[&<>"'`=\/]/g, function (s) {
+      return entityMap[s];
+    });
+  }
+
+  String.prototype.escapeSpecialChars = function() {
+    return this.replace(/\\n/g, "\\n")
+        .replace(/\\'/g, "\\'")
+        .replace(/\\"/g, '\\"')
+        .replace(/\\&/g, "\\&")
+        .replace(/\\r/g, "\\r")
+        .replace(/\\t/g, "\\t")
+        .replace(/\\b/g, "\\b")
+        .replace(/\\f/g, "\\f");
+  };

You could use encodeURIComponent and it's decodeURIComponent counterpart.

+++ b/config/schema/views_infinite_scroll.schema.yml
@@ -11,3 +11,6 @@ views.pager.infinite_scroll:
diff --git a/js/infinite-scroll.behaviors.js b/js/infinite-scroll.behaviors.js

Your latest patch seems to be missing this file. Are you sure you've got all relevant changes in there?

vinlaurens’s picture

StatusFileSize
new9.62 KB

Your latest patch seems to be missing this file. Are you sure you've got all relevant changes in there?

My bad. It was indeed accidentally omitted from the patch. I've corrected this in the new patch.

You could use encodeURIComponent and it's decodeURIComponent counterpart.

This doesn't seem to escape all special characters in my local environment. I see special characters popping up when loading content from sessionStorage. I will look into this further, but my current patch still uses the "old" method.

vinlaurens’s picture

Status: Needs work » Needs review
legolasbo’s picture

Status: Needs review » Needs work
  1. +++ b/js/infinite-scroll.behaviors.js
    @@ -0,0 +1,62 @@
    +    var matches = /(js-view-dom-id-\w+)/.exec($('div.view-id-' + viewId + '.view-display-id-' + viewDisplay).attr('class'));
    

    I'm not sure what this does exactly, but to me it seems like you're searching for some matches in the class list of an element selected through jQuery.

    Extracting the parameter for .exec() into a variable and giving that variable a meaningfull name would make this code easier to read and understand.

  2. +++ b/js/infinite-scroll.behaviors.js
    @@ -0,0 +1,62 @@
    +    sessionStorage.removeItem("viewPreviousData_"+viewIdentifier);
    

    I see this "viewsPreviousData_"+viewsIdentifier repeated quite a bit. how about extracting that into a getSessionStorageId(viewIdentifier) function.

  3. +++ b/js/infinite-scroll.behaviors.js
    @@ -0,0 +1,62 @@
    +        if (performance.navigation.type !== performance.navigation.TYPE_BACK_FORWARD) {
    +          emptySessionStorage(viewIdentifier);
    +          return;
    +        }
    
    if (!backButtonPressed()) {
      emptySessionStorage(viewIdentifier);
      return;
    }
    

    reads a lot better.

  4. +++ b/js/infinite-scroll.behaviors.js
    @@ -0,0 +1,62 @@
    +        $('.view-id-'+viewId+'.view-display-id-'+viewDisplay+'.js-view-dom-id-'+domViewId.replace('views_dom_id:', '')+' > .view-content > .views-infinite-scroll-content-wrapper', context).append(htmlDecode(data.articles));
    

    This could be something like

    var selector = .....replace(....);
    var decodedHtml = htmlDecode(data.articles);
    $(selector, context).append(decodedHtml);
    

    to make it easier to read and understand what's going on.

  5. +++ b/src/Plugin/views/pager/InfiniteScroll.php
    @@ -47,6 +47,9 @@ class InfiniteScroll extends SqlBase {
    +        'preserve_history' => [
    +          'default' => FALSE,
    +        ],
    

    Here you default preserve_history to FALSE in php. In javascript you do the opposite...

  6. +++ b/views_infinite_scroll.module
    @@ -28,6 +28,7 @@ function views_infinite_scroll_preprocess_views_infinite_scroll_pager(&$vars) {
    +    'data-drupal-views-infinite-scroll-history' => $vars['options']['preserve_history'] ? 'preserve-history' : TRUE,
    

    Here you default preserve-history to TRUE in javascript. In PHP you do the opposite...

In regards to encodeURIComponent... if it doesn't work, then it doesn't work.

vinlaurens’s picture

StatusFileSize
new10.29 KB

@legolasbo Thank you for your comments. I've changed the patch accordingly.

Regarding your points 5 and 6; I took the example of views_infinite_scroll itself in how it acts on the "automatic scrolling" setting. It also uses a default value of FALSE, while TRUE is defined in the preprocess function.

views_infinite_scroll.module

function views_infinite_scroll_preprocess_views_infinite_scroll_pager(&$vars) {
  $vars['attributes'] = new Attribute([
    'class' => ['js-pager__items', 'pager'],
    'data-drupal-views-infinite-scroll-pager' => $vars['options']['automatically_load_content'] ? 'automatic' : TRUE,
  ]);

InfiniteScroll.php

  public function defineOptions() {
    $options['views_infinite_scroll'] = [
        'contains' => [
          'automatically_load_content' => [
            'default' => FALSE,
          ],
      ],
    ];
}

I think this should be modified as well, in that case. It is not part of this change, so this is not included in this patch. I've tested the preserve history functionality with FALSE for "preserve-history" in views_infinite_scroll_preprocess_views_infinite_scroll_pager() and it appears to work correctly with that change. I've included the change for "preserve-history" in this patch as a consequence.

vinlaurens’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 16: views_infinite_scroll_history_2667516_5.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

vinlaurens’s picture

StatusFileSize
new10.29 KB

Apparently changing the value for preserve-history to FALSE will fail testing.

vinlaurens’s picture

Status: Needs work » Needs review
luksak’s picture

Status: Needs review » Needs work

There are a lot of selectors used in this script that don't have a js- prefix wich are not present in my custom theme and therefore completely breaks the functionality. After switching to the seven theme, the patch works perfectly. How could we resolve this?

vinlaurens’s picture

Lukas, few questions.

  • Can you point out which selectors are not working for your custom theme?
  • Is your custom theme based on another theme (subtheme)?

Initially I developed this patch for a customer with a custom theme based on "classy". Does your custom theme perhaps omit important Drupal css classes/ids?

YurkinPark’s picture

Hi all and thank you for your work. I was trying to implement this patch using composer and i couldn't. I double check what happened and realize that patch has useless modification for info.yml file (check git version and what can be downloaded, this file is different in 2 places :) ), i removed it and works ok + notice: to apply this patch on 8.x-1.5 you have to apply patch from this issue before https://www.drupal.org/node/2897611

YurkinPark’s picture

YurkinPark’s picture

Status: Needs work » Needs review
StatusFileSize
new10.06 KB

We found one more bug related to behaviors order, so ViewsInfiniteScrollHistory can be run after ViewsAjaxView and replaced pager can be just link wirhout AJAX attachments.

luksak’s picture

Status: Needs review » Needs work

Well, our theme is based on stable and most selectors used in JS in this patch don't work. here is one example:

var viewSelector = $('div.view-id-' + viewId + '.view-display-id-' + viewDisplay);

Basically the patch should work using the stable theme and not having the views wrapped in a <div> for example.

finnsky’s picture

after patch #25 was applied i catched issue when sessionStorage is empty for anonimous user on custom theme

dexterns88’s picture

With this patch views_infinite_scroll_history_2667516_8.patch I have missing 'views-row' element wrapper for new loaded element from cache. I made patch to fix this and store element with this wrapper.

YurkinPark’s picture

StatusFileSize
new9.95 KB

i got rid of selectors which are based on viewId and viewDisplayId. Now it works only using .js-view-dom-id- selector.

YurkinPark’s picture

Status: Needs work » Needs review
andypost’s picture

@YurkinPark please provide interdiff, it's really hard to follow your changes

YurkinPark’s picture

Interdiff

YurkinPark’s picture

StatusFileSize
new3.93 KB
vinlaurens’s picture

@YurkinPark, thanks for your contributions! I have applied views_infinite_scroll_history_2667516_10.patch to my project and it seems to be working as expected. I will try out these changes on a few other themes to see if I still run into things.

finnsky’s picture

On my side i had masonry module enabled. So after adding of

$('.views-infinite-scroll-content-wrapper', this).append(decodedContent);

masonry layout wasn't updated for me.
Suggested patch helps.

dtv_rb’s picture

Hi guys,

i was not able to apply the patches #35 or #29 via composer. After calling "composer update" the whole module folder "views_infinite_scroll" is gone. There was no error regarding applying the patch in composer update output. Any idea what could be the reason for this?

Composer config for the module is "drupal/views_infinite_scroll": "1.x-dev".

Drupal 8.5

Best,
Reiner

Edited: Got it running now. The patch in #23 solved my issue.

finnsky’s picture

StatusFileSize
new6.7 KB
new7.39 KB

Hi all! I added rework for #29
From my point of view it is better to put in storage loadMore urls. and attach them on back button. And better to use $.fn.infiniteScrollInsertView from module instead of simple html append.
Thanks.

timwood’s picture

StatusFileSize
new6.69 KB

Re-rolled patch for latest dev.

timwood’s picture

js/infinite-scroll.behaviors.js doesn't account for the case where you have a view configured for infinite scroll, but not have AJAX enabled. Errors with:

Uncaught TypeError: Cannot read property 'ajaxView' of undefined
    at infinite-scroll.behaviors.js?v=8.6.2:32
    at infinite-scroll.behaviors.js?v=8.6.2:91
timwood’s picture

In testing the module with this patch, I also saw issues where clicking a link from a view result, using back to go back to the view listing and clicking "load more" to display more results from the view would display duplicate results. Like it isn't remembering the right "page" of results I was on.

siavash’s picture

I'm experiencing the same problems. Also if you load more twice before clicking on an item and go back, the pages loaded again are in the wrong order. When you load more again, the page that was loaded first (But was last) is loaded again.
I'm also seeing js errors in the console when editing views ui, but it doesn't seem to be effecting anything (yet).

Thanks for working on this, I think it's an important feature to have!

Sia

siavash’s picture

I'm doing some debugging, it looks like the following two 'href's are stored and called on back button

(2) ["/products?search=&page=1", "/views/ajax?search=&page=2"]

Although these are triggered at the correct order, it seems like page 2 loads first. Could it be that it's faster because of the ajax callback or something?

I'm on the view page, exposed filter as a block with ajax enabled.

siavash’s picture

Seems like the url being different (page url vs internal views/ajax) doesn't matter, neither does the order of which they trigger. It always seems to load page 3 before 2 when you go back and then loads 3 again when you load more. Not sure what's going on.

gfed’s picture

StatusFileSize
new914 bytes

I've ran into the issue of preserving the state of infinite scroll (although with manual "load more" method). When using a module such as views_ajax_history, which mutates the URL to include exposed filter values as well as last page, we can modify the offset and limit values of the view using the "page" parameter (which will be in place as view_ajax_history pushes url changes to browser history using history.js library), in effect preserving state with minimal interference.

* Accidentally uploaded wrong file, not sure how to remove it. Actual patch below.

gfed’s picture

StatusFileSize
new1.15 KB

The last submitted patch, 44: login_redirect_to_front-3021203-1.diff, failed testing. View results

YurkinPark’s picture

StatusFileSize
new10 KB

In patch #47 i've re-rolled patch from #35. I've tested solution with ajax requests after clicking back and this works ugly for me: i've moved away from page after 4 load more and when i back - i've seen 4 ajax requests and infinite throbber.

YurkinPark’s picture

StatusFileSize
new12.57 KB
new2.36 KB

Provided front tests, seems like patch needs post update as well, will provide it too.

YurkinPark’s picture

StatusFileSize
new21.61 KB
new8.49 KB

Added post_update and update test.

nimoatwoodway’s picture

Re-rolled patch for latest dev.

Status: Needs review » Needs work

The last submitted patch, 50: views_infinite_scroll_history_2667516_50.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

YurkinPark’s picture

Status: Needs work » Needs review
StatusFileSize
new12.5 KB
new4.21 KB

New rerolled version

Status: Needs review » Needs work

The last submitted patch, 52: 2667516_52.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

dinesh18’s picture

I need to achieve the same thing on D7, Is there any patch available for D7 as well ?

YurkinPark’s picture

YurkinPark’s picture

Status: Needs work » Needs review
StatusFileSize
new12.41 KB
new670 bytes

Finally, i've realized that chrome doesn't set exact pixel position after clicking back button, confirmed even on desktop version. It seems like it started from some version.

ion.macaria’s picture

Great job. #56 works like a charm.

wturrell’s picture

(edited)

Small bug report with #56 if anyone can reproduce and has time to investigate?

- Keep clicking 'Load more' on your view until all items have been shown (and button therefore disappears)
- either click on an item and then navigate back OR don't click anything, but navigate back to preceding page, then go forward again

In either case, all items still visible, but "Undefined" shown in pager. Specifically:

<ul class="js-pager__items pager" data-drupal-views-infinite-scroll-pager="" data-drupal-views-infinite-scroll-history="preserve-history">undefined</ul>

No JS console errors.

Present in Firefox (70.0.1) and Chrome (78.0.3904.108) on macOS (10.13.6)
Safari (13.0.3) is OK though.

Drupal core 8.8-rc1.

Anonymous’s picture

StatusFileSize
new12.53 KB
new792 bytes

Fixed bug mentioned in #58

Anonymous’s picture

StatusFileSize
new12.63 KB

Not sure what I was thinking there, previous patch does not work. This one does.

Anonymous’s picture

StatusFileSize
new890 bytes

interdiff

lammensj’s picture

StatusFileSize
new12.78 KB
new4.13 KB

I was seeing console errors, complaining about an undefined index in `settings` (`settings.views.ajaxViews`). The included patch adds a check in `infinite-scroll.behaviors.js`.

olivier.br’s picture

StatusFileSize
new12.72 KB
new1.25 KB

Modifications from #62 were deleting my view content.
Here is a fix to that.

neslee canil pinto’s picture

Status: Needs review » Needs work
Issue tags: +Needs reroll

Patch failed to apply.

maithri shetty’s picture

Assigned: Unassigned » maithri shetty
YurkinPark’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll
StatusFileSize
new13.3 KB
YurkinPark’s picture

Not sure if this task is helpful since we have #2972129 already merged. I think task can be closed as outdated.

andypost’s picture

As it has tests and improves keyboard navigation - it makes sense)

luksak’s picture

Status: Needs review » Closed (outdated)
gambry’s picture

Status: Closed (outdated) » Needs review

I don't see how #2972129: Add option to initially load all pages up to the requested page when loading pages beyond the first fixes the problem in here?
I haven't tried myself so if someone can formulate if that brings history states and get the browser back button working that would be nice.

As #68 suggests this issue still bring benefits by introducing history state and tests.

Setting Needs Review back to trigger testbot, however likely this needs work for refactoring the code on top of the dev branch.

UPDATE: I've tried #2972129: Add option to initially load all pages up to the requested page when loading pages beyond the first and no, it doesn't bring history states and the back button doesn't work so this issue is still valid.

gambry’s picture

Status: Needs review » Needs work

Patch needs re-roll.

suresh prabhu parkala’s picture

Status: Needs work » Needs review
StatusFileSize
new13.45 KB

Just a re-roll.

YurkinPark’s picture

StatusFileSize
new13.31 KB
new3.14 KB

Fixing wrong conflict resolves in tests

gordon’s picture

I found this issue when I was trying to resolve an issue with Views ajax history when pressing the back after loading a few pages.

Why would I use this patch when the above module works and covers everything like filters, sorts and anything ajax and works when you are not using this pager.

This issue I was having was with going back, it would only load the last page, and and not all the previous pages. This has been resolved with 1.8 and the new option initially load all pages.

vuil’s picture

Status: Needs review » Reviewed & tested by the community

#73 patch works perfect for us.
I set the issue status to RTBC. Thank you @YurkinPark!

olivier.br’s picture

Version: 8.x-1.x-dev » 2.0.x-dev
StatusFileSize
new13.18 KB

Patch re-roll for 2.0 version

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 76: 2667516-76.patch, failed testing. View results

geophysicist’s picture

Thanks @gfed for the beautiful solution. Added some customization to apply #39 patch for 2.0.0 version.
It works with views_ajax_history

nicklasmf’s picture

#73 can't be applied anymore. I'm on Core 8.9 and views_infinite_scroll 1.9.

attisan’s picture

Status: Needs work » Reviewed & tested by the community

#78 + views_ajax_history = this is the way 💪

anybody’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs tests

Thanks all! Could this please be reworked as MR?

Furthermore I'm unsure if we should really merge it without being a separate option, that can be disabled. I think we should first have tests for this module to ensure it doesn't break important functionality.