glimmer-dsl-web 0.0.2 → 0.0.4
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 +14 -1
- data/README.md +472 -31
- data/VERSION +1 -1
- data/glimmer-dsl-web.gemspec +9 -5
- data/lib/glimmer/dsl/web/dsl.rb +6 -2
- data/lib/glimmer/dsl/web/element_expression.rb +2 -2
- data/lib/glimmer/dsl/web/listener_expression.rb +19 -0
- data/lib/glimmer/dsl/web/property_expression.rb +23 -0
- data/lib/glimmer/util/proc_tracker.rb +1 -1
- data/lib/glimmer/web/element_proxy.rb +118 -82
- data/lib/glimmer/web/listener_proxy.rb +39 -0
- data/lib/glimmer/web.rb +1 -1
- data/lib/glimmer-dsl-web/samples/hello/hello_button.rb +99 -0
- data/lib/glimmer-dsl-web/samples/hello/hello_world.rb +1 -1
- data/lib/glimmer-dsl-web.rb +1 -1
- metadata +11 -7
data/glimmer-dsl-web.gemspec
CHANGED
@@ -2,17 +2,17 @@
|
|
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.4 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.4".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 = "2023-12-
|
15
|
-
s.description = "Glimmer DSL for Web (Ruby in the Browser Web GUI 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
|
14
|
+
s.date = "2023-12-30"
|
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 = [
|
18
18
|
"CHANGELOG.md",
|
@@ -30,6 +30,7 @@ Gem::Specification.new do |s|
|
|
30
30
|
"lib/glimmer-dsl-web/ext/class.rb",
|
31
31
|
"lib/glimmer-dsl-web/ext/date.rb",
|
32
32
|
"lib/glimmer-dsl-web/ext/exception.rb",
|
33
|
+
"lib/glimmer-dsl-web/samples/hello/hello_button.rb",
|
33
34
|
"lib/glimmer-dsl-web/samples/hello/hello_world.rb",
|
34
35
|
"lib/glimmer-dsl-web/vendor/jquery.js",
|
35
36
|
"lib/glimmer/config/opal_logger.rb",
|
@@ -37,15 +38,18 @@ Gem::Specification.new do |s|
|
|
37
38
|
"lib/glimmer/data_binding/observable_element.rb",
|
38
39
|
"lib/glimmer/dsl/web/dsl.rb",
|
39
40
|
"lib/glimmer/dsl/web/element_expression.rb",
|
41
|
+
"lib/glimmer/dsl/web/listener_expression.rb",
|
42
|
+
"lib/glimmer/dsl/web/property_expression.rb",
|
40
43
|
"lib/glimmer/util/proc_tracker.rb",
|
41
44
|
"lib/glimmer/web.rb",
|
42
45
|
"lib/glimmer/web/element_proxy.rb",
|
46
|
+
"lib/glimmer/web/listener_proxy.rb",
|
43
47
|
"lib/glimmer/web/property_owner.rb"
|
44
48
|
]
|
45
49
|
s.homepage = "http://github.com/AndyObtiva/glimmer-dsl-web".freeze
|
46
50
|
s.licenses = ["MIT".freeze]
|
47
51
|
s.rubygems_version = "3.5.3".freeze
|
48
|
-
s.summary = "Glimmer DSL for Web".freeze
|
52
|
+
s.summary = "Glimmer DSL for Web (Ruby in the Browser Web GUI Frontend Library)".freeze
|
49
53
|
|
50
54
|
s.specification_version = 4
|
51
55
|
|
data/lib/glimmer/dsl/web/dsl.rb
CHANGED
@@ -1,21 +1,25 @@
|
|
1
1
|
require 'glimmer/dsl/engine'
|
2
2
|
# Dir[File.expand_path('../*_expression.rb', __FILE__)].each {|f| require f}
|
3
3
|
require 'glimmer/dsl/web/element_expression'
|
4
|
+
require 'glimmer/dsl/web/listener_expression'
|
5
|
+
require 'glimmer/dsl/web/property_expression'
|
4
6
|
|
5
7
|
module Glimmer
|
6
8
|
module DSL
|
7
9
|
module Web
|
8
10
|
# TODO implement all those expressions
|
9
11
|
# %w[
|
10
|
-
#
|
12
|
+
# listener
|
11
13
|
# data_binding
|
12
|
-
#
|
14
|
+
# property
|
13
15
|
# shine_data_binding
|
14
16
|
# element
|
15
17
|
# ]
|
16
18
|
Engine.add_dynamic_expressions(
|
17
19
|
Web,
|
18
20
|
%w[
|
21
|
+
listener
|
22
|
+
property
|
19
23
|
element
|
20
24
|
]
|
21
25
|
)
|
@@ -11,7 +11,7 @@ module Glimmer
|
|
11
11
|
def can_interpret?(parent, keyword, *args, &block)
|
12
12
|
# TODO automatically pass parent option as element if not passed instead of rejecting elements without a paraent nor root
|
13
13
|
# TODO raise a proper error if root is an element that is not found (maybe do this in model)
|
14
|
-
|
14
|
+
!keyword.to_s.start_with?('on_')
|
15
15
|
end
|
16
16
|
|
17
17
|
def interpret(parent, keyword, *args, &block)
|
@@ -21,7 +21,7 @@ module Glimmer
|
|
21
21
|
def add_content(parent, keyword, *args, &block)
|
22
22
|
if parent.rendered? || parent.skip_content_on_render_blocks?
|
23
23
|
return_value = super(parent, keyword, *args, &block)
|
24
|
-
if return_value.is_a?(String)
|
24
|
+
if return_value.is_a?(String) && parent.dom_element.text.to_s.empty?
|
25
25
|
parent.add_text_content(return_value)
|
26
26
|
end
|
27
27
|
parent.post_add_content
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'glimmer/dsl/expression'
|
2
|
+
|
3
|
+
module Glimmer
|
4
|
+
module DSL
|
5
|
+
module Web
|
6
|
+
class ListenerExpression < Expression
|
7
|
+
def can_interpret?(parent, keyword, *args, &block)
|
8
|
+
parent and
|
9
|
+
parent.respond_to?(:can_handle_observation_request?) and
|
10
|
+
parent.can_handle_observation_request?(keyword)
|
11
|
+
end
|
12
|
+
|
13
|
+
def interpret(parent, keyword, *args, &block)
|
14
|
+
parent.handle_observation_request(keyword, block)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'glimmer/dsl/expression'
|
2
|
+
|
3
|
+
require 'glimmer/web/element_proxy'
|
4
|
+
|
5
|
+
module Glimmer
|
6
|
+
module DSL
|
7
|
+
module Web
|
8
|
+
class PropertyExpression < Expression
|
9
|
+
def can_interpret?(parent, keyword, *args, &block)
|
10
|
+
parent.is_a?(Glimmer::Web::ElementProxy) and
|
11
|
+
(!args.empty?) and
|
12
|
+
parent.respond_to?("#{keyword}=") and
|
13
|
+
block.nil?
|
14
|
+
end
|
15
|
+
|
16
|
+
def interpret(parent, keyword, *args, &block)
|
17
|
+
parent.send("#{keyword}=", *args)
|
18
|
+
args
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c)
|
1
|
+
# Copyright (c) 2023 Andy Maleh
|
2
2
|
#
|
3
3
|
# Permission is hereby granted, free of charge, to any person obtaining
|
4
4
|
# a copy of this software and associated documentation files (the
|
@@ -21,6 +21,7 @@
|
|
21
21
|
|
22
22
|
# require 'glimmer/web/event_listener_proxy'
|
23
23
|
require 'glimmer/web/property_owner'
|
24
|
+
require 'glimmer/web/listener_proxy'
|
24
25
|
|
25
26
|
# TODO implement menu (which delays building it till render using add_content_on_render)
|
26
27
|
|
@@ -68,9 +69,11 @@ module Glimmer
|
|
68
69
|
|
69
70
|
include Glimmer
|
70
71
|
include PropertyOwner
|
71
|
-
|
72
|
+
|
72
73
|
Event = Struct.new(:widget, keyword_init: true)
|
73
|
-
|
74
|
+
|
75
|
+
GLIMMER_ATTRIBUTES = [:parent]
|
76
|
+
|
74
77
|
attr_reader :keyword, :parent, :args, :options, :children, :enabled, :foreground, :background, :focus, :removed?, :rendered
|
75
78
|
alias rendered? rendered
|
76
79
|
|
@@ -92,7 +95,7 @@ module Glimmer
|
|
92
95
|
|
93
96
|
# Executes for the parent of a child that just got removed
|
94
97
|
def post_remove_child(child)
|
95
|
-
@children
|
98
|
+
@children.delete(child)
|
96
99
|
end
|
97
100
|
|
98
101
|
# Executes at the closing of a parent widget curly braces after all children/properties have been added/set
|
@@ -105,26 +108,19 @@ module Glimmer
|
|
105
108
|
end
|
106
109
|
|
107
110
|
def remove
|
111
|
+
@children.dup.each do |child|
|
112
|
+
child.remove
|
113
|
+
end
|
108
114
|
remove_all_listeners
|
109
115
|
dom_element.remove
|
110
116
|
parent&.post_remove_child(self)
|
111
|
-
# children.each(:remove) # TODO enable this safely
|
112
117
|
@removed = true
|
113
|
-
|
118
|
+
# listeners_for('widget_removed').each {|listener| listener.call(Event.new(widget: self))}
|
114
119
|
end
|
115
120
|
|
116
121
|
def remove_all_listeners
|
117
|
-
|
118
|
-
|
119
|
-
observation_requests[keyword].to_a.each do |event_listener|
|
120
|
-
event = mapping[:event]
|
121
|
-
event_handler = mapping[:event_handler]
|
122
|
-
event_element_css_selector = mapping[:event_element_css_selector]
|
123
|
-
the_listener_dom_element = event_element_css_selector ? Element[event_element_css_selector] : listener_dom_element
|
124
|
-
the_listener_dom_element.off(event, event_listener)
|
125
|
-
# TODO improve to precisely remove the listeners that were added, no more no less. (or use the event_listener_proxies method instead or in collaboration)
|
126
|
-
end
|
127
|
-
end
|
122
|
+
listeners.each do |event, event_listeners|
|
123
|
+
event_listeners.dup.each(&:unregister)
|
128
124
|
end
|
129
125
|
end
|
130
126
|
|
@@ -198,6 +194,7 @@ module Glimmer
|
|
198
194
|
if parent_selector
|
199
195
|
Document.find(parent_selector)
|
200
196
|
else
|
197
|
+
# TODO consider moving this to initializer
|
201
198
|
options[:parent] ||= 'body'
|
202
199
|
Document.find(options[:parent])
|
203
200
|
end
|
@@ -240,7 +237,7 @@ module Glimmer
|
|
240
237
|
end
|
241
238
|
|
242
239
|
def add_text_content(text)
|
243
|
-
dom_element.append(text)
|
240
|
+
dom_element.append(text.to_s)
|
244
241
|
end
|
245
242
|
|
246
243
|
def content_on_render_blocks
|
@@ -263,33 +260,31 @@ module Glimmer
|
|
263
260
|
# TODO consider passing parent element instead and having table item include a table cell widget only for opal
|
264
261
|
@dom = nil
|
265
262
|
@dom = dom # TODO unify how to build dom for most widgets based on element, id, and name (class)
|
266
|
-
@dom = @parent.get_layout.dom(@dom) if @parent.respond_to?(:layout) && @parent.get_layout
|
267
263
|
@dom
|
268
264
|
end
|
269
265
|
|
270
266
|
def dom
|
271
|
-
body_class = ([name, element_id] + css_classes.to_a).join(' ')
|
272
267
|
# TODO auto-convert known glimmer attributes like parent to data attributes like data-parent
|
273
|
-
html_options = options.dup
|
274
|
-
html_options[:class] ||= ''
|
275
|
-
html_options[:class] = "#{html_options[:class]} #{body_class}".strip
|
276
268
|
@dom ||= html {
|
277
269
|
send(keyword, html_options) {
|
278
|
-
|
279
|
-
# style(class: 'common-style') {
|
280
|
-
# style_dom_css
|
281
|
-
# }
|
282
|
-
# [LayoutProxy, WidgetProxy].map(&:descendants).reduce(:+).each do |style_class|
|
283
|
-
# if style_class.constants.include?('STYLE')
|
284
|
-
# style(class: "#{style_class.name.split(':').last.underscore.gsub('_', '-').sub(/-proxy$/, '')}-style") {
|
285
|
-
# style_class::STYLE
|
286
|
-
# }
|
287
|
-
# end
|
288
|
-
# end
|
270
|
+
args.first if args.first.is_a?(String)
|
289
271
|
}
|
290
272
|
}.to_s
|
291
273
|
end
|
292
274
|
|
275
|
+
def html_options
|
276
|
+
body_class = ([name, element_id] + css_classes.to_a).join(' ')
|
277
|
+
html_options = options.dup
|
278
|
+
GLIMMER_ATTRIBUTES.each do |attribute|
|
279
|
+
next unless html_options.include?(attribute)
|
280
|
+
data_normalized_attribute = attribute.split('_').join('-')
|
281
|
+
html_options["data-#{data_normalized_attribute}"] = html_options.delete(attribute)
|
282
|
+
end
|
283
|
+
html_options[:class] ||= ''
|
284
|
+
html_options[:class] = "#{html_options[:class]} #{body_class}".strip
|
285
|
+
html_options
|
286
|
+
end
|
287
|
+
|
293
288
|
def content(&block)
|
294
289
|
Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::Web::ElementExpression.new, keyword, &block)
|
295
290
|
end
|
@@ -745,58 +740,70 @@ module Glimmer
|
|
745
740
|
listeners[listener_event.to_s] ||= []
|
746
741
|
end
|
747
742
|
|
748
|
-
def can_handle_observation_request?(
|
743
|
+
def can_handle_observation_request?(keyword)
|
749
744
|
# TODO sort this out for Opal
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
#
|
756
|
-
#
|
757
|
-
|
758
|
-
|
745
|
+
keyword = keyword.to_s
|
746
|
+
keyword.start_with?('on_')
|
747
|
+
# if keyword.start_with?('on_swt_')
|
748
|
+
# constant_name = keyword.sub(/^on_swt_/, '')
|
749
|
+
# SWTProxy.has_constant?(constant_name)
|
750
|
+
# elsif keyword.start_with?('on_')
|
751
|
+
# # event = keyword.sub(/^on_/, '')
|
752
|
+
# # can_add_listener?(event) || can_handle_drag_observation_request?(keyword) || can_handle_drop_observation_request?(keyword)
|
753
|
+
# true # TODO filter by valid listeners only in the future
|
754
|
+
# end
|
759
755
|
end
|
760
756
|
|
761
757
|
def handle_observation_request(keyword, original_event_listener)
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
758
|
+
# case keyword
|
759
|
+
# when 'on_widget_removed'
|
760
|
+
# listeners_for(keyword.sub(/^on_/, '')) << original_event_listener.to_proc
|
761
|
+
# else
|
766
762
|
handle_javascript_observation_request(keyword, original_event_listener)
|
767
|
-
|
763
|
+
# end
|
768
764
|
end
|
769
765
|
|
770
766
|
def handle_javascript_observation_request(keyword, original_event_listener)
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
#
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
#
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
767
|
+
listener = ListenerProxy.new(
|
768
|
+
element_proxy: self,
|
769
|
+
selector: selector,
|
770
|
+
dom_element: dom_element,
|
771
|
+
event: keyword.sub(/^on_/, ''),
|
772
|
+
listener: original_event_listener,
|
773
|
+
original_event_listener: original_event_listener
|
774
|
+
)
|
775
|
+
listener.register
|
776
|
+
listeners_for(keyword) << listener
|
777
|
+
listener
|
778
|
+
# return unless effective_observation_request_to_event_mapping.keys.include?(keyword)
|
779
|
+
# event = nil
|
780
|
+
# delegate = nil
|
781
|
+
# effective_observation_request_to_event_mapping[keyword].to_collection.each do |mapping|
|
782
|
+
# observation_requests[keyword] ||= Set.new
|
783
|
+
# observation_requests[keyword] << original_event_listener
|
784
|
+
# event = mapping[:event]
|
785
|
+
# event_handler = mapping[:event_handler]
|
786
|
+
# event_element_css_selector = mapping[:event_element_css_selector]
|
787
|
+
# potential_event_listener = event_handler&.call(original_event_listener)
|
788
|
+
# event_listener = potential_event_listener || original_event_listener
|
789
|
+
# async_event_listener = proc do |event|
|
790
|
+
## TODO look into the issue with using async::task.new here. maybe put it in event listener (like not being able to call preventDefault or return false successfully )
|
791
|
+
## maybe consider pushing inside the widget classes instead where needed only or implement universal doit support correctly to bypass this issue
|
792
|
+
## Async::Task.new do
|
793
|
+
# @@widget_handling_listener = self
|
794
|
+
## TODO also make sure to disable all widgets for suspension
|
795
|
+
# event_listener.call(event) unless dialog_ancestor&.event_handling_suspended?
|
796
|
+
# @widget_handling_listener = nil
|
797
|
+
## end
|
798
|
+
# end
|
799
|
+
# the_listener_dom_element = event_element_css_selector ? Element[event_element_css_selector] : listener_dom_element
|
800
|
+
# unless the_listener_dom_element.empty?
|
801
|
+
# the_listener_dom_element.on(event, &async_event_listener)
|
802
|
+
## TODO ensure uniqueness of insertion (perhaps adding equals/hash method to event listener proxy)
|
803
|
+
#
|
804
|
+
# event_listener_proxies << EventListenerProxy.new(element_proxy: self, selector: selector, dom_element: the_listener_dom_element, event: event, listener: async_event_listener, original_event_listener: original_event_listener)
|
805
|
+
# end
|
806
|
+
# end
|
800
807
|
end
|
801
808
|
|
802
809
|
def remove_event_listener_proxies
|
@@ -819,14 +826,43 @@ module Glimmer
|
|
819
826
|
super(attribute_name, *args) # PropertyOwner
|
820
827
|
end
|
821
828
|
|
822
|
-
def
|
823
|
-
|
824
|
-
|
829
|
+
def respond_to_missing?(method_name, include_private = false)
|
830
|
+
property_name = property_name_for(method_name)
|
831
|
+
super(method_name, include_private) ||
|
832
|
+
(dom_element && dom_element.length > 0 && Native.call(dom_element, '0').respond_to?(method_name.to_s.camelcase, include_private)) ||
|
833
|
+
dom_element.respond_to?(method_name, include_private) ||
|
834
|
+
(!dom_element.prop(property_name).nil? && !dom_element.prop(property_name).is_a?(Proc)) ||
|
835
|
+
method_name.to_s.start_with?('on_')
|
836
|
+
end
|
837
|
+
|
838
|
+
def method_missing(method_name, *args, &block)
|
839
|
+
property_name = property_name_for(method_name)
|
840
|
+
if method_name.to_s.start_with?('on_')
|
841
|
+
handle_observation_request(method_name, block)
|
842
|
+
elsif dom_element.respond_to?(method_name)
|
843
|
+
dom_element.send(method_name, *args, &block)
|
844
|
+
elsif !dom_element.prop(property_name).nil? && !dom_element.prop(property_name).is_a?(Proc)
|
845
|
+
if method_name.end_with?('=')
|
846
|
+
dom_element.prop(property_name, *args)
|
847
|
+
else
|
848
|
+
dom_element.prop(property_name)
|
849
|
+
end
|
850
|
+
elsif dom_element && dom_element.length > 0
|
851
|
+
begin
|
852
|
+
js_args = block.nil? ? args : (args + [block])
|
853
|
+
Native.call(dom_element, '0').method_missing(method_name.to_s.camelcase, *js_args)
|
854
|
+
rescue Exception => e
|
855
|
+
super(method_name, *args, &block)
|
856
|
+
end
|
825
857
|
else
|
826
|
-
super(
|
858
|
+
super(method_name, *args, &block)
|
827
859
|
end
|
828
860
|
end
|
829
861
|
|
862
|
+
def property_name_for(method_name)
|
863
|
+
method_name.end_with?('=') ? method_name.to_s[0...-1].camelcase : method_name.to_s.camelcase
|
864
|
+
end
|
865
|
+
|
830
866
|
def swt_widget
|
831
867
|
# only added for compatibility/adaptibility with Glimmer DSL for SWT
|
832
868
|
self
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Glimmer
|
2
|
+
module Web
|
3
|
+
class ListenerProxy
|
4
|
+
attr_reader :element_proxy, :event, :dom_element, :selector, :listener, :original_event_listener
|
5
|
+
|
6
|
+
def initialize(element_proxy:, event:, dom_element:, selector:, listener:)
|
7
|
+
@element_proxy = element_proxy
|
8
|
+
@event = event
|
9
|
+
@dom_element = dom_element
|
10
|
+
@selector = selector
|
11
|
+
@listener = listener
|
12
|
+
@js_listener = lambda do |event|
|
13
|
+
event.prevent
|
14
|
+
event.prevent_default
|
15
|
+
event.stop_propagation
|
16
|
+
event.stop_immediate_propagation
|
17
|
+
# TODO wrap event with a Ruby Event object before passing to listener
|
18
|
+
listener.call(event)
|
19
|
+
false
|
20
|
+
end
|
21
|
+
@original_event_listener = original_event_listener
|
22
|
+
end
|
23
|
+
|
24
|
+
def register
|
25
|
+
@dom_element.on(@event, &@js_listener)
|
26
|
+
end
|
27
|
+
alias observe register
|
28
|
+
alias reregister register
|
29
|
+
|
30
|
+
def unregister
|
31
|
+
# TODO contribute fix to opal to allow passing observer with & to off with selector not specified as nil
|
32
|
+
@dom_element.off(@event, @js_listener)
|
33
|
+
@element_proxy.listeners_for(@event).delete(self)
|
34
|
+
end
|
35
|
+
alias unobserve unregister
|
36
|
+
alias deregister unregister
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/glimmer/web.rb
CHANGED
@@ -0,0 +1,99 @@
|
|
1
|
+
# Copyright (c) 2023 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
|
+
include Glimmer
|
25
|
+
|
26
|
+
Document.ready? do
|
27
|
+
div {
|
28
|
+
h1('Contact Form')
|
29
|
+
form {
|
30
|
+
div(class: 'field-row') {
|
31
|
+
label('Name: ', for: 'name-field')
|
32
|
+
@name_input = input(id: 'name-field', class: 'field', type: 'text', required: true)
|
33
|
+
}
|
34
|
+
div(class: 'field-row') {
|
35
|
+
label('Email: ', for: 'email-field')
|
36
|
+
@email_input = input(id: 'email-field', class: 'field', type: 'email', required: true)
|
37
|
+
}
|
38
|
+
button('Add Contact', class: 'submit-button') {
|
39
|
+
on_click do
|
40
|
+
if ([@name_input, @email_input].all? {|input| input.check_validity })
|
41
|
+
@table.content {
|
42
|
+
tr {
|
43
|
+
td { @name_input.value }
|
44
|
+
td { @email_input.value }
|
45
|
+
}
|
46
|
+
}
|
47
|
+
@email_input.value = @name_input.value = ''
|
48
|
+
else
|
49
|
+
error_messages = []
|
50
|
+
error_messages << "Name is not valid! Make sure it is filled." if !@name_input.check_validity
|
51
|
+
error_messages << "Email is not valid! Make sure it is filled and has a valid format." if !@email_input.check_validity
|
52
|
+
$$.alert(error_messages.join("\n"))
|
53
|
+
end
|
54
|
+
end
|
55
|
+
}
|
56
|
+
}
|
57
|
+
h1('Contacts Table')
|
58
|
+
@table = table {
|
59
|
+
tr {
|
60
|
+
th('Name')
|
61
|
+
th('Email')
|
62
|
+
}
|
63
|
+
tr {
|
64
|
+
td('John Doe')
|
65
|
+
td('johndoe@example.com')
|
66
|
+
}
|
67
|
+
tr {
|
68
|
+
td('Jane Doe')
|
69
|
+
td('janedoe@example.com')
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
# CSS Styles
|
74
|
+
style {
|
75
|
+
<<~CSS
|
76
|
+
.field-row {
|
77
|
+
margin: 10px 5px;
|
78
|
+
}
|
79
|
+
.field {
|
80
|
+
margin-left: 5px;
|
81
|
+
}
|
82
|
+
.submit-button {
|
83
|
+
display: block;
|
84
|
+
margin: 10px 5px;
|
85
|
+
}
|
86
|
+
table {
|
87
|
+
border:1px solid grey;
|
88
|
+
border-spacing: 0;
|
89
|
+
}
|
90
|
+
table tr td, table tr th {
|
91
|
+
padding: 5px;
|
92
|
+
}
|
93
|
+
table tr:nth-child(even) {
|
94
|
+
background: #ccc;
|
95
|
+
}
|
96
|
+
CSS
|
97
|
+
}
|
98
|
+
}.render
|
99
|
+
end
|
data/lib/glimmer-dsl-web.rb
CHANGED
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.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andy Maleh
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-12-
|
11
|
+
date: 2023-12-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: glimmer
|
@@ -236,10 +236,10 @@ dependencies:
|
|
236
236
|
- - "~>"
|
237
237
|
- !ruby/object:Gem::Version
|
238
238
|
version: 0.4.4
|
239
|
-
description: Glimmer DSL for Web (Ruby in the Browser Web GUI Library) -
|
240
|
-
GUI development with Ruby by adopting a DSL that follows web-like
|
241
|
-
the transfer of HTML/CSS/JS skills to Ruby frontend development.
|
242
|
-
on Opal Ruby.
|
239
|
+
description: Glimmer DSL for Web (Ruby in the Browser Web GUI Frontend Library) -
|
240
|
+
Enables frontend GUI development with Ruby by adopting a DSL that follows web-like
|
241
|
+
HTML syntax, enabling the transfer of HTML/CSS/JS skills to Ruby frontend development.
|
242
|
+
This library relies on Opal Ruby.
|
243
243
|
email: andy.am@gmail.com
|
244
244
|
executables: []
|
245
245
|
extensions: []
|
@@ -258,6 +258,7 @@ files:
|
|
258
258
|
- lib/glimmer-dsl-web/ext/class.rb
|
259
259
|
- lib/glimmer-dsl-web/ext/date.rb
|
260
260
|
- lib/glimmer-dsl-web/ext/exception.rb
|
261
|
+
- lib/glimmer-dsl-web/samples/hello/hello_button.rb
|
261
262
|
- lib/glimmer-dsl-web/samples/hello/hello_world.rb
|
262
263
|
- lib/glimmer-dsl-web/vendor/jquery.js
|
263
264
|
- lib/glimmer/config/opal_logger.rb
|
@@ -265,9 +266,12 @@ files:
|
|
265
266
|
- lib/glimmer/data_binding/observable_element.rb
|
266
267
|
- lib/glimmer/dsl/web/dsl.rb
|
267
268
|
- lib/glimmer/dsl/web/element_expression.rb
|
269
|
+
- lib/glimmer/dsl/web/listener_expression.rb
|
270
|
+
- lib/glimmer/dsl/web/property_expression.rb
|
268
271
|
- lib/glimmer/util/proc_tracker.rb
|
269
272
|
- lib/glimmer/web.rb
|
270
273
|
- lib/glimmer/web/element_proxy.rb
|
274
|
+
- lib/glimmer/web/listener_proxy.rb
|
271
275
|
- lib/glimmer/web/property_owner.rb
|
272
276
|
homepage: http://github.com/AndyObtiva/glimmer-dsl-web
|
273
277
|
licenses:
|
@@ -291,5 +295,5 @@ requirements: []
|
|
291
295
|
rubygems_version: 3.5.3
|
292
296
|
signing_key:
|
293
297
|
specification_version: 4
|
294
|
-
summary: Glimmer DSL for Web
|
298
|
+
summary: Glimmer DSL for Web (Ruby in the Browser Web GUI Frontend Library)
|
295
299
|
test_files: []
|