netzke-core 0.12.3 → 1.0.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/CHANGELOG.md +65 -607
  2. data/Gemfile +1 -1
  3. data/LICENSE +2 -6
  4. data/README.md +77 -145
  5. data/javascripts/base.js +582 -96
  6. data/javascripts/core.js +62 -0
  7. data/javascripts/notifications.js +43 -0
  8. data/javascripts/remoting_provider.js +29 -0
  9. data/javascripts/routing.js +63 -0
  10. data/lib/netzke/base.rb +16 -83
  11. data/lib/netzke/core/action_config.rb +1 -5
  12. data/lib/netzke/core/actions.rb +59 -21
  13. data/lib/netzke/core/{client_class.rb → client_class_config.rb} +81 -73
  14. data/lib/netzke/core/client_code.rb +157 -0
  15. data/lib/netzke/core/component_config.rb +2 -2
  16. data/lib/netzke/core/composition.rb +85 -65
  17. data/lib/netzke/core/configuration.rb +26 -14
  18. data/lib/netzke/core/core_i18n.rb +17 -0
  19. data/lib/netzke/core/css_config.rb +6 -6
  20. data/lib/netzke/core/dynamic_assets.rb +17 -24
  21. data/lib/netzke/core/embedding.rb +2 -2
  22. data/lib/netzke/core/endpoint_response.rb +8 -2
  23. data/lib/netzke/core/inheritance.rb +33 -0
  24. data/lib/netzke/core/plugins.rb +1 -4
  25. data/lib/netzke/core/railz/action_view_ext.rb +1 -1
  26. data/lib/netzke/core/railz/controller_extensions.rb +21 -15
  27. data/lib/netzke/core/services.rb +61 -48
  28. data/lib/netzke/core/session.rb +0 -2
  29. data/lib/netzke/core/state.rb +11 -9
  30. data/lib/netzke/core/stylesheets.rb +3 -3
  31. data/lib/netzke/core/version.rb +1 -1
  32. data/lib/netzke/core.rb +3 -3
  33. data/lib/netzke/plugin.rb +2 -6
  34. data/stylesheets/core.css +2 -2
  35. metadata +11 -10
  36. data/TODO.md +0 -9
  37. data/javascripts/ext.js +0 -518
  38. data/lib/netzke/core/config_to_dsl_delegator.rb +0 -62
  39. data/lib/netzke/core/dsl_support.rb +0 -70
  40. data/lib/netzke/core/html.rb +0 -29
  41. data/lib/netzke/core/javascript.rb +0 -123
@@ -5,7 +5,7 @@ module Netzke::Core
5
5
  # class_attribute :title
6
6
  # self.title = "Title for all descendants of MyComponent"
7
7
  #
8
- # js_configure do |c|
8
+ # client_class do |c|
9
9
  # c.title = title
10
10
  # end
11
11
  # end
@@ -28,14 +28,30 @@ module Netzke::Core
28
28
  # config.enable_awesome_feature = true
29
29
  # end
30
30
  module ClassMethods
31
+ # Do class-level config of a component, e.g.:
32
+ #
33
+ # Netzke::Basepack::GridPanel.setup do |c|
34
+ # c.rows_reordering_available = false
35
+ # end
31
36
  def setup
32
37
  yield self
33
38
  end
34
39
 
35
40
  # An array of server class config options that should not be passed to the client class. Can be overridden.
36
41
  def server_side_config_options
37
- [:eager_loading, :klass, :client_config]
42
+ [:klass, :client_config]
38
43
  end
44
+
45
+ # Instance of component by config
46
+ def instance_by_config(config)
47
+ klass = config[:klass] || config[:class_name].constantize
48
+ klass.new(config)
49
+ end
50
+ end
51
+
52
+ included do
53
+ # Config that has all the config extensions applied (via `extend_item`)
54
+ attr_accessor :normalized_config
39
55
  end
