glimmer-dsl-web 0.0.4 → 0.0.6

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.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.4
1
+ 0.0.6
@@ -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.4 ruby lib
5
+ # stub: glimmer-dsl-web 0.0.6 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "glimmer-dsl-web".freeze
9
- s.version = "0.0.4".freeze
9
+ s.version = "0.0.6".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-30"
14
+ s.date = "2024-01-01"
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,18 +31,26 @@ 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_data_binding.rb",
35
+ "lib/glimmer-dsl-web/samples/hello/hello_form.rb",
34
36
  "lib/glimmer-dsl-web/samples/hello/hello_world.rb",
35
37
  "lib/glimmer-dsl-web/vendor/jquery.js",
36
38
  "lib/glimmer/config/opal_logger.rb",
37
39
  "lib/glimmer/data_binding/element_binding.rb",
38
- "lib/glimmer/data_binding/observable_element.rb",
40
+ "lib/glimmer/dsl/web/bind_expression.rb",
41
+ "lib/glimmer/dsl/web/data_binding_expression.rb",
39
42
  "lib/glimmer/dsl/web/dsl.rb",
40
43
  "lib/glimmer/dsl/web/element_expression.rb",
44
+ "lib/glimmer/dsl/web/general_element_expression.rb",
41
45
  "lib/glimmer/dsl/web/listener_expression.rb",
46
+ "lib/glimmer/dsl/web/p_expression.rb",
42
47
  "lib/glimmer/dsl/web/property_expression.rb",
48
+ "lib/glimmer/dsl/web/select_expression.rb",
49
+ "lib/glimmer/dsl/web/shine_data_binding_expression.rb",
43
50
  "lib/glimmer/util/proc_tracker.rb",
44
51
  "lib/glimmer/web.rb",
45
52
  "lib/glimmer/web/element_proxy.rb",
53
+ "lib/glimmer/web/event_proxy.rb",
46
54
  "lib/glimmer/web/listener_proxy.rb",
47
55
  "lib/glimmer/web/property_owner.rb"
48
56
  ]
@@ -58,7 +66,6 @@ Gem::Specification.new do |s|
58
66
  s.add_runtime_dependency(%q<glimmer-dsl-css>.freeze, ["~> 1.2.2".freeze])
59
67
  s.add_runtime_dependency(%q<opal-async>.freeze, ["~> 1.4.0".freeze])
60
68
  s.add_runtime_dependency(%q<to_collection>.freeze, [">= 2.0.1".freeze, "< 3.0.0".freeze])
61
- s.add_runtime_dependency(%q<pure-struct>.freeze, [">= 1.0.2".freeze, "< 2.0.0".freeze])
62
69
  s.add_development_dependency(%q<puts_debuggerer>.freeze, [">= 0".freeze])
63
70
  s.add_development_dependency(%q<rake>.freeze, [">= 10.1.0".freeze, "< 14.0.0".freeze])
64
71
  s.add_development_dependency(%q<rake-tui>.freeze, [">= 0".freeze])
@@ -4,7 +4,6 @@ require 'glimmer/data_binding/observer'
4
4
  module Glimmer
5
5
  module DataBinding
6
6
  class ElementBinding
7
- # TODO consider renaming to WidgetBinding since it's no longer dealing with elements directly yet widgets instead
8
7
  include Glimmer
9
8
  include Observable
10
9
  include Observer
@@ -15,7 +14,8 @@ module Glimmer
15
14
  @property = property
16
15
  @translator = translator || proc {|value| value}
17
16
 
18
- # TODO see if this is needed in Opal
17
+ # TODO implement automatic cleanup upon calling element.remove
18
+ # Alternatively, have this be built into ElementProxy and remove this code
19
19
  # if @element.respond_to?(:dispose)
20
20
  # @element.on_widget_disposed do |dispose_event|
21
21
  # unregister_all_observables
@@ -25,7 +25,7 @@ module Glimmer
25
25
 
26
26
  def call(value)
27
27
  converted_value = translated_value = @translator.call(value)
28
- @element.set_attribute(@property, converted_value) unless evaluate_property == converted_value
28
+ @element.send("#{@property}=", converted_value) unless evaluate_property == converted_value
29
29
  end
30
30
 
31
31
  def evaluate_property
