netzke-core 0.7.7 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (192) hide show
  1. data/.travis.yml +1 -2
  2. data/CHANGELOG.md +572 -0
  3. data/LICENSE +7 -1
  4. data/README.md +345 -29
  5. data/Rakefile +3 -3
  6. data/app/controllers/netzke_controller.rb +37 -48
  7. data/config/ci/before-travis.sh +3 -4
  8. data/javascripts/base.js +86 -150
  9. data/javascripts/ext.js +180 -210
  10. data/javascripts/{core_extensions.js → js_extensions.js} +0 -0
  11. data/lib/netzke-core.rb +16 -6
  12. data/lib/netzke/base.rb +84 -107
  13. data/lib/netzke/core.rb +7 -41
  14. data/lib/netzke/core/action_config.rb +37 -0
  15. data/lib/netzke/core/actions.rb +123 -0
  16. data/lib/netzke/core/client_class.rb +252 -0
  17. data/lib/netzke/core/component_config.rb +12 -0
  18. data/lib/netzke/core/composition.rb +274 -0
  19. data/lib/netzke/core/config_to_dsl_delegator.rb +69 -0
  20. data/lib/netzke/core/configuration.rb +63 -0
  21. data/lib/netzke/core/css_config.rb +51 -0
  22. data/lib/netzke/core/dynamic_assets.rb +19 -49
  23. data/lib/netzke/{embedding.rb → core/embedding.rb} +4 -6
  24. data/lib/netzke/core/endpoint_response.rb +15 -0
  25. data/lib/netzke/core/javascript.rb +111 -0
  26. data/lib/netzke/core/panel.rb +11 -0
  27. data/lib/netzke/{plugins.rb → core/plugins.rb} +10 -5
  28. data/lib/netzke/core/railz.rb +4 -0
  29. data/lib/netzke/{railz → core/railz}/action_view_ext.rb +22 -18
  30. data/lib/netzke/core/railz/action_view_ext/ext.rb +49 -0
  31. data/lib/netzke/core/railz/controller_extensions.rb +17 -0
  32. data/lib/netzke/core/railz/engine.rb +16 -0
  33. data/lib/netzke/core/railz/routes.rb +10 -0
  34. data/lib/netzke/core/ruby_ext.rb +5 -0
  35. data/lib/netzke/core/ruby_ext/array.rb +23 -0
  36. data/lib/netzke/core/ruby_ext/hash.rb +47 -0
  37. data/lib/netzke/{core_ext → core/ruby_ext}/string.rb +2 -7
  38. data/lib/netzke/core/ruby_ext/symbol.rb +13 -0
  39. data/lib/netzke/{core_ext → core/ruby_ext}/time_with_zone.rb +0 -0
  40. data/lib/netzke/core/services.rb +130 -0
  41. data/lib/netzke/core/session.rb +15 -19
  42. data/lib/netzke/core/state.rb +40 -0
  43. data/lib/netzke/core/stylesheets.rb +48 -0
  44. data/lib/netzke/core/version.rb +2 -2
  45. data/lib/netzke/plugin.rb +8 -11
  46. data/netzke-core.gemspec +69 -59
  47. data/test/core_test_app/Gemfile +2 -20
  48. data/test/core_test_app/Gemfile.lock +65 -74
  49. data/test/core_test_app/app/components/card_component_loader.rb +4 -4
  50. data/test/core_test_app/app/components/component_loader.rb +40 -120
  51. data/test/core_test_app/app/components/component_loader/javascripts/component_loader.js +49 -0
  52. data/test/core_test_app/app/components/component_with_actions.rb +61 -47
  53. data/test/core_test_app/app/components/component_with_custom_css.rb +8 -5
  54. data/test/core_test_app/app/components/component_with_js_mixin.rb +11 -5
  55. data/test/core_test_app/app/components/component_with_js_mixin/javascripts/extra_one.js +1 -1
  56. data/test/core_test_app/app/components/component_with_js_mixin/javascripts/extra_two.js +1 -1
  57. data/test/core_test_app/app/components/component_with_js_mixin/javascripts/method_set_one.js +1 -1
  58. data/test/core_test_app/app/components/component_with_nested_through.rb +2 -2
  59. data/test/core_test_app/app/components/component_with_prebuilt_toolbar_control.rb +12 -0
  60. data/test/core_test_app/app/components/component_with_prebuilt_toolbar_control/javascripts/component_with_prebuilt_toolbar_control.js +12 -0
  61. data/test/core_test_app/app/components/component_with_required_js.rb +24 -0
  62. data/test/core_test_app/app/components/configurable_on_class_level.rb +8 -0
  63. data/test/core_test_app/app/components/dsl_delegated_properties.rb +4 -0
  64. data/test/core_test_app/app/components/dsl_delegated_properties_base.rb +5 -0
  65. data/test/core_test_app/app/components/dynamic_tab_panel/javascripts/dynamic_tab_panel.js +2 -2
  66. data/test/core_test_app/app/components/ext_direct/composite.rb +32 -33
  67. data/test/core_test_app/app/components/ext_direct/details.rb +2 -4
  68. data/test/core_test_app/app/components/ext_direct/selector.rb +20 -22
  69. data/test/core_test_app/app/components/ext_direct/statistics.rb +2 -4
  70. data/test/core_test_app/app/components/extended_component_with_actions.rb +7 -3
  71. data/test/core_test_app/app/components/extended_component_with_js_mixin.rb +7 -4
  72. data/test/core_test_app/app/components/extended_component_with_js_mixin/javascripts/some_method_set.js +1 -1
  73. data/test/core_test_app/app/components/extended_server_caller.rb +20 -14
  74. data/test/core_test_app/app/components/hello_world.rb +23 -0
  75. data/test/core_test_app/app/components/hello_world/javascripts/hello_world.js +12 -0
  76. data/test/core_test_app/app/components/included.js +2 -2
  77. data/test/core_test_app/app/components/kinda_complex_component.rb +1 -3
  78. data/test/core_test_app/app/components/kinda_complex_component/basic_stuff.rb +15 -17
  79. data/test/core_test_app/app/components/kinda_complex_component/extra_stuff.rb +4 -5
  80. data/test/core_test_app/app/components/loader_of_component_with_custom_css.rb +14 -5
  81. data/test/core_test_app/app/components/localized_panel.rb +23 -25
  82. data/test/core_test_app/app/components/multipane_component_loader.rb +19 -20
  83. data/test/core_test_app/app/components/nested_component.rb +4 -5
  84. data/test/core_test_app/app/components/panel_with_plugin.rb +8 -3
  85. data/test/core_test_app/app/components/panel_with_tools.rb +15 -14
  86. data/test/core_test_app/app/components/plugin_with_components.rb +20 -12
  87. data/test/core_test_app/app/components/scoped_components/deep_scoped_components/some_deep_scoped_component.rb +5 -2
  88. data/test/core_test_app/app/components/scoped_components/extended_scoped_component.rb +5 -2
  89. data/test/core_test_app/app/components/scoped_components/some_scoped_component.rb +5 -2
  90. data/test/core_test_app/app/components/server_caller.rb +39 -17
  91. data/test/core_test_app/app/components/server_caller/javascripts/server_caller.js +42 -0
  92. data/test/core_test_app/app/components/server_counter.rb +18 -82
  93. data/test/core_test_app/app/components/server_counter/javascripts/server_counter.js +53 -0
  94. data/test/core_test_app/app/components/simple_authentication_component.rb +46 -0
  95. data/test/core_test_app/app/components/simple_component.rb +8 -3
  96. data/test/core_test_app/app/components/simple_composite.rb +12 -0
  97. data/test/core_test_app/app/components/simple_form_with_file_upload.rb +49 -0
  98. data/test/core_test_app/app/components/simple_panel.rb +2 -2
  99. data/test/core_test_app/app/components/simple_tab_panel.rb +24 -3
  100. data/test/core_test_app/app/components/simple_window.rb +4 -2
  101. data/test/core_test_app/app/components/some_composite.rb +77 -48
  102. data/test/core_test_app/app/components/some_plugin.rb +31 -30
  103. data/test/core_test_app/app/components/stateful_component.rb +46 -0
  104. data/test/core_test_app/app/components/stateful_component_with_shared_state.rb +11 -0
  105. data/test/core_test_app/app/components/window_with_simple_component.rb +14 -0
  106. data/test/core_test_app/app/views/layouts/application.html.erb +1 -1
  107. data/test/core_test_app/app/views/simple_rails/multiple_nested.html.erb +7 -19
  108. data/test/core_test_app/app/views/simple_rails/panel.html.erb +1 -0
  109. data/test/core_test_app/config/database.yml.travis +3 -5
  110. data/test/core_test_app/config/environments/production.rb +1 -1
  111. data/test/core_test_app/config/initializers/netzke.rb +3 -1
  112. data/test/core_test_app/config/locales/en.yml +9 -4
  113. data/test/core_test_app/config/locales/es.yml +4 -2
  114. data/test/core_test_app/config/routes.rb +2 -8
  115. data/test/core_test_app/db/schema.rb +3 -11
  116. data/test/core_test_app/features/actions_and_tools.feature +1 -0
  117. data/test/core_test_app/features/client-server.feature +7 -0
  118. data/test/core_test_app/features/component_loader.feature +13 -13
  119. data/test/core_test_app/features/composition.feature +14 -0
  120. data/test/core_test_app/features/config_to_dsl_delegation.feature +10 -0
  121. data/test/core_test_app/features/file_inclusion.feature +1 -1
  122. data/test/core_test_app/features/i18n.feature +4 -4
  123. data/test/core_test_app/features/js_include.feature +1 -1
  124. data/test/core_test_app/features/persistence.feature +21 -5
  125. data/test/core_test_app/features/step_definitions/generic_steps.rb +14 -0
  126. data/test/core_test_app/features/support/paths.rb +0 -3
  127. data/test/core_test_app/public/images/icons/accept.png +0 -0
  128. data/test/core_test_app/public/images/icons/anchor.png +0 -0
  129. data/test/core_test_app/public/images/icons/tick.png +0 -0
  130. data/test/core_test_app/spec/action_config_spec.rb +15 -0
  131. data/test/core_test_app/spec/{component/actions_spec.rb → actions_spec.rb} +38 -36
  132. data/test/core_test_app/spec/base_spec.rb +35 -0
  133. data/test/core_test_app/spec/client_class_spec.rb +17 -0
  134. data/test/core_test_app/spec/component +0 -0
  135. data/test/core_test_app/spec/composition_spec.rb +118 -0
  136. data/test/core_test_app/spec/core_ext_spec.rb +3 -14
  137. data/test/core_test_app/spec/endpoint_response_spec.rb +17 -0
  138. data/test/core_test_app/spec/javascript_spec.rb +33 -0
  139. data/test/core_test_app/spec/js_class_config_scope.rb +37 -0
  140. data/test/core_test_app/spec/panel_spec.rb +11 -0
  141. data/test/core_test_app/spec/services_spec.rb +16 -0
  142. data/test/core_test_app/spec/state_spec.rb +20 -0
  143. data/test/unit/core_ext_test.rb +0 -53
  144. data/test/unit/netzke_core_test.rb +11 -11
  145. metadata +76 -62
  146. data/CHANGELOG.rdoc +0 -325
  147. data/javascripts/touch.js +0 -58
  148. data/lib/netzke/actions.rb +0 -107
  149. data/lib/netzke/composition.rb +0 -224
  150. data/lib/netzke/config_to_dsl_delegator.rb +0 -43
  151. data/lib/netzke/configuration.rb +0 -195
  152. data/lib/netzke/core/masquerading.rb +0 -34
  153. data/lib/netzke/core_ext.rb +0 -6
  154. data/lib/netzke/core_ext/array.rb +0 -30
  155. data/lib/netzke/core_ext/hash.rb +0 -86
  156. data/lib/netzke/core_ext/symbol.rb +0 -21
  157. data/lib/netzke/ext_component.rb +0 -25
  158. data/lib/netzke/inheritance.rb +0 -31
  159. data/lib/netzke/javascript.rb +0 -382
  160. data/lib/netzke/javascript/scopes.rb +0 -39
  161. data/lib/netzke/railz.rb +0 -4
  162. data/lib/netzke/railz/action_view_ext/ext.rb +0 -64
  163. data/lib/netzke/railz/action_view_ext/touch.rb +0 -52
  164. data/lib/netzke/railz/controller_extensions.rb +0 -33
  165. data/lib/netzke/railz/engine.rb +0 -48
  166. data/lib/netzke/railz/routes.rb +0 -7
  167. data/lib/netzke/services.rb +0 -101
  168. data/lib/netzke/session.rb +0 -54
  169. data/lib/netzke/state.rb +0 -91
  170. data/lib/netzke/stylesheets.rb +0 -65
  171. data/test/core_test_app/app/components/component_with_included_js.rb +0 -16
  172. data/test/core_test_app/app/components/component_with_session_persistence.rb +0 -35
  173. data/test/core_test_app/app/components/deprecated/server_caller.rb +0 -20
  174. data/test/core_test_app/app/components/dynamic_tab_panel.rb +0 -19
  175. data/test/core_test_app/app/components/hello_world_component.rb +0 -31
  176. data/test/core_test_app/app/components/touch/hello_world_component.rb +0 -25
  177. data/test/core_test_app/app/components/touch/server_caller.rb +0 -28
  178. data/test/core_test_app/app/components/touch/simple_carousel.rb +0 -17
  179. data/test/core_test_app/app/controllers/touch_controller.rb +0 -6
  180. data/test/core_test_app/app/helpers/touch_helper.rb +0 -2
  181. data/test/core_test_app/app/views/layouts/touch.html.erb +0 -13
  182. data/test/core_test_app/db/migrate/20110110132720_create_netzke_component_states.rb +0 -20
  183. data/test/core_test_app/features/step_definitions/touch_steps.rb +0 -3
  184. data/test/core_test_app/features/touch.feature +0 -10
  185. data/test/core_test_app/gemfiles/rails3_1.gemfile +0 -16
  186. data/test/core_test_app/gemfiles/rails3_2.gemfile +0 -16
  187. data/test/core_test_app/spec/component/base_spec.rb +0 -36
  188. data/test/core_test_app/spec/component/component_spec.rb +0 -20
  189. data/test/core_test_app/spec/component/composition_spec.rb +0 -132
  190. data/test/core_test_app/spec/component/configuration_spec.rb +0 -61
  191. data/test/core_test_app/spec/component/javascript_spec.rb +0 -16
  192. data/test/core_test_app/spec/component/state_spec.rb +0 -18