40
56
 
41
57
  # Override to auto-configure components. Example:
@@ -60,7 +76,7 @@ module Netzke::Core
60
76
  @config ||= ActiveSupport::OrderedOptions.new
61
77
  end
62
78
 
63
- # Config options that have been set on the fly on the client side of the component in the `netzkeClientConfig` object. Can be
79
+ # Config options that have been set on the fly on the client side of the component in the `serverConfig` object. Can be
64
80
  # used to dynamically change component configuration. Those changes won't affect the way component is rendered, of
65
81
  # course, but can be useful to reconfigure child components, e.g.:
66
82
  #
@@ -69,7 +85,7 @@ module Netzke::Core
69
85
  # this.callParent();
70
86
  #
71
87
  # this.netzkeGetComponent('authors').on('rowclick', function(grid, record) {
72
- # this.netzkeClientConfig.author_id = record.getId();
88
+ # this.serverConfig.author_id = record.getId();
73
89
  # this.netzkeGetComponent('book_grid').getStore().load();
74
90
  # }
75
91
  # }
@@ -82,13 +98,14 @@ module Netzke::Core
82
98
  ActiveSupport::OrderedOptions.new.merge!(config.client_config)
83
99
  end
84
100
 
85
- protected
101
+ protected
86
102
 
87
- # Override to validate configuration and raise eventual exceptions
103
+ # Override to validate or enforce certain configuration options
88
104
  # E.g.:
89
105
  #
90
106
  # def validate_config(c)
91
107
  # raise ArgumentError, "Grid requires a model" if c.model.nil?
108
+ # c.paging = true if c.edit_inline
92
109
  # end
93
110
  def validate_config(c)
94
111
  end
@@ -104,12 +121,13 @@ module Netzke::Core
104
121
 
105
122
  # We'll build a couple of useful instance variables here:
106
123
  #
107
- # +components_in_config+ - an array of components (by name) referred in items
124
+ # +components_in_config+ - an array of components (by name) referred in `configure`
125
+ # +inline_components+ - a hash with configs of components defined inline in `configure`
108
126
  # +normalized_config+ - a config that has all the config extensions applied
109
127
  def normalize_config
110
- # @actions = @components = {} # in v1.0 this should replace DSL definition
111
128
  @components_in_config = []
112
129
  @implicit_component_index = 0
130
+ @inline_components = {}
113
131
  c = config.dup
114
132
  config.each_pair do |k, v|
115
133
  c.delete(k) if self.class.server_side_config_options.include?(k.to_sym)
@@ -119,11 +137,5 @@ module Netzke::Core
119
137
  end
120
138
  @normalized_config = c
121
139
  end
122
-
123
- # @return [Hash] config with all placeholders (like child components referred by symbols) expanded
124
- def normalized_config
125
- # make sure we call normalize_config first
126
- @normalized_config || (normalize_config || true) && @normalized_config
127
- end
128
140
  end
129
141
  end
@@ -0,0 +1,17 @@
1
+ module Netzke
2
+ module Core
3
+ module CoreI18n
4
+ extend ActiveSupport::Concern
5
+ module ClassMethods
6
+ # The ID used to locate this component's block in locale files
7
+ def i18n_id
8
+ name.split("::").map{|c| c.underscore}.join(".")
9
+ end
10
+ end
11
+
12
+ def i18n_id
13
+ self.class.i18n_id
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,9 +1,9 @@
1
1
  module Netzke
2
2
  module Core
3
- # This class is responsible of assemblage of stylesheet dependencies. It is passed as block parameter to the +css_configure+ DSL method:
3
+ # This class is responsible of assemblage of stylesheet dependencies. It is passed as block parameter to the +client_styles+ DSL method:
4
4
  #
5
5
  # class MyComponent < Netzke::Base
6
- # css_configure do |c|
6
+ # client_styles do |c|
7
7
  # c.require :extra_styles
