zephyr

package
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 30, 2021 License: MIT Imports: 11 Imported by: 0

README

Zephyr Core

The core package contains all the code needed to start the runtime, build components, etc. It's all in the same package for ease of use, but each file should be

Documentation

Overview

This file is responsible for implementing the bulk of the so-called "virtual DOM". In order to keep matching efficient, the VNode struct pretty much follows the implementation of the standard library HTML Node struct exactly.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AddEventListener

func AddEventListener(el js.Value, eventStr string, eFunc func(e *DOMEvent))

func EscapeString

func EscapeString(s string) string

EscapeString escapes special characters like "<" to become "&lt;". It escapes only five such characters: <, >, &, ' and ". UnescapeString(EscapeString(s)) == s always holds, but the converse isn't always true.

func GetByQuerySelector

func GetByQuerySelector(parent js.Value, selector string) js.Value

func GetElID

func GetElID(nodeTag string) string

func GetFirstElemWithClass

func GetFirstElemWithClass(parent js.Value, class string) js.Value

func InitWrapper

func InitWrapper(c Component)

func RemoveAttribute

func RemoveAttribute(el js.Value, key string)

func RenderHTML

func RenderHTML(w io.Writer, n *VNode) error

Renders HTML string from VNode tree. This file is extended directly from the net/http package; its documentation is below. TODO: namespaces

Render renders the parse tree n to the given writer.

Rendering is done on a 'best effort' basis: calling Parse on the output of Render will always result in something similar to the original tree, but it is not necessarily an exact clone unless the original tree was 'well-formed'. 'Well-formed' is not easily specified; the HTML5 specification is complicated.

Calling Parse on arbitrary input typically results in a 'well-formed' parse tree. However, it is possible for Parse to yield a 'badly-formed' parse tree. For example, in a 'well-formed' parse tree, no <a> element is a child of another <a> element: parsing "<a><a>" results in two sibling elements. Similarly, in a 'well-formed' parse tree, no <a> element is a child of a <table> element: parsing "<p><table><a>" results in a <p> with two sibling children; the <a> is reparented to the <table>'s parent. However, calling Parse on "<a><table><a>" does not return an error, but the result has an <a> element with an <a> child, and is therefore not 'well-formed'.

Programmatically constructed trees are typically also 'well-formed', but it is possible to construct a tree that looks innocuous but, when rendered and re-parsed, results in a different tree. A simple example is that a solitary text node would become a tree containing <html>, <head> and <body> elements. Another example is that the programmatic equivalent of "a<head>b</head>c" becomes "<html><head><head/><body>abc</body></html>".

func ReplaceElement

func ReplaceElement(el js.Value, newEl string)

func SetAttribute

func SetAttribute(el js.Value, key, val string)

func SetInnerHTML

func SetInnerHTML(el js.Value, content string)

func UnescapeString

func UnescapeString(s string) string

UnescapeString unescapes entities like "&lt;" to become "<". It unescapes a larger range of entities than EscapeString escapes. For example, "&aacute;" unescapes to "á", as does "&#225;" and "&xE1;". UnescapeString(EscapeString(s)) == s always holds, but the converse isn't always true.

func UpdateWrapper

func UpdateWrapper(c Component)

Types

type BaseComponent

type BaseComponent struct {

	// Node is a reference to the components
	// root vNode
	Node *VNode
	// contains filtered or unexported fields
}

func (*BaseComponent) BindProp

func (c *BaseComponent) BindProp(propName string) interface{}

func (*BaseComponent) Component

func (parent *BaseComponent) Component(c Component) *VNode

ChildComponent calls the render func of a child component

func (*BaseComponent) ComponentWithProps

func (parent *BaseComponent) ComponentWithProps(c Component, props map[string]interface{}) *VNode

ChildComponent calls the render func of a child component

type Component

type Component interface {

	// Public API
	Init()
	Render() *VNode
	// contains filtered or unexported methods
}

type ComputedFunc

type ComputedFunc func() interface{}

This probably will only allow one return value, is there a use case where this doesnt work??

type ConditionalRender

type ConditionalRender struct {
	Condition interface{}
	Render    *VNode
}

type DOMEvent

type DOMEvent struct {
	Target js.Value

	Bubbles          bool
	DefaultPrevented bool
}

func (*DOMEvent) PreventDefault

func (e *DOMEvent) PreventDefault()

func (*DOMEvent) StopPropagation

func (e *DOMEvent) StopPropagation()

type DOMOperation

type DOMOperation int
const (
	InitialRender DOMOperation = iota
	Insert
	Delete
	UpdateAttr
	UpdateAttrs
	SetAttrs
	RemoveAttr
	UpdateContent
	UpdateConditional
	Replace
	OverwriteInnerHTML
	AddEventListeners
	InsertBefore
	InsertAfter
	SwapChildren
)

type DOMUpdate

type DOMUpdate struct {
	ElementID string
	Data      interface{}
	Operation DOMOperation
}

type DataDep

