README

Vugu

Travis CI GoDoc stability-experimental

Vugu is an experimental library for web UIs written in Go and targeting webassembly. Guide and docs at https://www.vugu.org. Godoc at https://godoc.org/github.com/vugu/vugu.

If you've ever wanted to write a UI not in JS but pure Go... and run it in your browser, right now... That (experimental;) future is here!

Introducing Vugu (pronounced /ˈvuː.ɡuː/), a VueJS-inspired library in Go targeting wasm.

No node. No JS. No npm. No node_modules folder competing with your music library for disk space.

Updates ♨

  • 2020-11-08 Work in progress on a UI component library, the current concept is strongly influenced by both Bootstrap and Material Design. Some specific components, code and documentation will follow soonest.
  • 2020-09-13 v0.3.3 Lifecycle callbacks implemented (Init, Compute, Rendered, Destroy) plus documentation https://vugu.org/doc/components#lifecycle
  • 2020-06-21 v0.3.2 Vugu+TinyGo is now functional; test suite updated so most tests are run with both default Go and TinyGo compilation; docs updated; Vugu+TinyGo example works https://github.com/vugu-examples/tinygo
  • 2020-04-26 v0.3.0 Slots are now implemented. Plus vg-js-create/vg-js-populate, vg-template, vg-var; vgform package has initial prototype for form inputs; docs written for these features plus for router and wiring (several pages added to vugu.org plus other individual sections). There are two small but breaking changes with this release: vg-html now escapes markup by default and vugu.DOMEvent was changed from a struct to an interface. For the earlier vg-html behavior use vg-html='vugu.HTML("...")' (see https://www.vugu.org/doc/files/markup#vg-content) and existing DOMEvent code should fix by simply removing the pointer i.e. change event *vugu.DOMEvent to event vugu.DOMEvent - and also make sure to go get -u github.com/vugu/vugu/cmd/vugugen again. I generally try to avoid these sorts of breaking changes but it's better to do them sooner rather than later.
  • 2020-04-13 v0.2.3 much more flexible attribute support and SVGs now work (thanks to @tbe!); vugu-examples/simple set up, more to come; nested component rendering bug fixed (#117); tools doc page added to the site; devutil package; vgrun working
  • 2020-04-06 v0.2.0 released. vugu.org and playground ported over to it; vugugen now supports recursive and merge-single modes and output files end with _vgen.go; improved tests; various documentation updates; vgrgen route generator supports recursive and clean options
  • 2020-03-29 Vugu URL router is now functional (https://github.com/vugu/vgrouter). Features include optional fragment support, client and server-side use, two-way data binding for query and path parameters, and automatic route generation based on folder structure. The vg-comp tag now allows programmatic component selection. A pattern for wiring large applications with lots of components is in place and will be tested further as dev moves forward. Next steps include just a bit more dev and testing on the router and then updating vugu.org to use these new features and bring the documentation up to date.
  • 2019-12-08 First Vugu program successfully compiles with Tinygo. Testing and a bit more alternate implementation is still required but at least the compilation works now.
  • 2019-11-24 WASM test suite now working in Travis CI; getting closer on TinyGo support and merged refactor into master.
  • 2019-11-10 Support for tinygo is in-progress on the tinygo branch. No known blocking issues as yet, some minor refactor required but looks promising.
  • 2019-09-29 Router is work-in-progress. Will use radix tree to efficiently combine common prefixes. Struct tags will usable to two-way-bind path and query params, or it can be done manually. Some similarities to Angular and Vue routers but will be less declarative and more functional (instead of a big tree of objects with various config, you write path handler functions to set whatever properties need to be set, establish binding, etc). Plan is to get the bulk of this coded by next week.
  • 2019-09-22 Static HTML renderer (re)implemented. EventEnv bug fix and added it to to JS renderer to allow background requests at startup. Some initial work on a router: https://github.com/vugu/vgrouter
  • 2019-09-15 Refactor changes merged into master. Includes: updated sample code, component resolution at code-generation time, type-safe component params, optional component param map, BeforeBuild lifecycle callback, modification tracking system, JS property assignment syntax, "full HTML" support, improved DOM event handling, Go 1.13 support, import deduplication, and a brand new rendering pipeline! Initial documentation at https://github.com/vugu/vugu/wiki/Refactor-Notes---Sep-2019
  • 2019-09-08 Implemented ModTracker to keep track of changes to components and their data (this is also the beginning of Vuex-like functionality but without wrappers or events). Worked out the lifecycle of components in much more detail and work in progress on nested components implementation (component-refactor branch currently broken, but finally the core nested component functionality is going in - hopefully will finish next week).
  • 2019-09-07 Updated everything for Go 1.13, including both master and component-refactor branches, Vugu's js wrapper package, site documentation.
  • 2019-09-01 On component-refactor branch: Form element values and other related data now available on DOMEvent, .prop= syntax implemented, various cleanup, imports are deduplicated automatically now, started on nested component implementation and all of that craziness.
  • 2019-08-25 CSS now supported on component-refactor branch, including in full-HTML mode, working sample that pulls in Bootstrap CSS. Vugu's js wrapper package copied to master and made available.
  • 2019-08-18 Full HTML (root component can start with <html> tag) now supported on component-refactor branch, updated CSS and JS support figured out and implementation in-progress
  • 2019-08-12 Refactored DOM event listener code in-progress, event registration/deregistration works(-ish), filling out the remaining functionality to provide event summary, calls like preventDefault(), etc.
  • 2019-08-04 Some basic stuff in there on the DOM syncing rewrite and the new instruction workflow from VGNode -> binary encoded to raw bytes in Go -> read with DataView in JS -> DOM tree manipulation. With the pattern in place the rest should get easier.
  • 2019-07-28 Making some hard choices on how to do DOM syncing in a performant and reliable way. https://github.com/vugu/vugu/wiki/DOM-Syncing-Instructions
  • 2019-07-20 Some design info on how "data binding" (hashing actually) will work in Vugu: https://github.com/vugu/vugu/wiki/Data-Hashing-vs-Binding
  • 2019-07-16 Vugu has a logo! https://www.instagram.com/p/Bz3zmtYAYcM/ Good things are in the works, the plan is to get a bunch of much-awaited updates pushed to master before the end of the month.
  • 2019-05-19 Refactor still in progress - this is the cleaned-up architecture concept: https://github.com/vugu/vugu/wiki/Architecture-Overview
  • 2019-04-07 The Vugu Playground is up at: https://play.vugu.org/
  • 2019-04-05 Thanks to @erinpentecost, vugufmt is now available and provides gofmt-like functionality on your .vugu files. ("go get github.com/vugu/vugu/cmd/vugufmt && go install github.com/vugu/vugu/cmd/vugufmt")
  • 2019-04-05 The component playground should be available soon; followed by some internal work to properly handle nested components in a type-safe way; then probably a router...

Join the conversation: Gophers on Slack, channel #vugu

Highlights

  • Runs in-browser using WebAssembly
  • Single-file components
  • Vue-like markup syntax
  • Write idiomatic Go code
  • Rapid prototyping
  • ~3 minute setup
  • Standard Go build tools

Start

Get started: http://www.vugu.org/doc/start

Still a work in progress, but a lot of things are already functional. Some work really well.

Abbreviated Roadmap

  • Single-file components (looks similar to .vue); .vugu -> .go code generation.
  • Includes CSS in components.
  • Basic flow control with vg-if, vg-for and output with vg-content.
  • Dynamic attributes with <tag :prop='expr'>.
  • Nested components with dynamic properties
  • Efficiently syncs to browser DOM.
  • Static HTML output (great for tests).
  • DOM Events, click, etc.
  • Modification tracking to avoid unnecessary computation where possible.
  • Basic dev and prod server tooling, easy to get started
  • Rewrite everything so it is not so terrible internally
  • URL Router (in-progress)
  • Tinygo compilation support
  • Server-side rendering (works, needs more documentation and examples)
  • Go-only component events
  • Slots
  • Component library(s) (wip!)
  • Performance optimizations
  • And much more...

Notes

It's built more like a library than a framework. While Vugu does do code generation for your .vugu component files, (and will even output a default main_wasm.go for a new project and build your program automatically upon page refresh), fundamentally you are still in control. Overall program flow, application wiring and initialization, the render loop that keeps the page in sync with your components - you have control over all of that. Frameworks call your code. Vugu is a library, your code calls it (even if Vugu generates a bit of that for you in the beginning to make things easier). One of the primary goals for Vugu, when it comes to developers first encountering it, was to make it very fast and easy to get started, but without imposing unnecessary limitations on how a project is structured. Go build tooling (and now the module system) is awesome. The idea is to leverage that to the furthest extent possible, rather than reprogramming the wheel.

So you won't find a vugu command line tool that runs a development server, instead you'll find in the docs an appropriate snippet of code you can paste in a file and go run yourself. For the code generation while there is an http.Handler that can do this upon page refresh, you also can (and should!) run vugugen via go generate. There are many small decisions in Vugu which follow this philosophy: wherever reasonably possible, just use the existing mechanism instead of inventing anew. And keep doing that until there's proof that something else is really needed. So far it's been working well. And it allows Vugu to focus on the specific things it brings to the table.

Documentation

Overview

Package vugu provides core functionality including vugu->go codegen and in-browser DOM syncing running in WebAssembly. See http://www.vugu.org/

Since Vugu projects can have both client-side (running in WebAssembly) as well as server-side functionality many of the items in this package are available in both environments. Some however are either only available or only generally useful in one environment.

Common functionality includes the ComponentType interface, and ComponentInst struct corresponding to an instantiated componnet. VGNode and related structs are used to represent a virtual Document Object Model. It is based on golang.org/x/net/html but with additional fields needed for Vugu. Data hashing is performed by ComputeHash() and can be customized by implementing the DataHasher interface.

Client-side code uses JSEnv to maintain a render loop and regenerate virtual DOM and efficiently synchronize it with the browser as needed. DOMEvent is a wrapper around events from the browser and EventEnv is used to synchronize data access when writing event handler code that spawns goroutines. Where appropriate, server-side stubs are available so components can be compiled for both client (WebAssembly) and server (server-side rendering and testing).

Server-side code can use ParserGo and ParserGoPkg to parse .vugu files and code generate a corresponding .go file. StaticHTMLEnv can be used to generate static HTML, similar to the output of JSEnv but can be run on the server. Supported features are approximately the same minus event handling, unapplicable to static output.

Index

Constants

View Source
const (
	ErrorNode    = VGNodeType(0)
	TextNode     = VGNodeType(1)
	DocumentNode = VGNodeType(2)
	ElementNode  = VGNodeType(3)
	CommentNode  = VGNodeType(4)
	DoctypeNode  = VGNodeType(5)
)

Available VGNodeTypes.

Variables

This section is empty.

Functions

func MakeCompKeyID

func MakeCompKeyID(t time.Time, data uint32) uint64

MakeCompKeyID forms a value for CompKey.ID from the given time the uint32 you provide for the lower 32 bits.

func MakeCompKeyIDNowRand

func MakeCompKeyIDNowRand() uint64

MakeCompKeyIDNowRand generates a value for CompKey.ID based on the current unix timestamp in seconds for the top 32 bits and the bottom 32 bits populated from a random source

func MakeCompKeyIDTimeHash

func MakeCompKeyIDTimeHash(t time.Time, b []byte) uint64

MakeCompKeyIDTimeHash forms a value for CompKey.ID from the given time and a hash of the bytes you provide.

Types

type AttrMap

type AttrMap map[string]interface{}

AttrMap implements VGAttributeLister as a map[string]interface{}

func (AttrMap) AttributeList

func (m AttrMap) AttributeList() (ret []VGAttribute)

AttributeList returns an attribute list corresponding to this map using the rules from VGNode.AddAttrInterface.

type BeforeBuilder

type BeforeBuilder interface {
	BeforeBuild()
}

BeforeBuilder is deprecated. It is replaced by the Compute lifecycle callback.

type BuildEnv

type BuildEnv struct {
	// contains filtered or unexported fields
}

BuildEnv is the environment used when building virtual DOM.

func NewBuildEnv

func NewBuildEnv(eventEnv ...EventEnv) (*BuildEnv, error)

NewBuildEnv returns a newly initialized BuildEnv. The eventEnv is used to implement lifecycle callbacks on components, it's a vararg for now in order to avoid breaking earlier code but it should be provided in all new code written.

func (*BuildEnv) CachedComponent

func (e *BuildEnv) CachedComponent(compKey CompKey) Builder

CachedComponent will return the component that corresponds to a given CompKey. The CompKey must contain a unique ID for the instance in question, and an optional IterKey if applicable in the caller. A nil value will be returned if nothing is found. During a single build pass only one component will be returned for a specified key (it is removed from the pool), in order to protect against broken callers that accidentally forget to set IterKey properly and ask for the same component over and over, in whiich case the first call will return a value and subsequent calls will return nil.

func (*BuildEnv) RunBuild

func (e *BuildEnv) RunBuild(builder Builder) *BuildResults

RunBuild performs a bulid on a component, managing the lifecycles of nested components and related concerned. In the map that is output, m[builder] will give the BuildOut for the component in question. Child components can likewise be indexed using the component (which should be a struct pointer) as the key. Callers should not modify the return value as it is reused by subsequent calls.

func (*BuildEnv) SetWireFunc

func (e *BuildEnv) SetWireFunc(f func(component Builder))

SetWireFunc assigns the function to be called by WireComponent. If not set then WireComponent will have no effect.

func (*BuildEnv) UseComponent

func (e *BuildEnv) UseComponent(compKey CompKey, component Builder)

UseComponent indicates the component which was actually used for a specified CompKey during this build pass and stores it for later use. In the next build pass, components which have be provided UseComponent() will be available via CachedComponent().

func (*BuildEnv) WireComponent

func (e *BuildEnv) WireComponent(component Builder)

WireComponent calls the wire function on this component. This is called during component creation and use and provides an opportunity to inject things into this component.

type BuildIn

type BuildIn struct {

	// the overall build environment
	BuildEnv *BuildEnv

	// a stack of position hashes, the last one can be used by a component to get a unique hash for overall position
	PositionHashList []uint64
}

BuildIn is the input to a Build call.

func (*BuildIn) CurrentPositionHash

func (bi *BuildIn) CurrentPositionHash() uint64

CurrentPositionHash returns the hash value that can be used by a component to mix into it's own hash values to achieve uniqueness based on overall position in the output tree. Basically you should XOR this with whatever unique reference ID within the component itself used during Build. The purpose is to ensure that we use the same ID for the same component in the same position within the overall tree but a different one for the same component in a different position.

type BuildOut

type BuildOut struct {

	// output element(s) - usually just one that is parent to the rest but slots can have multiple
	Out []*VGNode

	// components that need to be built next - corresponding to each VGNode in Out with a Component value set,
	// we make the Builder populate this so BuildEnv doesn't have to traverse Out to gather up each node with a component
	// FIXME: should this be called ChildComponents, NextComponents? something to make it clear that these are pointers to more work to
	// do rather than something already done
	Components []Builder

	// optional CSS style or link tag(s)
	CSS []*VGNode

	// optional JS script tag(s)
	JS []*VGNode
}

BuildOut is the output from a Build call. It includes Out as the DOM elements produced, plus slices for CSS and JS elements.

func (*BuildOut) AppendCSS

func (b *BuildOut) AppendCSS(nlist ...*VGNode)

AppendCSS will append a unique node to CSS (nodes match exactly will not be added again).

func (*BuildOut) AppendJS

func (b *BuildOut) AppendJS(nlist ...*VGNode)

AppendJS will append a unique node to JS (nodes match exactly will not be added again).

type BuildResults

type BuildResults struct {
	Out *BuildOut
	// contains filtered or unexported fields
}

BuildResults contains the BuildOut values for full tree of components built.

func (*BuildResults) ResultFor

func (r *BuildResults) ResultFor(component interface{}) *BuildOut

ResultFor is alias for indexing into AllOut.

type Builder

type Builder interface {
	// Build is called to construct a tree of VGNodes corresponding to the DOM of this component.
	// Note that Build does not return an error because there is nothing the caller can do about
	// it except for stop rendering.  This way we force errors during Build to either be handled
	// internally or to explicitly result in a panic.
	Build(in *BuildIn) (out *BuildOut)
}

Builder is the interface that components implement.

func NewBuilderFunc

func NewBuilderFunc(f func(in *BuildIn) (out *BuildOut)) Builder

NewBuilderFunc returns a Builder from a function that is called for Build.

type ChangeCounter

type ChangeCounter int

ChangeCounter is a number that can be incremented to indicate modification. The ModCheck method is implemented using this number. A ChangeCounter can be used directly or embedded in a struct, with its methods calling Changed on each mutating operation, in order to track its modification.

func (*ChangeCounter) Changed

func (c *ChangeCounter) Changed()

Changed increments the counter to indicate a modification.

func (*ChangeCounter) ModCheck

func (c *ChangeCounter) ModCheck(mt *ModTracker, oldData interface{}) (isModified bool, newData interface{})

ModCheck implements the ModChecker interface.

type CompKey

type CompKey struct {
	ID      uint64      // unique ID for this instance of a component, randomly generated and embeded into source code
	IterKey interface{} // optional iteration key to distinguish the same component reference in source code but different loop iterations
}

CompKey is the key used to identify and look up a component instance.

func MakeCompKey

func MakeCompKey(id uint64, iterKey interface{}) CompKey

MakeCompKey creates a CompKey from the id and iteration key you provide. The purpose is to hide the implementation of CompKey as it can vary.

type ComputeCtx

type ComputeCtx interface {
	EventEnv() EventEnv
}

ComputeCtx is the context passed to a Compute callback.

type DOMEvent

type DOMEvent interface {

	// Prop returns a value from the EventSummary using the keys you specify.
	// The keys is a list of map keys to be looked up. For example:
	// e.Prop("target", "name") will return the same value as e.EventSummary()["target"]["name"],
	// except that Prop helps with some edge cases and if a value is missing
	// of the wrong type, nil will be returned, instead of panicing.
	Prop(keys ...string) interface{}

	// PropString is like Prop but returns it's value as a string.
	// No type conversion is done, if the requested value is not
	// already a string then an empty string will be returned.
	PropString(keys ...string) string

	// PropFloat64 is like Prop but returns it's value as a float64.
	// No type conversion is done, if the requested value is not
	// already a float64 then float64(0) will be returned.
	PropFloat64(keys ...string) float64

	// PropBool is like Prop but returns it's value as a bool.
	// No type conversion is done, if the requested value is not
	// already a bool then false will be returned.
	PropBool(keys ...string) bool

	// EventSummary returns a map with simple properties (primitive types) from the event.
	// Accessing values returns by EventSummary incurs no additional performance or memory
	// penalty, whereas calls to JSEvent, JSEventTarget, etc. require a call into the browser
	// JS engine and the attendant resource usage.  So if you can get the information you
	// need from the EventSummary, that's better.
	EventSummary() map[string]interface{}

	// JSEvent returns a js.Value in wasm that corresponds to the event object.
	// Non-wasm implementation returns nil.
	JSEvent() js.Value

	// JSEventTarget returns the value of the "target" property of the event, the element
	// that the event was originally fired/registered on.
	JSEventTarget() js.Value

	// JSEventCurrentTarget returns the value of the "currentTarget" property of the event, the element
	// that is currently processing the event.
	JSEventCurrentTarget() js.Value

	// EventEnv returns the EventEnv for the current environment and allows locking and unlocking around modifications.
	// See EventEnv struct.
	EventEnv() EventEnv

	// PreventDefault calls preventDefault() on the underlying DOM event.
	// May only be used within event handler in same goroutine.
	PreventDefault()

	// StopPropagation calls stopPropagation() on the underlying DOM event.
	// May only be used within event handler in same goroutine.
	StopPropagation()
}

DOMEvent is an event originated in the browser. It wraps the JS event that comes in. It is meant to be used in WebAssembly but some methods exist here so code can compile server-side as well (although DOMEvents should not ever be generated server-side).

func NewDOMEvent

func NewDOMEvent(eventEnv EventEnv, eventSummary map[string]interface{}) DOMEvent

NewDOMEvent returns a new initialized DOMEvent.

type DOMEventHandlerSpec

type DOMEventHandlerSpec struct {
	EventType string // "click", "mouseover", etc.
	Func      func(DOMEvent)
	Capture   bool
	Passive   bool
}

DOMEventHandlerSpec describes an event that gets registered with addEventListener.

type DestroyCtx

type DestroyCtx interface {
	EventEnv() EventEnv
}

DestroyCtx is the context passed to a Destroy callback.

type EventEnv

type EventEnv interface {
	Lock()         // acquire write lock
	UnlockOnly()   // release write lock
	UnlockRender() // release write lock and request re-render

	RLock()   // acquire read lock
	RUnlock() // release read lock
}

EventEnv provides locking mechanism to for rendering environment to events so data access and rendering can be synchronized and avoid race conditions.

type EventEnvImpl

type EventEnvImpl struct {
	// contains filtered or unexported fields
}

EventEnvImpl implements EventEnv

func NewEventEnvImpl

func NewEventEnvImpl(rwmu *sync.RWMutex, requestRenderCH chan bool) *EventEnvImpl

NewEventEnvImpl creates and returns a new EventEnvImpl.

func (*EventEnvImpl) Lock

func (ee *EventEnvImpl) Lock()

Lock will acquire write lock

func (*EventEnvImpl) RLock

func (ee *EventEnvImpl) RLock()

RLock will acquire a read lock

func (*EventEnvImpl) RUnlock

func (ee *EventEnvImpl) RUnlock()

RUnlock will release the read lock

func (*EventEnvImpl) UnlockOnly

func (ee *EventEnvImpl) UnlockOnly()

UnlockOnly will release the write lock

func (*EventEnvImpl) UnlockRender

func (ee *EventEnvImpl) UnlockRender()

UnlockRender will release write lock and request re-render

type HTML

type HTML string

HTML implements the HTMLer interface on a string with no transform, just returns the string as-is for raw HTML.

func (HTML) HTML

func (h HTML) HTML() string

HTML implements the HTMLer interface.

type HTMLer

type HTMLer interface {
	HTML() string // return raw html (with any needed escaping already done)
}

HTMLer describes something that can return HTML.

type InitCtx

type InitCtx interface {
	EventEnv() EventEnv
}

InitCtx is the context passed to an Init callback.

type JSValueFunc

type JSValueFunc func(js.Value)

JSValueFunc implements JSValueHandler as a function.

func (JSValueFunc) JSValueHandle

func (f JSValueFunc) JSValueHandle(v js.Value)

JSValueHandle implements the JSValueHandler interface.

type JSValueHandler

type JSValueHandler interface {
	JSValueHandle(js.Value)
}

JSValueHandler does something with a js.Value

type ModChecker

type ModChecker interface {
	ModCheck(mt *ModTracker, oldData interface{}) (isModified bool, newData interface{})
}

ModChecker interface is implemented by types that want to implement their own modification tracking. The ModCheck method is passed a ModTracker (for use in checking child values for modification if needed), and the prior data value stored corresponding to this value (will be nil on the first call). ModCheck should return true if this instance is modified, as well as a new data value to be stored. It is up to the specific implementation to decide what type to use for oldData and newData and how to compare them. In some cases it may be appropriate to return the value itself or a summarized version of it. But for types that use lots of memory and would otherwise take too much time to traverse, a counter or other value can be used to indicate that some changed is occured, with the rest of the application using mutator methods to increment this value upon change.

type ModTracker

type ModTracker struct {
	// contains filtered or unexported fields
}

ModTracker tracks modifications and maintains the appropriate state for this.

func NewModTracker

func NewModTracker() *ModTracker

NewModTracker creates an empty ModTracker, calls TrackNext on it, and returns it.

func (*ModTracker) ModCheckAll

func (mt *ModTracker) ModCheckAll(values ...interface{}) (ret bool)

ModCheckAll performs a modification check on the values provided. For values implementing the ModChecker interface, the ModCheck method will be called. All values passed should be pointers to the types described below. Single-value primitive types are supported. Structs are supported and and are traversed by calling ModCheckAll on each with the tag `vugu:"modcheck"`. Arrays and slices of supported types are supported, their length is compared as well as a pointer to each member. As a special case []byte is treated like a string. Maps are not supported at this time. Other weird and wonderful things like channels and funcs are not supported. Passing an unsupported type will result in a panic.

func (*ModTracker) TrackNext

func (mt *ModTracker) TrackNext()

TrackNext moves the "current" information to the "old" position - starting a new round of change tracking. Calls to ModCheckAll after calling TrackNext will compare current values to the values from before the call to TrackNext. It is generally called once at the start of each build and render cycle. This method must be called at least once before doing modification checks.

type RenderedCtx

type RenderedCtx interface {
	EventEnv() EventEnv // in case you need to request re-render
	First() bool        // true the first time this component is rendered
}

RenderedCtx is the context passed to the Rendered callback.

type VGAttribute

type VGAttribute struct {
	Namespace, Key, Val string
}

VGAttribute is the attribute on an HTML tag.

type VGAttributeLister

type VGAttributeLister interface {
	AttributeList() []VGAttribute
}

VGAttributeLister implements the required functionality, required by the `:=` attribute setter. Types may implement this interface, to

type VGAttributeListerFunc

type VGAttributeListerFunc func() []VGAttribute

The VGAttributeListerFunc type is an adapter to allow the use of functions as VGAttributeLister

func (VGAttributeListerFunc) AttributeList

func (f VGAttributeListerFunc) AttributeList() []VGAttribute

AttributeList calls the underlying function

type VGNode

type VGNode struct {
	Parent, FirstChild, LastChild, PrevSibling, NextSibling *VGNode

	Type VGNodeType
	// DataAtom  VGAtom // this needed to come out, we're not using it and without well-defined behavior it just becomes confusing and problematic
	Data      string
	Namespace string
	Attr      []VGAttribute

	// JS properties to e set during render
	Prop []VGProperty

	InnerHTML *string // indicates that children should be ignored and this raw HTML is the children of this tag; nil means not set, empty string means explicitly set to empty string

	DOMEventHandlerSpecList []DOMEventHandlerSpec // describes invocations when DOM events happen

	// indicates this node's output should be delegated to the specified component
	Component interface{}

	// if not-nil, called when element is created (but before examining child nodes)
	JSCreateHandler JSValueHandler
	// if not-nil, called after children have been visited
	JSPopulateHandler JSValueHandler
}

VGNode represents a node from our virtual DOM with the dynamic parts wired up into functions.

For the static parts, an instance of VGNode corresponds directly to the DOM representation of an HTML node. The pointers to other VGNode instances (Parent, FirstChild, etc.) are used to manage the tree. Type, Data, Namespace and Attr have the usual meanings for nodes.

The Component field, if not-nil indicates that rendering should be delegated to the specified component, all other fields are ignored.

Another special case is when Type is ElementNode and Data is an empty string (and Component is nil) then this node is a "template" (i.e. <vg-template>) and its children will be "flattened" into the DOM in position of this element and attributes, events, etc. ignored.

Prop contains JavaScript property values to be assigned during render. InnerHTML provides alternate HTML content instead of children. DOMEventHandlerSpecList specifies DOM handlers to register. And the JS...Handler fields are used to register callbacks to obtain information at JS render-time.

TODO: This and its related parts should probably move into a sub-package (vgnode?) and the "VG" prefixes removed.

func (*VGNode) AddAttrInterface

func (n *VGNode) AddAttrInterface(key string, val interface{})

AddAttrInterface sets an attribute based on the given interface. The followings types are supported - string - value is used as attr value as it is - int,float,... - the value is converted to string with strconv and used as attr value - bool - treat the attribute as a flag. If false, the attribute will be ignored, if true outputs the attribute without a value - fmt.Stringer - if the value implements fmt.Stringer, the returned string of StringVar() is used - ptr - If the ptr is nil, the attribute will be ignored. Else, the rules above apply any other type is handled via fmt.Sprintf()

func (*VGNode) AddAttrList

func (n *VGNode) AddAttrList(lister VGAttributeLister)

AddAttrList takes a VGAttributeLister and sets the returned attributes to the node

func (*VGNode) AppendChild

func (n *VGNode) AppendChild(c *VGNode)

AppendChild adds a node c as a child of n.

It will panic if c already has a parent or siblings.

func (*VGNode) InsertBefore

func (n *VGNode) InsertBefore(newChild, oldChild *VGNode)

InsertBefore inserts newChild as a child of n, immediately before oldChild in the sequence of n's children. oldChild may be nil, in which case newChild is appended to the end of n's children.

It will panic if newChild already has a parent or siblings.

func (*VGNode) IsComponent

func (n *VGNode) IsComponent() bool

IsComponent returns true if this is a component (Component != nil). Components have rendering delegated to them instead of processing this node.

func (*VGNode) IsTemplate

func (n *VGNode) IsTemplate() bool

IsTemplate returns true if this is a template (Type is ElementNode and Data is an empty string and not a Component). Templates have their children flattened into the output DOM instead of being processed directly.

func (*VGNode) RemoveChild

func (n *VGNode) RemoveChild(c *VGNode)

RemoveChild removes a node c that is a child of n. Afterwards, c will have no parent and no siblings.

It will panic if c's parent is not n.

func (*VGNode) SetInnerHTML

func (n *VGNode) SetInnerHTML(val interface{})

SetInnerHTML assigns the InnerHTML field with useful logic based on the type of input. Values of string type are escaped using html.EscapeString(). Values in the int or float type families or bool are converted to a string using the strconv package (no escaping is required). Nil values set InnerHTML to nil. Non-nil pointers are followed and the same rules applied. Values implementing HTMLer will have their HTML() method called and the result put into InnerHTML without escaping. Values implementing fmt.Stringer have thier String() method called and the escaped result used as in string above.

All other values have undefined behavior but are currently handled by setting InnerHTML to the result of: `html.EscapeString(fmt.Sprintf("%v", val))`

func (*VGNode) Walk

func (n *VGNode) Walk(f func(*VGNode) error) error

Walk will walk the tree under a VGNode using the specified callback function. If the function provided returns a non-nil error then walking will be stopped and this error will be returned. Only FirstChild and NextSibling are used while walking and so with well-formed documents should not loop. (But loops created manually by modifying FirstChild or NextSibling pointers could cause this function to recurse indefinitely.) Note that f may modify nodes as it visits them with predictable results as long as it does not modify elements higher on the tree (up, toward the parent); it is safe to modify self and children.

type VGNodeType

type VGNodeType uint32

VGNodeType is one of the valid node types (error, text, document, element, comment, doctype). Note that only text, element and comment are currently used.

type VGProperty

type VGProperty struct {
	Key     string
	JSONVal []byte // value as JSON expression
}

VGProperty is a JS property to be set on a DOM element.

Directories

Path Synopsis
cmd
vugugen
vugugen is a command line tool to convert .vugu files into Go source code.
vugugen is a command line tool to convert .vugu files into Go source code.
Package devutil has tooling to make Vugu development simpler.
Package devutil has tooling to make Vugu development simpler.
Package distutil has some useful functions for building your Vugu application's distribution Rather than introducing third party build tools.
Package distutil has some useful functions for building your Vugu application's distribution Rather than introducing third party build tools.
Package domrender has the rendering engine that takes virtual DOM from components and synchronizes it with the browser's DOM.
Package domrender has the rendering engine that takes virtual DOM from components and synchronizes it with the browser's DOM.
examples
Package js is a drop-in replacement for syscall/js that provides identical behavior in a WebAssembly environment, and useful non-functional behavior outside of WebAssembly.
Package js is a drop-in replacement for syscall/js that provides identical behavior in a WebAssembly environment, and useful non-functional behavior outside of WebAssembly.
Package simplehttp provides an http.Handler that makes it easy to serve Vugu applications.
Package simplehttp provides an http.Handler that makes it easy to serve Vugu applications.
Package staticrender contains the static renderer which converts virtual DOM output to HTML via io.Writer.
Package staticrender contains the static renderer which converts virtual DOM output to HTML via io.Writer.
Package vgform has Vugu components that wrap HTML form controls for convenience.
Package vgform has Vugu components that wrap HTML form controls for convenience.
Package vugufmt provides gofmt-like functionality for vugu files.
Package vugufmt provides gofmt-like functionality for vugu files.
internal
htmlx
Package htmlx is a fork of https://github.com/golang/net/html.
Package htmlx is a fork of https://github.com/golang/net/html.
htmlx/atom
Package atom provides integer codes (also known as atoms) for a fixed set of frequently occurring HTML strings: tag names and attribute keys such as "p" and "id".
Package atom provides integer codes (also known as atoms) for a fixed set of frequently occurring HTML strings: tag names and attribute keys such as "p" and "id".
htmlx/charset
Package charset provides common text encodings for HTML documents.
Package charset provides common text encodings for HTML documents.