@@ -0,0 +1,36 @@
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/static_expression'
23
+ require 'glimmer/dsl/bind_expression'
24
+ require 'glimmer/data_binding/model_binding'
25
+
26
+ module Glimmer
27
+ module DSL
28
+ module Web
29
+ # Responsible for setting up the return value of the bind keyword (command symbol)
30
+ # as a ModelBinding. It is then used by other data-binding expressions
31
+ class BindExpression < StaticExpression
32
+ include Glimmer::DSL::BindExpression
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,30 @@
1
+ require 'glimmer/dsl/expression'
2
+ require 'glimmer/data_binding/model_binding'
3
+ require 'glimmer/data_binding/element_binding'
4
+
5
+ module Glimmer
6
+ module DSL
7
+ module Web
8
+ # Responsible for wiring two-way data-binding for text and selection properties
9
+ # on Text, Button, and Spinner elements.
10
+ # Does so by using the output of the bind(model, property) command in the form
11
+ # of a ModelBinding, which is then connected to an anonymous element observer
12
+ # (aka element_data_binder as per element_data_binders array)
13
+ #
14
+ # Depends on BindCommandHandler
15
+ class DataBindingExpression < Expression
16
+ def can_interpret?(parent, keyword, *args, &block)
17
+ args.size == 1 and
18
+ args[0].is_a?(DataBinding::ModelBinding) and
19
+ parent.respond_to?(:data_bind)
20
+ end
21
+
22
+ def interpret(parent, keyword, *args, &block)
23
+ model_binding = args[0]
24
+ property = keyword
25
+ parent.data_bind(property, model_binding)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -3,6 +3,11 @@ require 'glimmer/dsl/engine'
3
3
  require 'glimmer/dsl/web/element_expression'
4
4
  require 'glimmer/dsl/web/listener_expression'
5
5
  require 'glimmer/dsl/web/property_expression'
6
+ require 'glimmer/dsl/web/p_expression'
7
+ require 'glimmer/dsl/web/select_expression'
8
+ require 'glimmer/dsl/web/bind_expression'
9
+ require 'glimmer/dsl/web/data_binding_expression'
10
+ require 'glimmer/dsl/web/shine_data_binding_expression'
6
11
 
7
12
  module Glimmer
8
13
  module DSL
@@ -19,7 +24,9 @@ module Glimmer
19
24
  Web,
20
25
  %w[
21
26
  listener
27
+ data_binding
22
28
  property
29
+ shine_data_binding
23
30
  element
24
31
  ]
25
32
  )
@@ -1,34 +1,16 @@
1
1
  require 'glimmer/dsl/expression'
2
- require 'glimmer/dsl/parent_expression'
3
- require 'glimmer/web/element_proxy'
2
+ require 'glimmer/dsl/web/general_element_expression'
4
3
 
5
4
  module Glimmer
6
5
  module DSL
7
6
  module Web
8
7
  class ElementExpression < Expression
9
- include ParentExpression
8
+ include GeneralElementExpression
10
9
 
11
10
  def can_interpret?(parent, keyword, *args, &block)
12
11
  # TODO automatically pass parent option as element if not passed instead of rejecting elements without a paraent nor root
13
12
  # TODO raise a proper error if root is an element that is not found (maybe do this in model)
14
- !keyword.to_s.start_with?('on_')
15
- end
16
-
17
- def interpret(parent, keyword, *args, &block)
18
- Glimmer::Web::ElementProxy.for(keyword, parent, args, block)
19
- end
20
-
21
- def add_content(parent, keyword, *args, &block)
22
- if parent.rendered? || parent.skip_content_on_render_blocks?
23
- return_value = super(parent, keyword, *args, &block)
24
- if return_value.is_a?(String) && parent.dom_element.text.to_s.empty?
25
- parent.add_text_content(return_value)
26
- end
27
- parent.post_add_content
28
- return_value
29
- else
30
- parent.add_content_on_render(&block)
31
- end
13
+ !keyword.to_s.start_with?('on')
32
14
  end
33
15
  end
34
16
  end
