Compare commits

...

2 Commits

Author SHA1 Message Date
anoshenko 9ac68ac0c9 Updated docs 2024-04-23 19:34:36 +03:00
anoshenko b1f085b891 Bug fixing 2024-04-23 18:24:51 +03:00
19 changed files with 189 additions and 75 deletions

View File

@ -34,6 +34,7 @@ func newColorPicker(session Session) View {
func (picker *colorPickerData) init(session Session) {
picker.viewData.init(session)
picker.tag = "ColorPicker"
picker.hasHtmlDisabled = true
picker.colorChangedListeners = []func(ColorPicker, Color, Color){}
picker.properties[Padding] = Px(0)
}
@ -153,13 +154,6 @@ func (picker *colorPickerData) htmlProperties(self View, buffer *strings.Builder
}
}
func (picker *colorPickerData) htmlDisabledProperties(self View, buffer *strings.Builder) {
if IsDisabled(self) {
buffer.WriteString(` disabled`)
}
picker.viewData.htmlDisabledProperties(self, buffer)
}
func (picker *colorPickerData) handleCommand(self View, command string, data DataObject) bool {
switch command {
case "textChanged":

View File

@ -188,10 +188,6 @@ func (customView *CustomViewData) htmlProperties(self View, buffer *strings.Buil
customView.superView.htmlProperties(customView.superView, buffer)
}
func (customView *CustomViewData) htmlDisabledProperties(self View, buffer *strings.Builder) {
customView.superView.htmlDisabledProperties(customView.superView, buffer)
}
func (customView *CustomViewData) cssStyle(self View, builder cssBuilder) {
customView.superView.cssStyle(customView.superView, builder)
}

View File

@ -40,6 +40,7 @@ func newDatePicker(session Session) View {
func (picker *datePickerData) init(session Session) {
picker.viewData.init(session)
picker.tag = "DatePicker"
picker.hasHtmlDisabled = true
picker.dateChangedListeners = []func(DatePicker, time.Time, time.Time){}
}
@ -303,13 +304,6 @@ func (picker *datePickerData) htmlProperties(self View, buffer *strings.Builder)
}
}
func (picker *datePickerData) htmlDisabledProperties(self View, buffer *strings.Builder) {
if IsDisabled(self) {
buffer.WriteString(` disabled`)
}
picker.viewData.htmlDisabledProperties(self, buffer)
}
func (picker *datePickerData) handleCommand(self View, command string, data DataObject) bool {
switch command {
case "textChanged":

View File

@ -39,6 +39,7 @@ func newDropDownList(session Session) View {
func (list *dropDownListData) init(session Session) {
list.viewData.init(session)
list.tag = "DropDownList"
list.hasHtmlDisabled = true
list.items = []string{}
list.disabledItems = []any{}
list.dropDownListener = []func(DropDownList, int, int){}
@ -370,13 +371,6 @@ func (list *dropDownListData) htmlProperties(self View, buffer *strings.Builder)
buffer.WriteString(` size="1" onchange="dropDownListEvent(this, event)"`)
}
func (list *dropDownListData) htmlDisabledProperties(self View, buffer *strings.Builder) {
list.viewData.htmlDisabledProperties(self, buffer)
if IsDisabled(list) {
buffer.WriteString(`disabled`)
}
}
func (list *dropDownListData) onSelectedItemChanged(number, old int) {
for _, listener := range list.dropDownListener {
listener(list, number, old)

View File

@ -58,6 +58,7 @@ func newEditView(session Session) View {
func (edit *editViewData) init(session Session) {
edit.viewData.init(session)
edit.hasHtmlDisabled = true
edit.textChangeListeners = []func(EditView, string, string){}
edit.tag = "EditView"
}
@ -466,13 +467,6 @@ func (edit *editViewData) htmlProperties(self View, buffer *strings.Builder) {
}
}
func (edit *editViewData) htmlDisabledProperties(self View, buffer *strings.Builder) {
if IsDisabled(self) {
buffer.WriteString(` disabled`)
}
edit.viewData.htmlDisabledProperties(self, buffer)
}
func (edit *editViewData) htmlSubviews(self View, buffer *strings.Builder) {
if GetEditViewType(edit) == MultiLineText {
buffer.WriteString(GetText(edit))

View File

@ -83,6 +83,7 @@ func newFilePicker(session Session) View {
func (picker *filePickerData) init(session Session) {
picker.viewData.init(session)
picker.tag = "FilePicker"
picker.hasHtmlDisabled = true
picker.files = []FileInfo{}
picker.loader = map[int]func(FileInfo, []byte){}
picker.fileSelectedListeners = []func(FilePicker, []FileInfo){}
@ -260,13 +261,6 @@ func (picker *filePickerData) htmlProperties(self View, buffer *strings.Builder)
}
}
func (picker *filePickerData) htmlDisabledProperties(self View, buffer *strings.Builder) {
if IsDisabled(self) {
buffer.WriteString(` disabled`)
}
picker.viewData.htmlDisabledProperties(self, buffer)
}
func (picker *filePickerData) handleCommand(self View, command string, data DataObject) bool {
switch command {
case "fileSelected":

View File

@ -2,8 +2,13 @@ package rui
// ListAdapter - the list data source
type ListAdapter interface {
// ListSize returns the number of elements in the list
ListSize() int
// ListItem creates a View of a list item at the given index
ListItem(index int, session Session) View
// IsListItemEnabled returns the status (enabled/disabled) of a list item at the given index
IsListItemEnabled(index int) bool
}

View File

@ -7,16 +7,22 @@ import (
const (
// TopDownOrientation - subviews are arranged from top to bottom. Synonym of VerticalOrientation
TopDownOrientation = 0
// StartToEndOrientation - subviews are arranged from left to right. Synonym of HorizontalOrientation
StartToEndOrientation = 1
// BottomUpOrientation - subviews are arranged from bottom to top
BottomUpOrientation = 2
// EndToStartOrientation - subviews are arranged from right to left
EndToStartOrientation = 3
// ListWrapOff - subviews are scrolled and "true" if a new row/column starts
ListWrapOff = 0
// ListWrapOn - the new row/column starts at bottom/right
ListWrapOn = 1
// ListWrapReverse - the new row/column starts at top/left
ListWrapReverse = 2
)

View File

@ -11,20 +11,25 @@ const (
// The "list-item-clicked" event occurs when the user clicks on an item in the list.
// The main listener format: func(ListView, int), where the second argument is the item index.
ListItemClickedEvent = "list-item-clicked"
// ListItemSelectedEvent is the constant for "list-item-selected" property tag.
// The "list-item-selected" event occurs when a list item becomes selected.
// The main listener format: func(ListView, int), where the second argument is the item index.
ListItemSelectedEvent = "list-item-selected"
// ListItemCheckedEvent is the constant for "list-item-checked" property tag.
// The "list-item-checked" event occurs when a list item checkbox becomes checked/unchecked.
// The main listener format: func(ListView, []int), where the second argument is the array of checked item indexes.
ListItemCheckedEvent = "list-item-checked"
// ListItemStyle is the constant for "list-item-style" property tag.
// The "list-item-style" string property defines the style of an unselected item
ListItemStyle = "list-item-style"
// CurrentStyle is the constant for "current-style" property tag.
// The "current-style" string property defines the style of the selected item when the ListView is focused.
CurrentStyle = "current-style"
// CurrentInactiveStyle is the constant for "current-inactive-style" property tag.
// The "current-inactive-style" string property defines the style of the selected item when the ListView is unfocused.
CurrentInactiveStyle = "current-inactive-style"

View File

@ -13,15 +13,18 @@ const (
// to control audio/video playback, including volume, seeking, and pause/resume playback.
// Its default value is false.
Controls = "controls"
// Loop is the constant for the "loop" property tag.
// If the "loop" bool property is "true", the audio/video player will automatically seek back
// to the start upon reaching the end of the audio/video.
// Its default value is false.
Loop = "loop"
// Muted is the constant for the "muted" property tag.
// The "muted" bool property indicates whether the audio/video will be initially silenced.
// Its default value is false.
Muted = "muted"
// Preload is the constant for the "preload" property tag.
// The "preload" int property is intended to provide a hint to the browser about what
// the author thinks will lead to the best user experience. It may have one of the following values:
@ -32,72 +35,94 @@ const (
// AbortEvent is the constant for the "abort-event" property tag.
// The "abort-event" event fired when the resource was not fully loaded, but not as the result of an error.
AbortEvent = "abort-event"
// CanPlayEvent is the constant for the "can-play-event" property tag.
// The "can-play-event" event occurs when the browser can play the media, but estimates that not enough data has been
// loaded to play the media up to its end without having to stop for further buffering of content.
CanPlayEvent = "can-play-event"
// CanPlayThroughEvent is the constant for the "can-play-through-event" property tag.
// The "can-play-through-event" event occurs when the browser estimates it can play the media up
// to its end without stopping for content buffering.
CanPlayThroughEvent = "can-play-through-event"
// CompleteEvent is the constant for the "complete-event" property tag.
// The "complete-event" event occurs when the rendering of an OfflineAudioContext is terminated.
CompleteEvent = "complete-event"
// DurationChangedEvent is the constant for the "duration-changed-event" property tag.
// The "duration-changed-event" event occurs when the duration attribute has been updated.
DurationChangedEvent = "duration-changed-event"
// EmptiedEvent is the constant for the "emptied-event" property tag.
// The "emptied-event" event occurs when the media has become empty; for example, this event is sent if the media has already been loaded
// (or partially loaded), and the HTMLMediaElement.load method is called to reload it.
EmptiedEvent = "emptied-event"
// EndedEvent is the constant for the "ended-event" property tag.
// The "ended-event" event occurs when the playback has stopped because the end of the media was reached.
EndedEvent = "ended-event"
// LoadedDataEvent is the constant for the "loaded-data-event" property tag.
// The "loaded-data-event" event occurs when the first frame of the media has finished loading.
LoadedDataEvent = "loaded-data-event"
// LoadedMetadataEvent is the constant for the "loaded-metadata-event" property tag.
// The "loaded-metadata-event" event occurs when the metadata has been loaded.
LoadedMetadataEvent = "loaded-metadata-event"
// LoadStartEvent is the constant for the "load-start-event" property tag.
// The "load-start-event" event is fired when the browser has started to load a resource.
LoadStartEvent = "load-start-event"
// PauseEvent is the constant for the "pause-event" property tag.
// The "pause-event" event occurs when the playback has been paused.
PauseEvent = "pause-event"
// PlayEvent is the constant for the "play-event" property tag.
// The "play-event" event occurs when the playback has begun.
PlayEvent = "play-event"
// PlayingEvent is the constant for the "playing-event" property tag.
// The "playing-event" event occurs when the playback is ready to start after having been paused or delayed due to lack of data.
PlayingEvent = "playing-event"
// ProgressEvent is the constant for the "progress-event" property tag.
// The "progress-event" event is fired periodically as the browser loads a resource.
ProgressEvent = "progress-event"
// RateChangeEvent is the constant for the "rate-change-event" property tag.
// The "rate-change-event" event occurs when the playback rate has changed.
RateChangedEvent = "rate-changed-event"
// SeekedEvent is the constant for the "seeked-event" property tag.
// The "seeked-event" event occurs when a seek operation completed.
SeekedEvent = "seeked-event"
// SeekingEvent is the constant for the "seeking-event" property tag.
// The "seeking-event" event occurs when a seek operation began.
SeekingEvent = "seeking-event"
// StalledEvent is the constant for the "stalled-event" property tag.
// The "stalled-event" event occurs when the user agent is trying to fetch media data, but data is unexpectedly not forthcoming.
StalledEvent = "stalled-event"
// SuspendEvent is the constant for the "suspend-event" property tag.
// The "suspend-event" event occurs when the media data loading has been suspended.
SuspendEvent = "suspend-event"
// TimeUpdateEvent is the constant for the "time-update-event" property tag.
// The "time-update-event" event occurs when the time indicated by the currentTime attribute has been updated.
TimeUpdateEvent = "time-update-event"
// VolumeChangedEvent is the constant for the "volume-change-event" property tag.
// The "volume-change-event" event occurs when the volume has changed.
VolumeChangedEvent = "volume-changed-event"
// WaitingEvent is the constant for the "waiting-event" property tag.
// The "waiting-event" event occurs when the playback has stopped because of a temporary lack of data
WaitingEvent = "waiting-event"
// PlayerErrorEvent is the constant for the "player-error-event" property tag.
// The "player-error-event" event is fired when the resource could not be loaded due to an error
// (for example, a network connectivity problem).
@ -105,51 +130,68 @@ const (
// PreloadNone - value of the view "preload" property: indicates that the audio/video should not be preloaded.
PreloadNone = 0
// PreloadMetadata - value of the view "preload" property: indicates that only audio/video metadata (e.g. length) is fetched.
PreloadMetadata = 1
// PreloadAuto - value of the view "preload" property: indicates that the whole audio file can be downloaded,
// even if the user is not expected to use it.
PreloadAuto = 2
// PlayerErrorUnknown - MediaPlayer error code: An unknown error.
PlayerErrorUnknown = 0
// PlayerErrorAborted - MediaPlayer error code: The fetching of the associated resource was aborted by the user's request.
PlayerErrorAborted = 1
// PlayerErrorNetwork - MediaPlayer error code: Some kind of network error occurred which prevented the media
// from being successfully fetched, despite having previously been available.
PlayerErrorNetwork = 2
// PlayerErrorDecode - MediaPlayer error code: Despite having previously been determined to be usable,
// an error occurred while trying to decode the media resource, resulting in an error.
PlayerErrorDecode = 3
// PlayerErrorSourceNotSupported - MediaPlayer error code: The associated resource or media provider object has been found to be unsuitable.
PlayerErrorSourceNotSupported = 4
)
type MediaPlayer interface {
View
// Play attempts to begin playback of the media.
Play()
// Pause will pause playback of the media, if the media is already in a paused state this method will have no effect.
Pause()
// SetCurrentTime sets the current playback time in seconds.
SetCurrentTime(seconds float64)
// CurrentTime returns the current playback time in seconds.
CurrentTime() float64
// Duration returns the value indicating the total duration of the media in seconds.
// If no media data is available, the returned value is NaN.
Duration() float64
// SetPlaybackRate sets the rate at which the media is being played back. This is used to implement user controls
// for fast forward, slow motion, and so forth. The normal playback rate is multiplied by this value to obtain
// the current rate, so a value of 1.0 indicates normal speed.
SetPlaybackRate(rate float64)
// PlaybackRate returns the rate at which the media is being played back.
PlaybackRate() float64
// SetVolume sets the audio volume, from 0.0 (silent) to 1.0 (loudest).
SetVolume(volume float64)
// Volume returns the audio volume, from 0.0 (silent) to 1.0 (loudest).
Volume() float64
// IsEnded function tells whether the media element is ended.
IsEnded() bool
// IsPaused function tells whether the media element is paused.
IsPaused() bool
}

View File

@ -82,24 +82,32 @@ const (
// PrimaryMouseButton is a number of the main pressed button, usually the left button or the un-initialized state
PrimaryMouseButton = 0
// AuxiliaryMouseButton is a number of the auxiliary pressed button, usually the wheel button
// or the middle button (if present)
AuxiliaryMouseButton = 1
// SecondaryMouseButton is a number of the secondary pressed button, usually the right button
SecondaryMouseButton = 2
// MouseButton4 is a number of the fourth button, typically the Browser Back button
MouseButton4 = 3
// MouseButton5 is a number of the fifth button, typically the Browser Forward button
MouseButton5 = 4
// PrimaryMouseMask is the mask of the primary button (usually the left button)
PrimaryMouseMask = 1
// SecondaryMouseMask is the mask of the secondary button (usually the right button)
SecondaryMouseMask = 2
// AuxiliaryMouseMask is the mask of the auxiliary button (usually the mouse wheel button or middle button)
AuxiliaryMouseMask = 4
// MouseMask4 is the mask of the 4th button (typically the "Browser Back" button)
MouseMask4 = 8
//MouseMask5 is the mask of the 5th button (typically the "Browser Forward" button)
MouseMask5 = 16
)

View File

@ -7,17 +7,37 @@ import (
)
const (
// NumberChangedEvent is the constant for the "" property tag.
// The "number-changed" property sets listener(s) that track the change in the entered value.
NumberChangedEvent = "number-changed"
NumberPickerType = "number-picker-type"
NumberPickerMin = "number-picker-min"
NumberPickerMax = "number-picker-max"
NumberPickerStep = "number-picker-step"
NumberPickerValue = "number-picker-value"
// NumberPickerType is the constant for the "number-picker-type" property tag.
// The "number-picker-type" int property sets the mode of NumberPicker. It can take the following values:
// * NumberEditor (0) - NumberPicker is presented by editor. Default value;
// * NumberSlider (1) - NumberPicker is presented by slider. |
NumberPickerType = "number-picker-type"
// NumberPickerMin is the constant for the "number-picker-min" property tag.
// The "number-picker-min" int property sets the minimum value of NumberPicker. The default value is 0.
NumberPickerMin = "number-picker-min"
// NumberPickerMax is the constant for the "number-picker-max" property tag.
// The "number-picker-max" int property sets the maximum value of NumberPicker. The default value is 1.
NumberPickerMax = "number-picker-max"
// NumberPickerStep is the constant for the "number-picker-step" property tag.
// The "number-picker-step" int property sets the value change step of NumberPicker
NumberPickerStep = "number-picker-step"
// NumberPickerValue is the constant for the "number-picker-value" property tag.
// The "number-picker-value" int property sets the current value of NumberPicker. The default value is 0.
NumberPickerValue = "number-picker-value"
)
const (
// NumberEditor - type of NumberPicker. NumberPicker is presented by editor
NumberEditor = 0
// NumberSlider - type of NumberPicker. NumberPicker is presented by slider
NumberSlider = 1
)
@ -47,6 +67,7 @@ func newNumberPicker(session Session) View {
func (picker *numberPickerData) init(session Session) {
picker.viewData.init(session)
picker.tag = "NumberPicker"
picker.hasHtmlDisabled = true
picker.numberChangedListeners = []func(NumberPicker, float64, float64){}
}
@ -232,13 +253,6 @@ func (picker *numberPickerData) htmlProperties(self View, buffer *strings.Builde
buffer.WriteString(` oninput="editViewInputEvent(this)"`)
}
func (picker *numberPickerData) htmlDisabledProperties(self View, buffer *strings.Builder) {
if IsDisabled(self) {
buffer.WriteString(` disabled`)
}
picker.viewData.htmlDisabledProperties(self, buffer)
}
func (picker *numberPickerData) handleCommand(self View, command string, data DataObject) bool {
switch command {
case "textChanged":

View File

@ -11,15 +11,19 @@ type Properties interface {
// The type of return value depends on the property. If the property is not set then nil is returned.
Get(tag string) any
getRaw(tag string) any
// Set sets the value (second argument) of the property with name defined by the first argument.
// Return "true" if the value has been set, in the opposite case "false" are returned and
// a description of the error is written to the log
Set(tag string, value any) bool
setRaw(tag string, value any)
// Remove removes the property with name defined by the argument
Remove(tag string)
// Clear removes all properties
Clear()
// AllTags returns an array of the set properties
AllTags() []string
}

View File

@ -22,10 +22,33 @@ const (
// StackLayout - list-container of View
type StackLayout interface {
ViewsContainer
// Peek returns the current (visible) View. If StackLayout is empty then it returns nil.
Peek() View
// RemovePeek removes the current View and returns it. If StackLayout is empty then it doesn't do anything and returns nil.
RemovePeek() View
// MoveToFront makes the given View current. Returns true if successful, false otherwise.
MoveToFront(view View) bool
// MoveToFrontByID makes the View current by viewID. Returns true if successful, false otherwise.
MoveToFrontByID(viewID string) bool
// Push adds a new View to the container and makes it current.
// It is similar to Append, but the addition is done using an animation effect.
// The animation type is specified by the second argument and can take the following values:
// * DefaultAnimation (0) - Default animation. For the Push function it is EndToStartAnimation, for Pop - StartToEndAnimation;
// * StartToEndAnimation (1) - Animation from beginning to end. The beginning and the end are determined by the direction of the text output;
// * EndToStartAnimation (2) - End-to-Beginning animation;
// * TopDownAnimation (3) - Top-down animation;
// * BottomUpAnimation (4) - Bottom up animation.
// The third argument `onPushFinished` is the function to be called when the animation ends. It may be nil.
Push(view View, animation int, onPushFinished func())
// Pop removes the current View from the container using animation.
// The second argument `onPopFinished`` is the function to be called when the animation ends. It may be nil.
// The function will return false if the StackLayout is empty and true if the current item has been removed.
Pop(animation int, onPopFinished func(View)) bool
}
@ -277,6 +300,10 @@ func (layout *stackLayoutData) RemoveView(index int) View {
return layout.viewsContainerData.RemoveView(index)
}
func (layout *stackLayoutData) RemovePeek() View {
return layout.RemoveView(len(layout.views) - 1)
}
func (layout *stackLayoutData) Push(view View, animation int, onPushFinished func()) {
if view == nil {
ErrorLog("StackLayout.Push(nil, ....) is forbidden")

View File

@ -40,6 +40,7 @@ func newTimePicker(session Session) View {
func (picker *timePickerData) init(session Session) {
picker.viewData.init(session)
picker.tag = "TimePicker"
picker.hasHtmlDisabled = true
picker.timeChangedListeners = []func(TimePicker, time.Time, time.Time){}
}
@ -291,13 +292,6 @@ func (picker *timePickerData) htmlProperties(self View, buffer *strings.Builder)
}
}
func (picker *timePickerData) htmlDisabledProperties(self View, buffer *strings.Builder) {
if IsDisabled(self) {
buffer.WriteString(` disabled`)
}
picker.viewData.htmlDisabledProperties(self, buffer)
}
func (picker *timePickerData) handleCommand(self View, command string, data DataObject) bool {
switch command {
case "textChanged":

View File

@ -8,9 +8,11 @@ const (
// VideoWidth is the constant for the "video-width" property tag of VideoPlayer.
// The "video-width" float property defines the width of the video's display area in pixels.
VideoWidth = "video-width"
// VideoHeight is the constant for the "video-height" property tag of VideoPlayer.
// The "video-height" float property defines the height of the video's display area in pixels.
VideoHeight = "video-height"
// Poster is the constant for the "poster" property tag of VideoPlayer.
// The "poster" property defines an URL for an image to be shown while the video is downloading.
// If this attribute isn't specified, nothing is displayed until the first frame is available,

69
view.go
View File

@ -35,24 +35,33 @@ type View interface {
// Session returns the current Session interface
Session() Session
// Parent returns the parent view
Parent() View
// Tag returns the tag of View interface
Tag() string
// ID returns the id of the view
ID() string
// Focusable returns true if the view receives the focus
Focusable() bool
// Frame returns the location and size of the view in pixels
Frame() Frame
// Scroll returns the location size of the scrollable view in pixels
Scroll() Frame
// SetAnimated sets the value (second argument) of the property with name defined by the first argument.
// Return "true" if the value has been set, in the opposite case "false" are returned and
// a description of the error is written to the log
SetAnimated(tag string, value any, animation Animation) bool
// SetChangeListener set the function to track the change of the View property
SetChangeListener(tag string, listener func(View, string))
// HasFocus returns 'true' if the view has focus
HasFocus() bool
@ -65,7 +74,6 @@ type View interface {
setParentID(parentID string)
htmlSubviews(self View, buffer *strings.Builder)
htmlProperties(self View, buffer *strings.Builder)
htmlDisabledProperties(self View, buffer *strings.Builder)
cssStyle(self View, builder cssBuilder)
addToCSSStyle(addCSS map[string]string)
@ -93,6 +101,7 @@ type viewData struct {
noResizeEvent bool
created bool
hasFocus bool
hasHtmlDisabled bool
//animation map[string]AnimationEndListener
}
@ -135,6 +144,7 @@ func (view *viewData) init(session Session) {
view.singleTransition = map[string]Animation{}
view.noResizeEvent = false
view.created = false
view.hasHtmlDisabled = false
}
func (view *viewData) Session() Session {
@ -302,7 +312,6 @@ func (view *viewData) propertyChangedEvent(tag string) {
if listener, ok := view.changeListener[tag]; ok {
listener(view, tag)
}
}
func (view *viewData) Set(tag string, value any) bool {
@ -404,7 +413,35 @@ func viewPropertyChanged(view *viewData, tag string) {
switch tag {
case Disabled:
updateInnerHTML(view.parentHTMLID(), session)
tabIndex := GetTabIndex(view, htmlID)
enabledClass := view.htmlClass(false)
disabledClass := view.htmlClass(true)
session.startUpdateScript(htmlID)
if IsDisabled(view) {
session.updateProperty(htmlID, "data-disabled", "1")
if view.hasHtmlDisabled {
session.updateProperty(htmlID, "disabled", true)
}
if tabIndex >= 0 {
session.updateProperty(htmlID, "tabindex", -1)
}
if enabledClass != disabledClass {
session.updateProperty(htmlID, "class", disabledClass)
}
} else {
session.updateProperty(htmlID, "data-disabled", "0")
if view.hasHtmlDisabled {
session.removeProperty(htmlID, "disabled")
}
if tabIndex >= 0 {
session.updateProperty(htmlID, "tabindex", tabIndex)
}
if enabledClass != disabledClass {
session.updateProperty(htmlID, "class", enabledClass)
}
}
session.finishUpdateScript(htmlID)
updateInnerHTML(htmlID, session)
return
case Visibility:
@ -759,20 +796,22 @@ func (view *viewData) cssStyle(self View, builder cssBuilder) {
func (view *viewData) htmlProperties(self View, buffer *strings.Builder) {
view.created = true
if IsDisabled(self) {
buffer.WriteString(` data-disabled="1"`)
if view.hasHtmlDisabled {
buffer.WriteString(` disabled`)
}
} else {
buffer.WriteString(` data-disabled="0"`)
}
if view.frame.Left != 0 || view.frame.Top != 0 || view.frame.Width != 0 || view.frame.Height != 0 {
buffer.WriteString(fmt.Sprintf(` data-left="%g" data-top="%g" data-width="%g" data-height="%g"`,
view.frame.Left, view.frame.Top, view.frame.Width, view.frame.Height))
}
}
func (view *viewData) htmlDisabledProperties(self View, buffer *strings.Builder) {
if IsDisabled(self) {
buffer.WriteString(` data-disabled="1"`)
} else {
buffer.WriteString(` data-disabled="0"`)
}
}
func viewHTML(view View, buffer *strings.Builder) {
viewHTMLTag := view.htmlTag()
buffer.WriteRune('<')
@ -800,8 +839,6 @@ func viewHTML(view View, buffer *strings.Builder) {
buffer.WriteRune(' ')
view.htmlProperties(view, buffer)
buffer.WriteRune(' ')
view.htmlDisabledProperties(view, buffer)
if view.isNoResizeEvent() {
buffer.WriteString(` data-noresize="1" `)
@ -810,12 +847,10 @@ func viewHTML(view View, buffer *strings.Builder) {
}
if !disabled {
if value, ok := intProperty(view, TabIndex, view.Session(), -1); ok {
if tabIndex := GetTabIndex(view); tabIndex >= 0 {
buffer.WriteString(`tabindex="`)
buffer.WriteString(strconv.Itoa(value))
buffer.WriteString(strconv.Itoa(tabIndex))
buffer.WriteString(`" `)
} else if view.Focusable() {
buffer.WriteString(`tabindex="0" `)
}
}

View File

@ -13,8 +13,10 @@ type ViewStyle interface {
// Transition returns the transition animation of the property. Returns nil is there is no transition animation.
Transition(tag string) Animation
// Transitions returns the map of transition animations. The result is always non-nil.
Transitions() map[string]Animation
// SetTransition sets the transition animation for the property if "animation" argument is not nil, and
// removes the transition animation of the property if "animation" argument is nil.
// The "tag" argument is the property name.

View File

@ -11,12 +11,16 @@ type ParentView interface {
type ViewsContainer interface {
View
ParentView
// Append appends a view to the end of the list of a view children
Append(view View)
// Insert inserts a view to the "index" position in the list of a view children
Insert(view View, index int)
// Remove removes a view from the list of a view children and return it
RemoveView(index int) View
// ViewIndex returns the index of view, -1 overwise
ViewIndex(view View) int
}