netzke-core 0.5.5 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (152) hide show
  1. data/.autotest +1 -1
  2. data/.gitignore +4 -2
  3. data/CHANGELOG.rdoc +37 -15
  4. data/README.rdoc +93 -28
  5. data/Rakefile +5 -7
  6. data/TODO +24 -3
  7. data/app/controllers/netzke_controller.rb +70 -0
  8. data/app/models/netzke_preference.rb +170 -0
  9. data/autotest/discover.rb +2 -3
  10. data/features/actions.feature +13 -0
  11. data/features/basic.feature +7 -0
  12. data/features/client-server.feature +15 -0
  13. data/features/complex_component.feature +18 -0
  14. data/features/component.feature +13 -0
  15. data/features/component_loader.feature +31 -0
  16. data/features/composition.feature +32 -0
  17. data/features/custom_css.feature +17 -0
  18. data/features/file_inclusion.feature +13 -0
  19. data/features/inheritance.feature +19 -0
  20. data/features/persistence.feature +16 -0
  21. data/features/scopes.feature +17 -0
  22. data/features/step_definitions/custom_css_steps.rb +7 -0
  23. data/features/step_definitions/generic_steps.rb +15 -0
  24. data/features/step_definitions/web_steps.rb +219 -0
  25. data/features/support/env.rb +62 -0
  26. data/features/support/paths.rb +45 -0
  27. data/generators/netzke_core/USAGE +3 -3
  28. data/generators/netzke_core/netzke_core_generator.rb +8 -0
  29. data/install.rb +1 -1
  30. data/javascripts/core.js +542 -499
  31. data/lib/generators/migration_helper.rb +32 -0
  32. data/lib/generators/netzke/USAGE +9 -0
  33. data/lib/generators/netzke/core_generator.rb +24 -0
  34. data/lib/netzke/actions.rb +102 -0
  35. data/lib/netzke/base.rb +77 -529
  36. data/lib/netzke/composition.rb +251 -0
  37. data/lib/netzke/configuration.rb +134 -0
  38. data/lib/netzke/core/masquerading.rb +34 -0
  39. data/lib/netzke/core/session.rb +30 -0
  40. data/lib/netzke/core/version.rb +11 -0
  41. data/lib/netzke/core.rb +53 -0
  42. data/lib/netzke/core_ext/array.rb +30 -0
  43. data/lib/netzke/core_ext/hash.rb +84 -0
  44. data/lib/netzke/core_ext/string.rb +26 -0
  45. data/lib/netzke/core_ext/symbol.rb +13 -0
  46. data/lib/netzke/core_ext/time_with_zone.rb +7 -0
  47. data/lib/netzke/core_ext.rb +5 -141
  48. data/lib/netzke/embedding.rb +21 -0
  49. data/lib/netzke/ext_component.rb +25 -0
  50. data/lib/netzke/javascript.rb +248 -0
  51. data/lib/netzke/persistence.rb +118 -0
  52. data/lib/netzke/rails/action_view_ext.rb +103 -0
  53. data/lib/netzke/{controller_extensions.rb → rails/controller_extensions.rb} +7 -2
  54. data/lib/netzke/rails/routes.rb +7 -0
  55. data/lib/netzke/services.rb +68 -0
  56. data/lib/netzke/session.rb +35 -0
  57. data/lib/netzke/stylesheets.rb +52 -0
  58. data/lib/netzke-core.rb +28 -29
  59. data/netzke-core.gemspec +253 -0
  60. data/spec/component/actions_spec.rb +94 -0
  61. data/spec/component/base_spec.rb +25 -0
  62. data/spec/component/composition_spec.rb +132 -0
  63. data/spec/component/javascript_spec.rb +15 -0
  64. data/spec/core_ext_spec.rb +16 -0
  65. data/spec/spec.opt +2 -0
  66. data/spec/spec_helper.rb +35 -0
  67. data/{test/app_root/db/migrate/20081222035855_create_netzke_preferences.rb → templates/core/create_netzke_preferences.rb} +4 -4
  68. data/test/rails_app/.gitignore +4 -0
  69. data/test/rails_app/Gemfile +36 -0
  70. data/test/rails_app/Gemfile.lock +137 -0
  71. data/test/rails_app/README +15 -0
  72. data/test/rails_app/Rakefile +7 -0
  73. data/test/rails_app/app/components/border_layout_panel.rb +4 -0
  74. data/test/rails_app/app/components/component_loader.rb +59 -0
  75. data/test/rails_app/app/components/component_with_actions.rb +58 -0
  76. data/test/rails_app/app/components/component_with_custom_css.rb +8 -0
  77. data/test/rails_app/app/components/component_with_included_js.rb +16 -0
  78. data/test/rails_app/app/components/component_with_session_persistence.rb +25 -0
  79. data/test/rails_app/app/components/custom.css +3 -0
  80. data/test/rails_app/app/components/deprecated/server_caller.rb +20 -0
  81. data/test/rails_app/app/components/extended_component_with_actions.rb +5 -0
  82. data/test/rails_app/app/components/extended_server_caller.rb +18 -0
  83. data/test/rails_app/app/components/included.js +5 -0
  84. data/test/rails_app/app/components/kinda_complex_component/basic_stuff.rb +35 -0
  85. data/test/rails_app/app/components/kinda_complex_component/extra_stuff.rb +16 -0
  86. data/test/rails_app/app/components/kinda_complex_component.rb +7 -0
  87. data/test/rails_app/app/components/loader_of_component_with_custom_css.rb +15 -0
  88. data/test/rails_app/app/components/scoped_components/deep_scoped_components/some_deep_scoped_component.rb +7 -0
  89. data/test/rails_app/app/components/scoped_components/extended_scoped_component.rb +5 -0
  90. data/test/rails_app/app/components/scoped_components/some_scoped_component.rb +5 -0
  91. data/test/rails_app/app/components/server_caller.rb +21 -0
  92. data/test/rails_app/app/components/simple_component.rb +5 -0
  93. data/test/rails_app/app/components/simple_tab_panel.rb +27 -0
  94. data/test/rails_app/app/components/simple_window.rb +3 -0
  95. data/test/rails_app/app/components/some_composite.rb +65 -0
  96. data/test/rails_app/app/components/some_ext_component.rb +8 -0
  97. data/test/{app_root → rails_app}/app/controllers/application_controller.rb +1 -0
  98. data/test/rails_app/app/controllers/components_controller.rb +12 -0
  99. data/test/rails_app/app/controllers/multiple_components_controller.rb +2 -0
  100. data/test/rails_app/app/controllers/welcome_controller.rb +5 -0
  101. data/test/rails_app/app/helpers/application_helper.rb +2 -0
  102. data/test/rails_app/app/views/layouts/application.html.erb +13 -0
  103. data/test/rails_app/app/views/multiple_components/set_one.html.erb +3 -0
  104. data/test/rails_app/config/application.rb +45 -0
  105. data/test/rails_app/config/boot.rb +13 -0
  106. data/test/rails_app/config/database.yml +22 -0
  107. data/test/rails_app/config/environment.rb +6 -0
  108. data/test/rails_app/config/environments/development.rb +22 -0
  109. data/test/rails_app/config/environments/production.rb +49 -0
  110. data/test/rails_app/config/environments/test.rb +35 -0
  111. data/test/rails_app/config/initializers/backtrace_silencers.rb +7 -0
  112. data/test/rails_app/config/initializers/inflections.rb +10 -0
  113. data/test/rails_app/config/initializers/mime_types.rb +5 -0
  114. data/test/rails_app/config/initializers/netzke.rb +3 -0
  115. data/test/rails_app/config/initializers/secret_token.rb +7 -0
  116. data/test/rails_app/config/initializers/session_store.rb +8 -0
  117. data/test/rails_app/config/locales/en.yml +5 -0
  118. data/test/rails_app/config/routes.rb +64 -0
  119. data/test/rails_app/config.ru +4 -0
  120. data/test/rails_app/db/development_structure.sql +4 -0
  121. data/{generators/netzke_core/templates/create_netzke_preferences.rb → test/rails_app/db/migrate/20100905214933_create_netzke_preferences.rb} +1 -3
  122. data/test/rails_app/db/schema.rb +24 -0
  123. data/test/rails_app/db/seeds.rb +7 -0
  124. data/test/{app_root/config/environments/in_memory.rb → rails_app/lib/tasks/.gitkeep} +0 -0
  125. data/test/rails_app/public/404.html +26 -0
  126. data/test/rails_app/public/422.html +26 -0
  127. data/test/rails_app/public/500.html +26 -0
  128. data/test/{app_root/config/environments/mysql.rb → rails_app/public/favicon.ico} +0 -0
  129. data/test/rails_app/public/images/rails.png +0 -0
  130. data/test/rails_app/public/robots.txt +5 -0
  131. data/test/rails_app/script/rails +6 -0
  132. data/test/{app_root/config/environments/postgresql.rb → rails_app/vendor/plugins/.gitkeep} +0 -0
  133. data/test/unit/netzke_core_test.rb +74 -75
  134. data/test/unit/netzke_preference_test.rb +2 -2
  135. metadata +176 -48
  136. data/lib/app/controllers/netzke_controller.rb +0 -46
  137. data/lib/app/models/netzke_preference.rb +0 -171
  138. data/lib/netzke/action_view_ext.rb +0 -81
  139. data/lib/netzke/base_js.rb +0 -339
  140. data/lib/netzke/routing.rb +0 -9
  141. data/test/app_root/app/models/role.rb +0 -3
  142. data/test/app_root/app/models/user.rb +0 -3
  143. data/test/app_root/config/boot.rb +0 -115
  144. data/test/app_root/config/database.yml +0 -31
  145. data/test/app_root/config/environment.rb +0 -14
  146. data/test/app_root/config/environments/sqlite.rb +0 -0
  147. data/test/app_root/config/environments/sqlite3.rb +0 -0
  148. data/test/app_root/config/routes.rb +0 -4
  149. data/test/app_root/db/migrate/20090423214303_create_roles.rb +0 -11
  150. data/test/app_root/db/migrate/20090423222114_create_users.rb +0 -12
  151. data/test/app_root/lib/console_with_fixtures.rb +0 -4
  152. data/test/app_root/script/console +0 -7
