netzke-core 0.4.5 → 0.4.5.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.rdoc CHANGED
@@ -1,4 +1,8 @@
1
- = edge
1
+ = v0.4.5.1 - 2009-11-09
2
+ * Regression: fixing inheritance and caching.
3
+ * FeedbackGhost is too simple to be a Netzke widget (having no server part), so, moved to static JavaScript.
4
+
5
+ = v0.4.5 - 2009-11-08
2
6
  * API change: Netzke::Base: <tt>id_name</tt> accessor renamed to <tt>global_id</tt>
3
7
  * Code: several internal code changes
4
8
  * Code: lightly better test coverage
data/Rakefile CHANGED
@@ -1,7 +1,7 @@
1
1
  begin
2
2
  require 'jeweler'
3
3
  Jeweler::Tasks.new do |gemspec|
4
- gemspec.version = "0.4.5"
4
+ gemspec.version = "0.4.5.1"
5
5
  gemspec.name = "netzke-core"
6
6
  gemspec.summary = "Build ExtJS/Rails widgets with minimum effort"
7
7
  gemspec.description = "Allows building ExtJS/Rails reusable code in a DRY way"
data/javascripts/core.js CHANGED
@@ -3,10 +3,11 @@ This file gets loaded along with the rest of Ext library at the initial load
3
3
  */
4
4
 
5
5
  Ext.BLANK_IMAGE_URL = "/extjs/resources/images/default/s.gif";
6
- Ext.namespace('Ext.netzke'); // namespace for extensions that depend on Ext
7
- Ext.namespace('Netzke.classes'); // namespace for extensions that do not depend on Ext
6
+ Ext.ns('Ext.netzke'); // namespace for extensions that depend on Ext
7
+ Ext.ns('Netzke'); // Netzke namespace
8
+ Netzke.cache = {}; // empty Netzke cache at the moment of loading
8
9
 
9
- Ext.QuickTips.init(); // seems obligatory in Ext v2.2.1, otherwise Ext.Component#destroy() stops working properly
10
+ Ext.QuickTips.init();
10
11
 
11
12
  // To comply with Rails' forgery protection
