ickcore

package
v0.1.6-alpha Latest Latest
Warning

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

Go to latest
Published: Oct 21, 2023 License: MIT Imports: 17 Imported by: 1

Documentation

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrBodyTagMissing            = errors.New("<body> tag missing")
	ErrTooManyRecursiveRendering = errors.New("too many recursive rendering")
	ErrNameMissing               = errors.New("'opening <ick-' tag found without name")
)

Functions

func CheckAttribute

func CheckAttribute(name string, value string) (err error)

CheckAttribute returns an error if the attribute name or its value are not valid. Following checks are done:

  • checks characters allowed in name (HTML5 standard).
  • checks characters allowed in id, class and style value.
  • checks tabindex value is numerical.

See the best practice (https://stackoverflow.com/questions/925994/what-characters-are-allowed-in-an-html-attribute-name) for rules we've applied for character allowed in Name.

blanks at the ends of the name are automatically trimmed. Attributes name are case-insensitve.

func GetUniqueId

func GetUniqueId(prefix string) (idx int, uid string)

GetUniqueId returns a unique id starting with prefix. if prefix is empty "ick-" is used to prefix the returned id. The returned id is always lowercase. GetUniqueId is thread safe.

func IsRegistered

func IsRegistered(_name string) bool

IsRegistered returns if the _name has already been regystered

func Map

func Map() map[string]*RegistryEntry

func RenderChild

func RenderChild(out io.Writer, parent RMetaProvider, child Composer, siblings ...Composer) error

RenderChild renders the HTML string of the composers to out, including its tag element its properties and its content. Rendering the content can renders child-snippets recursively. This can be done maxDEEP times max to avoid infinite loop.

If composer is a also a TagBuilder the output looks like this:

`<{tagname} id={xxx} name="{ick-tag}" [attributes]>[content]</tagname>`

otherwise only the content is written.

A snippet id can be setup up upfront (a) accessing any saved tag attribute within the snippet struct, or (b) within an html ick-tag attribute (for embedded snippet). Thes id will be lost if ther'e a parent, the snippet attributes will be overwritten with the unique id generated by the rendering process. Unique ids are generated by using the composer name (without "ick-" prefix) with a sequence number. sub-composer ids combine the id of the parent with the id of the sub-composer. if the component is not registered and so does't have a name, a global unique id is generated. This behaviour ensures that ids are uniques even for multiple instanciations of the same composer.

snippet may have none id on request. noid snippet attribute must be set to true to render the composer without id. The special attribute noid can be defined within an ick-tag html or with attribute's methods.

If the parent is not nil, the snippet is added to its embedded stack of sub-components.

Returns rendering errors, typically with the writer, or if there's too many recursive rendering.

func RenderString

func RenderString(w io.Writer, ss ...string) (n int, err error)

RenderString writes one or many strings to w. Returns the number of bytes written and errors from the writer.

func RenderStringIf

func RenderStringIf(condition bool, w io.Writer, ss ...string) (n int, err error)

RenderStringIf writes one or many strings to w only if the condition is true. Returns the number of bytes written and errors from the writer.

func RequireCSSFile

func RequireCSSFile(cssURL string)

RequireCSSFile allows to declare a required CSS file. This can be call in the init function of a package defining custom snippets.

func RequireCSSStyle

func RequireCSSStyle(ickTagName string, cssStyle string)

RequireCSSFile allows to declare a required CSS style string for a specific snippet. This can be call in the init function of a package defining custom snippets.

func RequiredCSSFile

func RequiredCSSFile() []url.URL

func RequiredCSSStyle

func RequiredCSSStyle() string

func ResetRegistry

func ResetRegistry()

ResetRegistry is only used for testing

func StringifyAttributeValue

func StringifyAttributeValue(value string) (string, error)

StringifyAttributeValue makes a valid attribute value string.

Returns an empty string if value is empty or if value == "true". Returns an unquoted string if the value is numerical. Returns a quoted value in any other cases. The enclosed quotes are a double quote `"` unless the value contains one otherwise quotes are a simple one `'`. If the value contains both kind of quotes an error is return.

Types

type AttributeMap

type AttributeMap map[string]string // map of HTML tag attributes

AttributeMap represents a list of valid HTML tag attributes, providing methods to easily set, update and extract each.

Validity of attributes is checked once when setting it. Most most of setters are chainable, so they does not returns errors. If verbose mode is turnned on, errors are printed out otherwise the setter fails and nothing happen. Use CheckAttribute to check the validity of an attribute and to receive an error.

HTML Attributes name are case insensitive: https://www.w3.org/TR/2010/WD-html-markup-20101019/documents.html

func ParseAttributes

func ParseAttributes(alist string) AttributeMap

ParseAttributes tries to parse attributes and ignore errors. errors are logged out if verbose mode is on.

func TryParseAttributes

func TryParseAttributes(alist string) (amap AttributeMap, err error)

TryParseAttribute splits alist of attributes separated by spaces and sets each to the returned AttributeMap. Always returns a not nil amap.

An attribute can be either a single name, usually a boolean attribute, either a name and a value at the right of an "=" symbol. The value can be delimited by quotes ( " or ' ) and in that case may contains whitespaces. The string is processed until the end or an error occurs when invalid char is met.

Use ParseAttributes to chain calls and ignore errors.

func (AttributeMap) AddClass

func (amap AttributeMap) AddClass(lists ...string) AttributeMap

AddClass adds each class in lists strings to the class attribute. Each lists class string can be either a single class or a string of multiple classes separated by spaces. Duplicates are not inserted twice.

func (AttributeMap) AddClassIf

func (amap AttributeMap) AddClassIf(condition bool, addlist ...string) AttributeMap

AddClassIf adds each c classe to the class attribute if the condition is true. Does nothing if the condition is false. See SetClassIf to also remove the class if the condition is false. Duplicates are not inserted twice.

func (AttributeMap) AddStyle

func (amap AttributeMap) AddStyle(style string) AttributeMap

AddStyle adds the style to the style attribute. AddStyle returns the map to allow chainning.

func (AttributeMap) Attribute

func (amap AttributeMap) Attribute(aname string) (value string, found bool)

Attribute returns the value of the attribute identified by its name. Returns false if the attribute does not exist.

Blanks at the ends of the name are automatically trimmed. Attribute's name are case sensitive

func (AttributeMap) AttributeString

func (amap AttributeMap) AttributeString() string

AttributeString returns the formated list of attributes, ready to use to generate the tag element. always sorted the same way : 1>id 2>name 3>class 4>others sorted alpha by name

func (AttributeMap) Classes

func (amap AttributeMap) Classes() string

Classes returns the class attribute as a full string.

func (AttributeMap) Clone

func (amap AttributeMap) Clone() AttributeMap

Clone clones the attribute map

func (AttributeMap) HasClass

func (amap AttributeMap) HasClass(class string) bool

HasClass returns if the class exists in the list of amap classes. Returns false if class is empty.

func (AttributeMap) Id

func (amap AttributeMap) Id() string

Id returns the id attribute if any

func (AttributeMap) IsDisabled

func (amap AttributeMap) IsDisabled() bool

IsDisabled returns true if the disabled attribute is set

func (AttributeMap) IsTrue

func (amap AttributeMap) IsTrue(aname string) bool

IsTrue returns true if the attribute exists and if it's value is not false nor 0.

Blanks at the ends of the name are automatically trimmed. Attribute's name is case sensitive.

func (AttributeMap) Name

func (amap AttributeMap) Name() string

Name returns the name attribute if any

func (AttributeMap) PickClass

func (amap AttributeMap) PickClass(classlist string, picked string) AttributeMap

PickClass set the picked classes and only that one, removing all others in the classlist. If picked is empty or not in the classlist then it's not added.

func (AttributeMap) RemoveAttribute

func (amap AttributeMap) RemoveAttribute(name string) AttributeMap

RemoveAttribute removes the attribute identified by its name. Does nothing if the name is not in the map.

Blanks at the ends of the name are automatically trimmed. Attribute's name are case sensitive

func (AttributeMap) RemoveClass

func (amap AttributeMap) RemoveClass(lists ...string) AttributeMap

RemoveClass removes each class in lists strings from the class attribute. Each lists class string can be either a single class or a string of multiple classes separated by spaces.

func (AttributeMap) ResetAttributes

func (amap AttributeMap) ResetAttributes() AttributeMap

ResetAttributes deletes all attributes in the map.

func (AttributeMap) ResetClass

func (amap AttributeMap) ResetClass() AttributeMap

ResetClass removes all classes by removing the class attribute

func (AttributeMap) SetAttribute

func (amap AttributeMap) SetAttribute(name string, value string) AttributeMap

SetAttribute creates an attribute in the map and set its value. If the attribute already exists in the map it is updated. SetAttribute returns the map to allow chainning and so never returns an error. If the name or the value are not valid nothing is created and a log is printed out if verbose mode is on. Use CheckAttribute to check name and value validity.

Blanks at the ends of the name are automatically trimmed. Attribute's name are case sensitive

func (AttributeMap) SetAttributeIf

func (amap AttributeMap) SetAttributeIf(condition bool, name string, valueiftrue string, valueiffalse ...string) AttributeMap

SetAttributeIf SetAttribute if the condition is true, otherwise remove the attribute.

Blanks at the ends of the name are automatically trimmed. Attribute's name are case sensitive.

func (AttributeMap) SetBool

func (amap AttributeMap) SetBool(aname string, f bool) AttributeMap

SetBool sets or overwrites a boolean attribute and returns the map to allow chainning. SetBool does nothing if trying to set id, style, name or class attribute to true.

func (AttributeMap) SetClassIf

func (amap AttributeMap) SetClassIf(condition bool, classiftrue string, classiffalse ...string) AttributeMap

SetClassIf adds each c classe to the class attribute if the condition is true, otherwise remove them. Duplicates are not inserted twice.

func (AttributeMap) SetDisabled

func (amap AttributeMap) SetDisabled(f bool) AttributeMap

SetDisabled sets the boolean disabled attribute

func (AttributeMap) SetId

func (amap AttributeMap) SetId(id string) AttributeMap

SetId sets or overwrites the id attribute. In HTML5 id is case sensitive. blanks at the ends of the id are automatically trimmed. if id is empty, the id attribute is removed.

SetId returns the map to allow chainning. SetId never returns an error. If the id is not valid nothing is setted and a log is printed out if verbose mode is on.

func (AttributeMap) SetName

func (amap AttributeMap) SetName(name string) AttributeMap

SetName sets or overwrites the name attribute. In HTML5 name is case sensitive. blanks at the ends of the id are automatically trimmed. if name is empty, the name attribute is removed.

SetName returns the map to allow chainning. If the name is not valid nothing is setted and a log is printed out if verbose mode is on.

func (AttributeMap) SetTabIndex

func (amap AttributeMap) SetTabIndex(idx int) AttributeMap

SetTabIndex sets or overwrites the tabindex attribute. SetTabIndex returns the map to allow chainning.

func (AttributeMap) SetURL

func (amap AttributeMap) SetURL(attributeName string, url *url.URL) AttributeMap

SetURL sets a url string as a value of a given attributeName. if url is nil or if its value is an empty string, the attribute name is setup with an "#" value.

func (AttributeMap) SetUniqueId

func (amap AttributeMap) SetUniqueId(prefix string)

SetUniqueId sets or overwrites the id attribute by generating a unique id starting with the prefix. "ick-" is used to prefix the returned id if prefix is empty.

func (AttributeMap) Style

func (amap AttributeMap) Style() string

Style returns the style attribute

func (AttributeMap) SubId

func (amap AttributeMap) SubId(id string) string

SubId build an id with the id attribute followed by a dot and by the provided is string. Returns an empty string if the id attribute or the provided id is empty.

func (AttributeMap) SwitchClass

func (amap AttributeMap) SwitchClass(removec string, addc string) AttributeMap

SwitchClass removes one class and set a new one

func (AttributeMap) TabIndex

func (amap AttributeMap) TabIndex() (i int)

TabIndex returns the TabIndex attribute. Returns 0 if tabindex attribute does not exists.

func (AttributeMap) ToggleAttribute

func (amap AttributeMap) ToggleAttribute(name string) AttributeMap

ToggleAttribute toggles an attribute like a boolean. If the attribute exists it's removed, if it does not exists it's created without value. id, tabindex, name, class and style can't be setup with this method. In verbose mode ToggleAttribute can log an error if the name is not valid.

Blanks at the ends of the name are automatically trimmed. Attribute's name are case sensitive

func (AttributeMap) TrySetAttribute

func (amap AttributeMap) TrySetAttribute(name string, value string) bool

TrySetAttribute creates an attribute in the map and set its value. If the attribute already exists in the map then does nothing. Returns if the attribute has been created/updated or not.

type BareSnippet

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

func (BareSnippet) Clone

func (bs BareSnippet) Clone() *BareSnippet

func (*BareSnippet) NeedRendering

func (bs *BareSnippet) NeedRendering() bool

func (*BareSnippet) RMeta

func (bs *BareSnippet) RMeta() *RMetaData

func (*BareSnippet) SetAttribute

func (bs *BareSnippet) SetAttribute(name string, value string)

func (*BareSnippet) Tag

func (bs *BareSnippet) Tag() *Tag

type Composer

type Composer interface {
	// Meta returns a reference to render meta data
	RMetaProvider

	// NeedRendering returns true if the composer needs rendering or has something to render.
	NeedRendering() bool
}

type ComposerMap

type ComposerMap map[string]RMetaProvider

type ContentComposer

type ContentComposer interface {
	Composer

	// RenderContent writes the HTML string corresponding to the content of the HTML element.
	// Return an error to stops the rendering process.
	RenderContent(out io.Writer) error
}

type ContentStack

type ContentStack struct {
	Stack []ContentComposer
}

ContentStack is a stack of ContentComposer than can easily be embedded into any custom snippet. Call Push to feed the stack and call RenderStack into the RenderContent fonction of the custom snippet.

func (*ContentStack) ClearContent

func (c *ContentStack) ClearContent()

Clear clears the rendering stack

func (ContentStack) Clone

func (c ContentStack) Clone() ContentStack

func (*ContentStack) NeedRendering

func (c *ContentStack) NeedRendering() bool

NeedRendering returns true is the content stack is not nil and it contains at least on item

func (*ContentStack) Push

func (c *ContentStack) Push(content ...ContentComposer)

Push adds one or many composers to the rendering stack. Returns the snippet to allow chaining calls.

Warning: Struct embedding ICKSnippet should be car of Push returns an ICKSnippet and not the parent stuct type.

func (*ContentStack) RenderStack

func (c *ContentStack) RenderStack(out io.Writer, parent RMetaProvider) (err error)

RenderStack writes the HTML string corresponding to the content of the HTML element. The default implementation for an HTMLSnippet snippet is to render all the internal stack of composers inside an enclosed HTML tag.

type HTMLString

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

HTMLString represents a string document fragment, mixing standard HTML syntax with <ick-tags/> inline components. HTMLString implements Elementcomposer interface and the string is rendered to an output stream with the icecake Rendering functions. It is part of the core icecake snippets.

func ToHTML

func ToHTML(s string) *HTMLString

ToHTML is the HTMLString factory allowing to convert a string into a new HTMLString reday for rendering. The string must contains safe string and can include icecake tags. TODO: html - think of a way to accept any types for ToHTML

func (HTMLString) Bytes

func (h HTMLString) Bytes() []byte

String returns a copy of the content

func (HTMLString) NeedRendering

func (s HTMLString) NeedRendering() bool

NeedRendering

func (*HTMLString) RMeta

func (h *HTMLString) RMeta() *RMetaData

Meta provides a reference to the RenderingMeta object associated with this composer. This is required by the icecake rendering process.

func (*HTMLString) RenderContent

func (h *HTMLString) RenderContent(out io.Writer) error

RenderContent writes the HTML string corresponding to the content of the HTML element. For an HTMLString snippet, RenderContent renders (unfold and generate HTML output) the internal string without enclosed tag. Use an HTMLSnippet snippet to renders the string inside an enclosed tag.

func (*HTMLString) Write

func (s *HTMLString) Write(p []byte) (n int, err error)

Writer interface

type IckTagNameError

type IckTagNameError struct {
	TagName string
	Message string
}

func (*IckTagNameError) Error

func (e *IckTagNameError) Error() string

type RMetaData

type RMetaData struct {
	Deep      int           // deepness of the HTMLContentComposer
	VirtualId string        // virtual id allocated to a Composer, always one
	TagId     string        // the id allocated to the Composer if any
	Parent    RMetaProvider // optional parent, may be an orphan
	IsRender  bool          // Indicates the HTMLContentComposer has been rendered at least once
	IsMounted bool          // Indicates the HTMLContentComposer has been mounted
	RError    error         // rendering error if any
	// contains filtered or unexported fields
}

RMetaData is rendering metadata for a single HTMLContentComposer

func (*RMetaData) Embed

func (rmeta *RMetaData) Embed(child RMetaProvider)

Embed adds child to the map of embedded components. If a child with the same key has already been embedded it's replaced and a warning is raised in verbose mode. The key is the id of the html element if any, otherwise it's its virtual id.

func (RMetaData) Embedded

func (rmeta RMetaData) Embedded() ComposerMap

Embedded returns the map of embedded components, keyed by their id.

func (*RMetaData) GenerateVirtualId

func (rmeta *RMetaData) GenerateVirtualId(cmp RMetaProvider) string

GenerateVirtualId generates a unique id for every rendering composer. The composer may not have a TagBuilder, so the Id is not necessarly the id attribute of the composer. The generated id pattern is:

`{{{parentid|orphan}.[cmpname.index]}|[cmpid]}`

rules:

  • if the rendering has a rendering parent, the virtual id starts with the parent's virtualid otherwise it's "orphan" followed by the component name
  • if the rendering does not have a rendering parent, the virtual id is the given cmpid if not empty, otherwise it's "orphan"
  • the dot "-" seperator is added followed by the cmpname if any

- the cmpname is added TODO: ickcore - GenerateVirtualId need to be reworked

func (*RMetaData) RMeta

func (rmeta *RMetaData) RMeta() *RMetaData

type RMetaProvider

type RMetaProvider interface {

	// Meta returns a reference to render meta data
	RMeta() *RMetaData
}

type RegistryEntry

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

RegistryEntry defines a component

func AddRegistryEntry

func AddRegistryEntry(name string, cmp any) *RegistryEntry

AddRegistryEntry create a new RegistryEntry and add it to the global and private registry. No check is done on name. If name is already registered a new registryentry overwrites the existing one. css is optional and can be nil.

func GetRegistryEntry

func GetRegistryEntry(name string) *RegistryEntry

GetRegistryEntry returns the RegistryEntry corresponding to the _name. If _name is empty GetRegistryEntry returns the RegistryEntry for "ick". If _name does not correspond to an existing entry in the resitry, then GetRegistryEntry create a default entry in the registry with that name. Also GetRegistryEntry always returns a RegistryEntry.

func LookupRegistryEntry

func LookupRegistryEntry(cmp any) *RegistryEntry

LookupRegistryEntry lookup for _cmp in the registry and returns the first RegistryEntry with matching type. _cmp must be a pointer, like it was registered with AddRegistryEntry. Return nil if nothing is found.

func RegisterComposer

func RegisterComposer(icktagname string, composer any) (entry *RegistryEntry, err error)

RegisterComposer registers a _composer with the unique _ickname. Registering a _composer is required to enable rendering of a composer embedded into an html string with an auto-closing ick-tag.

<link rel="stylesheet" href="{_css[n]}">

The ickname must start by `ick-` followed by at least one character. An error is returned in the following cases:

  • If the ickname has already been registered
  • If the ickname does not meet the pattern "ick-*"
  • If the composer does not implement the ElementComposer interface

func (RegistryEntry) Component

func (_r RegistryEntry) Component() any

Component returns the component type that must be instantiated

func (*RegistryEntry) Count

func (_r *RegistryEntry) Count() int

func (RegistryEntry) IckTagName

func (_r RegistryEntry) IckTagName() string

Name returns the unique name of the component starting with the `ick-` prefix.

type Tag

type Tag struct {
	AttributeMap      // map of all tag attributes of any type, including the id if there's one.
	NoName       bool // does not generate name attribute with the ick-name of the composer
	// contains filtered or unexported fields
}

Tag represents the tag of an HTML element with its attributes.

Example
render := func(w io.Writer, tag Tag, s string) {
	tag.RenderOpening(w)
	io.WriteString(w, s)
	tag.RenderClosing(w)
}

// create a new div tag
tag := NewTag("div", `class="example dark"`)

out := new(bytes.Buffer)
render(out, *tag, "example1")
fmt.Println(out.String())

// update div tag
active := true
tag.SwitchClass("dark", "light").SetClassIf(active, "is-active")

out.Reset()
render(out, *tag, "example2")
fmt.Println(out.String())
Output:

<div class="example dark">example1</div>
<div class="example light is-active">example2</div>

func BuildTag

func BuildTag(tb TagBuilder) Tag

BuildTag get a tag from the TagBuilder then set up name attribute and RMeta id

func EmptyTag

func EmptyTag() Tag

func NewTag

func NewTag(name string, attrs ...string) *Tag

Tag factory setting the tag named and allowing to assign an existing map of attibutes.

func (Tag) Clone

func (tag Tag) Clone() *Tag

clone clones the tag

func (Tag) IsEmpty

func (tag Tag) IsEmpty() bool

IsEmpty return if the tag has something to render or not

func (*Tag) ParseAttributes

func (tag *Tag) ParseAttributes(alists ...string) AttributeMap

ParseAttributes tries to parse attributes to the tag and ignore errors. alist will be added or will update existing tag attributes. errors are logged out if verbose mode is on.

func (*Tag) RenderClosing

func (tag *Tag) RenderClosing(out io.Writer) (err error)

RenderClosing renders the closing tag HTML string to out. if the tag name is empty or the tag is a selclosing one, nothing is rendered and there's no error. errors mays occurs from the writer only.

func (*Tag) RenderOpening

func (tag *Tag) RenderOpening(out io.Writer) (selfclosed bool, err error)

RenderOpening renders the HTML string of the opening tag including all the attributes. if the tag name is empty, nothing is rendered and there's no error. Returns selfclosed if the rendered opening tag as been closed too. errors mays occurs from the writer only.

func (*Tag) SetSelfClosing

func (tag *Tag) SetSelfClosing(sc bool) *Tag

SetSelfClosing forces the selfclosing flag of the tag. Should be called after SetName because SetName update the selfClosing flag.

func (*Tag) SetTagName

func (tag *Tag) SetTagName(name string) *Tag

SetTagName normalizes the name and automaticlally update the SelfClosing attribute according to standard HTML5 specifications https://developer.mozilla.org/en-US/docs/Glossary/Void_element

func (*Tag) TagName

func (tag *Tag) TagName() (string, bool)

TagName returns the name of the tag and it's selfclosing flag

type TagBuilder

type TagBuilder interface {
	Composer

	// SetAttribute creates a tag attribute and set its value.
	// If the attribute already exists then it is updated.
	//
	// Attribute's name is case sensitive
	SetAttribute(name string, value string)

	// BuildTag builds the tag used to render the html element.
	// The composer rendering processes call BuildTag once.
	// If the implementer builds an empty tag, only the body will be rendered.
	//
	// The returned tag can be built from scratch or on top of an embedded tag in the snippet.
	BuildTag() Tag
}

type TagProvider

type TagProvider interface {
	TagBuilder

	Tag() *Tag
}

Jump to

Keyboard shortcuts

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