@@ -0,0 +1,251 @@
1
+ # require 'active_support/core_ext/class/inheritable_attributes'
2
+
3
+ module Netzke
4
+ module Composition
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+
9
+ # Loads a component on browser's request. Every Nettzke component gets this endpoint.
10
+ # <tt>params</tt> should contain:
11
+ # * <tt>:cache</tt> - an array of component classes cached at the browser
12
+ # * <tt>:id</tt> - reference to the component
13
+ # * <tt>:container</tt> - Ext id of the container where in which the component will be rendered
14
+ endpoint :deliver_component do |params|
15
+ cache = params[:cache].gsub(".", "::").split(",") # array of cached class names (in Ruby)
16
+ component_name = params.delete(:name).underscore.to_sym
17
+ component = components[component_name] && component_instance(component_name)
18
+
19
+ if component
20
+ # inform the component that it's being loaded
21
+ component.before_load
22
+
23
+ [{
24
+ :eval_js => component.js_missing_code(cache),
25
+ :eval_css => component.css_missing_code(cache)
26
+ }, {
27
+ :component_delivered => component.js_config
28
+ }]
29
+ else
30
+ {:feedback => "Couldn't load component '#{component_name}'"}
31
+ end
32
+ end
33
+
34
+ end # included
35
+
36
+ module ClassMethods
37
+
38
+ # Defines a nested component.
39
+ # For example:
40
+ #
41
+ # component :users, :data_class => "GridPanel", :model => "User"
42
+ #
43
+ # It can also accept a block (receiving as parameter the eventual definition from super class):
44
+ #
45
+ # component :books do |orig|
46
+ # {:data_class => "Book", :title => orig[:title] + ", extended"}
47
+ # end
48
+ def component(name, config = {}, &block)
49
+ config = config.dup
50
+ config[:class_name] ||= name.to_s.camelize
51
+ config[:name] = name.to_s
52
+ method_name = "_#{name}_component"
53
+
54
+ if block_given?
55
+ define_method(method_name, &block)
56
+ else
57
+ define_method(method_name) do
58
+ config
59
+ end
60
+ end
61
+ end
62
+
63
+ # Component's js config used when embedding components as Container's items
64
+ # (see some_composite.rb for an example)
65
+ def js_component(name, config = {})
66
+ config.merge(:component => name)
67
+ end
68
+
69
+ end
70
+
71
+ module InstanceMethods
72
+
73
+ def items
74
+ @items_with_normalized_components
75
+ end
76
+
77
+ def initial_components
78
+ {}
79
+ end
80
+
81
+ # All components for this instance, which includes components defined on class level, and components detected in :items
82
+ def components
83
+ # items if @components.nil? # simply trigger collecting @components from items
84
+ # self.class.components.merge(@components || {})
85
+
86
+ @components ||= begin
87
+ method_regexp = /^_(.+)_component$/
88
+ self.class.instance_methods.grep(method_regexp).inject({}) do |r, m|
89
+ m.match(method_regexp)
90
+ r.merge($1.to_sym => send(m))
91
+ end
92
+ end
93
+ end
94
+
95
+ def non_late_components
96
+ components.reject{|k,v| v[:lazy_loading]}
97
+ end
98
+
99
+ def add_component(aggr)
100
+ components.merge!(aggr)
101
+ end
102
+
103
+ def remove_component(aggr)
104
+ if config[:persistent_config]
105
+ persistence_manager_class.delete_all_for_component("#{global_id}__#{aggr}")
106
+ end
107
+ components[aggr] = nil
108
+ end
109
+
110
+ # The difference between components and late components is the following: the former gets instantiated together with its composite and is normally *instantly* visible as a part of it (for example, the component in the initially expanded panel in an Accordion). A late component doesn't get instantiated along with its composite. Until it gets requested from the server, it doesn't take any part in its composite's life. An example of late component could be a component that is loaded dynamically into a previously collapsed panel of an Accordion, or a preferences window (late component) for a component (composite) that only gets shown when user wants to edit component's preferences.
111
+ def initial_late_components
112
+ {}
113
+ end
114
+
115
+ def add_late_component(aggr)
116
+ components.merge!(aggr.merge(:lazy_loading => true))
117
+ end
118
+
119
+ # called when the method_missing tries to processes a non-existing component
120
+ def component_missing(aggr)
121
+ flash :error => "Unknown component #{aggr} for component #{name}"
122
+ {:feedback => @flash}.to_nifty_json
123
+ end
124
+
125
+ # recursively instantiates an component based on its "path": e.g. if we have an component :aggr1 which in its turn has an component :aggr10, the path to the latter would be "aggr1__aggr10"
126
+ def component_instance(name, strong_config = {})
127
+ @cached_component_instances ||= {}
128
+ @cached_component_instances[name] ||= begin
129
+ composite = self
130
+ name.to_s.split('__').each do |aggr|
131
+ aggr = aggr.to_sym
132
+ component_config = composite.components[aggr]
133
+ raise ArgumentError, "No component '#{aggr}' defined for component '#{composite.global_id}'" if component_config.nil?
134
+ short_component_class_name = component_config[:class_name]
135
+ raise ArgumentError, "No class_name specified for component #{aggr} of #{composite.global_id}" if short_component_class_name.nil?
136
+ component_class = constantize_class_name(short_component_class_name)
137
+
138
+ conf = weak_children_config.
139
+ deep_merge(component_config).
140
+ deep_merge(strong_config). # we may want to reconfigure the component at the moment of instantiation
141
+ merge(:name => aggr)
142
+
143
+ composite = component_class.new(conf, composite) # params: config, parent
144
+ # composite.weak_children_config = weak_children_config
145
+ # composite.strong_children_config = strong_children_config
146
+ end
147
+ composite
148
+ end
149
+ end
150
+
151
+ def dependency_classes
152
+ res = []
153
+
154
+ non_late_components.keys.each do |aggr|
155
+ res += component_instance(aggr).dependency_classes
156
+ end
157
+
158
+ res += self.class.class_ancestors
159
+
160
+ res << self.class
161
+ res.uniq
162
+ end
163
+
164
+ ## Dependencies
165
+ # def dependencies
166
+ # @dependencies ||= begin
167
+ # non_late_components_component_classes = non_late_components.values.map{|v| v[:class_name]}
168
+ # (initial_dependencies + non_late_components_component_classes << self.class.short_component_class_name).uniq
169
+ # end
170
+ # end
171
+
172
+ # override this method if you need some extra dependencies, which are not the components
173
+ def initial_dependencies
174
+ []
175
+ end
176
+
177
+ def js_component(*args)
178
+ self.class.js_component(*args)
179
+ end
180
+
181
+ # Returns global id of a component in the hierarchy, based on passed reference that follows
182
+ # the double-underscore notation. Referring to "parent" is allowed. If going to far up the hierarchy will
183
+ # result in <tt>nil</tt>, while referring to a non-existent component will simply provide an erroneous ID.
184
+ # Example:
185
+ # <tt>parent__parent__child__subchild</tt> will traverse the hierarchy 2 levels up, then going down to "child",
186
+ # and further to "subchild". If such a component exists in the hierarchy, its global id will be returned, otherwise
187
+ # <tt>nil</tt> will be returned.
188
+ def global_id_by_reference(ref)
189
+ ref = ref.to_s
190
+ return parent && parent.global_id if ref == "parent"
191
+ substr = ref.sub(/^parent__/, "")
192
+ if substr == ref # there's no "parent__" in the beginning
193
+ return global_id + "__" + ref
194
+ else
195
+ return parent.global_id_by_reference(substr)
196
+ end
197
+ end
198
+
199
+ # Method dispatcher - instantiates an component and calls the method on it
200
+ # E.g.:
201
+ # users__center__get_data
202
+ # instantiates component "users", and calls "center__get_data" on it
203
+ # books__move_column
204
+ # instantiates component "books", and calls "endpoint_move_column" on it
205
+ def method_missing(method_name, params = {})
206
+ component, *action = method_name.to_s.split('__')
207
+ component = component.to_sym
208
+ action = !action.empty? && action.join("__").to_sym
209
+
210
+ if action
211
+ if components[component]
212
+ # only actions starting with "endpoint_" are accessible
213
+ endpoint_action = action.to_s.index('__') ? action : "endpoint_#{action}"
214
+ component_instance(component).send(endpoint_action, params)
215
+ else
216
+ component_missing(component)
217
+ end
218
+ else
219
+ super
220
+ end
221
+ end
222
+
223
+ private
224
+
225
+ def normalize_components(items)
226
+ @component_index ||= 0
227
+ @items_with_normalized_components = items.each_with_index.map do |item, i|
228
+ if is_component_config?(item)
229
+ component_name = item[:name] || :"#{item[:class_name].underscore.split("/").last}#{@component_index}"
230
+ @component_index += 1
231
+ self.class.component(component_name.to_sym, item)
232
+ js_component(component_name) # replace current item with a reference to component
233
+ elsif item.is_a?(Hash)
234
+ item[:items].is_a?(Array) ? item.merge(:items => normalize_components(item[:items])) : item
235
+ else
236
+ item
237
+ end
238
+ end
239
+ end
240
+
241
+ def normalize_components_in_items
242
+ normalize_components(config[:items]) if config[:items]
243
+ end
244
+
245
+ def is_component_config?(c)
246
+ !!(c.is_a?(Hash) && c[:class_name])
247
+ end
248
+ end
249
+
250
+ end
251
+ end
@@ -0,0 +1,134 @@
1
+ module Netzke
2
+ module Configuration
3
+ extend ActiveSupport::Concern
4
+
5
+ CONFIGURATION_LEVELS = [:default, :initial, :independent, :session, :final]
6
+
7
+ included do
8
+ CONFIGURATION_LEVELS.each do |level|
9
+ define_method("weak_#{level}_options"){ {} }
10
+ end
11
+ end
12
+
13
+ module ClassMethods
14
+ def setup
15
+ yield self
16
+ end
17
+
18
+ # Config options that should not go to the client side
19
+ def server_side_config_options
20
+ [:lazy_loading, :class_name]
21
+ end
22
+
23
+ def config(*args, &block)
24
+ level = args.first.is_a?(Symbol) ? args.first : :final
25
+ config_hash = args.last.is_a?(Hash) && args.last
26
+ raise ArgumentError, "Config hash or block required" if !block_given? && !config_hash
27
+ if block_given?
28
+ define_method(:"weak_#{level}_options", &block)
29
+ else
30
+ define_method(:"weak_#{level}_options") do
31
+ config_hash
32
+ end
33
+ end
34
+ end
35
+
36
+ end
37
+
38
+ module InstanceMethods
39
+ # Default config - before applying any passed configuration
40
+ def default_config
41
+ @default_config ||= {}.merge(weak_default_options).merge(self.class.default_instance_config)
42
+ end
43
+
44
+ # Static, hardcoded config. Consists of default values merged with config that was passed during instantiation
45
+ def initial_config
46
+ @initial_config ||= default_config.merge(weak_initial_options).merge(@passed_config)
47
+ end
48
+
49
+ # Config that is not overridden by parents and sessions
50
+ def independent_config
51
+ @independent_config ||= initial_config.merge(weak_independent_options).merge(persistent_options)
52
+ end
53
+
54
+ def session_config
55
+ @session_config ||= independent_config.merge(weak_session_options).merge(session_options)
56
+ end
57
+
58
+ # Last level config, overridden only by ineritance
59
+ def final_config
60
+ @strong_config ||= session_config.merge(weak_final_options).merge(strong_parent_config)
61
+ end
62
+
63
+ # Resulting config that takes into account all possible ways to configure a component. *Read only*.
64
+ # Translates into something like this:
65
+ #
66
+ # default_config.
67
+ # deep_merge(@passed_config).
68
+ # deep_merge(persistent_options).
69
+ # deep_merge(strong_parent_config).
70
+ # deep_merge(strong_session_config)
71
+ #
72
+ # Moved out to a separate method in order to provide for easy caching.
73
+ # *Do not override this method*, use +Base.config+ instead.
74
+ def config
75
+ @config ||= final_config
76
+ end
77
+
78
+ def flat_config(key = nil)
79
+ fc = config.flatten_with_type
80
+ key.nil? ? fc : fc.select{ |c| c[:name] == key.to_sym }.first.try(:value)
81
+ end
82
+
83
+ def strong_parent_config
84
+ @strong_parent_config ||= parent.nil? ? {} : parent.strong_children_config
85
+ end
86
+
87
+ def flat_independent_config(key = nil)
88
+ fc = independent_config.flatten_with_type
89
+ key.nil? ? fc : fc.select{ |c| c[:name] == key.to_sym }.first.try(:value)
90
+ end
91
+
92
+ def flat_default_config(key = nil)
93
+ fc = default_config.flatten_with_type
94
+ key.nil? ? fc : fc.select{ |c| c[:name] == key.to_sym }.first.try(:value)
95
+ end
96
+
97
+ def flat_initial_config(key = nil)
98
+ fc = initial_config.flatten_with_type
99
+ key.nil? ? fc : fc.select{ |c| c[:name] == key.to_sym }.first.try(:value)
100
+ end
101
+
102
+ # Like normal config, but stored in session
103
+ # def weak_session_config
104
+ # component_session[:weak_session_config] ||= {}
105
+ # end
106
+ #
107
+ # def strong_session_config
108
+ # component_session[:strong_session_config] ||= {}
109
+ # end
110
+
111
+
112
+
113
+ # configuration of all children will get deep_merge'd with strong_children_config
114
+ # def strong_children_config= (c)
115
+ # @strong_children_config = c
116
+ # end
117
+
118
+ # This config will be picked up by all the descendants
119
+ def strong_children_config
120
+ @strong_children_config ||= parent.nil? ? {} : parent.strong_children_config
121
+ end
122
+
123
+ # configuration of all children will get reverse_deep_merge'd with weak_children_config
124
+ # def weak_children_config= (c)
125
+ # @weak_children_config = c
126
+ # end
127
+
128
+ def weak_children_config
129
+ @weak_children_config ||= {}
130
+ end
131
+
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,34 @@
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
@@ -0,0 +1,30 @@
1
+ module Netzke
2
+ module Core
3
+ module Session
4
+ # Access to controller sessions
5
+ def session
6
+ @@session ||= {}
7
+ end
8
+
9
+ def session=(s)
10
+ @@session = s
11
+ end
12
+
13
+ # Should be called by session controller at the moment of successfull login
14
+ def login
15
+ session[:_netzke_next_request_is_first_after_login] = true
16
+ end
17
+
18
+ # Should be called by session controller at the moment of logout
19
+ def logout
20
+ session[:_netzke_next_request_is_first_after_logout] = true
21
+ end
22
+
23
+ # Register the configuration for the component in the session, and also remember that the code for it has been rendered
24
+ def reg_component(config)
25
+ session[:netzke_components] ||= {}
26
+ session[:netzke_components][config[:name]] = config
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,11 @@
1
+ module Netzke
2
+ module Core
3
+ module Version
4
+ MAJOR = 0
5
+ MINOR = 6
6
+ PATCH = 0
7
+
8
+ STRING = [MAJOR, MINOR, PATCH].compact.join('.')
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,53 @@
1
+ require 'active_support/core_ext'
2
+ require 'netzke/core/version'
3
+ require 'netzke/core/session'
4
+ require 'netzke/core/masquerading'
5
+
6
+ module Netzke
7
+ # You can configure Netzke::Core like this:
8
+ #
9
+ # Netzke::Core.setup do |config|
10
+ # config.ext_location = "/home/netzke/ext-3.3.0"
11
+ # config.icons_uri = "/images/famfamfam/icons"
12
+ # # ...
13
+ # end
14
+ #
15
+ # The following configuration options are available:
16
+ # * ext_location - absolute path to your Ext code root
17
+ # * icons_uri - relative URI to the icons
18
+ # * javascript_on_main_page (true/false, defaults to false) - if you want the JS classes to be inserted into the code of the page,
19
+ # rather than into netzke.js (setting to true can be handy for debugging)
20
+ module Core
21
+ extend Session
22
+ extend Masquerading
23
+
24
+ mattr_accessor :controller
25
+
26
+ mattr_accessor :javascripts
27
+ @@javascripts = ["#{File.dirname(__FILE__)}/../../javascripts/core.js"]
28
+
29
+ mattr_accessor :stylesheets
30
+ @@stylesheets = ["#{File.dirname(__FILE__)}/../../stylesheets/core.css"]
31
+
32
+ mattr_accessor :external_css
33
+ @@external_css = []
34
+
35
+ mattr_accessor :ext_location
36
+
37
+ mattr_accessor :with_icons
38
+
39
+ mattr_accessor :icons_uri
40
+ @@icons_uri = "/images/icons"
41
+
42
+ mattr_accessor :javascript_on_main_page
43
+ @@javascript_on_main_page = false
44
+
45
+ def self.setup
46
+ yield self
47
+ end
48
+
49
+ def self.reset_components_in_session
50
+ Netzke::Core.session[:netzke_components].try(:clear)
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,30 @@
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
@@ -0,0 +1,84 @@
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
+ # Javascrit-like access to Hash values
73
+ def method_missing(method, *args)
74
+ if method.to_s =~ /=$/
75
+ method_base = method.to_s.sub(/=$/,'').to_sym
76
+ key = self[method_base.to_s].nil? ? method_base : method_base.to_s
77
+ self[key] = args.first
78
+ else
79
+ key = self[method.to_s].nil? ? method : method.to_s
80
+ self[key]
81
+ end
82
+ end
83
+
84
+ end
@@ -0,0 +1,26 @@
1
+ class String
2
+ def jsonify
3
+ self.camelize(:lower)
4
+ end
5
+
6
+ # Converts self to "literal JSON"-string - one that doesn't get quotes appended when being sent "to_json" method
7
+ def l
8
+ ActiveSupport::JSON::Variable.new(self)
9
+ end
10
+
11
+ # removes JS-comments (both single- and multi-line) from the string
12
+ def strip_js_comments
13
+ regexp = /\/\/.*$|(?m:\/\*.*?\*\/)/
14
+ self.gsub!(regexp, '')
15
+
16
+ # also remove empty lines
17
+ regexp = /^\s*\n/
18
+ self.gsub!(regexp, '')
19
+ end
20
+
21
+ # "false" => false, "whatever_else" => true
22
+ def to_b
23
+ self != "false"
24
+ end
25
+
26
+ end
@@ -0,0 +1,13 @@
1
+ class Symbol
2
+ def jsonify
3
+ self.to_s.camelize(:lower).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.to_s)
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ module ActiveSupport
2
+ class TimeWithZone
3
+ def to_json(options = {})
4
+ self.to_s(:db).to_json
5
+ end
6
+ end
7
+ end