glimmer-dsl-web 0.0.4 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
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