-
Notifications
You must be signed in to change notification settings - Fork 0
/
element.go
123 lines (107 loc) · 4.18 KB
/
element.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package relative
import (
"encoding/xml"
"errors"
"github.com/bhollier/ui/pkg/ui/element"
"net/http"
)
// Wrapper type that stores an
// element.Element and its relative fields
type relativeElement struct {
// The parent layout
parent *Layout
// The filesystem to use
fs http.FileSystem
// The attribute for specifying which
// element this element goes on top of
TopOf relativePosition `uixml:"http://github.com/bhollier/ui/api/schema top-of,optional"`
// The attribute for specifying which
// element this element goes on the
// bottom of
BottomOf relativePosition `uixml:"http://github.com/bhollier/ui/api/schema bottom-of,optional"`
// The attribute for specifying which
// element this element goes to the
// left of
LeftOf relativePosition `uixml:"http://github.com/bhollier/ui/api/schema left-of,optional"`
// The attribute for specifying which
// element this element goes to the
// right of
RightOf relativePosition `uixml:"http://github.com/bhollier/ui/api/schema right-of,optional"`
// The element itself (the "hidden" tag
// means element.SetAttrs won't touch it)
element.Element `uixml:"hidden"`
}
// Function to create a relative element
func newRelativeElement(fs http.FileSystem, parent *Layout) relativeElement {
return relativeElement{parent: parent, fs: fs}
}
// Function to unmarshal an XML element into
// a relative element. This function is
// only called by xml.Unmarshal
func (e *relativeElement) UnmarshalXML(d *xml.Decoder, start xml.StartElement) (err error) {
// Create an element of the type
e.Element = element.New(e.fs, start.Name, e.parent)
// If the element wasn't created
if e.Element == nil {
return errors.New("unknown element type '" +
element.XMLNameToString(start.Name) + "'")
}
// Create an array of the relative
// attributes
relativeAttrs := make([]xml.Attr, 0)
// The names of the relative attributes
topOfName := xml.Name{Space: "http://github.com/bhollier/ui/api/schema", Local: "top-of"}
bottomOfName := xml.Name{Space: "http://github.com/bhollier/ui/api/schema", Local: "bottom-of"}
leftOfName := xml.Name{Space: "http://github.com/bhollier/ui/api/schema", Local: "left-of"}
rightOfName := xml.Name{Space: "http://github.com/bhollier/ui/api/schema", Local: "right-of"}
// Iterate over the attributes
for _, attr := range start.Attr {
// If the attribute isn't a relative attribute
if element.XMLNameMatch(attr.Name, topOfName) ||
element.XMLNameMatch(attr.Name, bottomOfName) ||
element.XMLNameMatch(attr.Name, leftOfName) ||
element.XMLNameMatch(attr.Name, rightOfName) {
// Add it to the attributes array
relativeAttrs = append(relativeAttrs, attr)
}
}
// Set the relative attributes
err = element.SetAttrs(e, relativeAttrs)
if err != nil {
return err
}
// If both top and bottom are set
/*if e.TopOf != zeroRelativePosition && e.BottomOf != zeroRelativePosition {
return errors.New("both 'top-of' and 'bottom-of' attributes set on XML element '" +
element.FullName(e, ".", false) + "'")
}
// If both left and right are set
if e.LeftOf != zeroRelativePosition && e.RightOf != zeroRelativePosition {
return errors.New("both 'left-of' and 'right-of' attributes set on XML element '" +
element.FullName(e, ".", false) + "'")
}*/
// If none of the attributes are set
if e.TopOf == zeroRelativePosition && e.BottomOf == zeroRelativePosition &&
e.LeftOf == zeroRelativePosition && e.RightOf == zeroRelativePosition {
return errors.New("XML element '" + element.FullName(e, ".", false) +
"' has no position attribute, must have at least 'top-of', 'bottom-of', 'left-of' or 'right-of'")
}
// Create an array of the element's
// attributes
elementAttrs := make([]xml.Attr, 0)
// Iterate over the attributes
for _, attr := range start.Attr {
// If the attribute isn't a relative attribute
if !element.XMLNameMatch(attr.Name, topOfName) &&
!element.XMLNameMatch(attr.Name, bottomOfName) &&
!element.XMLNameMatch(attr.Name, leftOfName) &&
!element.XMLNameMatch(attr.Name, rightOfName) {
// Add it to the attributes array
elementAttrs = append(elementAttrs, attr)
}
}
// Replace the attributes
start.Attr = elementAttrs
// Unmarshal the element itself
return e.Element.UnmarshalXML(d, start)
}