-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtutorial.html
219 lines (192 loc) · 7.65 KB
/
tutorial.html
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
<html>
<head>
<title></title>
<meta content="">
<style></style>
</head>
<body>
<script src="./decjs.js"></script>
<script>
// This library makes heavy use of the new Javascript Proxy feature. Proxy allows one to create an
// object that overrides basic operations like 'get' and 'set'. This library uses those features
// to create a system for easily creating html elements in a declarative style.
//
// This library defines an ElementHolderProxy. And it's features are explained below.
// 'proxy' is a function that wraps an already existing html element into
// a new ElementHolderProxy.
let P=decjs.proxy
// Here a new ElementHolderProxy is created to hold document.body
// and stored in 'bodyproxy'
let bodyproxy=P(document.body)
// An ElementHolderProxy can create new elements attached as children to the element it holds.
// Here we added a label to document.body
// Giving a string as argument appends to the element's 'innerHTML'
bodyproxy.label("Label!<br/>")
// Since we're using Proxy to turn any use of 'get property' into a ElementHolderProxy holding an
// element of that name, we can create a new element of ANY type, even
// ones that aren't defined! This creates an 'asdf' element.
bodyproxy.asdf("blah<br/>")
// While the previous label was added it was also stored in a new ElementHolderProxy and returned,
// so that it can be chained or added to later.
// Here we explicity store our new labelproxy
let labelproxy=bodyproxy.label("This time we have a reference to the proxy holding the label<br/>");
// We can also access the underlying element with 'getNode'
// We cannot do a normal property access because we overloaded 'get property'
// ElementHolderProxy uses a special property called '__Html_ElementHolder_Instance_e__'
// That is the only property name that won't return a new proxy.
let actualLabelElemeent=decjs.getElement(labelproxy)
// Here 'create' is an empty ElementHolderProxy (with its element set to null).
// 'create' makes it easy to nest several children in the same
// element.
let c=decjs.create
bodyproxy.div(
c.label("Child1<br/>"),
c.label("Child2<br/>")
)
// You can also add children in an array.
bodyproxy.div([
c.label("Child1InArray<br/>"),
c.label("Child2InArray<br/>")
])
// It also allows you to make elements that are not yet attached to the DOM.
let mycomponent=c.div(
c.label,
c.input,
c.button
)
// You can nest to your heart's content.
bodyproxy.div(
c.label("This is great!<br/>"),
c.label, // You can also create elements without parens
c.div.div(
c.label
), // and chain them.
c.div(
c.div(
c.button("Click me!"),
mycomponent // And you can include already created 'components'
),
c.label
),
c.label("Yep, sure is!<br/>")
).label("Yep!<br/>")
// Well, sure it's maybe nice to create all that stuff but now how can you access it?
// I created a proxy called 'ElementProxies' for just this purpose.
//
// Here is a normal object that will store references to elements we've created.
let elements={}
// Here we create a new 'ElementProxies' in 's'.
// Whenever a property of 's' is assigned (for example, s.deeplyNestedButton=c.button("Click me!")),
// 's' will save the button that was created and store it in 'elements' under the property that was assigned
// It also returns an ElementHolderProxy holding that element, which is then returned by the assignment.
let s=decjs.ElementProxies(elements)
// So with deeply nested declarative javascript code,
// we can deeply nest things and still conveniently assign their references...
bodyproxy.div(
c.label("This is great!<br/>"),
c.label,
c.div.div(
c.label
),
c.div(
c.div.div.div.div.div.div.div.div.div.div.div(
s.deeplyNestedButton=c.button("This button has a reference!")
),
c.label
),
c.label("Yep, sure is!<br/>")
).label("Yep!<br/>")
// ...and access those references in the object we passed as an argument to 'ElementProxies'.
elements.deeplyNestedButton.onclick=function(){
console.log("I can reference nested elements!")
}
// New elements can be initialized by passing in an object with the desired properties
bodyproxy.input({value:"Lots of input"})
// You can also initialize it by passing in a function.
bodyproxy.button(function(b){
b.onclick=function(){
console.log("Initialized button clicked! (If you can find it)")
}
})
// You can do this in any combination with ElementHolderProxies, functions, strings, and other objects.
// For basic objects, later object properties will overwrite older ones.
bodyproxy(
c.button(
"Strings will append to the current 'innerHTML'<br/>",
{class:"clickety",id:"3242343k34jk34"},
c.label("blah blah blah"), // this is nested
"Again<br/>",
{onclick:"console.log('clickety')",class:"clack"},
function(b){
b.onclick=function(){ console.log("clackety")} // this overrides the previous 'onclick' setting.
}
)
)
// decjs.body is a ElementHolderProxy holding the body element
decjs.body(
c.div({class:'maindiv'},
s.nameInput=c.input({value:"Already there!"}),
c.label("Click this button:"),
s.doneButton=c.button("Click me")
)
)
elements.doneButton.onclick=function(){
decjs.body(c.label(elements.nameInput.value))
}
// Finally, if you want to define your own 'overrides' that add in custom widgets of your choosing,
// 'override' allows you to set a function that will build that widget in place of the default
// behavior
let d=decjs.override({
newdiv:function(){
return c.div({class:"newdiv"},"newdiv")
}
})
decjs.body.div({class:'maindiv'},
s.nameInput=c.input({value:"Input!"}),
d.newdiv.div.newdiv,
c.label("Click this button:"),
s.doneButton=c.button("Click me!")
)
// You can also add an init function for a list of element names
// (Or all elements if you use 'initAll')
// Now any button or label d2 creates will be initialized in the way we specified
let assimilate=function(){console.log("we will assimilate you")}
let d2=decjs.initList(['button','label'],
function(elem){
elem.className+=" borg"
elem.innerHTML+='borg'
elem.onclick=assimilate
}
)
// all the elements created by 'd2' are initialized as specified above
decjs.body(
c.div(
'Borg Panel: ',
d2.button,
d2.button,
d2.label,
d2.button,
d2.button
)
)
// You can combine 'override' with 'initList'
d=decjs.override({
borgPanel:function(){
let c=d2
return c.div.div.div(
'Borg Panel: ',
c.button,
c.button,
c.label,
c.button,
c.button
)
}
})
// now 'd' knows how to build a 'borgPanel'
decjs.body(
d.borgPanel
)
</script>
</body>
</html>