Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

scan.gno

3.06 Kb · 77 lines
 1package home
 2
 3import (
 4	"strings"
 5
 6	"chain/runtime"
 7
 8	"gno.land/p/nym-moultest123/dynreplacer/v0"
 9	"gno.land/p/nym-moultest123/mygnoscan/v0"
10	"gno.land/r/nym-moultest123/config/v1"
11)
12
13// This file is the explorer half of the page: a handful of computed
14// placeholders that turn what this realm already knows (its own path, its
15// owner, the block it is rendering at) into links a reader can click.
16//
17// They are COMPUTED, not slots, so they are always current: the layout slot
18// says where a link goes on the page, and nothing in storage has to be
19// rewritten when the answer changes.
20//
21// The explorer they point at comes from gno.land/r/nym-moultest123/config, not from a
22// constant here. That is the whole point of the indirection: moving every one
23// of moul's realms to a different explorer is one transaction against config,
24// not a redeploy of each realm that links to one. When config has no setting,
25// mygnoscan.DefaultBase answers, so this realm renders correctly on a chain
26// where nothing was ever configured.
27
28// scanPlaceholders are the reserved slugs this file answers for. They are
29// listed in reservedSlugs (home.gno) so a slot can never take one of these
30// names and shadow the computed value.
31var scanPlaceholders = []string{
32	"scan",       // the explorer base URL, as plain text
33	"scan.realm", // this realm on the explorer
34	"scan.me",    // the owner's account page
35	"scan.block", // the block this render is happening at
36	"scan.links", // the three above, on one line
37}
38
39// scanner returns the configured link builder.
40//
41// config.Scanner() is a read, and a cheap one: an avl lookup plus a struct.
42// It is called once per render and the result reused, rather than once per
43// placeholder, because dynreplacer may invoke several of the callbacks below
44// and each would otherwise repeat the cross-realm call.
45func scanner() mygnoscan.Scanner { return config.Scanner() }
46
47// registerScanCallbacks adds the explorer placeholders to r.
48//
49// dynreplacer only invokes a callback whose placeholder actually occurs in the
50// layout, so a layout using none of these costs one config.Scanner() call and
51// nothing else.
52func registerScanCallbacks(r *dynreplacer.Replacer) {
53	s := scanner()
54
55	r.RegisterCallback(":scan:", func() string { return s.Base() })
56	r.RegisterCallback(":scan.realm:", func() string {
57		return mygnoscan.Link("mygnoscan", s.Realm(realmPath))
58	})
59	r.RegisterCallback(":scan.me:", func() string {
60		return mygnoscan.Link("my account", s.Address(admin))
61	})
62	r.RegisterCallback(":scan.block:", func() string {
63		return mygnoscan.Link("this block", s.Block(runtime.ChainHeight()))
64	})
65	r.RegisterCallback(":scan.links:", func() string { return scanLinks(s) })
66}
67
68// scanLinks is the :scan.links: placeholder: everything above on one line, for
69// a layout that wants the footer and does not want to lay it out by hand.
70func scanLinks(s mygnoscan.Scanner) string {
71	parts := []string{
72		mygnoscan.Link("this realm", s.Realm(realmPath)),
73		mygnoscan.Link("my account", s.Address(admin)),
74		mygnoscan.Link("this block", s.Block(runtime.ChainHeight())),
75	}
76	return strings.Join(parts, " · ")
77}