netzke-core 0.4.5 → 0.4.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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