mirror of https://github.com/anoshenko/rui.git
Added FilePicker
This commit is contained in:
parent
f64f6d2bca
commit
04bbd47f66
11
appLog.go
11
appLog.go
|
@ -45,8 +45,11 @@ func DebugLogF(format string, a ...interface{}) {
|
|||
}
|
||||
}
|
||||
|
||||
var lastError = ""
|
||||
|
||||
// ErrorLog print the text to the error log
|
||||
func ErrorLog(text string) {
|
||||
lastError = text
|
||||
if errorLogFunc != nil {
|
||||
errorLogFunc(text)
|
||||
errorStack()
|
||||
|
@ -55,12 +58,18 @@ func ErrorLog(text string) {
|
|||
|
||||
// ErrorLogF print the text to the error log
|
||||
func ErrorLogF(format string, a ...interface{}) {
|
||||
lastError = fmt.Sprintf(format, a...)
|
||||
if errorLogFunc != nil {
|
||||
errorLogFunc(fmt.Sprintf(format, a...))
|
||||
errorLogFunc(lastError)
|
||||
errorStack()
|
||||
}
|
||||
}
|
||||
|
||||
// LastError returns the last error text
|
||||
func LastError() string {
|
||||
return lastError
|
||||
}
|
||||
|
||||
func errorStack() {
|
||||
if errorLogFunc != nil {
|
||||
skip := 2
|
||||
|
|
|
@ -989,6 +989,50 @@ function setInputValue(elementId, text) {
|
|||
}
|
||||
}
|
||||
|
||||
function fileSelectedEvent(element) {
|
||||
var files = element.files;
|
||||
if (files) {
|
||||
var message = "fileSelected{session=" + sessionID + ",id=" + element.id + ",files=[";
|
||||
for(var i = 0; i < files.length; i++) {
|
||||
if (i > 0) {
|
||||
message += ",";
|
||||
}
|
||||
message += "_{name=\"" + files[i].name +
|
||||
"\",last-modified=" + files[i].lastModified +
|
||||
",size=" + files[i].size +
|
||||
",mime-type=\"" + files[i].type + "\"}";
|
||||
}
|
||||
sendMessage(message + "]}");
|
||||
}
|
||||
}
|
||||
|
||||
function loadSelectedFile(elementId, index) {
|
||||
var element = document.getElementById(elementId);
|
||||
if (element) {
|
||||
var files = element.files;
|
||||
if (files && index >= 0 && index < files.length) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = function() {
|
||||
sendMessage("fileLoaded{session=" + sessionID + ",id=" + element.id +
|
||||
",index=" + index +
|
||||
",name=\"" + files[index].name +
|
||||
"\",last-modified=" + files[index].lastModified +
|
||||
",size=" + files[index].size +
|
||||
",mime-type=\"" + files[index].type +
|
||||
"\",data=`" + reader.result + "`}");
|
||||
}
|
||||
reader.onerror = function(error) {
|
||||
sendMessage("fileLoadingError{session=" + sessionID + ",id=" + element.id + ",index=" + index + ",error=`" + error + "`}");
|
||||
}
|
||||
reader.readAsDataURL(files[index]);
|
||||
} else {
|
||||
sendMessage("fileLoadingError{session=" + sessionID + ",id=" + element.id + ",index=" + index + ",error=`File not found`}");
|
||||
}
|
||||
} else {
|
||||
sendMessage("fileLoadingError{session=" + sessionID + ",id=" + element.id + ",index=" + index + ",error=`Invalid FilePicker id`}");
|
||||
}
|
||||
}
|
||||
|
||||
function startResize(element, mx, my, event) {
|
||||
var view = element.parentNode;
|
||||
if (!view) {
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/anoshenko/rui"
|
||||
)
|
||||
|
||||
const filePickerDemoText = `
|
||||
GridLayout {
|
||||
width = 100%, height = 100%, cell-height = "auto, 1fr",
|
||||
content = [
|
||||
FilePicker {
|
||||
id = filePicker, accept = "txt, html"
|
||||
},
|
||||
EditView {
|
||||
id = selectedFileData, row = 1, type = multiline, read-only = true, wrap = true,
|
||||
}
|
||||
]
|
||||
}
|
||||
`
|
||||
|
||||
func createFilePickerDemo(session rui.Session) rui.View {
|
||||
view := rui.CreateViewFromText(session, filePickerDemoText)
|
||||
if view == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
rui.Set(view, "filePicker", rui.FileSelectedEvent, func(picker rui.FilePicker, files []rui.FileInfo) {
|
||||
if len(files) > 0 {
|
||||
picker.LoadFile(files[0], func(file rui.FileInfo, data []byte) {
|
||||
if data != nil {
|
||||
rui.Set(view, "selectedFileData", rui.Text, string(data))
|
||||
} else {
|
||||
rui.Set(view, "selectedFileData", rui.Text, rui.LastError())
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
return view
|
||||
}
|
|
@ -82,6 +82,7 @@ func createDemo(session rui.Session) rui.SessionContent {
|
|||
{"ListView", createListViewDemo, nil},
|
||||
{"Checkbox", createCheckboxDemo, nil},
|
||||
{"Controls", createControlsDemo, nil},
|
||||
{"FilePicker", createFilePickerDemo, nil},
|
||||
{"TableView", createTableViewDemo, nil},
|
||||
{"EditView", createEditDemo, nil},
|
||||
{"ImageView", createImageViewDemo, nil},
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
package main
|
||||
|
||||
/*
|
||||
import (
|
||||
"github.com/anoshenko/rui"
|
||||
)
|
||||
|
||||
const splitViewDemoText = `
|
||||
SplitView {
|
||||
width = 100%, height = 100%, orientation = vertical, anchor = bottom, padding = 2px,
|
||||
view1 = GridLayout { width = 100%, height = 75%, content = ["View 1"], cell-vertical-align = center, cell-horizontal-align = center,
|
||||
border = _{ width = 1px, style = solid, color = #FF000000 }, radius = 8px,},
|
||||
view2 = GridLayout { width = 100%, height = 25%, content = ["View 2"], cell-align = center,
|
||||
border = _{ width = 1px, style = solid, color = #FF000000 }, radius = 8px,},
|
||||
}
|
||||
`
|
||||
|
||||
func createSplitViewDemo(session rui.Session) rui.View {
|
||||
view := rui.CreateViewFromText(session, splitViewDemoText)
|
||||
if view == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return view
|
||||
}
|
||||
*/
|
|
@ -0,0 +1,414 @@
|
|||
package rui
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// FileSelectedEvent is the constant for "file-selected-event" property tag.
|
||||
// The "file-selected-event" is fired when user selects file(s) in the FilePicker.
|
||||
FileSelectedEvent = "file-selected-event"
|
||||
// Accept is the constant for "accept" property tag.
|
||||
// The "accept" property of the FilePicker sets the list of allowed file extensions or MIME types.
|
||||
Accept = "accept"
|
||||
// Multiple is the constant for "multiple" property tag.
|
||||
// The "multiple" bool property of the FilePicker sets whether multiple files can be selected
|
||||
Multiple = "multiple"
|
||||
)
|
||||
|
||||
// FileInfo describes a file which selected in the FilePicker view
|
||||
type FileInfo struct {
|
||||
// Name - the file's name.
|
||||
Name string
|
||||
// LastModified specifying the date and time at which the file was last modified
|
||||
LastModified time.Time
|
||||
// Size - the size of the file in bytes.
|
||||
Size int64
|
||||
// MimeType - the file's MIME type.
|
||||
MimeType string
|
||||
}
|
||||
|
||||
// FilePicker - the control view for the files selecting
|
||||
type FilePicker interface {
|
||||
View
|
||||
// Files returns the list of selected files.
|
||||
// If there are no files selected then an empty slice is returned (the result is always not nil)
|
||||
Files() []FileInfo
|
||||
// LoadFile loads the content of the selected file. This function is asynchronous.
|
||||
// The "result" function will be called after loading the data.
|
||||
LoadFile(file FileInfo, result func(FileInfo, []byte))
|
||||
}
|
||||
|
||||
type filePickerData struct {
|
||||
viewData
|
||||
files []FileInfo
|
||||
fileSelectedListeners []func(FilePicker, []FileInfo)
|
||||
loader map[int]func(FileInfo, []byte)
|
||||
}
|
||||
|
||||
func (file *FileInfo) initBy(node DataValue) {
|
||||
if obj := node.Object(); obj != nil {
|
||||
file.Name, _ = obj.PropertyValue("name")
|
||||
file.MimeType, _ = obj.PropertyValue("mime-type")
|
||||
|
||||
if size, ok := obj.PropertyValue("size"); ok {
|
||||
if n, err := strconv.ParseInt(size, 10, 64); err == nil {
|
||||
file.Size = n
|
||||
}
|
||||
}
|
||||
|
||||
if value, ok := obj.PropertyValue("last-modified"); ok {
|
||||
if n, err := strconv.ParseInt(value, 10, 64); err == nil {
|
||||
file.LastModified = time.UnixMilli(n)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NewFilePicker create new FilePicker object and return it
|
||||
func NewFilePicker(session Session, params Params) FilePicker {
|
||||
view := new(filePickerData)
|
||||
view.Init(session)
|
||||
setInitParams(view, params)
|
||||
return view
|
||||
}
|
||||
|
||||
func newFilePicker(session Session) View {
|
||||
return NewFilePicker(session, nil)
|
||||
}
|
||||
|
||||
func (picker *filePickerData) Init(session Session) {
|
||||
picker.viewData.Init(session)
|
||||
picker.tag = "FilePicker"
|
||||
picker.files = []FileInfo{}
|
||||
picker.loader = map[int]func(FileInfo, []byte){}
|
||||
picker.fileSelectedListeners = []func(FilePicker, []FileInfo){}
|
||||
}
|
||||
|
||||
func (picker *filePickerData) Files() []FileInfo {
|
||||
return picker.files
|
||||
}
|
||||
|
||||
func (picker *filePickerData) LoadFile(file FileInfo, result func(FileInfo, []byte)) {
|
||||
if result == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for i, info := range picker.files {
|
||||
if info.Name == file.Name && info.Size == file.Size && info.LastModified == file.LastModified {
|
||||
picker.loader[i] = result
|
||||
picker.Session().runScript(fmt.Sprintf(`loadSelectedFile("%s", %d)`, picker.htmlID(), i))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (picker *filePickerData) Remove(tag string) {
|
||||
picker.remove(strings.ToLower(tag))
|
||||
}
|
||||
|
||||
func (picker *filePickerData) remove(tag string) {
|
||||
switch tag {
|
||||
case FileSelectedEvent:
|
||||
picker.fileSelectedListeners = []func(FilePicker, []FileInfo){}
|
||||
|
||||
default:
|
||||
picker.viewData.remove(tag)
|
||||
}
|
||||
}
|
||||
|
||||
func (picker *filePickerData) Set(tag string, value interface{}) bool {
|
||||
return picker.set(strings.ToLower(tag), value)
|
||||
}
|
||||
|
||||
func (picker *filePickerData) set(tag string, value interface{}) bool {
|
||||
if value == nil {
|
||||
picker.remove(tag)
|
||||
return true
|
||||
}
|
||||
|
||||
switch tag {
|
||||
case FileSelectedEvent:
|
||||
switch value := value.(type) {
|
||||
case func(FilePicker, []FileInfo):
|
||||
picker.fileSelectedListeners = []func(FilePicker, []FileInfo){value}
|
||||
|
||||
case func([]FileInfo):
|
||||
fn := func(view FilePicker, files []FileInfo) {
|
||||
value(files)
|
||||
}
|
||||
picker.fileSelectedListeners = []func(FilePicker, []FileInfo){fn}
|
||||
|
||||
case []func(FilePicker, []FileInfo):
|
||||
picker.fileSelectedListeners = value
|
||||
|
||||
case []func([]FileInfo):
|
||||
listeners := make([]func(FilePicker, []FileInfo), len(value))
|
||||
for i, val := range value {
|
||||
if val == nil {
|
||||
notCompatibleType(tag, val)
|
||||
return false
|
||||
}
|
||||
|
||||
listeners[i] = func(view FilePicker, files []FileInfo) {
|
||||
val(files)
|
||||
}
|
||||
}
|
||||
picker.fileSelectedListeners = listeners
|
||||
|
||||
case []interface{}:
|
||||
listeners := make([]func(FilePicker, []FileInfo), len(value))
|
||||
for i, val := range value {
|
||||
if val == nil {
|
||||
notCompatibleType(tag, val)
|
||||
return false
|
||||
}
|
||||
|
||||
switch val := val.(type) {
|
||||
case func(FilePicker, []FileInfo):
|
||||
listeners[i] = val
|
||||
|
||||
case func([]FileInfo):
|
||||
listeners[i] = func(view FilePicker, files []FileInfo) {
|
||||
val(files)
|
||||
}
|
||||
|
||||
default:
|
||||
notCompatibleType(tag, val)
|
||||
return false
|
||||
}
|
||||
}
|
||||
picker.fileSelectedListeners = listeners
|
||||
}
|
||||
return true
|
||||
|
||||
case Accept:
|
||||
switch value := value.(type) {
|
||||
case string:
|
||||
value = strings.Trim(value, " \t\n")
|
||||
if value == "" {
|
||||
picker.remove(Accept)
|
||||
} else {
|
||||
picker.properties[Accept] = value
|
||||
}
|
||||
|
||||
case []string:
|
||||
buffer := allocStringBuilder()
|
||||
defer freeStringBuilder(buffer)
|
||||
for _, val := range value {
|
||||
val = strings.Trim(val, " \t\n")
|
||||
if val != "" {
|
||||
if buffer.Len() > 0 {
|
||||
buffer.WriteRune(',')
|
||||
}
|
||||
buffer.WriteString(val)
|
||||
}
|
||||
}
|
||||
if buffer.Len() == 0 {
|
||||
picker.remove(Accept)
|
||||
} else {
|
||||
picker.properties[Accept] = buffer.String()
|
||||
}
|
||||
|
||||
default:
|
||||
notCompatibleType(tag, value)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
||||
default:
|
||||
return picker.viewData.set(tag, value)
|
||||
}
|
||||
}
|
||||
|
||||
func (picker *filePickerData) htmlTag() string {
|
||||
return "input"
|
||||
}
|
||||
|
||||
func (picker *filePickerData) acceptCSS() string {
|
||||
accept, ok := stringProperty(picker, Accept, picker.Session())
|
||||
if !ok {
|
||||
accept, ok = valueFromStyle(picker, Accept)
|
||||
}
|
||||
if ok {
|
||||
buffer := allocStringBuilder()
|
||||
defer freeStringBuilder(buffer)
|
||||
for _, value := range strings.Split(accept, ",") {
|
||||
if value = strings.Trim(value, " \t\n"); value != "" {
|
||||
if buffer.Len() > 0 {
|
||||
buffer.WriteString(", ")
|
||||
}
|
||||
if value[0] != '.' && !strings.Contains(value, "/") {
|
||||
buffer.WriteRune('.')
|
||||
}
|
||||
buffer.WriteString(value)
|
||||
}
|
||||
}
|
||||
return buffer.String()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (picker *filePickerData) htmlProperties(self View, buffer *strings.Builder) {
|
||||
picker.viewData.htmlProperties(self, buffer)
|
||||
|
||||
if accept := picker.acceptCSS(); accept != "" {
|
||||
buffer.WriteString(` accept="`)
|
||||
buffer.WriteString(accept)
|
||||
buffer.WriteRune('"')
|
||||
}
|
||||
|
||||
buffer.WriteString(` type="file"`)
|
||||
if multiple, ok := boolStyledProperty(picker, Multiple); ok && multiple {
|
||||
buffer.WriteString(` multiple`)
|
||||
}
|
||||
|
||||
buffer.WriteString(` oninput="fileSelectedEvent(this)"`)
|
||||
}
|
||||
|
||||
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":
|
||||
if node := data.PropertyWithTag("files"); node != nil && node.Type() == ArrayNode {
|
||||
count := node.ArraySize()
|
||||
files := make([]FileInfo, count)
|
||||
for i := 0; i < count; i++ {
|
||||
if value := node.ArrayElement(i); value != nil {
|
||||
files[i].initBy(value)
|
||||
}
|
||||
}
|
||||
picker.files = files
|
||||
|
||||
for _, listener := range picker.fileSelectedListeners {
|
||||
listener(picker, files)
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
||||
case "fileLoaded":
|
||||
if index, ok := dataIntProperty(data, "index"); ok {
|
||||
if result, ok := picker.loader[index]; ok {
|
||||
var file FileInfo
|
||||
file.initBy(data)
|
||||
|
||||
var fileData []byte = nil
|
||||
if base64Data, ok := data.PropertyValue("data"); ok {
|
||||
if index := strings.LastIndex(base64Data, ","); index >= 0 {
|
||||
base64Data = base64Data[index+1:]
|
||||
}
|
||||
decode, err := base64.StdEncoding.DecodeString(base64Data)
|
||||
if err == nil {
|
||||
fileData = decode
|
||||
} else {
|
||||
ErrorLog(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
result(file, fileData)
|
||||
delete(picker.loader, index)
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
||||
case "fileLoadingError":
|
||||
if error, ok := data.PropertyValue("error"); ok {
|
||||
ErrorLog(error)
|
||||
}
|
||||
if index, ok := dataIntProperty(data, "index"); ok {
|
||||
if result, ok := picker.loader[index]; ok {
|
||||
if index >= 0 && index < len(picker.files) {
|
||||
result(picker.files[index], nil)
|
||||
} else {
|
||||
result(FileInfo{}, nil)
|
||||
}
|
||||
delete(picker.loader, index)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
return picker.viewData.handleCommand(self, command, data)
|
||||
}
|
||||
|
||||
// GetFilePickerFiles returns the list of FilePicker selected files
|
||||
// If there are no files selected then an empty slice is returned (the result is always not nil)
|
||||
// If the second argument (subviewID) is "" then selected files of the first argument (view) is returned
|
||||
func GetFilePickerFiles(view View, subviewID string) []FileInfo {
|
||||
if picker := FilePickerByID(view, subviewID); picker != nil {
|
||||
return picker.Files()
|
||||
}
|
||||
return []FileInfo{}
|
||||
}
|
||||
|
||||
// LoadFilePickerFile loads the content of the selected file. This function is asynchronous.
|
||||
// The "result" function will be called after loading the data.
|
||||
// If the second argument (subviewID) is "" then the file from the first argument (view) is loaded
|
||||
func LoadFilePickerFile(view View, subviewID string, file FileInfo, result func(FileInfo, []byte)) {
|
||||
if picker := FilePickerByID(view, subviewID); picker != nil {
|
||||
picker.LoadFile(file, result)
|
||||
}
|
||||
}
|
||||
|
||||
// IsMultipleFilePicker returns "true" if multiple files can be selected in the FilePicker, "false" otherwise.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func IsMultipleFilePicker(view View, subviewID string) bool {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if result, ok := boolStyledProperty(view, Multiple); ok {
|
||||
return result
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetFilePickerAccept returns sets the list of allowed file extensions or MIME types.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetFilePickerAccept(view View, subviewID string) []string {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
accept, ok := stringProperty(view, Accept, view.Session())
|
||||
if !ok {
|
||||
accept, ok = valueFromStyle(view, Accept)
|
||||
}
|
||||
if ok {
|
||||
result := strings.Split(accept, ",")
|
||||
for i := 0; i < len(result); i++ {
|
||||
result[i] = strings.Trim(result[i], " \t\n")
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
return []string{}
|
||||
}
|
||||
|
||||
// GetFileSelectedListeners returns the "file-selected-event" listener list.
|
||||
// If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetFileSelectedListeners(view View, subviewID string) []func(FilePicker, []FileInfo) {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if value := view.Get(FileSelectedEvent); value != nil {
|
||||
if result, ok := value.([]func(FilePicker, []FileInfo)); ok {
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
return []func(FilePicker, []FileInfo){}
|
||||
}
|
|
@ -844,7 +844,7 @@ func (player *mediaPlayerData) handleCommand(self View, command string, data Dat
|
|||
case PlayerErrorEvent:
|
||||
if value := player.getRaw(command); value != nil {
|
||||
if listeners, ok := value.([]func(MediaPlayer, int, string)); ok {
|
||||
code := dataIntProperty(data, "code")
|
||||
code, _ := dataIntProperty(data, "code")
|
||||
message, _ := data.PropertyValue("message")
|
||||
for _, listener := range listeners {
|
||||
listener(player, code, message)
|
||||
|
|
|
@ -328,8 +328,8 @@ func getTimeStamp(data DataObject) uint64 {
|
|||
func (event *MouseEvent) init(data DataObject) {
|
||||
|
||||
event.TimeStamp = getTimeStamp(data)
|
||||
event.Button = dataIntProperty(data, "button")
|
||||
event.Buttons = dataIntProperty(data, "buttons")
|
||||
event.Button, _ = dataIntProperty(data, "button")
|
||||
event.Buttons, _ = dataIntProperty(data, "buttons")
|
||||
event.X = dataFloatProperty(data, "x")
|
||||
event.Y = dataFloatProperty(data, "y")
|
||||
event.ClientX = dataFloatProperty(data, "clientX")
|
||||
|
|
|
@ -277,7 +277,7 @@ func pointerEventsHtml(view View, buffer *strings.Builder) {
|
|||
func (event *PointerEvent) init(data DataObject) {
|
||||
event.MouseEvent.init(data)
|
||||
|
||||
event.PointerID = dataIntProperty(data, "pointerId")
|
||||
event.PointerID, _ = dataIntProperty(data, "pointerId")
|
||||
event.Width = dataFloatProperty(data, "width")
|
||||
event.Height = dataFloatProperty(data, "height")
|
||||
event.Pressure = dataFloatProperty(data, "pressure")
|
||||
|
|
|
@ -55,6 +55,7 @@ var boolProperties = []string{
|
|||
Loop,
|
||||
Muted,
|
||||
AnimationPaused,
|
||||
Multiple,
|
||||
}
|
||||
|
||||
var intProperties = []string{
|
||||
|
|
6
utils.go
6
utils.go
|
@ -52,13 +52,13 @@ func GetLocalIP() string {
|
|||
return "localhost"
|
||||
}
|
||||
|
||||
func dataIntProperty(data DataObject, tag string) int {
|
||||
func dataIntProperty(data DataObject, tag string) (int, bool) {
|
||||
if value, ok := data.PropertyValue(tag); ok {
|
||||
if n, err := strconv.Atoi(value); err == nil {
|
||||
return n
|
||||
return n, true
|
||||
}
|
||||
}
|
||||
return 0
|
||||
return 0, false
|
||||
}
|
||||
|
||||
func dataBoolProperty(data DataObject, tag string) bool {
|
||||
|
|
86
viewByID.go
86
viewByID.go
|
@ -36,7 +36,7 @@ func viewByID(rootView ParanetView, id string) View {
|
|||
}
|
||||
|
||||
// ViewsContainerByID return a ViewsContainer with id equal to the argument of the function or
|
||||
// nil if there is no such View or View is not ViewsContainer
|
||||
// nil if there is no such View or View is not ViewsContainer
|
||||
func ViewsContainerByID(rootView View, id string) ViewsContainer {
|
||||
if view := ViewByID(rootView, id); view != nil {
|
||||
if list, ok := view.(ViewsContainer); ok {
|
||||
|
@ -48,7 +48,7 @@ func ViewsContainerByID(rootView View, id string) ViewsContainer {
|
|||
}
|
||||
|
||||
// ListLayoutByID return a ListLayout with id equal to the argument of the function or
|
||||
// nil if there is no such View or View is not ListLayout
|
||||
// nil if there is no such View or View is not ListLayout
|
||||
func ListLayoutByID(rootView View, id string) ListLayout {
|
||||
if view := ViewByID(rootView, id); view != nil {
|
||||
if list, ok := view.(ListLayout); ok {
|
||||
|
@ -60,7 +60,7 @@ func ListLayoutByID(rootView View, id string) ListLayout {
|
|||
}
|
||||
|
||||
// StackLayoutByID return a StackLayout with id equal to the argument of the function or
|
||||
// nil if there is no such View or View is not StackLayout
|
||||
// nil if there is no such View or View is not StackLayout
|
||||
func StackLayoutByID(rootView View, id string) StackLayout {
|
||||
if view := ViewByID(rootView, id); view != nil {
|
||||
if list, ok := view.(StackLayout); ok {
|
||||
|
@ -72,7 +72,7 @@ func StackLayoutByID(rootView View, id string) StackLayout {
|
|||
}
|
||||
|
||||
// GridLayoutByID return a GridLayout with id equal to the argument of the function or
|
||||
// nil if there is no such View or View is not GridLayout
|
||||
// nil if there is no such View or View is not GridLayout
|
||||
func GridLayoutByID(rootView View, id string) GridLayout {
|
||||
if view := ViewByID(rootView, id); view != nil {
|
||||
if list, ok := view.(GridLayout); ok {
|
||||
|
@ -84,7 +84,7 @@ func GridLayoutByID(rootView View, id string) GridLayout {
|
|||
}
|
||||
|
||||
// ColumnLayoutByID return a ColumnLayout with id equal to the argument of the function or
|
||||
// nil if there is no such View or View is not ColumnLayout
|
||||
// nil if there is no such View or View is not ColumnLayout
|
||||
func ColumnLayoutByID(rootView View, id string) ColumnLayout {
|
||||
if view := ViewByID(rootView, id); view != nil {
|
||||
if list, ok := view.(ColumnLayout); ok {
|
||||
|
@ -96,7 +96,7 @@ func ColumnLayoutByID(rootView View, id string) ColumnLayout {
|
|||
}
|
||||
|
||||
// DetailsViewByID return a ColumnLayout with id equal to the argument of the function or
|
||||
// nil if there is no such View or View is not DetailsView
|
||||
// nil if there is no such View or View is not DetailsView
|
||||
func DetailsViewByID(rootView View, id string) DetailsView {
|
||||
if view := ViewByID(rootView, id); view != nil {
|
||||
if details, ok := view.(DetailsView); ok {
|
||||
|
@ -108,7 +108,7 @@ func DetailsViewByID(rootView View, id string) DetailsView {
|
|||
}
|
||||
|
||||
// DropDownListByID return a DropDownListView with id equal to the argument of the function or
|
||||
// nil if there is no such View or View is not DropDownListView
|
||||
// nil if there is no such View or View is not DropDownListView
|
||||
func DropDownListByID(rootView View, id string) DropDownList {
|
||||
if view := ViewByID(rootView, id); view != nil {
|
||||
if list, ok := view.(DropDownList); ok {
|
||||
|
@ -120,7 +120,7 @@ func DropDownListByID(rootView View, id string) DropDownList {
|
|||
}
|
||||
|
||||
// TabsLayoutByID return a TabsLayout with id equal to the argument of the function or
|
||||
// nil if there is no such View or View is not TabsLayout
|
||||
// nil if there is no such View or View is not TabsLayout
|
||||
func TabsLayoutByID(rootView View, id string) TabsLayout {
|
||||
if view := ViewByID(rootView, id); view != nil {
|
||||
if list, ok := view.(TabsLayout); ok {
|
||||
|
@ -132,7 +132,7 @@ func TabsLayoutByID(rootView View, id string) TabsLayout {
|
|||
}
|
||||
|
||||
// ListViewByID return a ListView with id equal to the argument of the function or
|
||||
// nil if there is no such View or View is not ListView
|
||||
// nil if there is no such View or View is not ListView
|
||||
func ListViewByID(rootView View, id string) ListView {
|
||||
if view := ViewByID(rootView, id); view != nil {
|
||||
if list, ok := view.(ListView); ok {
|
||||
|
@ -144,7 +144,7 @@ func ListViewByID(rootView View, id string) ListView {
|
|||
}
|
||||
|
||||
// TextViewByID return a TextView with id equal to the argument of the function or
|
||||
// nil if there is no such View or View is not TextView
|
||||
// nil if there is no such View or View is not TextView
|
||||
func TextViewByID(rootView View, id string) TextView {
|
||||
if view := ViewByID(rootView, id); view != nil {
|
||||
if text, ok := view.(TextView); ok {
|
||||
|
@ -156,7 +156,7 @@ func TextViewByID(rootView View, id string) TextView {
|
|||
}
|
||||
|
||||
// ButtonByID return a Button with id equal to the argument of the function or
|
||||
// nil if there is no such View or View is not Button
|
||||
// nil if there is no such View or View is not Button
|
||||
func ButtonByID(rootView View, id string) Button {
|
||||
if view := ViewByID(rootView, id); view != nil {
|
||||
if button, ok := view.(Button); ok {
|
||||
|
@ -168,7 +168,7 @@ func ButtonByID(rootView View, id string) Button {
|
|||
}
|
||||
|
||||
// CheckboxByID return a Checkbox with id equal to the argument of the function or
|
||||
// nil if there is no such View or View is not Checkbox
|
||||
// nil if there is no such View or View is not Checkbox
|
||||
func CheckboxByID(rootView View, id string) Checkbox {
|
||||
if view := ViewByID(rootView, id); view != nil {
|
||||
if checkbox, ok := view.(Checkbox); ok {
|
||||
|
@ -180,7 +180,7 @@ func CheckboxByID(rootView View, id string) Checkbox {
|
|||
}
|
||||
|
||||
// EditViewByID return a EditView with id equal to the argument of the function or
|
||||
// nil if there is no such View or View is not EditView
|
||||
// nil if there is no such View or View is not EditView
|
||||
func EditViewByID(rootView View, id string) EditView {
|
||||
if view := ViewByID(rootView, id); view != nil {
|
||||
if buttons, ok := view.(EditView); ok {
|
||||
|
@ -192,7 +192,7 @@ func EditViewByID(rootView View, id string) EditView {
|
|||
}
|
||||
|
||||
// ProgressBarByID return a ProgressBar with id equal to the argument of the function or
|
||||
// nil if there is no such View or View is not ProgressBar
|
||||
// nil if there is no such View or View is not ProgressBar
|
||||
func ProgressBarByID(rootView View, id string) ProgressBar {
|
||||
if view := ViewByID(rootView, id); view != nil {
|
||||
if buttons, ok := view.(ProgressBar); ok {
|
||||
|
@ -203,8 +203,20 @@ func ProgressBarByID(rootView View, id string) ProgressBar {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ColorPickerByID return a ColorPicker with id equal to the argument of the function or
|
||||
// nil if there is no such View or View is not ColorPicker
|
||||
func ColorPickerByID(rootView View, id string) ColorPicker {
|
||||
if view := ViewByID(rootView, id); view != nil {
|
||||
if input, ok := view.(ColorPicker); ok {
|
||||
return input
|
||||
}
|
||||
ErrorLog(`ColorPickerByID(_, "` + id + `"): The found View is not ColorPicker`)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NumberPickerByID return a NumberPicker with id equal to the argument of the function or
|
||||
// nil if there is no such View or View is not NumberPicker
|
||||
// nil if there is no such View or View is not NumberPicker
|
||||
func NumberPickerByID(rootView View, id string) NumberPicker {
|
||||
if view := ViewByID(rootView, id); view != nil {
|
||||
if input, ok := view.(NumberPicker); ok {
|
||||
|
@ -215,8 +227,44 @@ func NumberPickerByID(rootView View, id string) NumberPicker {
|
|||
return nil
|
||||
}
|
||||
|
||||
// TimePickerByID return a TimePicker with id equal to the argument of the function or
|
||||
// nil if there is no such View or View is not TimePicker
|
||||
func TimePickerByID(rootView View, id string) TimePicker {
|
||||
if view := ViewByID(rootView, id); view != nil {
|
||||
if input, ok := view.(TimePicker); ok {
|
||||
return input
|
||||
}
|
||||
ErrorLog(`TimePickerByID(_, "` + id + `"): The found View is not TimePicker`)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DatePickerByID return a DatePicker with id equal to the argument of the function or
|
||||
// nil if there is no such View or View is not DatePicker
|
||||
func DatePickerByID(rootView View, id string) DatePicker {
|
||||
if view := ViewByID(rootView, id); view != nil {
|
||||
if input, ok := view.(DatePicker); ok {
|
||||
return input
|
||||
}
|
||||
ErrorLog(`DatePickerByID(_, "` + id + `"): The found View is not DatePicker`)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FilePickerByID return a FilePicker with id equal to the argument of the function or
|
||||
// nil if there is no such View or View is not FilePicker
|
||||
func FilePickerByID(rootView View, id string) FilePicker {
|
||||
if view := ViewByID(rootView, id); view != nil {
|
||||
if input, ok := view.(FilePicker); ok {
|
||||
return input
|
||||
}
|
||||
ErrorLog(`FilePickerByID(_, "` + id + `"): The found View is not FilePicker`)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CanvasViewByID return a CanvasView with id equal to the argument of the function or
|
||||
// nil if there is no such View or View is not CanvasView
|
||||
// nil if there is no such View or View is not CanvasView
|
||||
func CanvasViewByID(rootView View, id string) CanvasView {
|
||||
if view := ViewByID(rootView, id); view != nil {
|
||||
if canvas, ok := view.(CanvasView); ok {
|
||||
|
@ -229,7 +277,7 @@ func CanvasViewByID(rootView View, id string) CanvasView {
|
|||
|
||||
/*
|
||||
// TableViewByID return a TableView with id equal to the argument of the function or
|
||||
// nil if there is no such View or View is not TableView
|
||||
// nil if there is no such View or View is not TableView
|
||||
func TableViewByID(rootView View, id string) TableView {
|
||||
if view := ViewByID(rootView, id); view != nil {
|
||||
if canvas, ok := view.(TableView); ok {
|
||||
|
@ -242,7 +290,7 @@ func TableViewByID(rootView View, id string) TableView {
|
|||
*/
|
||||
|
||||
// AudioPlayerByID return a AudioPlayer with id equal to the argument of the function or
|
||||
// nil if there is no such View or View is not AudioPlayer
|
||||
// nil if there is no such View or View is not AudioPlayer
|
||||
func AudioPlayerByID(rootView View, id string) AudioPlayer {
|
||||
if view := ViewByID(rootView, id); view != nil {
|
||||
if canvas, ok := view.(AudioPlayer); ok {
|
||||
|
@ -254,7 +302,7 @@ func AudioPlayerByID(rootView View, id string) AudioPlayer {
|
|||
}
|
||||
|
||||
// VideoPlayerByID return a VideoPlayer with id equal to the argument of the function or
|
||||
// nil if there is no such View or View is not VideoPlayer
|
||||
// nil if there is no such View or View is not VideoPlayer
|
||||
func VideoPlayerByID(rootView View, id string) VideoPlayer {
|
||||
if view := ViewByID(rootView, id); view != nil {
|
||||
if canvas, ok := view.(VideoPlayer); ok {
|
||||
|
|
|
@ -24,6 +24,7 @@ var viewCreators = map[string]func(Session) View{
|
|||
"ColorPicker": newColorPicker,
|
||||
"DatePicker": newDatePicker,
|
||||
"TimePicker": newTimePicker,
|
||||
"FilePicker": newFilePicker,
|
||||
"EditView": newEditView,
|
||||
"ListView": newListView,
|
||||
"CanvasView": newCanvasView,
|
||||
|
|
22
viewUtils.go
22
viewUtils.go
|
@ -11,8 +11,8 @@ func Get(rootView View, viewID, tag string) interface{} {
|
|||
}
|
||||
|
||||
// Set sets the property with name "tag" of the "rootView" subview with "viewID" id by value. Result:
|
||||
// true - success,
|
||||
// false - error (incompatible type or invalid format of a string value, see AppLog).
|
||||
// true - success,
|
||||
// false - error (incompatible type or invalid format of a string value, see AppLog).
|
||||
func Set(rootView View, viewID, tag string, value interface{}) bool {
|
||||
if view := ViewByID(rootView, viewID); view != nil {
|
||||
return view.Set(tag, value)
|
||||
|
@ -21,8 +21,8 @@ func Set(rootView View, viewID, tag string, value interface{}) bool {
|
|||
}
|
||||
|
||||
// SetParams sets properties with name "tag" of the "rootView" subview. Result:
|
||||
// true - all properties were set successful,
|
||||
// false - error (incompatible type or invalid format of a string value, see AppLog).
|
||||
// true - all properties were set successful,
|
||||
// false - error (incompatible type or invalid format of a string value, see AppLog).
|
||||
func SetParams(rootView View, viewID string, params Params) bool {
|
||||
view := ViewByID(rootView, viewID)
|
||||
if view == nil {
|
||||
|
@ -678,8 +678,8 @@ func GetTextTransform(view View, subviewID string) int {
|
|||
}
|
||||
|
||||
// GetWritingMode returns whether lines of text are laid out horizontally or vertically, as well as
|
||||
// the direction in which blocks progress. Valid values are HorizontalTopToBottom (0),
|
||||
// HorizontalBottomToTop (1), VerticalRightToLeft (2) and VerticalLeftToRight (3)
|
||||
// the direction in which blocks progress. Valid values are HorizontalTopToBottom (0),
|
||||
// HorizontalBottomToTop (1), VerticalRightToLeft (2) and VerticalLeftToRight (3)
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetWritingMode(view View, subviewID string) int {
|
||||
if subviewID != "" {
|
||||
|
@ -697,7 +697,7 @@ func GetWritingMode(view View, subviewID string) int {
|
|||
}
|
||||
|
||||
// GetTextDirection - returns a direction of text, table columns, and horizontal overflow.
|
||||
// Valid values are Inherit (0), LeftToRightDirection (1), and RightToLeftDirection (2).
|
||||
// Valid values are Inherit (0), LeftToRightDirection (1), and RightToLeftDirection (2).
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetTextDirection(view View, subviewID string) int {
|
||||
if subviewID != "" {
|
||||
|
@ -716,8 +716,8 @@ func GetTextDirection(view View, subviewID string) int {
|
|||
}
|
||||
|
||||
// GetVerticalTextOrientation returns a orientation of the text characters in a line. It only affects text
|
||||
// in vertical mode (when "writing-mode" is "vertical-right-to-left" or "vertical-left-to-right").
|
||||
// Valid values are MixedTextOrientation (0), UprightTextOrientation (1), and SidewaysTextOrientation (2).
|
||||
// in vertical mode (when "writing-mode" is "vertical-right-to-left" or "vertical-left-to-right").
|
||||
// Valid values are MixedTextOrientation (0), UprightTextOrientation (1), and SidewaysTextOrientation (2).
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetVerticalTextOrientation(view View, subviewID string) int {
|
||||
if subviewID != "" {
|
||||
|
@ -804,8 +804,8 @@ func GetPerspectiveOrigin(view View, subviewID string) (SizeUnit, SizeUnit) {
|
|||
|
||||
// GetBackfaceVisible returns a bool property that sets whether the back face of an element is
|
||||
// visible when turned towards the user. Values:
|
||||
// true - the back face is visible when turned towards the user (default value).
|
||||
// false - the back face is hidden, effectively making the element invisible when turned away from the user.
|
||||
// true - the back face is visible when turned towards the user (default value).
|
||||
// false - the back face is hidden, effectively making the element invisible when turned away from the user.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetBackfaceVisible(view View, subviewID string) bool {
|
||||
if subviewID != "" {
|
||||
|
|
Loading…
Reference in New Issue