Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

report: enable jump to audit in nested details #5915

Closed
wants to merge 21 commits into from
Closed

report: enable jump to audit in nested details #5915

wants to merge 21 commits into from

Conversation

midzer
Copy link
Contributor

@midzer midzer commented Aug 27, 2018

Hi,

Summary

In report.html jump to respective audit on page load if hash is provided in URL. Collapsed content is opened automatically. Element is highlighted via CSS selector

At first i wanted to use https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView for scrolling to requested item, but somehow this didn't work. Any feedback is welcome.

Related Issues/PRs

Fixes #5640
Fixes #6668

@midzer midzer requested a review from paulirish as a code owner August 27, 2018 23:38
Copy link
Collaborator

@patrickhulce patrickhulce left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for jumping on this so quickly @midzer!

lighthouse-core/report/html/renderer/report-ui-features.js Outdated Show resolved Hide resolved
lighthouse-core/report/html/report-styles.css Outdated Show resolved Hide resolved
lighthouse-core/report/html/renderer/report-ui-features.js Outdated Show resolved Hide resolved
Copy link
Member

@brendankenny brendankenny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for the fix!

lighthouse-core/report/html/renderer/report-ui-features.js Outdated Show resolved Hide resolved
lighthouse-core/report/html/renderer/report-ui-features.js Outdated Show resolved Hide resolved
lighthouse-core/report/html/report-styles.css Outdated Show resolved Hide resolved
@patrickhulce patrickhulce changed the title introduce jumpToAudit report: enable jump to audit in nested details Aug 28, 2018
@midzer
Copy link
Contributor Author

midzer commented Aug 28, 2018

closest() returns an Element, so I can't use offsetTop any more. I replaced it by details.getBoundingClientRect().top + window.scrollY

Thanks for your feedback. Cya later

Copy link
Member

@brendankenny brendankenny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the long delay!

This is looking good to me, just a few lint errors and style nits.

@brendankenny
Copy link
Member

brendankenny commented Sep 14, 2018

closest() returns an Element, so I can't use offsetTop any more. I replaced it by details.getBoundingClientRect().top + window.scrollY

It does return an Element, but we know more specifically that it's an HTMLElement since we asked for a 'details', so there's no harm in treating it as such (in fact, the typescript checker even narrows it down to HTMLDetailsElement | null for us, and the conditional rules out the null

Copy link
Member

@brendankenny brendankenny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so trying it now, there are still a couple of more cases to handle:

  • as @patrickhulce noted, some of these are nested more than one <details> element deep (e.g. passed accessibility audits), so will need to do multiple steps up the DOM tree using el.closest('.lh-container details') (.lh-container will also prevent going outside our own subtree)
  • some audits aren't nested at all, don't have a details ancestor, so we can't scroll to that point. We'll have to handle scrolling for those cases too (e.g. try out jumping to the SEO #meta-description on a report for example.com)

@midzer
Copy link
Contributor Author

midzer commented Sep 16, 2018

First of all, many thanks for your insight testing and review @brendankenny . I tried to include proposed suggestions in latest commits. Somehow, tests are broken now though. Can't figure out right now whats going havoc there^^

Regarding scrolling to element I've played around with element.scrollIntoView() again which does the job as current window.scroll() implementation. Too bad, it does not work in all cases yet: for example #meta-description element is hidden below .lh-scores.header after scroll took place. Manual additions/subtractions to offsetTop seem not to have any effect. So I'm kinda stuck on further progress right now.

@midzer
Copy link
Contributor Author

midzer commented Nov 19, 2018

Just to bump this one to the top. I have time to help bring it to merge.

Is this PR out of focus now?

Copy link
Member

@brendankenny brendankenny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hi @midzer!

I think there is definitely still value in updating and landing this. I added some new comments on this version.

Two other things:

  • it would be great to get a test/some tests. e.g. report-ui-features-test could create a report, manually update the jsdom location and call _jumpToAudit, then check that all the <details> containing that audit are open. Not sure if there's an easier way to set the URL for jsdom so _jumpToAudit would be called as in a real report, or if there's a way to also test the scroll location
  • You mentioned scrolling to the audit with the big score header in the way. That's definitely an issue. Since the scrolling is being done in JS, there's no reason we couldn't do a little manual math to make sure the audit is visible. But maybe there are other options. cc @paulirish (who implemented proper permalinks for categories way back in Report: denser styling #2706)

Copy link
Collaborator

@patrickhulce patrickhulce left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very sorry for the crazy long review cycles :(

audit.firstElementChild.open = true;
}
this._openClosestDetails(audit);
if (audit instanceof HTMLElement) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems like this will always be true by this point, no? 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without this check, typescript throws Property 'offsetTop' does not exist on type 'Element'. in my IDE. I could not find another way around this issue

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah ok just for ts then?

let's flip it around then and add a comment to explain

// This should always be an HTMLElement by this point by ts doesn't know that
if (!(audit instanceof HTMLElement)) return;

unless @brendankenny has better ideas?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah ok just for ts then?

yeah, it's a tsc thing (technically it's correct, but we know if this particular document.querySelector response isn't null it's an HTMLElement).

We can either do your suggestion or do a cast above.

/** @type {?HTMLElement} */
const audit = this._document.querySelector(hash);
if (!audit || !audit.classList.contains('lh-audit')) {
  return;
}
// ...

either one sounds good to me

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fairly new to TypeScript, so I did not know how to do the cast. Thanks for your suggestion @brendankenny . pushed.to.branch

@@ -337,6 +337,10 @@
display: none;
}