12
13
  Ext.Ajax.extraParams = {
@@ -98,11 +99,11 @@ Ext.widgetMixIn = {
98
99
  var apiParams = Ext.apply({id: params.id, container: params.container}, params.params);
99
100
 
100
101
  // build the cached widgets list to send it to the server
101
- var cachedWidgetNames = [];
102
- for (name in Netzke.classes) {
103
- cachedWidgetNames.push(name);
102
+ var cachedWidgetNames = "";
103
+ for (name in Netzke.cache) {
104
+ cachedWidgetNames += name + ",";
104
105
  }
105
- apiParams.cache = Ext.encode(cachedWidgetNames);
106
+ apiParams.cache = cachedWidgetNames;
106
107
 
107
108
  // remember the passed callback for the future
108
109
  if (params.callback) {
@@ -415,7 +416,7 @@ Ext.widgetMixIn = {
415
416
  // At this moment component is fully initializied
416
417
  commonAfterConstructor : function(config){
417
418
  // From everywhere accessible FeedbackGhost
418
- this.feedbackGhost = Ext.getCmp('feedback_ghost');
419
+ this.feedbackGhost = new Netzke.FeedbackGhost();
419
420
 
420
421
  // Add the menus
421
422
  if (this.initialConfig.menu) {this.addMenu(this.initialConfig.menu, this);}
@@ -524,6 +525,9 @@ Ext.override(Ext.Container, {
524
525
  Ext.each(n.split("."), function(s){
525
526
  klass = klass[s];
526
527
  });
528
+ // Caching the class
529
+ Netzke.cache[n] = true;
530
+ // console.info(Netzke.cache);
527
531
  return klass;
528
532
  },
529
533
 
data/lib/netzke/base.rb CHANGED
@@ -47,12 +47,20 @@ module Netzke
47
47
  # Class-level Netzke::Base configuration. The defaults also get specified here.
48
48
  def self.config
49
49
  set_default_config({
50
- # which javascripts and stylesheets must get included at the initial load (see netzke-core.rb)
50
+ # Which javascripts and stylesheets must get included at the initial load (see netzke-core.rb)
51
51
  :javascripts => [],
52
52
  :stylesheets => [],
53
53
 
54
+ # AR model that provides us with persistent config functionality
54
55
  :persistent_config_manager => "NetzkePreference",
56
+
57
+ # Default location of extjs library
55
58
  :ext_location => defined?(RAILS_ROOT) && "#{RAILS_ROOT}/public/extjs",
59
+
60
+ # Default location of icons (TODO: has no effect for now)
61
+ :icons_location => defined?(RAILS_ROOT) && "#{RAILS_ROOT}/public/images/icons",
62
+
63
+ # Default instance config
56
64
  :default_config => {
57
65
  :persistent_config => true
58
66
  }
@@ -83,7 +91,7 @@ module Netzke
83
91
  # Short widget class name, e.g.:
84
92
  # Netzke::Module::SomeWidget => Module::SomeWidget
85
93
  def self.short_widget_class_name
86
- self.name.sub("Netzke::", "")
94
+ self.name.sub(/^Netzke::/, "")
87
95
  end
88
96
 
89
97
  # Access to controller sessions
@@ -397,6 +405,7 @@ module Netzke
397
405
  end
398
406
 
399
407
  # recursively instantiates an aggregatee based on its "path": e.g. if we have an aggregatee :aggr1 which in its turn has an aggregatee :aggr10, the path to the latter would be "aggr1__aggr10"
408
+ # TODO: introduce memoization
400
409
  def aggregatee_instance(name, strong_config = {})
401
410
  aggregator = self
402
411
  name.to_s.split('__').each do |aggr|
@@ -481,7 +490,7 @@ module Netzke
481
490
  # * <tt>:id</tt> - reference to the aggregatee
482
491
  # * <tt>:container</tt> - Ext id of the container where in which the aggregatee will be rendered
483
492
  def load_aggregatee_with_cache(params)
484
- cache = ActiveSupport::JSON.decode(params.delete(:cache))
493
+ cache = params[:cache].gsub(".", "::").split(",") # array of cached class names (in Ruby)
485
494
  relative_widget_id = params.delete(:id).underscore.to_sym
486
495
  widget = aggregatees[relative_widget_id] && aggregatee_instance(relative_widget_id)
487
496
 
@@ -57,7 +57,6 @@ module Netzke
57
57
  res[:persistent_config] = persistent_config_enabled?
58
58
 
59
59
  # Merge with all config options passed as hash to config[:ext_config]
60
- logger.debug "!!! ext_config: #{ext_config.inspect}\n"
61
60
  res.merge!(ext_config)
62
61
 
63
62
  res
@@ -65,16 +64,16 @@ module Netzke
65
64
 
66
65
  # All the JS-code required by this instance of the widget to be instantiated in the browser.
67
66
  # It includes the JS-class for the widget itself, as well as JS-classes for all widgets' (non-late) aggregatees.
68
- def js_missing_code(cached_dependencies = [])
67
+ def js_missing_code(cached = [])
69
68
  code = dependency_classes.inject("") do |r,k|
70
- cached_dependencies.include?(k) ? r : r + "Netzke::#{k}".constantize.js_code(cached_dependencies).strip_js_comments
69
+ cached.include?(k) ? r : r + "Netzke::#{k}".constantize.js_code(cached).strip_js_comments
71
70
  end
72
71
  code.blank? ? nil : code
73
72
  end
74
73
 
75
- def css_missing_code(cached_dependencies = [])
74
+ def css_missing_code(cached = [])
76
75
  code = dependency_classes.inject("") do |r,k|
77
- cached_dependencies.include?(k) ? r : r + "Netzke::#{k}".constantize.css_code(cached_dependencies)
76
+ cached.include?(k) ? r : r + "Netzke::#{k}".constantize.css_code(cached)
78
77
  end
79
78
  code.blank? ? nil : code
80
79
  end
@@ -90,13 +89,7 @@ module Netzke
90
89
 
91
90
  # rendering
92
91
  def js_widget_render
93
- %Q{
94
- if (#{name.jsonify}.isXType("netzkewindow")) {
95
- #{name.jsonify}.show();
96
- } else {
97
- #{name.jsonify}.render("#{name.to_s.split('_').join('-')}-div");
98
- }
99
- }
92
+ self.class.js_xtype == "netzkewindow" ? %Q{#{name.jsonify}.show();} : %Q{#{name.jsonify}.render("#{name.to_s.split('_').join('-')}-div");}
100
93
  end
101
94
 
102
95
  # container for rendering
@@ -132,35 +125,52 @@ module Netzke
132
125
  def js_extend_properties
133
126
  {}
134
127
  end
135
-
136
- # Returns the scope of this widget,
137
- # e.g. "Netzke.GridPanelLib"
128
+
129
+ # widget's menus
130
+ def js_menus; []; end
131
+
132
+ # Given class name, e.g. GridPanelLib::Widgets::RecordFormWindow,
133
+ # returns its scope: "Widgets.RecordFormWindow"
134
+ def js_class_name_to_scope(name)
135
+ name.split("::")[0..-2].join(".")
136
+ end
137
+
138
+ # Top level scope which will be used to cope out Netzke classes, e.g. "Netzke.classes" (default)
139
+ def js_default_scope
140
+ "Netzke.classes"
141
+ end
142
+
143
+ # Scope of this widget without default scope
144
+ # e.g.: GridPanelLib.Widgets
138
145
  def js_scope
139
- js_full_class_name.split(".")[0..-2].join(".")
146
+ js_class_name_to_scope(short_widget_class_name)
147
+ end
148
+
149
+ # Returns the scope of this widget
150
+ # e.g. "Netzke.classes.GridPanelLib"
151
+ def js_full_scope
152
+ js_scope.empty? ? js_default_scope : [js_default_scope, js_scope].join(".")
140
153
  end
141
154
 
142
- # Returns the name of the JavaScript class for this widget, including the scopes,
143
- # e.g.: "Netzke.GridPanelLib.RecordFormWindow"
155
+ # Returns the name of the JavaScript class for this widget, including the scope
156
+ # e.g.: "GridPanelLib.RecordFormWindow"
144
157
  def js_scoped_class_name
145
- name.gsub("::", ".")
158
+ short_widget_class_name.gsub("::", ".")
146
159
  end
147
160
 
148
161
  # Returns the full name of the JavaScript class, including the scopes *and* the common scope, which is
149
162
  # Netzke.classes.
150
163
  # E.g.: "Netzke.classes.Netzke.GridPanelLib.RecordFormWindow"
151
164
  def js_full_class_name
152
- "Netzke.classes." + js_scoped_class_name
165
+ [js_full_scope, short_widget_class_name.split("::").last].join(".")
153
166
  end
154
-
167
+
155
168
  # Builds this widget's xtype
156
169
  # E.g.: netzkewindow, netzkegridpanel
157
170
  def js_xtype
158
171
  name.gsub("::", "").downcase
159
172
  end
160
173
 
161
- # widget's menus
162
- def js_menus; []; end
163
-
164
174
  # are we using JS inheritance? for now, if js_base_class is a Netzke class - yes
165
175
  def js_inheritance?
166
176
  superclass != Netzke::Base
@@ -168,28 +178,40 @@ module Netzke
168
178
 
169
179
  # Declaration of widget's class (stored in the cache storage (Ext.netzke.cache) at the client side
170
180
  # to be reused at the moment of widget instantiation)
171
- def js_class
181
+ def js_class(cached = [])
182
+ # Setting the scope.
183
+ # TODO: invent an easy and error-prove way to check if adding this scope is necessary.
184
+ # For now setting it each and every time (very save and not really bothering).
185
+ res = %Q{
186
+ Ext.ns("#{js_full_scope}");
187
+ }
188
+
172
189
  if js_inheritance?
173
- # In case of using javascript inheritance, little needs to be done
174
- <<-END_OF_JAVASCRIPT
175
- // Define the scope
176
- Ext.ns("#{js_scope}");
177
- // Create the class
190
+ # Using javascript inheritance
191
+ res << <<-END_OF_JAVASCRIPT
192
+ // Costructor
178
193
  #{js_full_class_name} = function(config){
179
194
  #{js_full_class_name}.superclass.constructor.call(this, config);
180
195
  };
181
- // Extend it with the class that we inherit from, and mix in js_extend_properties
182
- Ext.extend(#{js_full_class_name}, #{superclass.js_full_class_name}, Ext.applyIf(#{js_extend_properties.to_nifty_json}, Ext.widgetMixIn));
183
- // Register xtype
184
- Ext.reg("#{js_xtype}", #{js_full_class_name});
196
+ END_OF_JAVASCRIPT
197
+
198
+ # Do we specify our own extend properties (overrriding js_extend_properties)? If so, include them, if not - don't re-include those from the parent!
199
+ res << (singleton_methods(false).include?("js_extend_properties") ? %Q{
200
+ Ext.extend(#{js_full_class_name}, #{superclass.js_full_class_name}, #{js_extend_properties.to_nifty_json});
201
+ } : %Q{
202
+ Ext.extend(#{js_full_class_name}, #{superclass.js_full_class_name});
203
+ })
185
204
 
205
+ res << <<-END_OF_JAVASCRIPT
206
+ // Register our xtype
207
+ Ext.reg("#{js_xtype}", #{js_full_class_name});
186
208
  END_OF_JAVASCRIPT
187
209
 
188
210
  else
211
+ # Menus
189
212
  js_add_menus = "this.addMenus(#{js_menus.to_nifty_json});" unless js_menus.empty?
190
- <<-END_OF_JAVASCRIPT
191
- // Define the scope
192
- Ext.ns("#{js_scope}");
213
+
214
+ res << <<-END_OF_JAVASCRIPT
193
215
  // Constructor
194
216
  #{js_full_class_name} = function(config){
195
217
  // Do all the initializations that every Netzke widget should do: create methods for API-points,
@@ -204,9 +226,10 @@ module Netzke
204
226
  Ext.extend(#{js_full_class_name}, #{js_base_class}, Ext.applyIf(#{js_extend_properties.to_nifty_json}, Ext.widgetMixIn));
205
227
  // Register xtype
206
228
  Ext.reg("#{js_xtype}", #{js_full_class_name});
207
-
208
229
  END_OF_JAVASCRIPT
209
230
  end
231
+
232
+ res
210
233
  end
211
234
 
212
235
  #
@@ -215,15 +238,16 @@ module Netzke
215
238
 
216
239
  # Override this method. Must return an array of paths to javascript files that we depend on.
217
240
  # This javascript code will be loaded along with the widget's class, and before it.
218
- def include_js
219
- []
220
- end
241
+ # def include_js
242
+ # []
243
+ # end
221
244
 
222
245
  # Returns all extra JavaScript-code (as string) required by this widget's class
223
246
  def js_included
224
247
  res = ""
225
-
226
- include_js.each do |path|
248
+
249
+ # Prevent re-including code that was already included by the parent
250
+ singleton_methods(false).include?("include_js") && include_js.each do |path|
227
251
  f = File.new(path)
228
252
  res << f.read << "\n"
229
253
  end
@@ -232,17 +256,19 @@ module Netzke
232
256
  end
233
257
 
234
258
  # All JavaScript code needed for this class, including one from the ancestor widget
235
- def js_code(cached_dependencies = [])
259
+ def js_code(cached = [])
236
260
  res = ""
237
261
 
238
262
  # include the base-class javascript if doing JS inheritance
239
- res << superclass.js_code << "\n" if js_inheritance? && !cached_dependencies.include?(superclass.short_widget_class_name)
263
+ if js_inheritance? && !cached.include?(superclass.short_widget_class_name)
264
+ res << superclass.js_code(cached) << "\n"
265
+ end
240
266
 
241
267
  # include static javascripts
242
268
  res << js_included << "\n"
243
269
 
244
270
  # our own JS class definition
245
- res << js_class
271
+ res << js_class(cached)
246
272
  res
247
273
  end
248
274
 
@@ -251,15 +277,15 @@ module Netzke
251
277
  #
252
278
 
253
279
  # Override this method. Must return an array of paths to css files that we depend on.
254
- def include_css
255
- []
256
- end
280
+ # def include_css
281
+ # []
282
+ # end
257
283
 
258
284
  # Returns all extra CSS code (as string) required by this widget's class
259
285
  def css_included
260
286
  res = ""
261
287
 
262
- include_css.each do |path|
288
+ singleton_methods(false).include?("include_css") && include_css.each do |path|
263
289
  f = File.new(path)
264
290
  res << f.read << "\n"
265
291
  end
@@ -268,11 +294,11 @@ module Netzke
268
294
  end
269
295
 
270
296
  # All CSS code needed for this class including the one from the ancestor widget
271
- def css_code(cached_dependencies = [])
297
+ def css_code(cached = [])
272
298
  res = ""
273
299
 
274
300
  # include the base-class javascript if doing JS inheritance
275
- res << superclass.css_code << "\n" if js_inheritance? && !cached_dependencies.include?(superclass.short_widget_class_name)
301
+ res << superclass.css_code << "\n" if js_inheritance? && !cached.include?(superclass.short_widget_class_name)
276
302
 
277
303
  res << css_included << "\n"
278
304
 
data/lib/netzke-core.rb CHANGED
@@ -8,8 +8,6 @@ require 'netzke/controller_extensions'
8
8
  require 'netzke/core_ext'
9
9
  require 'netzke/routing'
10
10
 
11
- require 'netzke/feedback_ghost'
12
-
13
11
  # Load models and controllers from lib/app
14
12
  %w{ models controllers }.each do |dir|
15
13
  path = File.join(File.dirname(__FILE__), 'app', dir)
@@ -56,6 +56,11 @@ module Netzke
56
56
  class JsInheritanceWidget < Widget
57
57
  end
58
58
 
59
+ module ScopedWidgets
60
+ class SomeScopedWidget < Base
61
+ end
62
+ end
63
+
59
64
  class InheritedWidget < Widget
60
65
  def self.config
61
66
  super.merge({
@@ -144,8 +149,8 @@ class NetzkeCoreTest < ActiveSupport::TestCase
144
149
 
145
150
  test "js inheritance" do
146
151
  widget = JsInheritanceWidget.new
147
- assert(widget.js_missing_code.index("Netzke.classes.Netzke.JsInheritanceWidget"))
148
- assert(widget.js_missing_code.index("Netzke.classes.Netzke.Widget"))
152
+ assert(widget.js_missing_code.index("Netzke.classes.JsInheritanceWidget"))
153
+ assert(widget.js_missing_code.index("Netzke.classes.Widget"))
149
154
  end
150
155
 
151
156
  test "class-level configuration" do
@@ -163,4 +168,16 @@ class NetzkeCoreTest < ActiveSupport::TestCase
163
168
 
164
169
  end
165
170
 
171
+ test "JS class names and scopes" do
172
+ klass = Netzke::NestedWidgetOne
173
+ assert_equal("Netzke.classes", klass.js_full_scope)
174
+ assert_equal("", klass.js_class_name_to_scope(klass.short_widget_class_name))
175
+
176
+ klass = Netzke::ScopedWidgets::SomeScopedWidget
177
+ assert_equal("Netzke.classes", klass.js_default_scope)
178
+ assert_equal("ScopedWidgets::SomeScopedWidget", klass.short_widget_class_name)
179
+ assert_equal("ScopedWidgets", klass.js_class_name_to_scope(klass.short_widget_class_name))
180
+ assert_equal("Netzke.classes.ScopedWidgets", klass.js_full_scope)
181
+ end
182
+
166
183
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: netzke-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.5
4
+ version: 0.4.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sergei Kozlov
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-11-08 00:00:00 -06:00
12
+ date: 2009-11-09 00:00:00 -06:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -46,7 +46,6 @@ files:
46
46
  - lib/netzke/base_js.rb
47
47
  - lib/netzke/controller_extensions.rb
48
48
  - lib/netzke/core_ext.rb
49
- - lib/netzke/feedback_ghost.rb
50
49
  - lib/netzke/routing.rb
51
50
  - stylesheets/core.css
52
51
  - tasks/netzke_core_tasks.rake
@@ -1,43 +0,0 @@
1
- module Netzke
2
- #
3
- # An invisible component that provides feedback service for all Netzke widgets
4
- #
5
- class FeedbackGhost < Base
6
- def self.js_base_class
7
- "Ext.Component" # yes, invisible
8
- end
9
-
10
- def self.js_extend_properties
11
- {
12
- :show_feedback => <<-END_OF_JAVASCRIPT.l,
13
- function(msg){
14
- var createBox = function(s, l){
15
- return ['<div class="msg">',
16
- '<div class="x-box-tl"><div class="x-box-tr"><div class="x-box-tc"></div></div></div>',
17
- '<div class="x-box-ml"><div class="x-box-mr"><div class="x-box-mc">', s, '</div></div></div>',
18
- '<div class="x-box-bl"><div class="x-box-br"><div class="x-box-bc"></div></div></div>',
19
- '</div>'].join('');
20
- }
21
-
22
- var showBox = function(msg, lvl){
23
- if (!lvl) {lvl = 'notice'};
24
- var msgCt = Ext.DomHelper.insertFirst(document.body, {'class':'netzke-feedback'}, true);
25
- var m = Ext.DomHelper.append(msgCt, {html:createBox(msg,lvl)}, true);
26
- m.slideIn('t').pause(2).ghost("b", {remove:true});
27
- }
28
-
29
- if (typeof msg != 'string') {
30
- var compoundMsg = "";
31
- Ext.each(msg, function(m){
32
- compoundMsg += m.msg + '<br>';
33
- });
34
- if (compoundMsg != "") showBox(compoundMsg, null); // the second parameter will be level
35
- } else {
36
- showBox(msg);
37
- }
38
- }
39
- END_OF_JAVASCRIPT
40
- }
41
- end
42
- end
43
- end