type DataDep struct {
	Data      interface{}
	Listeners map[string]Listener
}

DataDep is the struct that acts as the struct implementation of the Subject.

func NewDep

func NewDep(data interface{}) DataDep

NewDep creates and returns a new DataDep struct with the given data.

func (*DataDep) Notify

func (rd *DataDep) Notify()

func (*DataDep) Register

func (rd *DataDep) Register(l Listener)

Register is handles and registers the various listener implementations.

type Document

type Document js.Value

func GetDocument

func GetDocument() Document

func (Document) GetByID

func (d Document) GetByID(id string) js.Value

func (Document) QuerySelector

func (d Document) QuerySelector(selector string) js.Value

QuerySelector is an idiomatic wrapper function around the regular syscall/js function

type Emitter

type Emitter interface {
	Call()
}

type Listener

type Listener interface {
	Update()
	Identifier() string
}

Listener lets implementations call an Update() function, which triggers a DOM update in the reactive data types

type LiveArray

type LiveArray func() *DataDep

LiveArr is the LiveData implementation for the `string` type.

func NewLiveArray

func NewLiveArray(data interface{}) LiveArray

NewLiveString returns a "live" string (reactive type LiveString)

func (LiveArray) Append

func (arr LiveArray) Append(val interface{})

func (LiveArray) At

func (arr LiveArray) At(l Listener, i int) interface{}

func (LiveArray) Set

func (arr LiveArray) Set(newData interface{})

Set implements LiveData.Set(interface{}), and is used to set and notify listeners.

func (LiveArray) Value

func (arr LiveArray) Value(l Listener) interface{}

type LiveBool

type LiveBool func() *DataDep

LiveBool is the LiveData implementation for the `string` type.

func NewLiveBool

func NewLiveBool(data bool) LiveBool

NewLiveString returns a "live" string (reactive type LiveString)

func (LiveBool) Set

func (b LiveBool) Set(newData interface{})

Set implements LiveData.Set(interface{}), and is used to set and notify listeners.

func (LiveBool) Value

func (b LiveBool) Value(l Listener) interface{}

type LiveData

type LiveData interface {
	// Set must be implemented on all data types.
	// Type checking occurs in implementations.
	Set(interface{})

	// Value returns the value stored inside
	// the reactive data; requires type assert
	Value(l Listener) interface{}
	// contains filtered or unexported methods
}

LiveData is the interface for using reactive data in components. Implementations are functions that return their resp. types.

type LiveInt

type LiveInt func() *DataDep

LiveInt is the LiveData implementation for the `string` type.

func NewLiveInt

func NewLiveInt(data int) LiveInt

NewLiveString returns a "live" string (reactive type LiveString)

func (LiveInt) Set

func (i LiveInt) Set(newData interface{})

Set implements LiveData.Set(interface{}), and is used to set and notify listeners.

func (LiveInt) Value

func (i LiveInt) Value(l Listener) interface{}

type LiveString

type LiveString func() *DataDep

LiveString is the LiveData implementation for the `string` type.

func NewLiveString

func NewLiveString(data string) LiveString

NewLiveString returns a "live" string (reactive type LiveString)

func (LiveString) Set

func (str LiveString) Set(newData interface{})

Set implements LiveData.Set(interface{}), and is used to set and notify listeners.

func (LiveString) Value

func (str LiveString) Value(l Listener) interface{}

type LiveStruct

type LiveStruct interface {
	Notify()
	Register(l Listener)
}

type LiveStructImpl

type LiveStructImpl struct {
	Listeners map[string]Listener
}

func (LiveStructImpl) Notify

func (s LiveStructImpl) Notify()

func (*LiveStructImpl) Register

func (s *LiveStructImpl) Register(l Listener)

type Mounter

type Mounter interface {
	OnMount()
}

type Subject

type Subject interface {
	Register(l Listener)
	Notify()
}

Subject lets implementations register listeners and notify their listeners. May want to add removal in the future.

type Updater

type Updater interface {
	OnUpdate()
}

type VNAttrListener

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

func (VNAttrListener) Identifier

func (l VNAttrListener) Identifier() string

func (VNAttrListener) Update

func (l VNAttrListener) Update()

type VNCalculatorListener

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

func (VNCalculatorListener) Identifier

func (l VNCalculatorListener) Identifier() string

func (VNCalculatorListener) Update

func (l VNCalculatorListener) Update()

type VNConditionalListener

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

func (VNConditionalListener) Identifier

func (l VNConditionalListener) Identifier() string

func (VNConditionalListener) Update

func (l VNConditionalListener) Update()

type VNContentListener

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

func (VNContentListener) Identifier

func (l VNContentListener) Identifier() string

func (VNContentListener) Update

func (l VNContentListener) Update()

type VNIteratorListener

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

func (VNIteratorListener) Identifier

func (l VNIteratorListener) Identifier() string

func (VNIteratorListener) Update

func (l VNIteratorListener) Update()

type VNPropListener

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

func (VNPropListener) Identifier