@@ -1,34 +0,0 @@
1
- module Netzke
2
- module Core
3
- module Masquerading
4
- # Example:
5
- # masquarade_as(:role, 2)
6
- # masquarade_as(:user, 4)
7
- # masquarade_as(:world)
8
- def masquerade_as(authority_level, authority_id = true)
9
- reset_masquerading
10
- session.merge!(:"masq_#{authority_level}" => authority_id)
11
- end
12
-
13
- def reset_masquerading
14
- session[:masq_world] = session[:masq_role] = session[:masq_user] = nil
15
- end
16
-
17
- # Who are we acting as?
18
- def authority_level
19
- if session[:masq_world]
20
- :world
21
- elsif session[:masq_role]
22
- [:role, session[:masq_role]]
23
- elsif session[:masq_user]
24
- [:user, session[:masq_user]]
25
- elsif session[:netzke_user_id]
26
- [:self, session[:netzke_user_id]]
27
- else
28
- :none # or nil ?
29
- end
30
- end
31
-
32
- end
33
- end
34
- end
@@ -1,6 +0,0 @@
1
- require "netzke/core_ext/array"
2
- require "netzke/core_ext/hash"
3
- require "netzke/core_ext/string"
4
- require "netzke/core_ext/symbol"
5
- require "netzke/core_ext/time_with_zone"
6
-
@@ -1,30 +0,0 @@
1
- class Array
2
- def jsonify
3
- self.map{ |el| el.instance_of?(Array) || el.instance_of?(Hash) ? el.jsonify : el }
4
- end
5
-
6
- # Camelizes the keys of hashes and converts them to JSON
7
- def to_nifty_json
8
- self.recursive_delete_if_nil.jsonify.to_json
9
- end
10
-
11
- # Applies deep_convert_keys to each element which responds to deep_convert_keys
12
- def deep_convert_keys(&block)
13
- block_given? ? self.map do |i|
14
- i.respond_to?('deep_convert_keys') ? i.deep_convert_keys(&block) : i
15
- end : self
16
- end
17
-
18
- def deep_each_pair(&block)
19
- self.each{ |el| el.respond_to?('deep_each_pair') && el.deep_each_pair(&block) }
20
- end
21
-
22
- def recursive_delete_if_nil
23
- self.map{|el| el.respond_to?('recursive_delete_if_nil') ? el.recursive_delete_if_nil : el}
24
- end
25
-
26
- def deep_freeze
27
- each { |j| j.deep_freeze if j.respond_to? :deep_freeze }
28
- freeze
29
- end
30
- end
@@ -1,86 +0,0 @@
1
- class Hash
2
- def deep_each_pair(&block)
3
- self.each_pair do |k,v|
4
- v.respond_to?('deep_each_pair') ? v.deep_each_pair(&block) : yield(k,v)
5
- end
6
- end
7
-
8
- # Recursively convert the keys. Example:
9
- # {:bla_bla => 1, "wow_now" => {:look_ma => true}}.deep_convert_keys{|k| k.to_s.camelize.to_sym}
10
- # => {:BlaBla => 1, "WowNow" => {:LookMa => true}}
11
- def deep_convert_keys(&block)
12
- block_given? ? self.inject({}) do |h,(k,v)|
13
- h[yield(k)] = v.respond_to?('deep_convert_keys') ? v.deep_convert_keys(&block) : v
14
- h
15
- end : self
16
- end
17
-
18
- def jsonify
19
- self.inject({}) do |h,(k,v)|
20
- new_key = k.instance_of?(String) || k.instance_of?(Symbol) ? k.jsonify : k
21
- new_value = v.instance_of?(Array) || v.instance_of?(Hash) ? v.jsonify : v
22
- h.merge(new_key => new_value)
23
- end
24
- end
25
-
26
- # First camelizes the keys, then convert the whole hash to JSON
27
- def to_nifty_json
28
- self.recursive_delete_if_nil.jsonify.to_json
29
- end
30
-
31
- # Converts values of a Hash in such a way that they can be easily stored in the database: hashes and arrays are jsonified, symbols - stringified
32
- def deebeefy_values
33
- inject({}) do |options, (k, v)|
34
- options[k] = v.is_a?(Symbol) ? v.to_s : (v.is_a?(Hash) || v.is_a?(Array)) ? v.to_json : v
35
- options
36
- end
37
- end
38
-
39
- # We don't need to pass null values in JSON, they are null by simply being absent
40
- def recursive_delete_if_nil
41
- self.inject({}) do |h,(k,v)|
42
- if !v.nil?
43
- h[k] = v.respond_to?('recursive_delete_if_nil') ? v.recursive_delete_if_nil : v
44
- end
45
- h
46
- end
47
- end
48
-
49
- # add flatten_with_type method to Hash
50
- def flatten_with_type(preffix = "")
51
- res = []
52
- self.each_pair do |k,v|
53
- name = ((preffix.to_s.empty? ? "" : preffix.to_s + "__") + k.to_s).to_sym
54
- if v.is_a?(Hash)
55
- res += v.flatten_with_type(name)
56
- else
57
- res << {
58
- :name => name,
59
- :value => v,
60
- :type => (["TrueClass", "FalseClass"].include?(v.class.name) ? 'Boolean' : v.class.name).to_sym
61
- }
62
- end
63
- end
64
- res
65
- end
66
-
67
- def deep_freeze
68
- each { |k,v| v.deep_freeze if v.respond_to? :deep_freeze }
69
- freeze
70
- end
71
-
72
- # From http://rubyworks.github.com/facets
73
- def update_keys #:yield:
74
- if block_given?
75
- keys.each { |old_key| store(yield(old_key), delete(old_key)) }
76
- else
77
- to_enum(:update_keys)
78
- end
79
- end
80
-
81
- def literalize_keys
82
- update_keys{ |k| k.to_s.l }
83
- self
84
- end
85
-
86
- end
@@ -1,21 +0,0 @@
1
- class Symbol
2
- def jsonify
3
- self.to_s.jsonify.to_sym
4
- end
5
-
6
- def l
7
- ActiveSupport::JSON::Variable.new(self.to_s)
8
- end
9
-
10
- def action(config = {})
11
- config.merge(:action => self)
12
- end
13
-
14
- def component(config = {})
15
- config.merge(:netzke_component => self)
16
- end
17
-
18
- def to_cls_attr
19
- "__#{self}__".to_sym
20
- end
21
- end
@@ -1,25 +0,0 @@
1
- module Netzke
2
- class ExtComponent
3
- attr_accessor :name
4
-
5
- def initialize(name, config = {})
6
- @name = name
7
- @config = config
8
- end
9
-
10
- def config
11
- @config ||= {}
12
- end
13
-
14
- # Rendering
15
- def js_component_render
16
- %Q{Ext.ComponentManager.create("#{js_full_class_name}", #{config.to_nifty_json}).render("ext-#{name.to_s.split('_').join('-')}");}
17
- end
18
-
19
- # Container for rendering
20
- def js_component_html
21
- %Q{<div id="ext-#{name.to_s.split('_').join('-')}" class="ext-component"></div>}
22
- end
23
-
24
- end
25
- end
@@ -1,31 +0,0 @@
1
- module Netzke
2
- module Inheritance
3
- extend ActiveSupport::Concern
4
-
5
- module ClassMethods
6
- # All ancestor classes in the Netzke class hierarchy (i.e. up to Netzke::Base)
7
- def class_ancestors
8
- if self == Netzke::Base
9
- []
10
- else
11
- superclass.class_ancestors + [self]
12
- end
13
- end
14
-
15
- # Same as +class_attribute+ returning a hash, but returns empty hash when it's equal to superclass's
16
- def clean_class_attribute_hash(attr_name)
17
- res = self.send(attr_name)
18
- # We don't want here any values from the superclass (which is the consequence of using class attributes).
19
- res == self.superclass.send(attr_name) ? {} : res
20
- end
21
-
22
- # Same as +class_attribute+ returning an array, but returns empty array when it's equal to superclass's
23
- def clean_class_attribute_array(attr_name)
24
- res = self.send(attr_name) || []
25
- # We don't want here any values from the superclass (which is the consequence of using class attributes).
26
- res == self.superclass.send(attr_name) ? [] : res
27
- end
28
-
29
- end
30
- end
31
- end
@@ -1,382 +0,0 @@
1
- require "netzke/javascript/scopes"
2
- module Netzke
3
- # == Component's JavaScript class generation
4
- # Each component operates on both client and server side. At the server side it's represented by a Ruby class, at the client side it's represented by a corresponding JavaScript class (extending one of the Ext JS classes, specified by Netzke::Base.js_base_class, or, in case of extending an existing Netzke component, that component's JavaScript class).
5
- #
6
- # The following public JavaScript methods are defined on all Netzke components
7
- # *
8
- #
9
- # Here's a brief explanation on how a javascript class for a component gets built.
10
- # Component gets defined as a constructor (a function) by +js_class+ class method (see "Inside component's contstructor").
11
- # +Ext.extend+ provides inheritance from an Ext class specified in +js_base_class+ class method.
12
- #
13
- # == Inside component's constructor
14
- # * Component's constructor gets called with a parameter that is a configuration object provided by +config+ instance method. This configuration is specific for the instance of the component, and, for example, contains this component's unique id. As another example, by means of this configuration object, a grid receives the configuration array for its columns, a form - for its fields, etc.
15
- module Javascript
16
- extend ActiveSupport::Concern
17
-
18
- included do
19
- include Scopes
20
-
21
- class_attribute :js_included_files
22
- self.js_included_files = []
23
-
24
- # Returns all JS method definitions in a hash
25
- class_attribute :js_methods_attr
26
- self.js_methods_attr = {}
27
-
28
- class_attribute :js_properties_attr
29
- self.js_properties_attr = {}
30
-
31
- # Returns all objects to be mixed in (as array of strings)
32
- class_attribute :js_mixins_attr
33
- self.js_mixins_attr = []
34
-
35
- class_attribute :js_translated_properties_attr
36
- self.js_translated_properties_attr = {}
37
-
38
- class_attribute :js_base_class_attr
39
- self.js_base_class_attr = 'Ext.panel.Panel'
40
- end
41
-
42
- module ClassMethods
43
-
44
- # Used it to specify what JavaScript class this component's JavaScript class will be extending, e.g.:
45
- #
46
- # js_base_class "Ext.TabPanel"
47
- #
48
- # By default, "Ext.Panel" is assumed.
49
- #
50
- # If called without parameters, returns the JS base class declared for the component.
51
- def js_base_class(class_name = nil)
52
- class_name.nil? ? self.js_base_class_attr : self.js_base_class_attr = class_name
53
- end
54
-
55
- # Use it to define a public method of the component's JavaScript class, e.g.:
56
- #
57
- # js_method :do_something, <<-JS
58
- # function(params){
59
- # // implementation, maybe dynamically generated
60
- # }
61
- # JS
62
- #
63
- # This will effectively result in definition of a public method called +doSomething+ in the JavaScript class (note the conversion from underscore_name to camelCaseName).
64
- def js_method(name, definition = nil)
65
- definition = yield.l if block_given?
66
- current_js_methods = clean_class_attribute_hash(:js_methods_attr).dup
67
- self.js_methods_attr = current_js_methods.merge(name => definition.l)
68
- end
69
-
70
- # Returns all JS method definitions in a hash
71
- def js_methods
72
- clean_class_attribute_hash(:js_methods_attr)
73
- end
74
-
75
- # Use it to specify JS files to be loaded before this component's JS code. Useful when using external extensions required by this component.
76
- # It may accept one or more symbols or strings. Strings will be interpreted as full paths to included JS file:
77
- #
78
- # js_include "#{File.dirname(__FILE__)}/my_component/one.js","#{File.dirname(__FILE__)}/my_component/two.js"
79
- #
80
- # Symbols will be expanded following a convention, e.g.:
81
- #
82
- # class MyComponent < Netzke::Base
83
- # js_include :some_library
84
- # # ...
85
- # end
86
- #
87
- # This will "include" a JavaScript file +{component_location}/my_component/javascripts/some_library.js+
88
- def js_include(*args)
89
- callr = caller.first
90
-
91
- self.js_included_files |= args.map{ |a| a.is_a?(Symbol) ? expand_js_include_path(a, callr) : a }
92
- end
93
-
94
- # Used to define default properties of the JavaScript class, e.g.:
95
- #
96
- # js_properties :collapsible => true, :hide_collapse_tool => true
97
- #
98
- # (this will result in the definition of the following properties in the JavaScript class's prototype: +collapsible+ and +hideCollapseTool+ (note the automatic conversion from underscore to camelcase))
99
- #
100
- # Also, +js_property+ can be used to define properties one by one.
101
- #
102
- # For the complete list of available options refer to the Ext documentation, the "Config Options" section of a the component specified with +js_base_class+.
103
- # Note, that not all the configuration options can be defined on the prototype of the class. For example, defining +items+ on the prototype won't take any effect, so, +items+ should be passed as a configuration option at the moment of instantiation (see Netzke::Base#configuration and Netzke::Base#default_config).
104
- def js_properties(hsh = nil)
105
- if hsh.nil?
106
- clean_class_attribute_hash(:js_properties_attr)
107
- else
108
- current_js_properties = clean_class_attribute_hash(:js_properties_attr).dup
109
- self.js_properties_attr = current_js_properties.merge(hsh)
110
- end
111
- end
112
-
113
- # Used to define a single JS class property, e.g.:
114
- # js_property :title, "My Netzke Component"
115
- def js_property(name, value = nil)
116
- name = name.to_sym
117
- if value.nil?
118
- clean_class_attribute_hash(:js_properties_attr)[name]
119
- else
120
- current_js_properties = clean_class_attribute_hash(:js_properties_attr).dup
121
- current_js_properties[name] = value
122
- self.js_properties_attr = current_js_properties
123
- end
124
- end
125
-
126
- # Defines the "i18n" config property, that is a translation object for this component, such as:
127
- # i18n: {
128
- # overwriteConfirm: "Are you sure you want to overwrite preset '{0}'?",
129
- # overwriteConfirmTitle: "Overwriting preset",
130
- # deleteConfirm: "Are you sure you want to delete preset '{0}'?",
131
- # deleteConfirmTitle: "Deleting preset"
132
- # }
133
- #
134
- # E.g.:
135
- # js_translate :overwrite_confirm, :overwrite_confirm_title, :delete_confirm, :delete_confirm_title
136
- #
137
- # TODO: make the name of the root property configurable
138
- def js_translate(*properties)
139
- if properties.empty?
140
- clean_class_attribute_hash(:js_translated_properties_attr)
141
- else
142
- current_translated_properties = clean_class_attribute_hash(:js_translated_properties_attr).dup
143
- properties.each do |p|
144
- if p.is_a?(Hash)
145
- # TODO: make it possible to nest translated objects
146
- else
147
- current_translated_properties[p] = p
148
- end
149
- end
150
-
151
- self.js_translated_properties_attr = current_translated_properties
152
- end
153
- end
154
-
155
- # Use it to "mixin" JavaScript objects defined in a separate file.
156
- #
157
- # You do not _have_ to use +js_method+ or +js_properties+ if those methods or properties are not supposed to be changed _dynamically_ (by means of configuring the component on the class level). Instead, you may "mixin" a JavaScript object defined in the JavaScript file named following a certain convention. This way static JavaScript code will rest in a corresponding .js file, not in the Ruby class. E.g.:
158
- #
159
- # class MyComponent < Netzke::Base
160
- # js_mixin :some_functionality
161
- # #...
162
- # end
163
- #
164
- # This will "mixin" a JavaScript object defined in a file called +{component_location}/my_component/javascripts/some_functionality.js+, which way contain something like this:
165
- #
166
- # {
167
- # someProperty: 100,
168
- #
169
- # someMethod: function(params){
170
- # // ...
171
- # }
172
- # }
173
- #
174
- # Also accepts a string, which will be interpreted as a full path to the file (useful for sharing mixins between classes).
175
- # With no parameters, will assume :component_class_name_underscored.
176
- def js_mixin(*args)
177
- args << name.split("::").last.underscore.to_sym if args.empty? # if no args provided, component_class_underscored_name is assumed
178
- current_mixins = clean_class_attribute_array(:js_mixins_attr)
179
- callr = caller.first
180
- args.each{ |a| current_mixins << (a.is_a?(Symbol) ? File.read(expand_js_include_path(a, callr)) : File.read(a))}
181
- self.js_mixins_attr = current_mixins
182
- end
183
-
184
- # Returns all objects to be mixed in (as array of strings)
185
- def js_mixins
186
- clean_class_attribute_array(:js_mixins_attr)
187
- end
188
-
189
- # Builds this component's xtype
190
- # E.g.: netzkebasepackwindow, netzkebasepackgridpanel
191
- def js_xtype
192
- name.gsub("::", "").downcase
193
- end
194
-
195
- # Alias prefix. Overridden for plugins.
196
- def js_alias_prefix
197
- "widget"
198
- end
199
-
200
- # Builds this component's alias
201
- # E.g.: netzke.basepack.window, netzke.basepack.gridpanel
202
- #
203
- # MAV from http://stackoverflow.com/questions/5380770/replacing-ext-reg-xtype-in-extjs4
204
- # "When you use an xtype in Ext JS 4 it looks for a class with an alias of 'widget.[xtype]'"
205
- def js_alias
206
- [js_alias_prefix, js_xtype].join(".")
207
- end
208
-
209
- # Component's JavaScript class declaration.
210
- # It gets stored in the JS class cache storage (Netzke.classes) at the client side to be reused at the moment of component instantiation.
211
- def js_class
212
- res = []
213
- # Defining the scope if it isn't known yet
214
- res << %{Ext.ns("#{js_full_scope}");} unless js_full_scope == js_default_scope
215
-
216
- res << (extends_netzke_component? ? js_class_declaration_extending_component : js_class_declaration_new_component)
217
-
218
- # Store created class xtype in the cache
219
- res << %(
220
- Netzke.cache.push('#{js_xtype}');
221
- )
222
-
223
- res.join("\n")
224
- end
225
-
226
-
227
- # Returns all included JavaScript files as a string
228
- def js_included
229
- res = ""
230
-
231
- # Prevent re-including code that was already included by the parent
232
- # (thus, only include those JS files when include_js was defined in the current class, not in its ancestors)
233
- ((singleton_methods(false).map(&:to_sym).include?(:include_js) ? include_js : []) + js_included_files).each do |path|
234
- f = File.new(path)
235
- res << f.read << "\n"
236
- end
237
-
238
- res
239
- end
240
-
241
- # DEPRECATED. Returns an array of included files. Made to be overridden. +js_include+ is preferred way.
242
- def include_js
243
- []
244
- end
245
-
246
- # JavaScript code needed for this particulaer class. Includes external JS code and the JS class definition for self.
247
- def js_code
248
- [js_included, js_class].join("\n")
249
- end
250
-
251
- protected
252
-
253
- # Little helper
254
- def this; "this".l; end
255
-
256
- # Little helper. E.g.:
257
- #
258
- # js_property :load_mask, null
259
- def null; "null".l; end
260
-
261
- # JS properties and methods merged together
262
- def js_extend_properties
263
- @js_extend_properties ||= js_properties.merge(js_methods)
264
- end
265
-
266
- # Generates declaration of the JS class as direct extension of a Ext component
267
- def js_class_declaration_new_component
268
- mixins = js_mixins.empty? ? "" : %(#{js_mixins.join(", \n")}, )
269
-
270
- # Resulting JS:
271
- %(Ext.define('#{js_full_class_name}', Netzke.chainApply({
272
- extend: '#{js_base_class}',
273
- alias: '#{js_alias}',
274
- constructor: function(config) {
275
- Netzke.aliasMethodChain(this, "initComponent", "netzke");
276
- #{js_full_class_name}.superclass.constructor.call(this, config);
277
- }
278
- }, Netzke.componentMixin,\n#{mixins} #{js_extend_properties.to_nifty_json}));)
279
- end
280
-
281
- # Generates declaration of the JS class as extension of another Netzke component
282
- def js_class_declaration_extending_component
283
- base_class = superclass.js_full_class_name
284
-
285
- mixins = js_mixins.empty? ? "" : %(#{js_mixins.join(", \n")}, )
286
-
287
- # Resulting JS:
288
- %(Ext.define('#{js_full_class_name}', Netzke.chainApply(#{mixins}#{js_extend_properties.to_nifty_json}, {
289
- extend: '#{base_class}',
290
- alias: '#{js_alias}'
291
- }));)
292
- end
293
-
294
- def expand_js_include_path(sym, callr) # :nodoc:
295
- %Q(#{callr.split(".rb:").first}/javascripts/#{sym}.js)
296
- end
297
-
298
- def extends_netzke_component? # :nodoc:
299
- superclass != Netzke::Base
300
- end
301
-
302
- end
303
-
304
- # The result of this method (a hash) is converted to a JSON object and passed as options
305
- # to the constructor of our JavaScript class. Override it when you want to pass any extra configuration
306
- # to the JavaScript side.
307
- def js_config
308
- {}.tap do |res|
309
- # Unique id of the component
310
- res[:id] = global_id
311
-
312
- # Non-lazy-loaded components
313
- comp_hash = {}
314
- eager_loaded_components.each_pair do |comp_name, comp_config|
315
- comp_instance = component_instance(comp_name.to_sym)
316
- comp_instance.before_load
317
- comp_hash[comp_name] = comp_instance.js_config
318
- end
319
-
320
- # Configuration for all of our non-lazy-loaded children specified here. We can refer to them in +items+ so they get instantiated by Ext.
321
- res[:netzke_components] = comp_hash unless comp_hash.empty?
322
-
323
- # Endpoints (besides the default "deliver_component" - JavaScript side already knows about it)
324
- endpoints = self.class.endpoints.keys - [:deliver_component]
325
- res[:endpoints] = endpoints unless endpoints.empty?
326
-
327
- # Inform the JavaScript side if persistent_config is enabled
328
- # res[:persistent_config] = persistence_enabled?
329
-
330
- # Include our xtype
331
- res[:xtype] = self.class.js_xtype
332
-
333
- # Include our alias: Ext.createByAlias may be used to instantiate the component.
334
- res[:alias] = self.class.js_alias
335
-
336
- # Merge with the rest of config options, besides those that are only meant for the server side
337
- res.merge!(config.reject{ |k,v| self.class.server_side_config_options.include?(k.to_sym) })
338
-
339
- if config[:ext_config].present?
340
- ::ActiveSupport::Deprecation.warn("Using ext_config option is deprecated. All config options must be specified at the same level in the hash.", caller)
341
- res.merge!(config[:ext_config])
342
- end
343
-
344
- # Items (nested Ext/Netzke components)
345
- res[:items] = items unless items.blank?
346
-
347
- # So we can use getComponent(<component_name>) to retrieve a child component
348
- res[:item_id] ||= name
349
-
350
- res[:i18n] = js_translate_properties if js_translate_properties.present?
351
-
352
- res[:netzke_plugins] = plugins.map{ |p| p.to_s.camelcase(:lower) } if plugins.present?
353
- end
354
- end
355
-
356
- # All the JS-code required by this instance of the component to be instantiated in the browser.
357
- # It includes JS-classes for the parents, non-lazy-loaded child components, and itself.
358
- def js_missing_code(cached = [])
359
- code = dependency_classes.inject("") do |r,k|
360
- cached.include?(k.js_xtype) ? r : r + k.js_code#.strip_js_comments
361
- end
362
- code.blank? ? nil : code
363
- end
364
-
365
- # DEPRECATED. Helper to access config[:ext_config].
366
- def ext_config
367
- ::ActiveSupport::Deprecation.warn("Using ext_config is deprecated. All config options must be specified at the same level in the hash.", caller)
368
- config[:ext_config] || {}
369
- end
370
-
371
- private
372
-
373
- # Merges all the translations in the class hierarchy
374
- def js_translate_properties
375
- @js_translate_properties ||= self.class.class_ancestors.inject({}) do |r,klass|
376
- hsh = klass.js_translate.keys.inject({}) { |h,t| h.merge(t => I18n.t("#{klass.i18n_id}.#{t}")) }
377
- r.merge(hsh)
378
- end
379
- end
380
-
381
- end
382
- end