skipto-landmarks-headings / page-script-5

Dynamically determines the most important landmarks and headings on a web page and presents them to the user in a menu.
Other
8 stars 1 forks source link

Enhancement Request: Scroll to view + Highlight #16

Open Gcamara14 opened 3 weeks ago

Gcamara14 commented 3 weeks ago

Problem:

Potential Solution:

Benefit

Cons:

Image 1

image

Image 2

image
Gcamara14 commented 3 weeks ago

Did a quick search - This chrome extension does highlighting:

https://chromewebstore.google.com/detail/landmark-navigation-via-k/ddpokpbjopmeeiiolheejjpkonlkklgp

Gcamara14 commented 3 weeks ago

It can be found on github aswell:

https://github.com/matatk/landmarks?tab=readme-ov-file

jongund commented 3 weeks ago

@Gcamara14

Thank you for the references, I have some highlighting code from some other projects. If you have a minute checkout "AInspector for Firefox" highlighting feature. AInspector for Firefox

Would also be interested in your opinion of AInspector features.

I have started a SkipTo.js branch with highlighting feature: https://github.com/skipto-landmarks-headings/page-script-5/tree/dev/5.4

Thank you again for your interest in SkipTo.js

Jon

Gcamara14 commented 3 weeks ago

Yes I can review the other tool. and That's a fantastic start Jon! I was encountering bugs with the scrolling feature, it so I made a small enhancement with the help of ChatGPT:

Before:

After:

Gcamara14 commented 3 weeks ago

Here is the ChatGPT code if you want to update the PR:

To integrate the function ensuring that the element does not scroll the page if it is already within the viewport, you'll need to carefully place the new JavaScript code within the context of your existing skipto.js file. Given the structure and length of your existing file, it is advisable to place the new functions near the top of the file, but after the initial setup and imports to ensure all necessary components are loaded.

Here’s a step-by-step guide on where to place your new functions:

  1. Identify the Initialization Section: Locate the section where the script begins to initialize variables and define functions. This is typically after any imports or initial setup code.

  2. Insert the Utility Functions: Place the isElementInViewport and scrollToElement functions in a section where utility functions are defined. This is typically at the beginning of the script, but after the initial setup comments and imports.

  3. Integrate with Existing Code: Identify where the element you wish to apply this functionality to is being manipulated. This might be within event listeners or specific function calls handling focus or scroll behaviors.

Here is how you can incorporate it:

Step 1: Define Utility Functions

Place these functions after the initial setup and before any main logic or event listeners are defined:

/* Utility functions */
function isElementInViewport(el) {
    var rect = el.getBoundingClientRect();
    return (
        rect.top >= 0 &&
        rect.left >= 0 &&
        rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
        rect.right <= (window.innerWidth || document.documentElement.clientWidth)
    );
}

function scrollToElement(element) {
    if (!isElementInViewport(element)) {
        element.scrollIntoView({ behavior: 'smooth', block: 'center' });
    }
}

Step 2: Integrate with Existing Functionality

Find the part of the script where elements are being scrolled into view or focused. Typically, this would be in functions handling element highlighting or focus management. For example, if you have a function like highlightElement, you should update it as follows:

function highlightElement(id) {
    const mediaQuery = window.matchMedia(`(prefers-reduced-motion: reduce)`);
    const isReduced = !mediaQuery || mediaQuery.matches;
    const node = queryDOMForSkipToId(id);
    console.log(`[${node}]: ${node.getAttribute('data-skip-to-id')} isReduced: ${isReduced}`);

    if (!isReduced) {
        if (lastHighlightElement) {
            lastHighlightElement.remove();
        }
        lastHighlightElement = addOverlayElement(node);
        console.log(`Highlight content: ${lastHighlightElement}`);

        // Use the new function here
        scrollToElement(node);
    }
}

Complete Example Integration:

(function () {
  'use strict';

  // Utility functions
  function isElementInViewport(el) {
      var rect = el.getBoundingClientRect();
      return (
          rect.top >= 0 &&
          rect.left >= 0 &&
          rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
          rect.right <= (window.innerWidth || document.documentElement.clientWidth)
      );
  }

  function scrollToElement(element) {
      if (!isElementInViewport(element)) {
          element.scrollIntoView({ behavior: 'smooth', block: 'center' });
      }
  }

  /* ... rest of the skipto.js code ... */

  function highlightElement(id) {
      const mediaQuery = window.matchMedia(`(prefers-reduced-motion: reduce)`);
      const isReduced = !mediaQuery || mediaQuery.matches;
      const node = queryDOMForSkipToId(id);
      console.log(`[${node}]: ${node.getAttribute('data-skip-to-id')} isReduced: ${isReduced}`);

      if (!isReduced) {
          if (lastHighlightElement) {
              lastHighlightElement.remove();
          }
          lastHighlightElement = addOverlayElement(node);
          console.log(`Highlight content: ${lastHighlightElement}`);

          // Use the new function here
          scrollToElement(node);
      }
  }

  /* ... rest of the existing functions and event listeners ... */

})();

Final Notes:

Ensure that your new functions are well-commented and placed logically within your script to maintain readability and manageability. This approach ensures that the utility functions are defined early and can be reused throughout the script, while the main logic incorporates the new behavior seamlessly.

jongund commented 3 weeks ago

@ I am putting the new functions in a highlight function in a module: highlightElement.js in dev/v5.4 branch