func (l VNPropListener) Identifier() string

func (VNPropListener) Update

func (l VNPropListener) Update()

type VNode

type VNode struct {
	// NodeType is the virtual nodes DOM node type
	NodeType VNodeType

	// Tag is the HTML tag - only used for ElementNodes
	Tag string

	// DOM_ID is the auto-generated ID that is used to update the node
	DOM_ID string

	// Content
	Content interface{}

	// Attrs stores the attributes for the ZNode
	Attrs map[string]interface{}
	// ParsedAttrs is a map[string]string of ready-to-render
	// attributes.
	ParsedAttrs map[string]string

	RenderChan chan DOMUpdate

	// Other node refs
	Parent, FirstChild, LastChild, PrevSibling, NextSibling *VNode

	// Flags
	Static    bool
	Component bool

	// Special fields - may want to interface it up
	ConditionalRenders []ConditionalRender
	CurrentCondition   int
	ConditionUpdated   bool
	Keys               []interface{}

	IterRender func(int, interface{}) *VNode
	// contains filtered or unexported fields
}

VNode struct is a simple intermediary between the stdlib html.Node and a Zephyr Component instance. There are also a few extra fields for optimizing patching. Its all on the heap :( I feel like this is bad, but I don't know how else to have ref variables inited in the func. FP maybe? Will investigate.

func Comment

func Comment(commentMsg string) VNode

func DynamicText

func DynamicText(dynamicData interface{}) *VNode

works with computed props!

func Element

func Element(tag string, attrs map[string]interface{}, children []*VNode) *VNode

Element will create VNodes for the element and all of its children

func RenderFor

func RenderFor(iterator LiveArray, r func(index int, val interface{}) *VNode) *VNode

func RenderIf

func RenderIf(condition interface{}, r *VNode) *VNode

func RenderWrapper

func RenderWrapper(c Component, updateQueue chan DOMUpdate) *VNode

func StaticText

func StaticText(content string) *VNode

func (*VNode) BindEvent

func (node *VNode) BindEvent(event string, callback func(e *DOMEvent)) *VNode

func (*VNode) GetDOMSelector

func (node *VNode) GetDOMSelector() string

func (*VNode) GetOrCreateListener

func (node *VNode) GetOrCreateListener(lID string) Listener

func (*VNode) Key

func (vnode *VNode) Key(keyVal interface{}) *VNode

func (*VNode) RenderElse

func (vnode *VNode) RenderElse(r *VNode) *VNode

func (*VNode) RenderElseIf

func (vnode *VNode) RenderElseIf(condition interface{}, r *VNode) *VNode

type VNodeListener

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

func (VNodeListener) Identifier

func (l VNodeListener) Identifier() string

func (VNodeListener) Update

func (l VNodeListener) Update()

type VNodeType

type VNodeType int
const (
	ErrorNode VNodeType = iota
	TextNode
	DocumentNode
	ElementNode
	CommentNode
	DoctypeNode
	// RawNode nodes are not returned by the parser, but can be part of the
	// Node tree passed to func Render to insert raw HTML (without escaping).
	// If so, this package makes no guarantee that the rendered HTML is secure
	// (from e.g. Cross Site Scripting attacks) or well-formed.
	RawNode

	// The following are types that don't follow the Go HTML package. They are
	// used for conditional and iterative rendering
	ConditionalNode
	IterativeNode
)

(follows html package exactly)

type ZephyrApp

type ZephyrApp struct {
	// Anchor is a JS Value representing an HTMLElement
	// object.
	Anchor         js.Value
	AnchorSelector string

	// UpdateQueue is a channel that receives a DOMUpdate,
	// which holds the id of the DOM element, the op, and data
	UpdateQueue chan DOMUpdate

	// DOMNodes is a map that stores each element by its
	// js.Value, which can be retrieved from the DOMElements
	// map
	DOMNodes map[string]*VNode

	// DOMElements holds each element on the pages js.Value
	// by its id. I think this is faster than calling getElementById
	// in JS
	DOMElements map[string]js.Value

	// ComponentInstance is the instance of the root component
	RootComponent Component

	RootNode *VNode
	// contains filtered or unexported fields
}

func CreateApp

func CreateApp(rootInstance Component) ZephyrApp

CreateApp creates and returns an instance of a ZephyrApp, after doing app-wide initialization (plugins and other stuff maybe)

func (*ZephyrApp) Mount

func (z *ZephyrApp) Mount(querySelector string)

Mount will mount the ZephyrApp to the given document found by the querySelector. It will also begin the rendering and patching process

func (*ZephyrApp) RenderLoop

func (z *ZephyrApp) RenderLoop()

type ZephyrAttr

type ZephyrAttr struct {
	// Namespace is currently unused
	Namespace, Key string
	// Value should be a regular Go
	// data type.
	Value interface{}
}

ZephyrAttrs represents the HTML attributes for a VNode in a key/value map. e.g. <input type="text" /> -> "type": "text"

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL