dmitri.shuralyov.com/app/changes/...

frontend: Fix jump to hash on page load.

It was adding a listener for DOMContentLoaded event in code that runs
when that event has just fired, so the listener never ran.

Also clean up and simplify some relevant code.

Similar to https://github.com/shurcooL/issuesapp/commit/c25bd476f001893e3608cd5aa6b016760236ad2d.
dmitshur committed 6 years ago commit c60fe8490545910eb10f58822541daa8c840db45
Collapse all
frontend/scroll.go
@@ -2,40 +2,23 @@ package main

import (
	"fmt"
	"net/url"
	"strings"
	"time"

	"github.com/gopherjs/gopherjs/js"
	"github.com/shurcooL/go/gopherjs_http/jsutil"
	"honnef.co/go/js/dom"
)

func setupScroll() {
	js.Global.Set("AnchorScroll", jsutil.Wrap(AnchorScroll))

	processHashSet := func() {
		// Scroll to hash target.
		targetID := strings.TrimPrefix(dom.GetWindow().Location().Hash, "#")
		target, ok := document.GetElementByID(targetID).(dom.HTMLElement)
		if ok {
			centerWindowOn(target)
		}

		processHash(target)
	}
	// Jump to desired hash after page finishes loading (and override browser's default hash jumping).
	document.AddEventListener("DOMContentLoaded", false, func(_ dom.Event) {
		go func() {
			// This needs to be in a goroutine or else it "happens too early".
			// TODO: See if there's a better event than DOMContentLoaded.
			processHashSet()
		}()
	})
	// Start watching for hashchange events.
	dom.GetWindow().AddEventListener("hashchange", false, func(event dom.Event) {
		processHashSet()
		processHash()

		event.PreventDefault()
	})

	document.Body().AddEventListener("keydown", false, func(event dom.Event) {
@@ -50,11 +33,11 @@ func setupScroll() {
				return
			}

			setFragment("")

			processHashSet()
			highlight(nil)

			ke.PreventDefault()

		// 'p' keyboard shortcut to go to previous commit.
		case ke.KeyCode == 'P' && !ke.Repeat && !ke.CtrlKey && !ke.AltKey && !ke.MetaKey && !ke.ShiftKey:
@@ -70,10 +53,28 @@ func setupScroll() {
			}
			dom.GetWindow().Location().Href = state.NextSHA
			ke.PreventDefault()
		}
	})

	// Jump to desired hash slightly after page loads (override browser's default hash jumping).
	go func() {
		// This needs to be delayed, or else it "happens too early".
		time.Sleep(time.Millisecond)
		processHash()
	}()
}

func processHash() {
	// Scroll to hash target.
	targetID := strings.TrimPrefix(dom.GetWindow().Location().Hash, "#")
	target, ok := document.GetElementByID(targetID).(dom.HTMLElement)
	if ok {
		centerWindowOn(target)
	}

	highlight(target)
}

// AnchorScroll scrolls window to target that is pointed by fragment of href of given anchor element.
// It must point to a valid target.
func AnchorScroll(anchor dom.HTMLElement, e dom.Event) {
@@ -88,26 +89,28 @@ func AnchorScroll(anchor dom.HTMLElement, e dom.Event) {
	setFragment(targetID)

	// TODO: Decide if it's better to do this or not to.
	centerWindowOn(target)

	processHash(target)
	highlight(target)

	e.PreventDefault()
}

// processHash highlights the selected element by giving it a "hash-selected" class.
// target can be nil if there isn't a valid target.
func processHash(target dom.HTMLElement) {
	// Clear everything.
// highlight highlights the selected element by giving it a "hash-selected" class.
// target can be nil to highlight nothing.
func highlight(target dom.HTMLElement) {
	// Clear all past highlights.
	for _, e := range document.GetElementsByClassName("hash-selected") {
		e.Class().Remove("hash-selected")
	}

	if target != nil {
		target.Class().Add("hash-selected")
	// Highlight target, if any.
	if target == nil {
		return
	}
	target.Class().Add("hash-selected")
}

// centerWindowOn scrolls window so that (the middle of) target is in the middle of window.
func centerWindowOn(target dom.HTMLElement) {
	windowHalfHeight := dom.GetWindow().InnerHeight() / 2