@@ -0,0 +1,29 @@
1
+ require 'glimmer/dsl/parent_expression'
2
+ require 'glimmer/web/element_proxy'
3
+
4
+ module Glimmer
5
+ module DSL
6
+ module Web
7
+ module GeneralElementExpression
8
+ include ParentExpression
9
+
10
+ def interpret(parent, keyword, *args, &block)
11
+ Glimmer::Web::ElementProxy.for(keyword, parent, args, block)
12
+ end
13
+
14
+ def add_content(parent, keyword, *args, &block)
15
+ if parent.rendered? || parent.skip_content_on_render_blocks?
16
+ return_value = super(parent, keyword, *args, &block)
17
+ if return_value.is_a?(String) && parent.dom_element.text.to_s.empty?
18
+ parent.add_text_content(return_value)
19
+ end
20
+ parent.post_add_content
21
+ return_value
22
+ else
23
+ parent.add_content_on_render(&block)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,12 @@
1
+ require 'glimmer/dsl/static_expression'
2
+ require 'glimmer/dsl/web/general_element_expression'
3
+
4
+ module Glimmer
5
+ module DSL
6
+ module Web
7
+ class PExpression < StaticExpression
8
+ include GeneralElementExpression
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ require 'glimmer/dsl/static_expression'
2
+ require 'glimmer/dsl/web/general_element_expression'
3
+
4
+ module Glimmer
5
+ module DSL
6
+ module Web
7
+ class SelectExpression < StaticExpression
8
+ include GeneralElementExpression
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,42 @@
1
+ # Copyright (c) 2020-2022 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
+ require 'glimmer/data_binding/model_binding'
24
+ require 'glimmer/data_binding/shine'
25
+
26
+ module Glimmer
27
+ module DSL
28
+ module Web
29
+ class ShineDataBindingExpression < Expression
30
+ def can_interpret?(parent, keyword, *args, &block)
31
+ args.size == 0 and
32
+ block.nil? and
33
+ (parent.respond_to?("#{keyword}=") and parent.respond_to?(keyword))
34
+ end
35
+
36
+ def interpret(parent, keyword, *args, &block)
37
+ Glimmer::DataBinding::Shine.new(parent, keyword)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -74,7 +74,7 @@ module Glimmer
74
74
 
75
75
  GLIMMER_ATTRIBUTES = [:parent]
76
76
 
77
- attr_reader :keyword, :parent, :args, :options, :children, :enabled, :foreground, :background, :focus, :removed?, :rendered
77
+ attr_reader :keyword, :parent, :args, :options, :children, :enabled, :foreground, :background, :removed?, :rendered
78
78
  alias rendered? rendered
79
79
 
80
80
  def initialize(keyword, parent, args, block)
@@ -176,16 +176,6 @@ module Glimmer
176
176
  dom_element.css('background-color', background.to_css) unless background.nil?
177
177
  end
178
178
 
179
- def focus=(value)
180
- @focus = value
181
- dom_element.focus # TODO consider if a delay or async_exec is needed here
182
- end
183
-
184
- def set_focus
185
- self.focus = true
186
- end
187
- alias setFocus set_focus
188
-
189
179
  def parent_selector
190
180
  @parent&.selector
191
181
  end
@@ -196,7 +186,9 @@ module Glimmer
196
186
  else
197
187
  # TODO consider moving this to initializer
198
188
  options[:parent] ||= 'body'
199
- Document.find(options[:parent])
189
+ the_element = Document.find(options[:parent])
190
+ the_element = Document.find('body') if the_element.length == 0
191
+ the_element
200
192
  end
201
193
  end
202
194
 
@@ -226,7 +218,7 @@ module Glimmer
226
218
  end
227
219
  end
228
220
  end
229
- alias redraw render
221
+ alias rerender render
230
222
 
231
223
  def attach(the_parent_dom_element)
232
224
  the_parent_dom_element.append(@dom)
@@ -743,7 +735,7 @@ module Glimmer
743
735
  def can_handle_observation_request?(keyword)
744
736
  # TODO sort this out for Opal
745
737
  keyword = keyword.to_s
746
- keyword.start_with?('on_')
738
+ keyword.start_with?('on')
747
739
  # if keyword.start_with?('on_swt_')
748
740
  # constant_name = keyword.sub(/^on_swt_/, '')
749
741
  # SWTProxy.has_constant?(constant_name)
@@ -765,10 +757,10 @@ module Glimmer
765
757
 
766
758
  def handle_javascript_observation_request(keyword, original_event_listener)