.lh-audit:target {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not convinced we need this. It's a bit odd given that the only thing that will make it go away is clicking another category, not just another audit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has been requested by @paulirish here #5640 (comment)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh! OK :)

@paulirish I'm not convinced we need this. It's a bit odd given that the only thing that will make it go away is clicking another category, not just another audit.

if (audit instanceof HTMLElement) {
const scoresWrapper = this._dom.find('.lh-scores-wrapper', this._document);
window.scroll({
top: audit.offsetTop + scoresWrapper.clientHeight,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this needs to be full height of .lh-header-container not just .lh-scores-wrapper. Also don't we need - not +? The audits are all offscreen for me on navigation.

Copy link
Member

@brendankenny brendankenny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM (with selector fix)

over to @patrickhulce and @paulirish

audit.firstElementChild.open = true;
}
this._openClosestDetails(audit);
const headerContainer = this._dom.find('lh-header-container', this._document);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'.lh-header-container'

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooooops :) thanks

@paulirish
Copy link
Member

This scrolling is pretty flaky and I tried experimenting with different combos of rAF/setTimeout/etc and thought I got something good: https://github.com/midzer/lighthouse/pull/1

And then I put my test page online and its no longer scrolling 100% reliably. https://envious-cave.surge.sh/cnn.html#js-libraries (try with reload and also with pasting into a new tab)

I dont think we can guarantee an animated scroll (until some browser bug is fixed?), but we can at least guarantee the page is scrolled to the right spot.

I do like setting focus on the <summary> instead of using :target though. Seems like a nice solution to the CSS discussion above: https://github.com/midzer/lighthouse/blob/7ce0f63cff7ccd3676d3c6c582b3ab790f7849a7/lighthouse-core/report/html/renderer/report-ui-features.js#L324-L327

@brendankenny
Copy link
Member

Thanks for all your work @midzer.

I'm going to close for now since the scrolling logic never entirely panned out here due to how long it takes the report to construct the entire DOM after load. We're gearing up for a report UI refresh as we close in on May, and I'm hoping we can restructure report rendering and the DOM a little bit to make scrolling to individual audits more feasible. Hopefully then we can revisit this PR and make it work!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants