glimmer-dsl-web 0.0.2 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|