767
759
  listener = ListenerProxy.new(
768
- element_proxy: self,
760
+ element: self,
769
761
  selector: selector,
770
762
  dom_element: dom_element,
771
- event: keyword.sub(/^on_/, ''),
763
+ event_attribute: keyword,
772
764
  listener: original_event_listener,
773
765
  original_event_listener: original_event_listener
774
766
  )
@@ -813,11 +805,19 @@ module Glimmer
813
805
  event_listener_proxies.clear
814
806
  end
815
807
 
816
- def add_observer(observer, property_name)
817
- property_listener_installers = self.class&.ancestors&.to_a.map {|ancestor| widget_property_listener_installers[ancestor]}.compact
818
- widget_listener_installers = property_listener_installers.map{|installer| installer[property_name.to_s.to_sym]}.compact if !property_listener_installers.empty?
819
- widget_listener_installers.to_a.each do |widget_listener_installer|
820
- widget_listener_installer.call(observer)
808
+ def data_bind(property, model_binding)
809
+ element_binding_parameters = [self, property]
810
+ element_binding = DataBinding::ElementBinding.new(*element_binding_parameters)
811
+ element_binding.call(model_binding.evaluate_property)
812
+ #TODO make this options observer dependent and all similar observers in element specific data binding handlers
813
+ element_binding.observe(model_binding)
814
+ unless model_binding.binding_options[:read_only]
815
+ # TODO add guards against nil cases for hash below
816
+ listener_keyword = data_binding_element_keyword_to_property_listener_map[keyword][property]
817
+ data_binding_read_listener = lambda do |event|
818
+ model_binding.call(send(property))
819
+ end
820
+ handle_observation_request(listener_keyword, data_binding_read_listener)
821
821
  end
822
822
  end
823
823
 
@@ -827,6 +827,7 @@ module Glimmer
827
827
  end
828
828
 
829
829
  def respond_to_missing?(method_name, include_private = false)
830
+ # TODO consider doing more correct checking of availability of properties/methods using native `` ticks
830
831
  property_name = property_name_for(method_name)
831
832
  super(method_name, include_private) ||
832
833
  (dom_element && dom_element.length > 0 && Native.call(dom_element, '0').respond_to?(method_name.to_s.camelcase, include_private)) ||
@@ -836,6 +837,7 @@ module Glimmer
836
837
  end
837
838
 
838
839
  def method_missing(method_name, *args, &block)
840
+ # TODO consider doing more correct checking of availability of properties/methods using native `` ticks
839
841
  property_name = property_name_for(method_name)
840
842
  if method_name.to_s.start_with?('on_')
841
843
  handle_observation_request(method_name, block)
@@ -931,144 +933,17 @@ module Glimmer
931
933
  }
932
934
  end
933
935
 
