glimmer-dsl-web 0.0.3 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Gem Version](https://badge.fury.io/rb/glimmer-dsl-web.svg)](http://badge.fury.io/rb/glimmer-dsl-web)
|
4
4
|
[![Join the chat at https://gitter.im/AndyObtiva/glimmer](https://badges.gitter.im/AndyObtiva/glimmer.svg)](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
|
![setup is working](/images/glimmer-dsl-web-setup-example-working.png)
|
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
|
+
![Hello, Button!](/images/glimmer-dsl-web-samples-hello-hello-button.gif)
|
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
|
-
![Hello, Button!](/images/glimmer-dsl-web-samples-hello-hello-button.png)
|
265
|
+
Screenshot:
|
231
266
|
|
232
|
-
|
233
|
-
|
234
|
-
***Hello, Button! Submitted Invalid Data***
|
235
|
-
|
236
|
-
![Hello, Button! Invalid Data](/images/glimmer-dsl-web-samples-hello-hello-button-invalid-data.png)
|
237
|
-
|
238
|
-
---
|
239
|
-
|
240
|
-
***Hello, Button! Filled Valid Name and Email***
|
241
|
-
|
242
|
-
![Hello, Button! Filled](/images/glimmer-dsl-web-samples-hello-hello-button-filled-name-and-email.png)
|
243
|
-
|
244
|
-
---
|
245
|
-
|
246
|
-
***Hello, Button! Added Contact***
|
247
|
-
|
248
|
-
![Hello, Button! Added Contact](/images/glimmer-dsl-web-samples-hello-hello-button-added-contact.png)
|
249
|
-
|
250
|
-
---
|
267
|
+
![Hello, Form!](/images/glimmer-dsl-web-samples-hello-hello-form.gif)
|
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
|
+
![setup is working](/images/glimmer-dsl-web-setup-example-working.png)
|
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
|
+
![setup is working](/images/glimmer-dsl-web-setup-example-working.png)
|
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
|
+
![Hello, Button!](/images/glimmer-dsl-web-samples-hello-hello-button.gif)
|
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
|
-
![Hello, Button!](/images/glimmer-dsl-web-samples-hello-hello-button.png)
|
853
|
-
|
854
|
-
---
|
855
|
-
|
856
|
-
***Hello, Button! Submitted Invalid Data***
|
857
|
-
|
858
|
-
![Hello, Button! Invalid Data](/images/glimmer-dsl-web-samples-hello-hello-button-invalid-data.png)
|
859
|
-
|
860
|
-
---
|
861
|
-
|
862
|
-
***Hello, Button! Filled Valid Name and Email***
|
863
|
-
|
864
|
-
![Hello, Button! Filled](/images/glimmer-dsl-web-samples-hello-hello-button-filled-name-and-email.png)
|
865
|
-
|
866
|
-
---
|
867
|
-
|
868
|
-
***Hello, Button! Added Contact***
|
869
|
-
|
870
|
-
![Hello, Button! Added Contact](/images/glimmer-dsl-web-samples-hello-hello-button-added-contact.png)
|
1005
|
+
Screenshot:
|
871
1006
|
|
872
|
-
|
1007
|
+
![Hello, Form!](/images/glimmer-dsl-web-samples-hello-hello-form.gif)
|
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
|
}
|