8
8
  # end
9
9
  # end
@@ -23,16 +23,16 @@ module Netzke
23
23
  # Symbols will be expanded following a convention, e.g.:
24
24
  #
25
25
  # class MyComponent < Netzke::Base
26
- # css_configure do |c|
26
+ # client_styles do |c|
27
27
  # c.require :some_styles
28
28
  # end
29
29
  # end
30
30
  #
31
- # This will "require" a stylesheet file +{component_location}/my_component/stylesheets/some_styles.js+
31
+ # This will "require" a stylesheet file +{component_location}/my_component/client/some_styles.css+
32
32
  #
33
33
  # Strings will be interpreted as full paths to the required JavaScript file:
34
34
  #
35
- # css_configure do |c|
35
+ # client_styles do |c|
36
36
  # c.require "#{File.dirname(__FILE__)}/my_component/one.css", "#{File.dirname(__FILE__)}/my_component/two.css"
37
37
  # end
38
38
  def require(*args)
@@ -43,7 +43,7 @@ module Netzke
43
43
  private
44
44
 
45
45
  def expand_css_require_path(sym, callr)
46
- %Q(#{callr.split(".rb:").first}/stylesheets/#{sym}.css)
46
+ %Q(#{callr.split(".rb:").first}/client/#{sym}.css)
47
47
  end
48
48
 
49
49
  end
@@ -3,14 +3,13 @@ require 'uglifier'
3
3
  module Netzke
4
4
  module Core
5
5
  module DynamicAssets
6
+ CORE_FILES = %w[js_extensions core notifications remoting_provider base routing]
7
+
6
8
  class << self
7
9
  def ext_js(form_authenticity_token)
8
10
  res = initial_dynamic_javascript(form_authenticity_token) << "\n"
9
11
 
10
- include_base_js(res)
11
-
12
- # Ext-specific JavaScript
13
- res << File.new(File.expand_path("../../../../javascripts/ext.js", __FILE__)).read
12
+ include_core_js(res)
14
13
 
15
14
  # Pluggable JavaScript (used by other Netzke-powered gems like netzke-basepack)
16
15
  Netzke::Core.ext_javascripts.each do |path|
@@ -35,7 +34,7 @@ module Netzke
35
34
 
36
35
  def minify_js(js_string)
37
36
  if ::Rails.env.test? || ::Rails.env.development?
38
- js_string
37
+ js_string.gsub(/\/\*\*[^*]*\*+(?:[^*\/][^*]*\*+)*\//, '') # strip docs
39
38
  else
40
39
  Uglifier.compile(js_string)
41
40
  end
@@ -45,28 +44,22 @@ module Netzke
45
44
 
46
45
  # Generates initial javascript code that is dependent on Rails settings
47
46
  def initial_dynamic_javascript(form_authenticity_token)
48
- res = []
49
- res << %(Ext.Ajax.setExtraParams({authenticity_token: '#{form_authenticity_token}'}); // Rails' forgery protection)
50
- res << %{Ext.ns('Netzke');}
51
- res << %{Ext.ns('Netzke.core');}
52
- res << %{Netzke.RelativeUrlRoot = '#{ActionController::Base.config.relative_url_root}';}
53
- res << %{Netzke.ControllerUrl = '#{ActionController::Base.config.relative_url_root}#{Rails.application.routes.url_helpers.netzke_path}/';}
54
- res << %{Netzke.RelativeExtUrl = '#{ActionController::Base.config.relative_url_root}#{Netzke::Core.ext_uri}';}
55
-
56
- res << %{Netzke.core.directMaxRetries = #{Netzke::Core.js_direct_max_retries};}
57
- res << %{Netzke.core.FeedbackDelay = #{Netzke::Core.js_feedback_delay};}
58
-
59
- res.join("\n")
47
+ url_root = ActionController::Base.config.relative_url_root
48
+ %(Ext.Ajax.setExtraParams({authenticity_token: '#{form_authenticity_token}'});
49
+ Ext.ns('Netzke.Core');
50
+ Netzke.RelativeUrlRoot = '#{url_root}';
51
+ Netzke.ControllerUrl = '#{url_root}#{Rails.application.routes.url_helpers.netzke_path}/';
52
+ Netzke.RelativeExtUrl = '#{url_root}#{Netzke::Core.ext_uri}';
53
+ Netzke.Core.directMaxRetries = #{Netzke::Core.js_direct_max_retries};
54
+ Netzke.Core.NotificationDelay = #{Netzke::Core.client_notification_delay};
55
+ )
60
56
  end
61
57
 
62
- def include_base_js(arry)
63
- # JavaScript extensions
64
- arry << File.new(File.expand_path("../../../../javascripts/js_extensions.js", __FILE__)).read
65
-
66
- # Base Netzke component JavaScript
67
- arry << File.new(File.expand_path("../../../../javascripts/base.js", __FILE__)).read
58
+ def include_core_js(arry)
59
+ CORE_FILES.each do |script|
60
+ arry << File.new(File.expand_path("../../../../javascripts/#{script}.js", __FILE__)).read
61
+ end
68
62
  end
69
-
70
63
  end
71
64
  end
72
65
  end
@@ -3,12 +3,12 @@ module Netzke::Core
3
3
  module Embedding
4
4
  # Instantiating
5
5
  def js_component_instance
6
- %Q{Netzke.page.#{name.to_s.camelize(:lower)} = Ext.create("#{self.class.js_config.class_alias}", #{js_config.netzke_jsonify.to_json});}
6
+ %Q{Netzke.page.#{name.to_s.camelize(:lower)} = Ext.create("#{self.class.client_class_config.class_alias}", #{js_config.netzke_jsonify.to_json});}
7
7
  end
8
8
 
9
9
  # Rendering
10
10
  def js_component_render
11
- %Q{Netzke.page.#{name.to_s.camelize(:lower)}.render("#{name.to_s.split('_').join('-')}-netzke");} unless self.class.js_config.xtype == "netzkewindow"
11
+ %Q{Netzke.page.#{name.to_s.camelize(:lower)}.render("#{name.to_s.split('_').join('-')}-netzke");} unless self.class.client_class_config.xtype == "netzkewindow"
12
12
  end
13
13
 
14
14
  # Container for rendering
@@ -1,6 +1,12 @@
1
1
  module Netzke::Core
2
- # Represents the endpoint response at the server side.
3
- # An instance of it is passed as the second parameter to the +endpoint+ block.
2
+ # Represents the endpoint response at the server side. Collects instructions for the client-side object. Accessible as
3
+ # the `client` in the endpoint calls, e.g.:
4
+ #
5
+ # class SimpleComponent < Netzke::Base
6
+ # endpoint :whats_up_server do
7
+ # client.set_title("Response from server")
8
+ # end
9
+ # end
4
10
  class EndpointResponse < ::Hash
5
11
  def method_missing(name, *params)
6
12
  if name.to_s =~ /(.+)=$/
@@ -0,0 +1,33 @@
1
+ module Netzke
2
+ module Core
3
+ module Inheritance
4
+ extend ActiveSupport::Concern
5
+ module ClassMethods
6
+ attr_accessor :called_from
7
+
8
+ # Ancestor classes in the Netzke class hierarchy up to (and excluding) +Netzke::Base+, including self; in comparison to Ruby's own Class.ancestors, the order is reversed.
9
+ def netzke_ancestors
10
+ if self == Netzke::Base
11
+ []
12
+ else
13
+ superclass.netzke_ancestors + [self]
14
+ end
15
+ end
16
+
17
+ # Keep track of component's file. Inspired by Rails railties code.
18
+ def inherited(base)
19
+ base.called_from = begin
20
+ cllr = if Kernel.respond_to?(:caller_locations)
21
+ location = caller_locations.first
22
+ location.absolute_path || location.path
23
+ else
24
+ caller.first
25
+ end
26
+
27
+ cllr.split(".rb").first
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -12,11 +12,8 @@ module Netzke::Core
12
12
  # Defines a plugin
13
13
  def plugin(name, &block)
14
14
  register_plugin(name)
15
- component name do |c|
15
+ component name, eager_load: true do |c|
16
16
  block.call(c) if block_given?
17
-
18
- # plugins are *always* eagerly loaded
19
- c.eager_loading = true
20
17
  end
21
18
  end
22
19
 
@@ -54,7 +54,7 @@ module Netzke
54
54
  content_for :netzke_on_ready, raw("#{cmp.js_component_instance}\n\n#{cmp.js_component_render}")
55
55
 
56
56
  # Now mark all this component's dependency classes (including self) as rendered (by storing their xtypes), so that we only generate a class once per view
57
- @rendered_classes = (@rendered_classes + cmp.dependency_classes.map{|k| k.js_config.xtype}).uniq
57
+ @rendered_classes = (@rendered_classes + cmp.dependency_classes.map{|k| k.client_class_config.xtype}).uniq
58
58
 
59
59
  # Return the html for this component
60
60
  raw(cmp.js_component_html)
@@ -15,15 +15,13 @@ module Netzke
15
15
  @params[:endpoint].underscore
16
16
  end
17
17
 
18
+ # arguments for endpoint call
18
19
  def args
19
- # for backward compatibility, fall back to old data structure (with the endpoint params being in the root of
20
- # 'data')
21
- remoting_args.has_key?("args") ? remoting_args["args"] : remoting_args.reject{|k,v| k == 'configs' }
20
+ res = remoting_args.has_key?("args") ? remoting_args["args"] : remoting_args
21
+ res.is_a?(Array) ? res : [res].compact # need to wrap into array to normalize
22
22
  end
23
23
 
24
24
  def client_configs
25
- # if no configs are provided, the behavior is the old one, and thus all instances the same child component
26
- # will be treated as one
27
25
  remoting_args["configs"] || []
28
26
  end
29
27
 
@@ -33,8 +31,9 @@ module Netzke
33
31
 
34
32
  private
35
33
 
34
+ # raw arguments from the client
36
35
  def remoting_args
37
- @_remoting_args ||= @params[:data].first
36
+ @_remoting_args ||= @params[:data]
38
37
  end
39
38
  end
40
39
 
@@ -87,6 +86,7 @@ module Netzke
87
86
 
88
87
  protected
89
88
 
89
+ # Receives DirectRequest and result of invoke_endpoint, returns hash understood by client-side's Direct function
90
90
  def direct_response(request, endpoint_response)
91
91
  component_name, *sub_components = request.cmp_path.split('__')
92
92
 
@@ -101,17 +101,16 @@ module Netzke
101
101
  }
102
102
  end
103
103
 
104
+ # Receives DirectRequest, returns an array/hash of methods for the client side (consumed by netzkeBulkExecute)
104
105
  def invoke_endpoint(request)
105
106
  component_name, *sub_components = request.cmp_path.split('__')
106
- components_in_session = session[:netzke_components].try(:symbolize_keys)
107
107
 
108
- if components_in_session
109
- cmp_config = components_in_session[component_name.to_sym].symbolize_keys
108
+ if cmp_config = config_in_session(component_name)
110
109
  cmp_config[:client_config] = request.client_configs.shift || {}
111
110
  component_instance = Netzke::Base.instance_by_config(cmp_config)
112
111
  component_instance.invoke_endpoint((sub_components + [request.endpoint]).join("__"), request.args, request.client_configs)
113
112
  else
114
- {netzke_session_expired: []}
113
+ { netzke_on_session_expired: [] }
115
114
  end
116
115
  end
117
116
 
@@ -120,19 +119,26 @@ module Netzke
120
119
  # E.g.: some_grid__post_grid_data.
121
120
  def endpoint_dispatch(endpoint_path)
122
121
  component_name, *sub_components = endpoint_path.split('__')
123
- component_instance = Netzke::Base.instance_by_config(session[:netzke_components][component_name.to_sym])
124
122
 
125
- # We can't do this here; this method is only used for classic form submission, and the response from the server
126
- # should be the (default) "text/html"
127
- # response.headers["Content-Type"] = "text/plain; charset=utf-8"
123
+ if cmp_config = config_in_session(component_name)
124
+ cmp_config[:client_config] = ActiveSupport::JSON.decode(params[:configs]).shift || {}
125
+ component_instance = Netzke::Base.instance_by_config(cmp_config)
128
126
 
129
- render :text => component_instance.invoke_endpoint(sub_components.join("__"), params).netzke_jsonify.to_json, :layout => false
127
+ render text: component_instance.invoke_endpoint(sub_components.join("__"), [params]).netzke_jsonify.to_json, layout: false
128
+ else
129
+ render text: { netzke_on_session_expired: [] }.to_json, layout: false
130
+ end
130
131
  end
131
132
 
132
133
  def set_controller_and_session
133
134
  Netzke::Base.controller = self
134
135
  Netzke::Base.session = session
135
136
  end
137
+
138
+ def config_in_session(component_name)
139
+ components_in_session = (session[:netzke_components] || {}).symbolize_keys
140
+ components_in_session[component_name.to_sym].try(:symbolize_keys)
141
+ end
136
142
  end
137
143
  end
138
144
  end
@@ -5,7 +5,7 @@ module Netzke::Core
5
5
  #
6
6
  # An endpoint is defined through the +endpoint+ class method on the Ruby class:
7
7
  #
8
- # endpoint :do_something do |params, this|
8
+ # endpoint :do_something do
9
9
  # # ...
10
10
  # end
11
11
  #
@@ -14,74 +14,78 @@ module Netzke::Core
14
14
  #
15
15
  # == Calling an endpoint from JavaScript
16
16
  #
17
- # By defining the endpoint on the Ruby class, the client side automatically gets an equally named (but camelcased) method that is used to call the endpoint at the server. In the previous example, that would be +doSomething+. Its signature goes as follows:
17
+ # By defining the endpoint on the Ruby class, the client side automatically gets an equally named (in camelCase) function that is used to call the endpoint. In the previous example, that would be +doSomething+. Its signature goes as follows:
18
18
  #
19
- # this.doSomething(argsObject, callbackFunction, scope);
19
+ # this.server.doSomething(args..., callback, scope);
20
20
  #
21
- # * +argsObject+ is what the server side will receive as the +params+ argument
22
- # * +callbackFunction+ (optional) will be called after the server successfully processes the request
23
- # * +scope+ (optional) the scope in which +callbackFunction+ will be called
21
+ # * +args+ (optional) is what the +endpoint+ block at the server will receive as parameters
22
+ # * +callback+ (optional) will be called after the server successfully processes the request
23
+ # * +scope+ (optional) the scope in which +callback+ will be called, defaults to component instance
24
24
  #
25
25
  # The callback function can optionally receive an argument set by the endpoint at the server (see "Providing the argument to the callback function").
26
26
  #
27
27
  # == Envoking JavaScript methods from the server
28
28
  #
29
- # An endpoint, after doing some useful job at the server, is able to instruct the client side of the component to call multiple methods (preserving the call order) with provided arguments. It's done by using the second parameter of the endpoint block (which is illustratively called 'this'):
29
+ # An endpoint, after doing some useful job at the server, is able to instruct the client side of the component to call multiple methods (preserving the call order) with provided arguments. It's done via the +client+ variable:
30
30
  #
31
- # endpoint :do_something do |params, this|
31
+ # endpoint :do_something do
32
32
  # # ... do the thing
33
- # this.set_title("New title")
34
- # this.add_class("some-extra-css")
33
+ # client.set_title("New title")
34
+ # client.add_class("some-extra-css")
35
35
  # end
36
36
  #
37
- # This will result in successive calling the +setTitle+ and +addClass+ methods on the JavaScript instance of our component.
37
+ # This will result in successive calling the +setTitle+ and +addClass+ methods on the JavaScript instance of the component.
38
38
  #
39
39
  # Besides "calling" methods on the current component itself, it's also possible to address its instantiated children at any level of the hierarchy:
40
40
  #
41
- # endpoint :do_something do |params, this|
41
+ # endpoint :do_something do
42
42
  # # ... do the thing
43
- # this.east_panel_component.set_title("New east panel title")
44
- # this.east_panel_component.deep_nested_component.do_something_very_special("With", "some", "arguments")
43
+ # client.east_panel_component.set_title("New east panel title")
44
+ # client.east_panel_component.deep_nested_component.do_something_very_special("With", "some", "arguments")
45
45
  # end
46
46
  #
47
47
  # == Providing arguments to the callback function
48
48
  #
49
- # The callback function provided at the moment of calling an endpoint may receive an argument set by the endpoint by "calling" the special +netzke_set_result+ method. :
49
+ # The callback function provided at the moment of calling an endpoint will receive as its only argument the result of
50
+ # the +endpoint+ block execution:
50
51
  #
51
- # endpoint :do_something do |params, this|
52
+ # endpoint :get_the_answer do
52
53
  # # ... do the thing
53
- # this.netzke_set_result(42)
54
+ # 42
54
55
  # end
55
56
  #
56
57
  # By calling the endpoint from the client side like this:
57
58
  #
58
- # this.doSomething({}, function(result){ console.debug(result); });
59
+ # this.server.getTheAnswer(function(result){ console.debug(result); });
59
60
  #
60
- # ... the value of +result+ after the execution of the endpoint will be set to 42. Using this mechanism can be seen as doing an asyncronous call to a function at the server, which returns a value.
61
+ # ... the value of +result+ after the endpoint execution will be 42. Using this mechanism can be seen as doing an asyncronous call to a server-side function that returns a value.
61
62
  #
62
63
  # == Overriding an endpoint
63
64
  #
64
65
  # When overriding an endpoint, you can call the original endpoint by using +super+ and explicitely providing the block parameters to it:
65
66
  #
66
- # endpoint :do_something do |params, this|
67
- # super(params, this)
68
- # this.doMore
67
+ # endpoint :do_something do |arg1, arg2|
68
+ # super(arg1, arg2)
69
+ # client.do_more
69
70
  # end
70
71
  #
71
- # If you want to reuse the original arguments set in +super+, you can access them from the +this+ object. Provided we are overriding the +do_something+ endpoint from the example in "Envoking JavaScript methods from the server", we will have:
72
+ # If you want to reuse the original arguments set in +super+, you can access them from the +client+ object. Provided we are overriding the +do_something+ endpoint from the example in "Envoking JavaScript methods from the server", we will have:
72
73
  #
73
- # endpoint :do_something do |params, this|
74
- # super(params, this)
75
- # original_arguments_for_set_title = this.set_title # => ["New title"]
76
- # original_arguments_for_add_class = this.add_class # => ["some-extra-css"]
74
+ # endpoint :do_something do |params|
75
+ # super(params)
76
+ # original_arguments_for_set_title = client.set_title # => ["New title"]
77
+ # original_arguments_for_add_class = client.add_class # => ["some-extra-css"]
77
78
  # end
78
79
  module Services
79
80
  extend ActiveSupport::Concern
80
81
 
81
82
  included do
82
- # Returns all endpoints as a hash
83
+ # Returns all endpoints as a hash
83
84
  class_attribute :endpoints
84
85
  self.endpoints = {}
86
+
87
+ # instance of EndpointResponse
88
+ attr_accessor :client
85
89
  end
86
90
 
87
91
  module ClassMethods
@@ -99,34 +103,33 @@ module Netzke::Core
99
103
  end
100
104
  end
101
105
 
102
- # Invokes an endpoint call
106
+ # Invokes an endpoint
107
+ #
103
108
  # +endpoint+ may contain the path to the endpoint in a component down the hierarchy, e.g.:
109
+ # +params+ contains an Array of parameters to pass to the endpoint
104
110
  #
105
111
  # invoke_endpoint(:users__center__get_data, params)
112
+ #
113
+ # Returns instance of EndpointResponse
106
114
  def invoke_endpoint(endpoint, params, configs = [])
107
- endpoint_response = Netzke::Core::EndpointResponse.new
115
+ self.client = Netzke::Core::EndpointResponse.new
108
116
 
109
117
  if has_endpoint?(endpoint)
110
- send("#{endpoint}_endpoint", params, endpoint_response)
111
- endpoint_response
118
+ client.netzke_set_result(send("#{endpoint}_endpoint", *params))
119
+ client
112
120
  else
113
- # Let's try to find it recursively in a component down the hierarchy
121
+ # Let's try to find it in a component down the tree
114
122
  child_component, *action = endpoint.to_s.split('__')
115
- child_component = child_component.to_sym
123
+
116
124
  action = !action.empty? && action.join("__").to_sym
125
+ return unknown_exception(:endpoint, endpoint) if !action
126
+
127
+ client_config = configs.shift || {}
128
+ child_config = component_config(child_component.to_sym, client_config: client_config)
117
129
 
118
- raise RuntimeError, "Component '#{self.class.name}' does not have endpoint '#{endpoint}'" if !action
119
-
120
- if components[child_component]
121
- client_config = configs.shift || {}
122
- js_id = client_config.delete("component_id")
123
- cmp_strong_config = {client_config: client_config, js_id: js_id}
124
- component_instance(child_component, cmp_strong_config).invoke_endpoint(action, params, configs)
125
- else
126
- # component_missing can be overridden if necessary
127
- component_missing(child_component, params, endpoint_response)
128
- endpoint_response
129
- end
130
+ return unknown_exception(:component, child_component) if child_config.nil?
131
+
132
+ component_instance(child_config).invoke_endpoint(action, params, configs)
130
133
  end
131
134
  end
132
135
 
@@ -136,9 +139,19 @@ module Netzke::Core
136
139
 
137
140
  # Called when the method_missing tries to processes a non-existing component. Override when needed.
138
141
  # Note: this should actually never happen unless you mess up with Netzke component loading mechanisms.
139
- def component_missing(missing_component, params, this)
140
- this.netzke_feedback "Unknown component '#{missing_component}' in '#{name}'"
142
+ def component_missing(missing_component, *params)
143
+ client.netzke_notify "Unknown component '#{missing_component}' in '#{name}'"
141
144
  end
142
145
 
146
+ private
147
+
148
+ def unknown_exception(entity_name, entity)
149
+ client.netzke_set_result(error: {
150
+ type: "UNKNOWN_#{entity_name.to_s.upcase}",
151
+ msg: "Component '#{self.class.name}' does not have #{entity_name} '#{entity}'"
152
+ })
153
+
154
+ client
155
+ end
143
156
  end
144
157
  end
@@ -7,8 +7,6 @@ module Netzke::Core
7
7
  @component_id = component_id.to_s
8
8
  Netzke::Base.session ||= {}
9
9
  Netzke::Base.session[:netzke_sessions] ||= {}
10
- # @session = Netzke::Base.session[:netzke_sessions][@component_id] ||= {}
11
- # @session = {}
12
10
  end
13
11
 
14
12
  # Delegate everything to session