934
- def widget_property_listener_installers
935
- @swt_widget_property_listener_installers ||= {
936
- # WidgetProxy => {
937
- # :focus => proc do |observer|
938
- # on_focus_gained { |focus_event|
939
- # observer.call(true)
940
- # }
941
- # on_focus_lost { |focus_event|
942
- # observer.call(false)
943
- # }
944
- # end,
945
- # },
946
- MenuItemProxy => {
947
- :selection => proc do |observer|
948
- on_widget_selected { |selection_event|
949
- # TODO look into validity of this and perhaps move toggle logic to MenuItemProxy
950
- if check?
951
- observer.call(!selection)
952
- else
953
- observer.call(selection)
954
- end
955
- }
956
- end
957
- },
958
- ScaleProxy => {
959
- :selection => proc do |observer|
960
- on_widget_selected { |selection_event|
961
- observer.call(selection)
962
- }
963
- end
964
- },
965
- SliderProxy => {
966
- :selection => proc do |observer|
967
- on_widget_selected { |selection_event|
968
- observer.call(selection)
969
- }
970
- end
936
+ def data_binding_element_keyword_to_property_listener_map
937
+ @data_binding_element_keyword_to_property_listener_map ||= {
938
+ 'input' => {
939
+ 'value' => 'oninput',
971
940
  },
972
- SpinnerProxy => {
973
- :selection => proc do |observer|
974
- on_widget_selected { |selection_event|
975
- observer.call(selection)
976
- }
977
- end
941
+ 'select' => {
942
+ 'value' => 'onchange',
978
943
  },
979
- TextProxy => {
980
- :text => proc do |observer|
981
- on_modify_text { |modify_event|
982
- observer.call(text)
983
- }
984
- end,
985
- # :caret_position => proc do |observer|
986
- # on_event_keydown { |event|
987
- # observer.call(getCaretPosition)
988
- # }
989
- # on_event_keyup { |event|
990
- # observer.call(getCaretPosition)
991
- # }
992
- # on_event_mousedown { |event|
993
- # observer.call(getCaretPosition)
994
- # }
995
- # on_event_mouseup { |event|
996
- # observer.call(getCaretPosition)
997
- # }
998
- # end,
999
- # :selection => proc do |observer|
1000
- # on_event_keydown { |event|
1001
- # observer.call(getSelection)
1002
- # }
1003
- # on_event_keyup { |event|
1004
- # observer.call(getSelection)
1005
- # }
1006
- # on_event_mousedown { |event|
1007
- # observer.call(getSelection)
1008
- # }
1009
- # on_event_mouseup { |event|
1010
- # observer.call(getSelection)
1011
- # }
1012
- # end,
1013
- # :selection_count => proc do |observer|
1014
- # on_event_keydown { |event|
1015
- # observer.call(getSelectionCount)
1016
- # }
1017
- # on_event_keyup { |event|
1018
- # observer.call(getSelectionCount)
1019
- # }
1020
- # on_event_mousedown { |event|
1021
- # observer.call(getSelectionCount)
1022
- # }
1023
- # on_event_mouseup { |event|
1024
- # observer.call(getSelectionCount)
1025
- # }
1026
- # end,
1027
- # :top_index => proc do |observer|
1028
- # @last_top_index = getTopIndex
1029
- # on_paint_control { |event|
1030
- # if getTopIndex != @last_top_index
1031
- # @last_top_index = getTopIndex
1032
- # observer.call(@last_top_index)
1033
- # end
1034
- # }
1035
- # end,
1036
- },
1037
- # Java::OrgEclipseSwtCustom::StyledText => {
1038
- # :text => proc do |observer|
1039
- # on_modify_text { |modify_event|
1040
- # observer.call(getText)
1041
- # }
1042
- # end,
1043
- # },
1044
- DateTimeProxy => {
1045
- :date_time => proc do |observer|
1046
- on_widget_selected { |selection_event|
1047
- observer.call(date_time)
1048
- }
1049
- end
944
+ 'textarea' => {
945
+ 'value' => 'oninput',
1050
946
  },
1051
- RadioProxy => { #radio?
1052
- :selection => proc do |observer|
1053
- on_widget_selected { |selection_event|
1054
- observer.call(selection)
1055
- }
1056
- end
1057
- },
1058
- TableProxy => {
1059
- :selection => proc do |observer|
1060
- on_widget_selected { |selection_event|
1061
- observer.call(selection_event.table_item.get_data) # TODO ensure selection doesn't conflict with editing
1062
- }
1063
- end,
1064
- },
1065
- # Java::OrgEclipseSwtWidgets::MenuItem => {
1066
- # :selection => proc do |observer|
1067
- # on_widget_selected { |selection_event|
1068
- # observer.call(getSelection)
1069
- # }
1070
- # end
1071
- # },
1072
947
  }
1073
948
  end
1074
949
 
@@ -0,0 +1,59 @@
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
+ module Glimmer
23
+ module Web
24
+ class EventProxy
25
+ attr_reader :js_event, :listener
26
+
27
+ def initialize(js_event:, listener:)
28
+ @js_event = js_event
29
+ @listener = listener
30
+ end
31
+
32
+ def element = listener.element
33
+ def event_name = listener.event_name
34
+ def event_attribute = listener.event_attribute
35
+
36
+ def original_event
37
+ Native(`#{js_event.to_n}.originalEvent`)
38
+ end
39
+
40
+ def respond_to_missing?(method_name, include_private = false)
41
+ property_name = method_name.to_s.camelcase
42
+ super(method_name, include_private) ||
43
+ js_event.respond_to?(method_name, include_private) ||
44
+ `#{property_name} in #{original_event.to_n}`
45
+ end
46
+
47
+ def method_missing(method_name, *args, &block)
48
+ property_name = method_name.to_s.camelcase
49
+ if js_event.respond_to?(method_name, true)
50
+ js_event.send(method_name, *args, &block)
51
+ elsif `#{property_name} in #{original_event.to_n}`
52
+ original_event[property_name]
53
+ else
54
+ super(method_name, *args, &block)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end