2

I want to scroll down the page at page load time to bring a feature that might be below the fold into the viewport. Script works fine for anonymous, but for authenticated user, Toolbar module overlays the content I just scrolled to.

I've read that the way to resolve this is using Drupal.displace.offsets.top but when I call that from within my behavior Drupal.displace is undefined. I've been using comment-new-indicator.js from comment module as my guide here, and clearly my usecase is a little different because I'm doing this around page load time.

The problem is two fold: Drupal.displace isn't loaded when my script is called AND Toolbar hasn't done its stuff yet. I've cleared caches both in browser and drush numerous times. I've mucked with JS weights in libraries.yml -- nothing works.

One thought was to delay the initial execution with a 500 ms smudge to wait for some eventual viewport adjustment milliseconds later (that may or may not ever happen). So far this isn't really working well either, I don't want to delay the smudge longer for normal users because it becomes too noticeable.

Another thought was to register an event listener for drupalViewportOffsetChange but for some reason that never gets triggered.

mytheme.libraries.yml

custom-scroll-feature:
  js:
    js/custom-scroll-feature.js: { weight: -1 }
  dependencies:
    - core/jquery
    - core/drupal
    - core/drupal.displace

js/custom-scroll-feature.js

(function ($, Drupal) {

  'use strict';

  Drupal.behaviors.customScrollFeature = {
    attach: function (context, settings) {

      console.log(Drupal.displace);
      // outputs 'undefined' 

      console.log(Drupal);
      // outputs
      // {behaviors: {…}, locale: {…}, throwError: ƒ, attachBehaviors: ƒ, detachBehaviors: ƒ, …}
      // no mention of Drupal.displace


      var start = time();
      $(document).on('drupalViewportOffsetChange', function () {
        console.log(Drupal);
        console.log(displace);
        var end = time(),
          elapsed = end - start;
        console.log("elapsed: " + elapsed);
        // The above never gets triggered.
      });

    }
  };

})(jQuery, Drupal);

With JS aggregation off, I've confirmed that jquery.js, drupal.js, and displace.js are all present in the list of requests on chrome network tab and appear before custom-scroll-feature.js is requested.

After I let the page load, and type the following into the javascript console, i get the expected value:

> Drupal.displace.offsets.top
79

To be clear I do not want to make a dependency on Toolbar, because then that would load more javascript for all users but I want to be sure that this script runs after Toolbar may have run, if it existed in the requests. I would have thought that automagically the weight of js added by themes would be higher than that of core modules, no?

1
  • Issue #2367655 sounds along the lines of what is needed to solve this problem. maybe? Aug 10, 2018 at 1:10

1 Answer 1

4

Your thought to use drupalViewportOffsetChange is the way to go. The actual event is drupalViewportOffsetChange.toolbar. Here is an example:

  Drupal.behaviors.myTheme = {
    attach: function attach(context) {
      if (context === document) {
        $(context).on("drupalViewportOffsetChange.toolbar", function (event, offsets) {
          var selectors = [".class-of-thing-i-want-to-offset"];
          selectors.forEach(function (selector) {
            if ($(selector).length > 0 && offsets.top > 0) {
              $(selector).css("top", offsets.top);
            }
          });
        });
      }
    }
  };
1
  • Thanks @Evil E! was unaware of the suffix .toolbar required. I'll have to go back and remember what project / context I wrote this question about and give it a try, and mark your answer accepted. Jan 25, 2019 at 16:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.