glimmer-dsl-web 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/README.md +339 -204
- data/VERSION +1 -1
- data/glimmer-dsl-web.gemspec +9 -6
- data/lib/glimmer/dsl/web/dsl.rb +4 -1
- data/lib/glimmer/dsl/web/element_expression.rb +1 -1
- data/lib/glimmer/dsl/web/p_expression.rb +31 -0
- data/lib/glimmer/dsl/web/property_expression.rb +23 -0
- data/lib/glimmer/web/element_proxy.rb +30 -43
- data/lib/glimmer/web/event_proxy.rb +59 -0
- data/lib/glimmer/web/listener_proxy.rb +37 -13
- data/lib/glimmer-dsl-web/samples/hello/hello_button.rb +4 -69
- data/lib/glimmer-dsl-web/samples/hello/hello_form.rb +102 -0
- data/lib/glimmer-dsl-web.rb +1 -6
- metadata +11 -8
- data/lib/glimmer/data_binding/observable_element.rb +0 -14
data/README.md
CHANGED
@@ -1,15 +1,11 @@
|
|
1
|
-
# [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for Web 0.0.
|
2
|
-
## Ruby in the Browser Web GUI Library
|
1
|
+
# [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for Web 0.0.5 (Early Alpha)
|
2
|
+
## Ruby in the Browser Web GUI Frontend Library
|
3
3
|
[](http://badge.fury.io/rb/glimmer-dsl-web)
|
4
4
|
[](https://gitter.im/AndyObtiva/glimmer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
5
5
|
|
6
|
-
|
6
|
+
[Glimmer](https://github.com/AndyObtiva/glimmer) DSL for Web enables building Web GUI frontends using [Ruby in the Browser](https://www.youtube.com/watch?v=4AdcfbI6A4c), as per [Matz's recommendation in his RubyConf 2022 keynote speech to replace JavaScript with Ruby](https://youtu.be/knutsgHTrfQ?t=789). It aims at providing the simplest frontend library in existence. You can finally live in pure Rubyland on the Web in both the frontend and backend with [Glimmer DSL for Web](https://rubygems.org/gems/glimmer-dsl-web)!
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
### You can finally live in pure Rubyland on the web!
|
11
|
-
|
12
|
-
[Glimmer](https://github.com/AndyObtiva/glimmer) DSL for Web is an upcoming **pre-alpha** [gem](https://rubygems.org/gems/glimmer-dsl-web) that enables building web GUI in pure Ruby via [Opal](https://opalrb.com/) on [Rails](https://rubyonrails.org/) (and potentially [Ruby WASM](https://github.com/ruby/ruby.wasm) in the future).
|
8
|
+
This project is inspired by [Glimmer DSL for Opal](https://github.com/AndyObtiva/glimmer-dsl-opal) and is similar in enabling frontend GUI development with Ruby. [Glimmer DSL for Web](https://rubygems.org/gems/glimmer-dsl-web) mainly differs from Glimmer DSL for Opal by adopting a DSL that follows web-like HTML syntax in Ruby to facilitate leveraging existing HTML/CSS/JS skills instead of adopting a desktop GUI DSL that is webified.
|
13
9
|
|
14
10
|
**Sample**
|
15
11
|
|
@@ -44,7 +40,7 @@ That produces:
|
|
44
40
|
```html
|
45
41
|
...
|
46
42
|
<div id="app-container">
|
47
|
-
<div parent="#app-container" class="element element-1">
|
43
|
+
<div data-parent="#app-container" class="element element-1">
|
48
44
|
<label class="greeting element element-2">
|
49
45
|
Hello, World!
|
50
46
|
</label>
|
@@ -74,14 +70,50 @@ end
|
|
74
70
|
That produces the following under `<body></body>`:
|
75
71
|
|
76
72
|
```html
|
77
|
-
<div parent="body" class="element element-1">
|
73
|
+
<div data-parent="body" class="element element-1">
|
78
74
|
Hello, World!
|
79
75
|
</div>
|
80
76
|
```
|
81
77
|
|
82
78
|

|
83
79
|
|
84
|
-
**Hello, Button
|
80
|
+
**Hello, Button!**
|
81
|
+
|
82
|
+
Event listeners can be setup on any element using the same event names used in HTML (e.g. `onclick`) while passing in a standard Ruby block to handle behavior. `$$` gives access to `window` to invoke functions like `alert`.
|
83
|
+
|
84
|
+
Glimmer GUI code:
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
require 'glimmer-dsl-web'
|
88
|
+
|
89
|
+
include Glimmer
|
90
|
+
|
91
|
+
Document.ready? do
|
92
|
+
div {
|
93
|
+
button('Greet') {
|
94
|
+
onclick do
|
95
|
+
$$.alert('Hello, Button!')
|
96
|
+
end
|
97
|
+
}
|
98
|
+
}.render
|
99
|
+
end
|
100
|
+
```
|
101
|
+
|
102
|
+
That produces the following under `<body></body>`:
|
103
|
+
|
104
|
+
```html
|
105
|
+
<div data-parent="body" class="element element-1">
|
106
|
+
<button class="element element-2">Greet</button>
|
107
|
+
</div>
|
108
|
+
```
|
109
|
+
|
110
|
+
Screenshot:
|
111
|
+
|
112
|
+

|
113
|
+
|
114
|
+
**Hello, Form!**
|
115
|
+
|
116
|
+
[Glimmer DSL for Web](https://rubygems.org/gems/glimmer-dsl-web) gives access to all Web Browser built-in features like HTML form validations, input focus, events, and element functions from a very terse and productive Ruby GUI DSL.
|
85
117
|
|
86
118
|
Glimmer GUI code:
|
87
119
|
|
@@ -93,44 +125,50 @@ include Glimmer
|
|
93
125
|
Document.ready? do
|
94
126
|
div {
|
95
127
|
h1('Contact Form')
|
128
|
+
|
96
129
|
form {
|
97
|
-
div
|
130
|
+
div {
|
98
131
|
label('Name: ', for: 'name-field')
|
99
|
-
@name_input = input(
|
132
|
+
@name_input = input(type: 'text', id: 'name-field', required: true, autofocus: true)
|
100
133
|
}
|
101
|
-
|
134
|
+
|
135
|
+
div {
|
102
136
|
label('Email: ', for: 'email-field')
|
103
|
-
@email_input = input(
|
137
|
+
@email_input = input(type: 'email', id: 'email-field', required: true)
|
104
138
|
}
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
139
|
+
|
140
|
+
div {
|
141
|
+
input(type: 'submit', value: 'Add Contact') {
|
142
|
+
onclick do |event|
|
143
|
+
if ([@name_input, @email_input].all? {|input| input.check_validity })
|
144
|
+
# re-open table content and add row
|
145
|
+
@table.content {
|
146
|
+
tr {
|
147
|
+
td { @name_input.value }
|
148
|
+
td { @email_input.value }
|
149
|
+
}
|
112
150
|
}
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
error_messages = []
|
117
|
-
error_messages << "Name is not valid! Make sure it is filled." if !@name_input.check_validity
|
118
|
-
error_messages << "Email is not valid! Make sure it is filled and has a valid format." if !@email_input.check_validity
|
119
|
-
$$.alert(error_messages.join("\n"))
|
151
|
+
@email_input.value = @name_input.value = ''
|
152
|
+
@name_input.focus
|
153
|
+
end
|
120
154
|
end
|
121
|
-
|
155
|
+
}
|
122
156
|
}
|
123
157
|
}
|
158
|
+
|
124
159
|
h1('Contacts Table')
|
160
|
+
|
125
161
|
@table = table {
|
126
162
|
tr {
|
127
163
|
th('Name')
|
128
164
|
th('Email')
|
129
165
|
}
|
166
|
+
|
130
167
|
tr {
|
131
168
|
td('John Doe')
|
132
169
|
td('johndoe@example.com')
|
133
170
|
}
|
171
|
+
|
134
172
|
tr {
|
135
173
|
td('Jane Doe')
|
136
174
|
td('janedoe@example.com')
|
@@ -140,15 +178,11 @@ Document.ready? do
|
|
140
178
|
# CSS Styles
|
141
179
|
style {
|
142
180
|
<<~CSS
|
143
|
-
|
144
|
-
margin:
|
181
|
+
input {
|
182
|
+
margin: 5px;
|
145
183
|
}
|
146
|
-
|
147
|
-
margin
|
148
|
-
}
|
149
|
-
.submit-button {
|
150
|
-
display: block;
|
151
|
-
margin: 10px 5px;
|
184
|
+
input[type=submit] {
|
185
|
+
margin: 5px 0;
|
152
186
|
}
|
153
187
|
table {
|
154
188
|
border:1px solid grey;
|
@@ -171,83 +205,66 @@ That produces the following under `<body></body>`:
|
|
171
205
|
```html
|
172
206
|
<div data-parent="body" class="element element-1">
|
173
207
|
<h1 class="element element-2">Contact Form</h1>
|
208
|
+
|
174
209
|
<form class="element element-3">
|
175
|
-
<div class="
|
210
|
+
<div class="element element-4">
|
176
211
|
<label for="name-field" class="element element-5">Name: </label>
|
177
|
-
<input id="name-field"
|
212
|
+
<input type="text" id="name-field" required="true" autofocus="true" class="element element-6">
|
178
213
|
</div>
|
179
|
-
|
214
|
+
|
215
|
+
<div class="element element-7">
|
180
216
|
<label for="email-field" class="element element-8">Email: </label>
|
181
|
-
<input id="email-field" class="
|
217
|
+
<input type="email" id="email-field" required="true" class="element element-9">
|
218
|
+
</div>
|
219
|
+
|
220
|
+
<div class="element element-10">
|
221
|
+
<input type="submit" value="Add Contact" class="element element-11">
|
182
222
|
</div>
|
183
|
-
<button class="submit-button element element-10">Add Contact</button>
|
184
223
|
</form>
|
185
|
-
|
186
|
-
<
|
187
|
-
|
188
|
-
|
189
|
-
|
224
|
+
|
225
|
+
<h1 class="element element-12">Contacts Table</h1>
|
226
|
+
|
227
|
+
<table class="element element-13">
|
228
|
+
<tr class="element element-14">
|
229
|
+
<th class="element element-15">Name</th>
|
230
|
+
<th class="element element-16">Email</th>
|
190
231
|
</tr>
|
191
|
-
|
192
|
-
|
193
|
-
<td class="element element-18">
|
232
|
+
|
233
|
+
<tr class="element element-17">
|
234
|
+
<td class="element element-18">John Doe</td>
|
235
|
+
<td class="element element-19">johndoe@example.com</td>
|
194
236
|
</tr>
|
195
|
-
|
196
|
-
|
197
|
-
<td class="element element-21">
|
237
|
+
|
238
|
+
<tr class="element element-20">
|
239
|
+
<td class="element element-21">Jane Doe</td>
|
240
|
+
<td class="element element-22">janedoe@example.com</td>
|
198
241
|
</tr>
|
199
242
|
</table>
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
background: #ccc;
|
219
|
-
}
|
243
|
+
|
244
|
+
<style class="element element-23">
|
245
|
+
input {
|
246
|
+
margin: 5px;
|
247
|
+
}
|
248
|
+
input[type=submit] {
|
249
|
+
margin: 5px 0;
|
250
|
+
}
|
251
|
+
table {
|
252
|
+
border:1px solid grey;
|
253
|
+
border-spacing: 0;
|
254
|
+
}
|
255
|
+
table tr td, table tr th {
|
256
|
+
padding: 5px;
|
257
|
+
}
|
258
|
+
table tr:nth-child(even) {
|
259
|
+
background: #ccc;
|
260
|
+
}
|
220
261
|
</style>
|
221
262
|
</div>
|
222
263
|
```
|
223
264
|
|
224
|
-
|
225
|
-
|
226
|
-
---
|
227
|
-
|
228
|
-
***Hello, Button!***
|
229
|
-
|
230
|
-

|
265
|
+
Screenshot:
|
231
266
|
|
232
|
-
|
233
|
-
|
234
|
-
***Hello, Button! Submitted Invalid Data***
|
235
|
-
|
236
|
-

|
237
|
-
|
238
|
-
---
|
239
|
-
|
240
|
-
***Hello, Button! Filled Valid Name and Email***
|
241
|
-
|
242
|
-

|
243
|
-
|
244
|
-
---
|
245
|
-
|
246
|
-
***Hello, Button! Added Contact***
|
247
|
-
|
248
|
-

|
249
|
-
|
250
|
-
---
|
267
|
+

|
251
268
|
|
252
269
|
**Button Counter Sample**
|
253
270
|
|
@@ -279,7 +296,7 @@ class HelloButton
|
|
279
296
|
|
280
297
|
markup {
|
281
298
|
# This will hook into element #app-container and then build HTML inside it using Ruby DSL code
|
282
|
-
div(
|
299
|
+
div(parent: parent_selector) {
|
283
300
|
text 'Button Counter'
|
284
301
|
|
285
302
|
button {
|
@@ -288,7 +305,7 @@ class HelloButton
|
|
288
305
|
# copied to button innerText (content) to display to the user
|
289
306
|
inner_text <= [@counter, :count, on_read: ->(value) { "Click To Increment: #{value} " }]
|
290
307
|
|
291
|
-
|
308
|
+
onclick {
|
292
309
|
@counter.increment!
|
293
310
|
}
|
294
311
|
}
|
@@ -344,11 +361,12 @@ Learn more about the differences between various [Glimmer](https://github.com/An
|
|
344
361
|
- [Background](#background)
|
345
362
|
- [Prerequisites](#prerequisites)
|
346
363
|
- [Setup](#setup)
|
364
|
+
- [Usage](#usage)
|
347
365
|
- [Supported Glimmer DSL Keywords](#supported-glimmer-dsl-keywords)
|
348
366
|
- [Samples](#samples)
|
349
367
|
- [Hello Samples](#hello-samples)
|
350
368
|
- [Hello, World!](#hello-world)
|
351
|
-
- [Hello,
|
369
|
+
- [Hello, Form!](#hello-form)
|
352
370
|
- [Button Counter](#button-counter)
|
353
371
|
- [Glimmer Process](#glimmer-process)
|
354
372
|
- [Help](#help)
|
@@ -362,10 +380,12 @@ Learn more about the differences between various [Glimmer](https://github.com/An
|
|
362
380
|
|
363
381
|
## Prerequisites
|
364
382
|
|
383
|
+
[Glimmer DSL for Web](https://rubygems.org/gems/glimmer-dsl-web) will begin by supporting [Opal Ruby](https://opalrb.com/) on [Rails](https://rubyonrails.org/). [Opal](https://opalrb.com/) is a lightweight Ruby to JavaScript transpiler that results in small downloadables compared to WASM. In the future, the project might grow to support [Ruby WASM](https://github.com/ruby/ruby.wasm) as an alternative to [Opal Ruby](https://opalrb.com/) that could be switched to with a simple configuration change.
|
384
|
+
|
385
|
+
- Ruby 3.0 (newer Ruby versions are not supported at this time)
|
365
386
|
- Rails 6-7: [https://github.com/rails/rails](https://github.com/rails/rails)
|
366
|
-
- Opal 1.4.1 for Rails 6-7
|
367
|
-
- Opal-Rails 2.0.2 for Rails 6-7
|
368
|
-
- jQuery 3 (included): [https://code.jquery.com/](https://code.jquery.com/) (jQuery 3.6.0 is included in the [glimmer-dsl-web](https://rubygems.org/gems/glimmer-dsl-web) gem)
|
387
|
+
- Opal 1.4.1 for Rails 6-7: [https://github.com/opal/opal](https://github.com/opal/opal)
|
388
|
+
- Opal-Rails 2.0.2 for Rails 6-7: [https://github.com/opal/opal-rails](https://github.com/opal/opal-rails)
|
369
389
|
|
370
390
|
## Setup
|
371
391
|
|
@@ -396,7 +416,7 @@ gem 'opal', '1.4.1'
|
|
396
416
|
gem 'opal-rails', '2.0.2'
|
397
417
|
gem 'opal-async', '~> 1.4.0'
|
398
418
|
gem 'opal-jquery', '~> 0.4.6'
|
399
|
-
gem 'glimmer-dsl-web', '~> 0.0.
|
419
|
+
gem 'glimmer-dsl-web', '~> 0.0.5'
|
400
420
|
gem 'glimmer-dsl-xml', '~> 1.3.1', require: false
|
401
421
|
gem 'glimmer-dsl-css', '~> 1.2.1', require: false
|
402
422
|
```
|
@@ -488,7 +508,7 @@ That produces:
|
|
488
508
|
```html
|
489
509
|
...
|
490
510
|
<div id="app-container">
|
491
|
-
<div parent="#app-container" class="element element-1">
|
511
|
+
<div data-parent="#app-container" class="element element-1">
|
492
512
|
<label class="greeting element element-2">
|
493
513
|
Hello, World!
|
494
514
|
</label>
|
@@ -541,7 +561,7 @@ gem 'opal', '1.4.1'
|
|
541
561
|
gem 'opal-rails', '2.0.2'
|
542
562
|
gem 'opal-async', '~> 1.4.0'
|
543
563
|
gem 'opal-jquery', '~> 0.4.6'
|
544
|
-
gem 'glimmer-dsl-web', '~> 0.0.
|
564
|
+
gem 'glimmer-dsl-web', '~> 0.0.5'
|
545
565
|
gem 'glimmer-dsl-xml', '~> 1.3.1', require: false
|
546
566
|
gem 'glimmer-dsl-css', '~> 1.2.1', require: false
|
547
567
|
```
|
@@ -637,7 +657,7 @@ That produces:
|
|
637
657
|
```html
|
638
658
|
...
|
639
659
|
<div id="app-container">
|
640
|
-
<div parent="#app-container" class="element element-1">
|
660
|
+
<div data-parent="#app-container" class="element element-1">
|
641
661
|
<label class="greeting element element-2">
|
642
662
|
Hello, World!
|
643
663
|
</label>
|
@@ -663,11 +683,85 @@ If you run into any issues in setup, refer to the [Sample Glimmer DSL for Web Ra
|
|
663
683
|
|
664
684
|
Otherwise, if you still cannot setup successfully (even with the help of the sample project, or if the sample project stops working), please do not hesitate to report an [Issue request](https://github.com/AndyObtiva/glimmer-dsl-web/issues) or fix and submit a [Pull Request](https://github.com/AndyObtiva/glimmer-dsl-web/pulls).
|
665
685
|
|
686
|
+
## Usage
|
687
|
+
|
688
|
+
Glimmer DSL for Web offers a GUI DSL for building HTML Web User Interfaces declaratively in Ruby.
|
689
|
+
|
690
|
+
1- **Keywords (HTML Elements)**
|
691
|
+
|
692
|
+
You can declare any HTML element by simply using the lowercase underscored version of its name (Ruby convention for method names) like `div`, `span`, `form`, `input`, `button`, `table`, `tr`, `th`, and `td`.
|
693
|
+
|
694
|
+
Under the hood, HTML element DSL keywords are invoked as Ruby methods.
|
695
|
+
|
696
|
+
2- **Arguments (HTML Attributes + Text Content)**
|
697
|
+
|
698
|
+
You can set any HTML element attributes by passing as keyword arguments to element methods like `div(id: 'container', class: 'stack')` or `input(type: 'email', required: true)`
|
699
|
+
|
700
|
+
Also, if the element has a little bit of text content that can fit in one line, it can be passed as the 1st argument like `label('Name: ', for: 'name_field')`, `button('Calculate', class: 'round-button')`, or `span('Mr')`
|
701
|
+
|
702
|
+
3- **Content Block (Properties + Listeners + Nested Elements + Text Content)**
|
703
|
+
|
704
|
+
Element methods can accept a Ruby content block. It intentionally has a `{...}` style even as a multi-line block to indicate that the code is declarative GUI structure code.
|
705
|
+
|
706
|
+
You can nest HTML element properties under an element like:
|
707
|
+
|
708
|
+
```ruby
|
709
|
+
input(type: 'text') {
|
710
|
+
content_editable false
|
711
|
+
}
|
712
|
+
```
|
713
|
+
|
714
|
+
You can nest HTML event listeners under an element by using the HTML event listener name (e.g. `onclick`, `onchange`, `onblur`):
|
715
|
+
|
716
|
+
```ruby
|
717
|
+
button('Add') {
|
718
|
+
onclick do
|
719
|
+
@model.add_selected_element
|
720
|
+
end
|
721
|
+
}
|
722
|
+
```
|
723
|
+
|
724
|
+
Given that listener code is imperative, it uses a `do; end` style for Ruby blocks to separate it from declarative GUI structure code and enable quicker readability of the code.
|
725
|
+
|
726
|
+
You can nest other HTML elements under an HTML element the same way you do so in HTML, like:
|
727
|
+
|
728
|
+
```ruby
|
729
|
+
form {
|
730
|
+
div(class: 'field-row') {
|
731
|
+
label('Name: ', for: 'name-field')
|
732
|
+
input(id: 'name-field', class: 'field', type: 'text', required: true)
|
733
|
+
}
|
734
|
+
div(class: 'field-row') {
|
735
|
+
label('Email: ', for: 'email-field')
|
736
|
+
input(id: 'email-field', class: 'field', type: 'email', required: true)
|
737
|
+
}
|
738
|
+
button('Add Contact', class: 'submit-button') {
|
739
|
+
onclick do
|
740
|
+
...
|
741
|
+
end
|
742
|
+
}
|
743
|
+
}
|
744
|
+
```
|
745
|
+
|
746
|
+
You can nest text content underneath an element's Ruby block, like:
|
747
|
+
|
748
|
+
```ruby
|
749
|
+
p(class: 'summary') {
|
750
|
+
'This text content is going into the body of the span element'
|
751
|
+
}
|
752
|
+
```
|
753
|
+
|
754
|
+
4- **Operations (Properties + Functions)**
|
755
|
+
|
756
|
+
You can get/set any element property or invoke any element function by simply calling the lowercase underscored version of their name in Ruby like `input.check_validity`, `input.value`, and `input.id`.
|
757
|
+
|
666
758
|
## Supported Glimmer DSL Keywords
|
667
759
|
|
668
|
-
All HTML elements.
|
760
|
+
[All HTML elements](https://developer.mozilla.org/en-US/docs/Web/HTML/Element).
|
761
|
+
|
762
|
+
[All HTML attributes](https://www.w3schools.com/html/html_attributes.asp).
|
669
763
|
|
670
|
-
All HTML
|
764
|
+
[All HTML events](https://www.w3schools.com/tags/ref_eventattributes.asp).
|
671
765
|
|
672
766
|
## Samples
|
673
767
|
|
@@ -698,11 +792,35 @@ end
|
|
698
792
|
That produces the following under `<body></body>`:
|
699
793
|
|
700
794
|
```html
|
701
|
-
<div parent="body" class="element element-1">
|
795
|
+
<div data-parent="body" class="element element-1">
|
796
|
+
Hello, World!
|
797
|
+
</div>
|
798
|
+
```
|
799
|
+
|
800
|
+

|
801
|
+
|
802
|
+
Alternative syntax when an element only has text content:
|
803
|
+
|
804
|
+
```ruby
|
805
|
+
require 'glimmer-dsl-web'
|
806
|
+
|
807
|
+
include Glimmer
|
808
|
+
|
809
|
+
Document.ready? do
|
810
|
+
div('Hello, World!').render
|
811
|
+
end
|
812
|
+
```
|
813
|
+
|
814
|
+
That produces the following under `<body></body>`:
|
815
|
+
|
816
|
+
```html
|
817
|
+
<div data-parent="body" class="element element-1">
|
702
818
|
Hello, World!
|
703
819
|
</div>
|
704
820
|
```
|
705
821
|
|
822
|
+

|
823
|
+
|
706
824
|
#### Hello, Button!
|
707
825
|
|
708
826
|
Glimmer GUI code:
|
@@ -712,47 +830,85 @@ require 'glimmer-dsl-web'
|
|
712
830
|
|
713
831
|
include Glimmer
|
714
832
|
|
833
|
+
Document.ready? do
|
834
|
+
div {
|
835
|
+
button('Greet') {
|
836
|
+
onclick do
|
837
|
+
$$.alert('Hello, Button!')
|
838
|
+
end
|
839
|
+
}
|
840
|
+
}.render
|
841
|
+
end
|
842
|
+
```
|
843
|
+
|
844
|
+
That produces the following under `<body></body>`:
|
845
|
+
|
846
|
+
```html
|
847
|
+
<div data-parent="body" class="element element-1">
|
848
|
+
<button class="element element-2">Greet</button>
|
849
|
+
</div>
|
850
|
+
```
|
851
|
+
|
852
|
+
Screenshot:
|
853
|
+
|
854
|
+

|
855
|
+
|
856
|
+
#### Hello, Form!
|
857
|
+
|
858
|
+
Glimmer GUI code:
|
859
|
+
|
860
|
+
```ruby
|
861
|
+
require 'glimmer-dsl-web'
|
862
|
+
|
863
|
+
include Glimmer
|
864
|
+
|
715
865
|
Document.ready? do
|
716
866
|
div {
|
717
867
|
h1('Contact Form')
|
868
|
+
|
718
869
|
form {
|
719
|
-
div
|
870
|
+
div {
|
720
871
|
label('Name: ', for: 'name-field')
|
721
|
-
@name_input = input(
|
872
|
+
@name_input = input(type: 'text', id: 'name-field', required: true, autofocus: true)
|
722
873
|
}
|
723
|
-
|
874
|
+
|
875
|
+
div {
|
724
876
|
label('Email: ', for: 'email-field')
|
725
|
-
@email_input = input(
|
877
|
+
@email_input = input(type: 'email', id: 'email-field', required: true)
|
726
878
|
}
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
879
|
+
|
880
|
+
div {
|
881
|
+
input(type: 'submit', value: 'Add Contact') {
|
882
|
+
onclick do |event|
|
883
|
+
if ([@name_input, @email_input].all? {|input| input.check_validity })
|
884
|
+
# re-open table content and add row
|
885
|
+
@table.content {
|
886
|
+
tr {
|
887
|
+
td { @name_input.value }
|
888
|
+
td { @email_input.value }
|
889
|
+
}
|
734
890
|
}
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
error_messages = []
|
739
|
-
error_messages << "Name is not valid! Make sure it is filled." if !@name_input.check_validity
|
740
|
-
error_messages << "Email is not valid! Make sure it is filled and has a valid format." if !@email_input.check_validity
|
741
|
-
$$.alert(error_messages.join("\n"))
|
891
|
+
@email_input.value = @name_input.value = ''
|
892
|
+
@name_input.focus
|
893
|
+
end
|
742
894
|
end
|
743
|
-
|
895
|
+
}
|
744
896
|
}
|
745
897
|
}
|
898
|
+
|
746
899
|
h1('Contacts Table')
|
900
|
+
|
747
901
|
@table = table {
|
748
902
|
tr {
|
749
903
|
th('Name')
|
750
904
|
th('Email')
|
751
905
|
}
|
906
|
+
|
752
907
|
tr {
|
753
908
|
td('John Doe')
|
754
909
|
td('johndoe@example.com')
|
755
910
|
}
|
911
|
+
|
756
912
|
tr {
|
757
913
|
td('Jane Doe')
|
758
914
|
td('janedoe@example.com')
|
@@ -762,15 +918,11 @@ Document.ready? do
|
|
762
918
|
# CSS Styles
|
763
919
|
style {
|
764
920
|
<<~CSS
|
765
|
-
|
766
|
-
margin:
|
921
|
+
input {
|
922
|
+
margin: 5px;
|
767
923
|
}
|
768
|
-
|
769
|
-
margin
|
770
|
-
}
|
771
|
-
.submit-button {
|
772
|
-
display: block;
|
773
|
-
margin: 10px 5px;
|
924
|
+
input[type=submit] {
|
925
|
+
margin: 5px 0;
|
774
926
|
}
|
775
927
|
table {
|
776
928
|
border:1px solid grey;
|
@@ -793,83 +945,66 @@ That produces the following under `<body></body>`:
|
|
793
945
|
```html
|
794
946
|
<div data-parent="body" class="element element-1">
|
795
947
|
<h1 class="element element-2">Contact Form</h1>
|
948
|
+
|
796
949
|
<form class="element element-3">
|
797
|
-
<div class="
|
950
|
+
<div class="element element-4">
|
798
951
|
<label for="name-field" class="element element-5">Name: </label>
|
799
|
-
<input id="name-field"
|
952
|
+
<input type="text" id="name-field" required="true" autofocus="true" class="element element-6">
|
800
953
|
</div>
|
801
|
-
|
954
|
+
|
955
|
+
<div class="element element-7">
|
802
956
|
<label for="email-field" class="element element-8">Email: </label>
|
803
|
-
<input id="email-field" class="
|
957
|
+
<input type="email" id="email-field" required="true" class="element element-9">
|
958
|
+
</div>
|
959
|
+
|
960
|
+
<div class="element element-10">
|
961
|
+
<input type="submit" value="Add Contact" class="element element-11">
|
804
962
|
</div>
|
805
|
-
<button class="submit-button element element-10">Add Contact</button>
|
806
963
|
</form>
|
807
|
-
|
808
|
-
<
|
809
|
-
|
810
|
-
|
811
|
-
|
964
|
+
|
965
|
+
<h1 class="element element-12">Contacts Table</h1>
|
966
|
+
|
967
|
+
<table class="element element-13">
|
968
|
+
<tr class="element element-14">
|
969
|
+
<th class="element element-15">Name</th>
|
970
|
+
<th class="element element-16">Email</th>
|
812
971
|
</tr>
|
813
|
-
|
814
|
-
|
815
|
-
<td class="element element-18">
|
972
|
+
|
973
|
+
<tr class="element element-17">
|
974
|
+
<td class="element element-18">John Doe</td>
|
975
|
+
<td class="element element-19">johndoe@example.com</td>
|
816
976
|
</tr>
|
817
|
-
|
818
|
-
|
819
|
-
<td class="element element-21">
|
977
|
+
|
978
|
+
<tr class="element element-20">
|
979
|
+
<td class="element element-21">Jane Doe</td>
|
980
|
+
<td class="element element-22">janedoe@example.com</td>
|
820
981
|
</tr>
|
821
982
|
</table>
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
background: #ccc;
|
841
|
-
}
|
983
|
+
|
984
|
+
<style class="element element-23">
|
985
|
+
input {
|
986
|
+
margin: 5px;
|
987
|
+
}
|
988
|
+
input[type=submit] {
|
989
|
+
margin: 5px 0;
|
990
|
+
}
|
991
|
+
table {
|
992
|
+
border:1px solid grey;
|
993
|
+
border-spacing: 0;
|
994
|
+
}
|
995
|
+
table tr td, table tr th {
|
996
|
+
padding: 5px;
|
997
|
+
}
|
998
|
+
table tr:nth-child(even) {
|
999
|
+
background: #ccc;
|
1000
|
+
}
|
842
1001
|
</style>
|
843
1002
|
</div>
|
844
1003
|
```
|
845
1004
|
|
846
|
-
|
847
|
-
|
848
|
-
---
|
849
|
-
|
850
|
-
***Hello, Button!***
|
851
|
-
|
852
|
-

|
853
|
-
|
854
|
-
---
|
855
|
-
|
856
|
-
***Hello, Button! Submitted Invalid Data***
|
857
|
-
|
858
|
-

|
859
|
-
|
860
|
-
---
|
861
|
-
|
862
|
-
***Hello, Button! Filled Valid Name and Email***
|
863
|
-
|
864
|
-

|
865
|
-
|
866
|
-
---
|
867
|
-
|
868
|
-
***Hello, Button! Added Contact***
|
869
|
-
|
870
|
-

|
1005
|
+
Screenshot:
|
871
1006
|
|
872
|
-
|
1007
|
+

|
873
1008
|
|
874
1009
|
#### Button Counter
|
875
1010
|
|
@@ -901,7 +1036,7 @@ class HelloButton
|
|
901
1036
|
|
902
1037
|
markup {
|
903
1038
|
# This will hook into element #app-container and then build HTML inside it using Ruby DSL code
|
904
|
-
div(
|
1039
|
+
div(parent: parent_selector) {
|
905
1040
|
text 'Button Counter'
|
906
1041
|
|
907
1042
|
button {
|
@@ -910,7 +1045,7 @@ class HelloButton
|
|
910
1045
|
# copied to button innerText (content) to display to the user
|
911
1046
|
inner_text <= [@counter, :count, on_read: ->(value) { "Click To Increment: #{value} " }]
|
912
1047
|
|
913
|
-
|
1048
|
+
onclick {
|
914
1049
|
@counter.increment!
|
915
1050
|
}
|
916
1051
|
}
|