glimmer-dsl-web 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/README.md +265 -16
- data/VERSION +1 -1
- data/glimmer-dsl-web.gemspec +9 -6
- data/lib/glimmer/dsl/web/content_data_binding_expression.rb +41 -0
- data/lib/glimmer/dsl/web/dsl.rb +2 -9
- data/lib/glimmer/dsl/web/element_expression.rb +3 -3
- data/lib/glimmer/web/element_proxy.rb +70 -3
- data/lib/glimmer/web/listener_proxy.rb +0 -1
- data/lib/glimmer-dsl-web/samples/hello/hello_content_data_binding.rb +137 -0
- data/lib/glimmer-dsl-web.rb +6 -2
- metadata +48 -32
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '028be0c05ee74f8e639b3b43adbdd52e7b90e7e5b52a0e7026fbf74e0d017300'
|
4
|
+
data.tar.gz: d2b8e3fc639dfa55655f05faf740fd36fcf518bc143eb8f08a874be3e34f72ec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e9a0add34e7db5cd7d0816e0006ed0426f9bc739402e4951f672195f6dcce472943b5f5c501213269b0ec84fb636aaea701fe35326639827bd580b94db370a5a
|
7
|
+
data.tar.gz: 19ccf1280735e472c6f643a21e105f0b1020fdacc53a66f63588be6f7b8faddb1e8391667094687a204c3d1363ee760c6b752c84866b86323437c17b8fdbe7d6
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,21 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## 0.0.8
|
4
|
+
|
5
|
+
- Validate that element keywords belong to the valid list of HTML element tag names to prevent rendering fake elements the keyword does not match a real HTML element tag
|
6
|
+
- Support inner_html/outer_html properties (it seems they did not convert to innerHTML/outerHTML correctly because of the all caps HTML)
|
7
|
+
- Support element properties via original JS names (e.g. innerHTML) to prevent logic from breaking if some do not convert correctly from underscored versions
|
8
|
+
- Package dependencies properly in the gem to avoid instructing users to add in Rails Gemfile manually
|
9
|
+
- Content Data-Binding support to regenerate element content based on changes to an observed model attribute.
|
10
|
+
Content Data-Binding Example:
|
11
|
+
content(*data_binding_options) { |data_binding_value|
|
12
|
+
li {
|
13
|
+
data_binding_value
|
14
|
+
}
|
15
|
+
}
|
16
|
+
- Ensuring removing data-binding model listeners when calling `element#remove` in addition to already removing standard HTML event listeners
|
17
|
+
- New Hello, Content Data-Binding! Sample: `require 'glimmer-dsl-web/samples/hello/hello_content_data_binding'`
|
18
|
+
|
3
19
|
## 0.0.7
|
4
20
|
|
5
21
|
- Support input[type=number] value data-binding as a Ruby Numeric object (Integer or Float)
|
data/README.md
CHANGED
@@ -1,9 +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.
|
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.8 (Early Alpha)
|
2
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
|
-
[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, most intuitive,
|
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, most intuitive, most straight-forward, and most productive frontend library in existence. The library follows the Ruby way (with [DSLs](https://martinfowler.com/books/dsl.html) and [TIMTOWTDI](https://en.wiktionary.org/wiki/TMTOWTDI#English)) and the Rails way ([Convention over Configuration](https://rubyonrails.org/doctrine)) while supporting both Unidirectional (One-Way) Data-Binding (using `<=`) and Bidirectional (Two-Way) Data-Binding (using `<=>`). Dynamic rendering (and re-rendering) of HTML content is also supported via Content Data-Binding. 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
|
+
|
8
|
+
(the project plans to add component support very soon, albeit components are already supported by creating your own Ruby classes and having them render part of the GUI hierarchy)
|
7
9
|
|
8
10
|
**Hello, World! Sample**
|
9
11
|
|
@@ -337,6 +339,137 @@ Screenshot:
|
|
337
339
|
|
338
340
|
![Hello, Data-Binding!](/images/glimmer-dsl-web-samples-hello-hello-data-binding.gif)
|
339
341
|
|
342
|
+
**Hello, Content Data-Binding!**
|
343
|
+
|
344
|
+
If you need to regenerate HTML element content dynamically, you can use Content Data-Binding to effortlessly
|
345
|
+
rebuild HTML elements based on changes in a Model attribute that provides the source data.
|
346
|
+
In this example, we generate multiple address forms based on the number of addresses the user has.
|
347
|
+
|
348
|
+
Glimmer GUI code:
|
349
|
+
|
350
|
+
```ruby
|
351
|
+
require 'glimmer-dsl-web'
|
352
|
+
|
353
|
+
class Address
|
354
|
+
attr_accessor :text
|
355
|
+
attr_reader :name, :street, :city, :state, :zip
|
356
|
+
|
357
|
+
def name=(value)
|
358
|
+
@name = value
|
359
|
+
update_text
|
360
|
+
end
|
361
|
+
|
362
|
+
def street=(value)
|
363
|
+
@street = value
|
364
|
+
update_text
|
365
|
+
end
|
366
|
+
|
367
|
+
def city=(value)
|
368
|
+
@city = value
|
369
|
+
update_text
|
370
|
+
end
|
371
|
+
|
372
|
+
def state=(value)
|
373
|
+
@state = value
|
374
|
+
update_text
|
375
|
+
end
|
376
|
+
|
377
|
+
def zip=(value)
|
378
|
+
@zip = value
|
379
|
+
update_text
|
380
|
+
end
|
381
|
+
|
382
|
+
private
|
383
|
+
|
384
|
+
def update_text
|
385
|
+
self.text = [name, street, city, state, zip].compact.reject(&:empty?).join(', ')
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
class User
|
390
|
+
attr_accessor :addresses
|
391
|
+
attr_reader :address_count
|
392
|
+
|
393
|
+
def initialize
|
394
|
+
@address_count = 1
|
395
|
+
@addresses = []
|
396
|
+
update_addresses
|
397
|
+
end
|
398
|
+
|
399
|
+
def address_count=(value)
|
400
|
+
value = [[1, value.to_i].max, 3].min
|
401
|
+
@address_count = value
|
402
|
+
update_addresses
|
403
|
+
end
|
404
|
+
|
405
|
+
private
|
406
|
+
|
407
|
+
def update_addresses
|
408
|
+
address_count_change = address_count - addresses.size
|
409
|
+
if address_count_change > 0
|
410
|
+
address_count_change.times { addresses << Address.new }
|
411
|
+
else
|
412
|
+
address_count_change.abs.times { addresses.pop }
|
413
|
+
end
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
@user = User.new
|
418
|
+
|
419
|
+
div {
|
420
|
+
div {
|
421
|
+
label('Number of addresses: ', for: 'address-count-field')
|
422
|
+
input(id: 'address-count-field', type: 'number', min: 1, max: 3) {
|
423
|
+
value <=> [@user, :address_count]
|
424
|
+
}
|
425
|
+
}
|
426
|
+
|
427
|
+
div {
|
428
|
+
# Content Data-Binding is used to dynamically (re)generate content of div
|
429
|
+
# based on changes to @user.addresses, replacing older content on every change
|
430
|
+
content(@user, :addresses) do
|
431
|
+
@user.addresses.each do |address|
|
432
|
+
div {
|
433
|
+
div(style: 'display: grid; grid-auto-columns: 80px 280px;') { |address_div|
|
434
|
+
[:name, :street, :city, :state, :zip].each do |attribute|
|
435
|
+
label(attribute.to_s.capitalize, for: "#{attribute}-field")
|
436
|
+
input(id: "#{attribute}-field", type: 'text') {
|
437
|
+
value <=> [address, attribute]
|
438
|
+
}
|
439
|
+
end
|
440
|
+
|
441
|
+
div(style: 'grid-column: 1 / span 2;') {
|
442
|
+
inner_text <= [address, :text]
|
443
|
+
}
|
444
|
+
|
445
|
+
style {
|
446
|
+
<<~CSS
|
447
|
+
#{address_div.selector} {
|
448
|
+
margin: 10px 0;
|
449
|
+
}
|
450
|
+
#{address_div.selector} * {
|
451
|
+
margin: 5px;
|
452
|
+
}
|
453
|
+
#{address_div.selector} label {
|
454
|
+
grid-column: 1;
|
455
|
+
}
|
456
|
+
#{address_div.selector} input, #{address_div.selector} select {
|
457
|
+
grid-column: 2;
|
458
|
+
}
|
459
|
+
CSS
|
460
|
+
}
|
461
|
+
}
|
462
|
+
}
|
463
|
+
end
|
464
|
+
end
|
465
|
+
}
|
466
|
+
}.render
|
467
|
+
```
|
468
|
+
|
469
|
+
Screenshot:
|
470
|
+
|
471
|
+
![Hello, Content Data-Binding!](/images/glimmer-dsl-web-samples-hello-hello-content-data-binding.gif)
|
472
|
+
|
340
473
|
**Button Counter Sample**
|
341
474
|
|
342
475
|
**UPCOMING (NOT RELEASED OR SUPPORTED YET)**
|
@@ -441,6 +574,7 @@ Learn more about the differences between various [Glimmer](https://github.com/An
|
|
441
574
|
- [Hello, Button!](#hello-button)
|
442
575
|
- [Hello, Form!](#hello-form)
|
443
576
|
- [Hello, Data-Binding!](#hello-data-binding)
|
577
|
+
- [Hello, Content Data-Binding!](#hello-content-data-binding)
|
444
578
|
- [Hello, Input (Date/Time)!](#hello-input-datetime)
|
445
579
|
- [Button Counter](#button-counter)
|
446
580
|
- [Glimmer Process](#glimmer-process)
|
@@ -487,13 +621,7 @@ rails new glimmer_app_server
|
|
487
621
|
Add the following to `Gemfile`:
|
488
622
|
|
489
623
|
```
|
490
|
-
gem '
|
491
|
-
gem 'opal-rails', '2.0.2'
|
492
|
-
gem 'opal-async', '~> 1.4.0'
|
493
|
-
gem 'opal-jquery', '~> 0.4.6'
|
494
|
-
gem 'glimmer-dsl-web', '~> 0.0.7'
|
495
|
-
gem 'glimmer-dsl-xml', '~> 1.3.1', require: false
|
496
|
-
gem 'glimmer-dsl-css', '~> 1.2.1', require: false
|
624
|
+
gem 'glimmer-dsl-web', '~> 0.0.8'
|
497
625
|
```
|
498
626
|
|
499
627
|
Run:
|
@@ -632,13 +760,7 @@ Disable the `webpacker` gem line in `Gemfile`:
|
|
632
760
|
Add the following to `Gemfile`:
|
633
761
|
|
634
762
|
```ruby
|
635
|
-
gem '
|
636
|
-
gem 'opal-rails', '2.0.2'
|
637
|
-
gem 'opal-async', '~> 1.4.0'
|
638
|
-
gem 'opal-jquery', '~> 0.4.6'
|
639
|
-
gem 'glimmer-dsl-web', '~> 0.0.7'
|
640
|
-
gem 'glimmer-dsl-xml', '~> 1.3.1', require: false
|
641
|
-
gem 'glimmer-dsl-css', '~> 1.2.1', require: false
|
763
|
+
gem 'glimmer-dsl-web', '~> 0.0.8'
|
642
764
|
```
|
643
765
|
|
644
766
|
Run:
|
@@ -1254,6 +1376,133 @@ Screenshot:
|
|
1254
1376
|
|
1255
1377
|
![Hello, Data-Binding!](/images/glimmer-dsl-web-samples-hello-hello-data-binding.gif)
|
1256
1378
|
|
1379
|
+
#### Hello, Content Data-Binding!
|
1380
|
+
|
1381
|
+
Glimmer GUI code:
|
1382
|
+
|
1383
|
+
```ruby
|
1384
|
+
require 'glimmer-dsl-web'
|
1385
|
+
|
1386
|
+
class Address
|
1387
|
+
attr_accessor :text
|
1388
|
+
attr_reader :name, :street, :city, :state, :zip
|
1389
|
+
|
1390
|
+
def name=(value)
|
1391
|
+
@name = value
|
1392
|
+
update_text
|
1393
|
+
end
|
1394
|
+
|
1395
|
+
def street=(value)
|
1396
|
+
@street = value
|
1397
|
+
update_text
|
1398
|
+
end
|
1399
|
+
|
1400
|
+
def city=(value)
|
1401
|
+
@city = value
|
1402
|
+
update_text
|
1403
|
+
end
|
1404
|
+
|
1405
|
+
def state=(value)
|
1406
|
+
@state = value
|
1407
|
+
update_text
|
1408
|
+
end
|
1409
|
+
|
1410
|
+
def zip=(value)
|
1411
|
+
@zip = value
|
1412
|
+
update_text
|
1413
|
+
end
|
1414
|
+
|
1415
|
+
private
|
1416
|
+
|
1417
|
+
def update_text
|
1418
|
+
self.text = [name, street, city, state, zip].compact.reject(&:empty?).join(', ')
|
1419
|
+
end
|
1420
|
+
end
|
1421
|
+
|
1422
|
+
class User
|
1423
|
+
attr_accessor :addresses
|
1424
|
+
attr_reader :address_count
|
1425
|
+
|
1426
|
+
def initialize
|
1427
|
+
@address_count = 1
|
1428
|
+
@addresses = []
|
1429
|
+
update_addresses
|
1430
|
+
end
|
1431
|
+
|
1432
|
+
def address_count=(value)
|
1433
|
+
value = [[1, value.to_i].max, 3].min
|
1434
|
+
@address_count = value
|
1435
|
+
update_addresses
|
1436
|
+
end
|
1437
|
+
|
1438
|
+
private
|
1439
|
+
|
1440
|
+
def update_addresses
|
1441
|
+
address_count_change = address_count - addresses.size
|
1442
|
+
if address_count_change > 0
|
1443
|
+
address_count_change.times { addresses << Address.new }
|
1444
|
+
else
|
1445
|
+
address_count_change.abs.times { addresses.pop }
|
1446
|
+
end
|
1447
|
+
end
|
1448
|
+
end
|
1449
|
+
|
1450
|
+
@user = User.new
|
1451
|
+
|
1452
|
+
div {
|
1453
|
+
div {
|
1454
|
+
label('Number of addresses: ', for: 'address-count-field')
|
1455
|
+
input(id: 'address-count-field', type: 'number', min: 1, max: 3) {
|
1456
|
+
value <=> [@user, :address_count]
|
1457
|
+
}
|
1458
|
+
}
|
1459
|
+
|
1460
|
+
div {
|
1461
|
+
# Content Data-Binding is used to dynamically (re)generate content of div
|
1462
|
+
# based on changes to @user.addresses, replacing older content on every change
|
1463
|
+
content(@user, :addresses) do
|
1464
|
+
@user.addresses.each do |address|
|
1465
|
+
div {
|
1466
|
+
div(style: 'display: grid; grid-auto-columns: 80px 280px;') { |address_div|
|
1467
|
+
[:name, :street, :city, :state, :zip].each do |attribute|
|
1468
|
+
label(attribute.to_s.capitalize, for: "#{attribute}-field")
|
1469
|
+
input(id: "#{attribute}-field", type: 'text') {
|
1470
|
+
value <=> [address, attribute]
|
1471
|
+
}
|
1472
|
+
end
|
1473
|
+
|
1474
|
+
div(style: 'grid-column: 1 / span 2;') {
|
1475
|
+
inner_text <= [address, :text]
|
1476
|
+
}
|
1477
|
+
|
1478
|
+
style {
|
1479
|
+
<<~CSS
|
1480
|
+
#{address_div.selector} {
|
1481
|
+
margin: 10px 0;
|
1482
|
+
}
|
1483
|
+
#{address_div.selector} * {
|
1484
|
+
margin: 5px;
|
1485
|
+
}
|
1486
|
+
#{address_div.selector} label {
|
1487
|
+
grid-column: 1;
|
1488
|
+
}
|
1489
|
+
#{address_div.selector} input, #{address_div.selector} select {
|
1490
|
+
grid-column: 2;
|
1491
|
+
}
|
1492
|
+
CSS
|
1493
|
+
}
|
1494
|
+
}
|
1495
|
+
}
|
1496
|
+
end
|
1497
|
+
end
|
1498
|
+
}
|
1499
|
+
}.render
|
1500
|
+
```
|
1501
|
+
|
1502
|
+
Screenshot:
|
1503
|
+
|
1504
|
+
![Hello, Content Data-Binding!](/images/glimmer-dsl-web-samples-hello-hello-content-data-binding.gif)
|
1505
|
+
|
1257
1506
|
#### Hello, Input (Date/Time)!
|
1258
1507
|
|
1259
1508
|
Glimmer GUI code:
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.8
|
data/glimmer-dsl-web.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: glimmer-dsl-web 0.0.
|
5
|
+
# stub: glimmer-dsl-web 0.0.8 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "glimmer-dsl-web".freeze
|
9
|
-
s.version = "0.0.
|
9
|
+
s.version = "0.0.8".freeze
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib".freeze]
|
13
13
|
s.authors = ["Andy Maleh".freeze]
|
14
|
-
s.date = "2024-01-
|
14
|
+
s.date = "2024-01-03"
|
15
15
|
s.description = "Glimmer DSL for Web (Ruby in the Browser Web GUI Frontend Library) - Enables frontend GUI development with Ruby by adopting a DSL that follows web-like HTML syntax, enabling the transfer of HTML/CSS/JS skills to Ruby frontend development. This library relies on Opal Ruby.".freeze
|
16
16
|
s.email = "andy.am@gmail.com".freeze
|
17
17
|
s.extra_rdoc_files = [
|
@@ -31,6 +31,7 @@ Gem::Specification.new do |s|
|
|
31
31
|
"lib/glimmer-dsl-web/ext/date.rb",
|
32
32
|
"lib/glimmer-dsl-web/ext/exception.rb",
|
33
33
|
"lib/glimmer-dsl-web/samples/hello/hello_button.rb",
|
34
|
+
"lib/glimmer-dsl-web/samples/hello/hello_content_data_binding.rb",
|
34
35
|
"lib/glimmer-dsl-web/samples/hello/hello_data_binding.rb",
|
35
36
|
"lib/glimmer-dsl-web/samples/hello/hello_form.rb",
|
36
37
|
"lib/glimmer-dsl-web/samples/hello/hello_input_date_time.rb",
|
@@ -39,6 +40,7 @@ Gem::Specification.new do |s|
|
|
39
40
|
"lib/glimmer/config/opal_logger.rb",
|
40
41
|
"lib/glimmer/data_binding/element_binding.rb",
|
41
42
|
"lib/glimmer/dsl/web/bind_expression.rb",
|
43
|
+
"lib/glimmer/dsl/web/content_data_binding_expression.rb",
|
42
44
|
"lib/glimmer/dsl/web/data_binding_expression.rb",
|
43
45
|
"lib/glimmer/dsl/web/dsl.rb",
|
44
46
|
"lib/glimmer/dsl/web/element_expression.rb",
|
@@ -61,10 +63,13 @@ Gem::Specification.new do |s|
|
|
61
63
|
|
62
64
|
s.specification_version = 4
|
63
65
|
|
64
|
-
s.add_runtime_dependency(%q<glimmer>.freeze, ["~> 2.
|
66
|
+
s.add_runtime_dependency(%q<glimmer>.freeze, ["~> 2.7.6".freeze])
|
65
67
|
s.add_runtime_dependency(%q<glimmer-dsl-xml>.freeze, ["~> 1.3.2".freeze])
|
66
68
|
s.add_runtime_dependency(%q<glimmer-dsl-css>.freeze, ["~> 1.2.2".freeze])
|
69
|
+
s.add_runtime_dependency(%q<opal>.freeze, ["= 1.4.1".freeze])
|
70
|
+
s.add_runtime_dependency(%q<opal-rails>.freeze, ["= 2.0.2".freeze])
|
67
71
|
s.add_runtime_dependency(%q<opal-async>.freeze, ["~> 1.4.0".freeze])
|
72
|
+
s.add_runtime_dependency(%q<opal-jquery>.freeze, ["~> 0.4.6".freeze])
|
68
73
|
s.add_runtime_dependency(%q<to_collection>.freeze, [">= 2.0.1".freeze, "< 3.0.0".freeze])
|
69
74
|
s.add_development_dependency(%q<puts_debuggerer>.freeze, [">= 0".freeze])
|
70
75
|
s.add_development_dependency(%q<rake>.freeze, [">= 10.1.0".freeze, "< 14.0.0".freeze])
|
@@ -72,7 +77,5 @@ Gem::Specification.new do |s|
|
|
72
77
|
s.add_development_dependency(%q<jeweler>.freeze, [">= 2.3.9".freeze, "< 3.0.0".freeze])
|
73
78
|
s.add_development_dependency(%q<rdoc>.freeze, [">= 6.2.1".freeze, "< 7.0.0".freeze])
|
74
79
|
s.add_development_dependency(%q<opal-rspec>.freeze, ["~> 0.8.0.alpha2".freeze])
|
75
|
-
s.add_development_dependency(%q<opal-rails>.freeze, ["~> 1.1.2".freeze])
|
76
|
-
s.add_development_dependency(%q<opal-jquery>.freeze, ["~> 0.4.4".freeze])
|
77
80
|
end
|
78
81
|
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# Copyright (c) 2023-2024 Andy Maleh
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
# a copy of this software and associated documentation files (the
|
5
|
+
# "Software"), to deal in the Software without restriction, including
|
6
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
# the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be
|
12
|
+
# included in all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
22
|
+
require 'glimmer/dsl/expression'
|
23
|
+
|
24
|
+
module Glimmer
|
25
|
+
module DSL
|
26
|
+
module Web
|
27
|
+
class ContentDataBindingExpression < Expression
|
28
|
+
def can_interpret?(parent, keyword, *args, &block)
|
29
|
+
keyword == 'content' &&
|
30
|
+
block_given? &&
|
31
|
+
args.size > 0 &&
|
32
|
+
parent&.respond_to?(:bind_content)
|
33
|
+
end
|
34
|
+
|
35
|
+
def interpret(parent, keyword, *args, &block)
|
36
|
+
parent.bind_content(*args, &block)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/glimmer/dsl/web/dsl.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'glimmer/dsl/engine'
|
2
|
-
# Dir[File.expand_path('../*_expression.rb', __FILE__)].each {|f| require f}
|
3
2
|
require 'glimmer/dsl/web/element_expression'
|
4
3
|
require 'glimmer/dsl/web/listener_expression'
|
5
4
|
require 'glimmer/dsl/web/property_expression'
|
@@ -7,25 +6,19 @@ require 'glimmer/dsl/web/p_expression'
|
|
7
6
|
require 'glimmer/dsl/web/select_expression'
|
8
7
|
require 'glimmer/dsl/web/bind_expression'
|
9
8
|
require 'glimmer/dsl/web/data_binding_expression'
|
9
|
+
require 'glimmer/dsl/web/content_data_binding_expression'
|
10
10
|
require 'glimmer/dsl/web/shine_data_binding_expression'
|
11
11
|
|
12
12
|
module Glimmer
|
13
13
|
module DSL
|
14
14
|
module Web
|
15
|
-
# TODO implement all those expressions
|
16
|
-
# %w[
|
17
|
-
# listener
|
18
|
-
# data_binding
|
19
|
-
# property
|
20
|
-
# shine_data_binding
|
21
|
-
# element
|
22
|
-
# ]
|
23
15
|
Engine.add_dynamic_expressions(
|
24
16
|
Web,
|
25
17
|
%w[
|
26
18
|
listener
|
27
19
|
data_binding
|
28
20
|
property
|
21
|
+
content_data_binding
|
29
22
|
shine_data_binding
|
30
23
|
element
|
31
24
|
]
|
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'glimmer/dsl/expression'
|
2
2
|
require 'glimmer/dsl/web/general_element_expression'
|
3
3
|
|
4
|
+
require 'glimmer/web/element_proxy'
|
5
|
+
|
4
6
|
module Glimmer
|
5
7
|
module DSL
|
6
8
|
module Web
|
@@ -8,9 +10,7 @@ module Glimmer
|
|
8
10
|
include GeneralElementExpression
|
9
11
|
|
10
12
|
def can_interpret?(parent, keyword, *args, &block)
|
11
|
-
|
12
|
-
# TODO raise a proper error if root is an element that is not found (maybe do this in model)
|
13
|
-
!keyword.to_s.start_with?('on')
|
13
|
+
Glimmer::Web::ElementProxy.keyword_supported?(keyword)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
@@ -25,6 +25,10 @@ module Glimmer
|
|
25
25
|
module Web
|
26
26
|
class ElementProxy
|
27
27
|
class << self
|
28
|
+
def keyword_supported?(keyword)
|
29
|
+
ELEMENT_KEYWORDS.include?(keyword.to_s)
|
30
|
+
end
|
31
|
+
|
28
32
|
# Factory Method that translates a Glimmer DSL keyword into a ElementProxy object
|
29
33
|
def for(keyword, parent, args, block)
|
30
34
|
element_type(keyword).new(keyword, parent, args, block)
|
@@ -67,7 +71,28 @@ module Glimmer
|
|
67
71
|
|
68
72
|
Event = Struct.new(:widget, keyword_init: true)
|
69
73
|
|
74
|
+
ELEMENT_KEYWORDS = [
|
75
|
+
"a", "abbr", "acronym", "address", "applet", "area", "article", "aside", "audio", "b",
|
76
|
+
"base", "basefont", "bdi", "bdo", "bgsound", "big", "blink", "blockquote", "body", "br",
|
77
|
+
"button", "canvas", "caption", "center", "cite", "code", "col", "colgroup", "content", "data",
|
78
|
+
"datalist", "dd", "decorator", "del", "details", "dfn", "dir", "div", "dl", "dt",
|
79
|
+
"element", "em", "embed", "fieldset", "figcaption", "figure", "font", "footer", "form", "frame",
|
80
|
+
"frameset", "h1", "h2", "h3", "h4", "h5", "h6", "head", "header", "hgroup",
|
81
|
+
"hr", "html", "i", "iframe", "img", "input", "ins", "isindex", "kbd", "keygen",
|
82
|
+
"label", "legend", "li", "link", "listing", "main", "map", "mark", "marquee", "menu",
|
83
|
+
"menuitem", "meta", "meter", "nav", "nobr", "noframes", "noscript", "object", "ol", "optgroup",
|
84
|
+
"option", "output", "p", "param", "plaintext", "pre", "progress", "q", "rp", "rt",
|
85
|
+
"ruby", "s", "samp", "script", "section", "select", "shadow", "small", "source", "spacer",
|
86
|
+
"span", "strike", "strong", "style", "sub", "summary", "sup", "table", "tbody", "td",
|
87
|
+
"template", "textarea", "tfoot", "th", "thead", "time", "title", "tr", "track", "tt",
|
88
|
+
"u", "ul", "var", "video", "wbr", "xmp",
|
89
|
+
]
|
90
|
+
|
70
91
|
GLIMMER_ATTRIBUTES = [:parent]
|
92
|
+
PROPERTY_ALIASES = {
|
93
|
+
'inner_html' => 'innerHTML',
|
94
|
+
'outer_html' => 'outerHTML',
|
95
|
+
}
|
71
96
|
FORMAT_DATETIME = '%Y-%m-%dT%H:%M'
|
72
97
|
FORMAT_DATE = '%Y-%m-%d'
|
73
98
|
FORMAT_TIME = '%H:%M'
|
@@ -123,6 +148,11 @@ module Glimmer
|
|
123
148
|
listeners.each do |event, event_listeners|
|
124
149
|
event_listeners.dup.each(&:unregister)
|
125
150
|
end
|
151
|
+
listeners.clear
|
152
|
+
data_bindings.each do |element_binding, model_binding|
|
153
|
+
element_binding.unregister_all_observables
|
154
|
+
end
|
155
|
+
data_bindings.clear
|
126
156
|
end
|
127
157
|
|
128
158
|
# Subclasses can override with their own selector
|
@@ -423,6 +453,10 @@ module Glimmer
|
|
423
453
|
event_listener_proxies.clear
|
424
454
|
end
|
425
455
|
|
456
|
+
def data_bindings
|
457
|
+
@data_bindings ||= {}
|
458
|
+
end
|
459
|
+
|
426
460
|
def data_bind(property, model_binding)
|
427
461
|
element_binding_translator = value_converters_for_input_type(type)[:model_to_view]
|
428
462
|
element_binding_parameters = [self, property, element_binding_translator]
|
@@ -430,6 +464,7 @@ module Glimmer
|
|
430
464
|
element_binding.call(model_binding.evaluate_property)
|
431
465
|
#TODO make this options observer dependent and all similar observers in element specific data binding handlers
|
432
466
|
element_binding.observe(model_binding)
|
467
|
+
data_bindings[element_binding] = model_binding
|
433
468
|
unless model_binding.binding_options[:read_only]
|
434
469
|
# TODO add guards against nil cases for hash below
|
435
470
|
listener_keyword = data_binding_listener_for_element_and_property(keyword, property)
|
@@ -444,19 +479,36 @@ module Glimmer
|
|
444
479
|
end
|
445
480
|
end
|
446
481
|
|
482
|
+
# Data-binds the generation of nested content to a model/property (in binding args)
|
483
|
+
# consider providing an option to avoid initial rendering without any changes happening
|
484
|
+
def bind_content(*binding_args, &content_block)
|
485
|
+
# TODO in the future, consider optimizing code by diffing content if that makes sense
|
486
|
+
content_binding_work = proc do |*values|
|
487
|
+
children.dup.each { |child| child.remove }
|
488
|
+
content(&content_block)
|
489
|
+
end
|
490
|
+
content_binding_observer = Glimmer::DataBinding::Observer.proc(&content_binding_work)
|
491
|
+
content_binding_observer.observe(*binding_args)
|
492
|
+
content_binding_work.call # TODO inspect if we need to pass args here (from observed attributes) [but it's simpler not to pass anything at first]
|
493
|
+
end
|
494
|
+
|
447
495
|
def respond_to_missing?(method_name, include_private = false)
|
448
496
|
# TODO consider doing more correct checking of availability of properties/methods using native `` ticks
|
449
497
|
property_name = property_name_for(method_name)
|
498
|
+
unnormalized_property_name = unnormalized_property_name_for(method_name)
|
450
499
|
super(method_name, include_private) ||
|
451
500
|
(dom_element && dom_element.length > 0 && Native.call(dom_element, '0').respond_to?(method_name.to_s.camelcase, include_private)) ||
|
501
|
+
(dom_element && dom_element.length > 0 && Native.call(dom_element, '0').respond_to?(method_name.to_s, include_private)) ||
|
452
502
|
dom_element.respond_to?(method_name, include_private) ||
|
453
503
|
(!dom_element.prop(property_name).nil? && !dom_element.prop(property_name).is_a?(Proc)) ||
|
504
|
+
(!dom_element.prop(unnormalized_property_name).nil? && !dom_element.prop(unnormalized_property_name).is_a?(Proc)) ||
|
454
505
|
method_name.to_s.start_with?('on_')
|
455
506
|
end
|
456
507
|
|
457
508
|
def method_missing(method_name, *args, &block)
|
458
509
|
# TODO consider doing more correct checking of availability of properties/methods using native `` ticks
|
459
510
|
property_name = property_name_for(method_name)
|
511
|
+
unnormalized_property_name = unnormalized_property_name_for(method_name)
|
460
512
|
if method_name.to_s.start_with?('on_')
|
461
513
|
handle_observation_request(method_name, block)
|
462
514
|
elsif dom_element.respond_to?(method_name)
|
@@ -467,12 +519,22 @@ module Glimmer
|
|
467
519
|
else
|
468
520
|
dom_element.prop(property_name)
|
469
521
|
end
|
522
|
+
elsif !dom_element.prop(unnormalized_property_name).nil? && !dom_element.prop(unnormalized_property_name).is_a?(Proc)
|
523
|
+
if method_name.end_with?('=')
|
524
|
+
dom_element.prop(unnormalized_property_name, *args)
|
525
|
+
else
|
526
|
+
dom_element.prop(unnormalized_property_name)
|
527
|
+
end
|
470
528
|
elsif dom_element && dom_element.length > 0
|
529
|
+
js_args = block.nil? ? args : (args + [block])
|
471
530
|
begin
|
472
|
-
js_args = block.nil? ? args : (args + [block])
|
473
531
|
Native.call(dom_element, '0').method_missing(method_name.to_s.camelcase, *js_args)
|
474
532
|
rescue Exception => e
|
475
|
-
|
533
|
+
begin
|
534
|
+
Native.call(dom_element, '0').method_missing(method_name.to_s, *js_args)
|
535
|
+
rescue Exception => e
|
536
|
+
super(method_name, *args, &block)
|
537
|
+
end
|
476
538
|
end
|
477
539
|
else
|
478
540
|
super(method_name, *args, &block)
|
@@ -480,7 +542,12 @@ module Glimmer
|
|
480
542
|
end
|
481
543
|
|
482
544
|
def property_name_for(method_name)
|
483
|
-
method_name.end_with?('=') ? method_name.to_s[0...-1]
|
545
|
+
attribute_name = method_name.end_with?('=') ? method_name.to_s[0...-1] : method_name.to_s
|
546
|
+
PROPERTY_ALIASES[attribute_name] || attribute_name.camelcase
|
547
|
+
end
|
548
|
+
|
549
|
+
def unnormalized_property_name_for(method_name)
|
550
|
+
method_name.end_with?('=') ? method_name.to_s[0...-1] : method_name.to_s
|
484
551
|
end
|
485
552
|
|
486
553
|
def swt_widget
|
@@ -34,7 +34,6 @@ module Glimmer
|
|
34
34
|
@selector = selector
|
35
35
|
@listener = listener
|
36
36
|
@js_listener = lambda do |js_event|
|
37
|
-
# TODO wrap event with a Ruby Event object before passing to listener
|
38
37
|
event = EventProxy.new(js_event: js_event, listener: self)
|
39
38
|
result = listener.call(event)
|
40
39
|
result = true if result.nil?
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# Copyright (c) 2023-2024 Andy Maleh
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
# a copy of this software and associated documentation files (the
|
5
|
+
# "Software"), to deal in the Software without restriction, including
|
6
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
# the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be
|
12
|
+
# included in all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
22
|
+
require 'glimmer-dsl-web'
|
23
|
+
|
24
|
+
class Address
|
25
|
+
attr_accessor :text
|
26
|
+
attr_reader :name, :street, :city, :state, :zip
|
27
|
+
|
28
|
+
def name=(value)
|
29
|
+
@name = value
|
30
|
+
update_text
|
31
|
+
end
|
32
|
+
|
33
|
+
def street=(value)
|
34
|
+
@street = value
|
35
|
+
update_text
|
36
|
+
end
|
37
|
+
|
38
|
+
def city=(value)
|
39
|
+
@city = value
|
40
|
+
update_text
|
41
|
+
end
|
42
|
+
|
43
|
+
def state=(value)
|
44
|
+
@state = value
|
45
|
+
update_text
|
46
|
+
end
|
47
|
+
|
48
|
+
def zip=(value)
|
49
|
+
@zip = value
|
50
|
+
update_text
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def update_text
|
56
|
+
self.text = [name, street, city, state, zip].compact.reject(&:empty?).join(', ')
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class User
|
61
|
+
attr_accessor :addresses
|
62
|
+
attr_reader :address_count
|
63
|
+
|
64
|
+
def initialize
|
65
|
+
@address_count = 1
|
66
|
+
@addresses = []
|
67
|
+
update_addresses
|
68
|
+
end
|
69
|
+
|
70
|
+
def address_count=(value)
|
71
|
+
value = [[1, value.to_i].max, 3].min
|
72
|
+
@address_count = value
|
73
|
+
update_addresses
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def update_addresses
|
79
|
+
address_count_change = address_count - addresses.size
|
80
|
+
if address_count_change > 0
|
81
|
+
address_count_change.times { addresses << Address.new }
|
82
|
+
else
|
83
|
+
address_count_change.abs.times { addresses.pop }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
@user = User.new
|
89
|
+
|
90
|
+
div {
|
91
|
+
div {
|
92
|
+
label('Number of addresses: ', for: 'address-count-field')
|
93
|
+
input(id: 'address-count-field', type: 'number', min: 1, max: 3) {
|
94
|
+
value <=> [@user, :address_count]
|
95
|
+
}
|
96
|
+
}
|
97
|
+
|
98
|
+
div {
|
99
|
+
# Content Data-Binding is used to dynamically (re)generate content of div
|
100
|
+
# based on changes to @user.addresses, replacing older content on every change
|
101
|
+
content(@user, :addresses) do
|
102
|
+
@user.addresses.each do |address|
|
103
|
+
div {
|
104
|
+
div(style: 'display: grid; grid-auto-columns: 80px 280px;') { |address_div|
|
105
|
+
[:name, :street, :city, :state, :zip].each do |attribute|
|
106
|
+
label(attribute.to_s.capitalize, for: "#{attribute}-field")
|
107
|
+
input(id: "#{attribute}-field", type: 'text') {
|
108
|
+
value <=> [address, attribute]
|
109
|
+
}
|
110
|
+
end
|
111
|
+
|
112
|
+
div(style: 'grid-column: 1 / span 2;') {
|
113
|
+
inner_text <= [address, :text]
|
114
|
+
}
|
115
|
+
|
116
|
+
style {
|
117
|
+
<<~CSS
|
118
|
+
#{address_div.selector} {
|
119
|
+
margin: 10px 0;
|
120
|
+
}
|
121
|
+
#{address_div.selector} * {
|
122
|
+
margin: 5px;
|
123
|
+
}
|
124
|
+
#{address_div.selector} label {
|
125
|
+
grid-column: 1;
|
126
|
+
}
|
127
|
+
#{address_div.selector} input, #{address_div.selector} select {
|
128
|
+
grid-column: 2;
|
129
|
+
}
|
130
|
+
CSS
|
131
|
+
}
|
132
|
+
}
|
133
|
+
}
|
134
|
+
end
|
135
|
+
end
|
136
|
+
}
|
137
|
+
}.render
|
data/lib/glimmer-dsl-web.rb
CHANGED
@@ -26,7 +26,11 @@ GLIMMER_DSL_OPAL_LIB = File.join(GLIMMER_DSL_OPAL_ROOT, 'lib')
|
|
26
26
|
|
27
27
|
$LOAD_PATH.unshift(GLIMMER_DSL_OPAL_LIB)
|
28
28
|
|
29
|
-
if RUBY_ENGINE
|
29
|
+
if RUBY_ENGINE != 'opal'
|
30
|
+
require 'opal-rails'
|
31
|
+
require 'opal-async'
|
32
|
+
require 'opal-jquery'
|
33
|
+
else
|
30
34
|
# GLIMMER_DSL_OPAL_MISSING = File.join(GLIMMER_DSL_OPAL_ROOT, 'lib', 'glimmer-dsl-opal', 'missing')
|
31
35
|
|
32
36
|
# $LOAD_PATH.unshift(GLIMMER_DSL_OPAL_MISSING) # missing Ruby classes/methods
|
@@ -75,7 +79,7 @@ if RUBY_ENGINE == 'opal'
|
|
75
79
|
require 'glimmer-dsl-xml'
|
76
80
|
require 'glimmer-dsl-css'
|
77
81
|
|
78
|
-
Glimmer::Config.loop_max_count =
|
82
|
+
Glimmer::Config.loop_max_count = 50 # TODO consider disabling if preferred
|
79
83
|
|
80
84
|
original_logger_level = Glimmer::Config.logger.level
|
81
85
|
Glimmer::Config.logger = Glimmer::Config::OpalLogger.new(STDOUT)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: glimmer-dsl-web
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andy Maleh
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-01-
|
11
|
+
date: 2024-01-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: glimmer
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 2.
|
19
|
+
version: 2.7.6
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 2.
|
26
|
+
version: 2.7.6
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: glimmer-dsl-xml
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,6 +52,34 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: 1.2.2
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: opal
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.4.1
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 1.4.1
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: opal-rails
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 2.0.2
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 2.0.2
|
55
83
|
- !ruby/object:Gem::Dependency
|
56
84
|
name: opal-async
|
57
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,6 +94,20 @@ dependencies:
|
|
66
94
|
- - "~>"
|
67
95
|
- !ruby/object:Gem::Version
|
68
96
|
version: 1.4.0
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: opal-jquery
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 0.4.6
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 0.4.6
|
69
111
|
- !ruby/object:Gem::Dependency
|
70
112
|
name: to_collection
|
71
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -188,34 +230,6 @@ dependencies:
|
|
188
230
|
- - "~>"
|
189
231
|
- !ruby/object:Gem::Version
|
190
232
|
version: 0.8.0.alpha2
|
191
|
-
- !ruby/object:Gem::Dependency
|
192
|
-
name: opal-rails
|
193
|
-
requirement: !ruby/object:Gem::Requirement
|
194
|
-
requirements:
|
195
|
-
- - "~>"
|
196
|
-
- !ruby/object:Gem::Version
|
197
|
-
version: 1.1.2
|
198
|
-
type: :development
|
199
|
-
prerelease: false
|
200
|
-
version_requirements: !ruby/object:Gem::Requirement
|
201
|
-
requirements:
|
202
|
-
- - "~>"
|
203
|
-
- !ruby/object:Gem::Version
|
204
|
-
version: 1.1.2
|
205
|
-
- !ruby/object:Gem::Dependency
|
206
|
-
name: opal-jquery
|
207
|
-
requirement: !ruby/object:Gem::Requirement
|
208
|
-
requirements:
|
209
|
-
- - "~>"
|
210
|
-
- !ruby/object:Gem::Version
|
211
|
-
version: 0.4.4
|
212
|
-
type: :development
|
213
|
-
prerelease: false
|
214
|
-
version_requirements: !ruby/object:Gem::Requirement
|
215
|
-
requirements:
|
216
|
-
- - "~>"
|
217
|
-
- !ruby/object:Gem::Version
|
218
|
-
version: 0.4.4
|
219
233
|
description: Glimmer DSL for Web (Ruby in the Browser Web GUI Frontend Library) -
|
220
234
|
Enables frontend GUI development with Ruby by adopting a DSL that follows web-like
|
221
235
|
HTML syntax, enabling the transfer of HTML/CSS/JS skills to Ruby frontend development.
|
@@ -239,6 +253,7 @@ files:
|
|
239
253
|
- lib/glimmer-dsl-web/ext/date.rb
|
240
254
|
- lib/glimmer-dsl-web/ext/exception.rb
|
241
255
|
- lib/glimmer-dsl-web/samples/hello/hello_button.rb
|
256
|
+
- lib/glimmer-dsl-web/samples/hello/hello_content_data_binding.rb
|
242
257
|
- lib/glimmer-dsl-web/samples/hello/hello_data_binding.rb
|
243
258
|
- lib/glimmer-dsl-web/samples/hello/hello_form.rb
|
244
259
|
- lib/glimmer-dsl-web/samples/hello/hello_input_date_time.rb
|
@@ -247,6 +262,7 @@ files:
|
|
247
262
|
- lib/glimmer/config/opal_logger.rb
|
248
263
|
- lib/glimmer/data_binding/element_binding.rb
|
249
264
|
- lib/glimmer/dsl/web/bind_expression.rb
|
265
|
+
- lib/glimmer/dsl/web/content_data_binding_expression.rb
|
250
266
|
- lib/glimmer/dsl/web/data_binding_expression.rb
|
251
267
|
- lib/glimmer/dsl/web/dsl.rb
|
252
268
|
- lib/glimmer/dsl/web/element_expression.rb
|