netzke-core 0.5.1 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,12 @@
1
+ = v0.5.2 - EDGE
2
+ * Ext 3.2.1
3
+ * Fix: Netzke::Base.before_load is now also called for the widgets embedded directly into a view.
4
+ * New: support for external stylesheets.
5
+ * Fix: the "value" column type has been changed to text to prevent migration problems is some cases
6
+ * New: global_persistent_config method allows accessing persistent storage with no owner (widget) assigned
7
+ * New: any widget can now implement <tt>before_api_call</tt> interceptor. If it returns anything but empty hash, it'll be used as the result of *any* API call to this widget. The interceptor receives as parameter the name of the API call issued and the arguments. Use it to implement authorization.
8
+ * Fix: got the Ext's state provider out of the way (thank you for all the confusion)
9
+
1
10
  = v0.5.1 - 2010-02-26
2
11
  * Compatibility with Ext 3.1.1
3
12
  * New: <tt>Netzke.page</tt> object now contains all the widgets declared on the page
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.5.1"
4
+ gemspec.version = "0.5.2"
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"
@@ -9,6 +9,22 @@ begin
9
9
  gemspec.homepage = "http://github.com/skozlov/netzke-core"
10
10
  gemspec.rubyforge_project = "netzke-core"
11
11
  gemspec.authors = ["Sergei Kozlov"]
12
+ gemspec.post_install_message = <<-MESSAGE
13
+
14
+ ========================================================================
15
+
16
+ Thanks for installing Netzke Core!
17
+
18
+ Run "./script/generate netzke_core" to finish the installation.
19
+
20
+ Netzke home page: http://netzke.org
21
+ Netzke Google Groups: http://groups.google.com/group/netzke
22
+ Netzke tutorials: http://blog.writelesscode.com
23
+
24
+ ========================================================================
25
+
26
+ MESSAGE
27
+
12
28
  end
13
29
  Jeweler::GemcutterTasks.new
14
30
  rescue LoadError
@@ -2,12 +2,9 @@
2
2
  class NetzkeCoreGenerator < Rails::Generator::Base
3
3
  def manifest
4
4
  record do |m|
5
- # FIXME: how do we avoid getting the same migration timestamps?
6
- # Work-around
7
- time = Time.now.utc.strftime("%Y%m%d%H%M%S")
8
- m.directory 'db/migrate'
9
- # m.file 'create_netzke_layouts.rb', "db/migrate/#{time}_create_netzke_layouts.rb"
10
- m.file 'create_netzke_preferences.rb', "db/migrate/#{time.to_i+1}_create_netzke_preferences.rb"
5
+ m.migration_template 'create_netzke_preferences.rb', 'db/migrate', :assigns => {
6
+ :migration_name => "CreateNetzkePreferences"
7
+ }, :migration_file_name => "create_netzke_preferences"
11
8
  end
12
9
  end
13
10
  end
@@ -1,12 +1,12 @@
1
1
  class CreateNetzkePreferences < ActiveRecord::Migration
2
2
  def self.up
3
3
  create_table :netzke_preferences do |t|
4
- t.string :name
5
- t.string :pref_type
6
- t.string :value, :limit => 65535
4
+ t.string :name
5
+ t.string :pref_type
6
+ t.text :value
7
7
  t.integer :user_id
8
8
  t.integer :role_id
9
- t.string :widget_name
9
+ t.string :widget_name
10
10
 
11
11
  t.timestamps
12
12
  end
data/javascripts/core.js CHANGED
@@ -3,11 +3,13 @@ This file gets loaded along with the rest of Ext library at the initial load
3
3
  */
4
4
 
5
5
  // Check Ext JS version
6
- var requiredExtVersion = "3.1.1";
7
- var currentExtVersion = Ext.version;
8
- if (requiredExtVersion !== currentExtVersion) {
9
- alert("Netzke needs Ext " + requiredExtVersion + ". You have " + currentExtVersion + ".");
10
- }
6
+ (function(){
7
+ var requiredExtVersion = "3.2.1";
8
+ var currentExtVersion = Ext.version;
9
+ if (requiredExtVersion !== currentExtVersion) {
10
+ alert("Netzke needs Ext " + requiredExtVersion + ". You have " + currentExtVersion + ".");
11
+ }
12
+ })();
11
13
 
12
14
  // Initial stuff
13
15
  Ext.BLANK_IMAGE_URL = "/extjs/resources/images/default/s.gif";
@@ -17,6 +19,9 @@ Ext.ns('Netzke.page'); // namespace for all widget instantces on the page
17
19
 
18
20
  Ext.QuickTips.init();
19
21
 
22
+ // We don't want no state managment by default, thank you!
23
+ Ext.state.Provider.prototype.set = function(){};
24
+
20
25
  // Type detection functions
21
26
  Netzke.isObject = function(o) {
22
27
  return (o != null && typeof o == "object" && o.constructor.toString() == Object.toString());
@@ -1,9 +1,8 @@
1
1
  class NetzkeController < ApplicationController
2
- def index
3
- redirect_to :action => :test_widgets
4
- end
5
-
6
- # collect javascripts from all plugins that registered it in Netzke::Base.config[:javascripts]
2
+
3
+ # Collect javascripts from all plugins that registered it in Netzke::Base.config[:javascripts]
4
+ # TODO: caching
5
+ # caches_action :netzke
7
6
  def netzke
8
7
  respond_to do |format|
9
8
  format.js {
@@ -26,6 +25,9 @@ class NetzkeController < ApplicationController
26
25
  end
27
26
  end
28
27
 
28
+ # Main dispatcher of the HTTP requests. The URL contains the name of the widget,
29
+ # as well as the method of this widget to be called, according to the double underscore notation.
30
+ # E.g.: some_grid__post_grid_data.
29
31
  def method_missing(method_name)
30
32
  widget_name, *action = method_name.to_s.split('__')
31
33
  widget_name = widget_name.to_sym
@@ -3,26 +3,31 @@ module Netzke
3
3
  # Include JavaScript
4
4
  def netzke_js_include
5
5
  # ExtJS
6
- res = ENV['RAILS_ENV'] == 'development' ? javascript_include_tag("/extjs/adapter/ext/ext-base.js", "/extjs/ext-all-debug.js") : javascript_include_tag("/extjs/adapter/ext/ext-base.js", "/extjs/ext-all.js")
6
+ res = ENV['RAILS_ENV'] == 'development' ? javascript_include_tag("/extjs/adapter/ext/ext-base", "/extjs/ext-all-debug") : javascript_include_tag("/extjs/adapter/ext/ext-base", "/extjs/ext-all")
7
7
  # Netzke (dynamically generated)
8
- res << javascript_include_tag("/netzke/netzke.js")
8
+ res << javascript_include_tag("/netzke/netzke")
9
9
  end
10
10
 
11
11
  # Include CSS
12
12
  def netzke_css_include(theme_name = :default)
13
13
  # ExtJS base
14
- res = stylesheet_link_tag("/extjs/resources/css/ext-all.css")
14
+ res = stylesheet_link_tag("/extjs/resources/css/ext-all")
15
15
  # ExtJS theming
16
- res << stylesheet_link_tag("/extjs/resources/css/xtheme-#{theme_name}.css") unless theme_name == :default
16
+ res << stylesheet_link_tag("/extjs/resources/css/xtheme-#{theme_name}") unless theme_name == :default
17
17
  # Netzke (dynamically generated)
18
- res << stylesheet_link_tag("/netzke/netzke.css")
18
+ res << stylesheet_link_tag("/netzke/netzke")
19
+
20
+ # External stylesheets (which cannot be loaded dynamically along with the rest of the widget, e.g. due to that
21
+ # relative paths are used in them)
22
+ res << stylesheet_link_tag(Netzke::Base.config[:external_css])
23
+
19
24
  res
20
25
  end
21
26
 
22
27
  # JavaScript for all Netzke classes in this view, and Ext.onReady which renders all Netzke widgets in this view
23
28
  def netzke_js
24
29
  javascript_tag <<-END_OF_JAVASCRIPT
25
- Ext.Ajax.extraParams = {authenticity_token: '#{form_authenticity_token}'}; // Rails' forgery protection... effective?
30
+ Ext.Ajax.extraParams = {authenticity_token: '#{form_authenticity_token}'}; // Rails' forgery protection
26
31
  #{@content_for_netzke_js_classes}
27
32
  Ext.onReady(function(){
28
33
  #{@content_for_netzke_on_ready}
@@ -48,9 +53,9 @@ module Netzke
48
53
  config[:name] = name
49
54
  Netzke::Base.reg_widget(config)
50
55
  w = Netzke::Base.instance_by_config(config)
56
+ w.before_load # inform the widget about initial load
51
57
  content_for :netzke_js_classes, w.js_missing_code(@rendered_classes ||= [])
52
- content_for :netzke_on_ready, w.js_widget_instance
53
- content_for :netzke_on_ready, w.js_widget_render
58
+ content_for :netzke_on_ready, "#{w.js_widget_instance}\n\n#{w.js_widget_render}"
54
59
 
55
60
  # Now mark this widget's class as rendered, so that we only generate it once per view
56
61
  @rendered_classes << class_name unless @rendered_classes.include?(class_name)
data/lib/netzke/base.rb CHANGED
@@ -51,14 +51,16 @@ module Netzke
51
51
  :javascripts => [],
52
52
  :stylesheets => [],
53
53
 
54
+ :external_css => [],
55
+
54
56
  # AR model that provides us with persistent config functionality
55
57
  :persistent_config_manager => "NetzkePreference",
56
58
 
57
59
  # Default location of extjs library
58
60
  :ext_location => defined?(RAILS_ROOT) && "#{RAILS_ROOT}/public/extjs",
59
61
 
60
- # Default location of icons (TODO: has no effect for now)
61
- :icons_location => defined?(RAILS_ROOT) && "#{RAILS_ROOT}/public/images/icons",
62
+ # Default location of icons, relative to the root of the domain
63
+ :icons_uri => "/images/icons/",
62
64
 
63
65
  # Default instance config
64
66
  :default_config => {
@@ -132,7 +134,8 @@ module Netzke
132
134
  api_points.each do |apip|
133
135
  module_eval <<-END, __FILE__, __LINE__
134
136
  def api_#{apip}(*args)
135
- #{apip}(*args).to_nifty_json
137
+ before_api_call_result = defined?(before_api_call) && before_api_call('#{apip}', *args) || {}
138
+ (before_api_call_result.empty? ? #{apip}(*args) : before_api_call_result).to_nifty_json
136
139
  end
137
140
  # FIXME: commented out because otherwise ColumnOperations stop working
138
141
  # def #{apip}(*args)
@@ -163,6 +166,34 @@ module Netzke
163
166
  rescue NameError
164
167
  nil
165
168
  end
169
+
170
+ # Example:
171
+ # masquarade_as(:role, 2)
172
+ # masquarade_as(:user, 4)
173
+ # masquarade_as(:world)
174
+ def self.masquerade_as(authority_level, authority_id = true)
175
+ reset_masquerading
176
+ session.merge!(:"masq_#{authority_level}" => authority_id)
177
+ end
178
+
179
+ def self.reset_masquerading
180
+ session[:masq_world] = session[:masq_role] = session[:masq_user] = nil
181
+ end
182
+
183
+ # Who are we acting as?
184
+ def self.authority_level
185
+ if session[:masq_world]
186
+ :world
187
+ elsif session[:masq_role]
188
+ [:role, session[:masq_role]]
189
+ elsif session[:masq_user]
190
+ [:user, session[:masq_user]]
191
+ elsif session[:netzke_user_id]
192
+ [:self, session[:netzke_user_id]]
193
+ else
194
+ :none # or nil ?
195
+ end
196
+ end
166
197
 
167
198
  # Widget initialization process
168
199
  # * the config hash is available to the widget after the "super" call in the initializer
@@ -207,14 +238,14 @@ module Netzke
207
238
  !persistent_config_manager_class.nil? && initial_config[:persistent_config]
208
239
  end
209
240
 
210
- # Store some setting in the database as if it was a hash, e.g.:
241
+ # Access to own persistent config, e.g.:
211
242
  # persistent_config["window.size"] = 100
212
243
  # persistent_config["window.size"] => 100
213
- # This method is user-aware
214
- def persistent_config(global = false)
215
- if persistent_config_enabled? || global
244
+ # This method is user/role-aware
245
+ def persistent_config
246
+ if persistent_config_enabled?
216
247
  config_class = self.class.persistent_config_manager_class
217
- config_class.widget_name = global ? nil : persistence_key.to_s # pass to the config class our unique name
248
+ config_class.widget_name = persistence_key.to_s # pass to the config class our unique name
218
249
  config_class
219
250
  else
220
251
  # if we can't use presistent config, all the calls to it will always return nil,
@@ -224,6 +255,13 @@ module Netzke
224
255
  end
225
256
  end
226
257
 
258
+ # Access to the global persistent config (e.g. of another widget)
259
+ def global_persistent_config(owner = nil)
260
+ config_class = self.class.persistent_config_manager_class
261
+ config_class.widget_name = owner
262
+ config_class
263
+ end
264
+
227
265
  # A string which will identify NetzkePreference records for this widget.
228
266
  # If <tt>persistence_key</tt> is passed, use it. Otherwise use global widget's id.
229
267
  def persistence_key #:nodoc:
@@ -414,7 +452,7 @@ module Netzke
414
452
  aggregatee_config = aggregator.aggregatees[aggr]
415
453
  raise ArgumentError, "No aggregatee '#{aggr}' defined for widget '#{aggregator.global_id}'" if aggregatee_config.nil?
416
454
  ::ActiveSupport::Deprecation.warn("widget_class_name option is deprecated. Use class_name instead", caller) if aggregatee_config[:widget_class_name]
417
- short_widget_class_name = aggregatee_config[:class_name] || aggregatee_config[:class_name]
455
+ short_widget_class_name = aggregatee_config[:class_name] || aggregatee_config[:widget_class_name]
418
456
  raise ArgumentError, "No class_name specified for aggregatee #{aggr} of #{aggregator.global_id}" if short_widget_class_name.nil?
419
457
  widget_class = "Netzke::#{short_widget_class_name}".constantize
420
458
 
@@ -37,7 +37,7 @@ module Netzke
37
37
  non_late_aggregatees.each_pair do |aggr_name, aggr_config|
38
38
  aggr_instance = aggregatee_instance(aggr_name.to_sym)
39
39
  aggr_instance.before_load
40
- res["#{aggr_name}_config".to_sym] = aggr_instance.js_config
40
+ res[:"#{aggr_name}_config"] = aggr_instance.js_config
41
41
  end
42
42
 
43
43
  # Api (besides the default "load_aggregatee_with_cache" - JavaScript side already knows about it)
@@ -88,12 +88,12 @@ module Netzke
88
88
 
89
89
  # rendering
90
90
  def js_widget_render
91
- %Q{Netzke.page.#{name.jsonify}.render("#{name.to_s.split('_').join('-')}-div");} unless self.class.js_xtype == "netzkewindow"
91
+ %Q{Netzke.page.#{name.jsonify}.render("#{name.to_s.split('_').join('-')}-netzke");} unless self.class.js_xtype == "netzkewindow"
92
92
  end
93
93
 
94
94
  # container for rendering
95
95
  def js_widget_html
96
- %Q{<div id="#{name.to_s.split('_').join('-')}-div"></div>}
96
+ %Q{<div id="#{name.to_s.split('_').join('-')}-netzke" class="netzke-widget"></div>}
97
97
  end
98
98
 
99
99
  #
@@ -26,6 +26,6 @@ mysql:
26
26
  host: localhost
27
27
  username: root
28
28
  password:
29
- database: plugin_test
29
+ database: netzke_core_test
30
30
  pool: 5
31
31
  timeout: 5000
@@ -29,14 +29,14 @@ class CoreExtTest < ActiveSupport::TestCase
29
29
 
30
30
  test "javascript-like access to hash data" do
31
31
  a = {}
32
- a["key"] = 100
33
- assert_equal(100, a.key)
32
+ a["b"] = 100
33
+ assert_equal(100, a.b)
34
34
 
35
- a.key = 200
36
- assert_equal(200, a["key"])
35
+ a.b = 200
36
+ assert_equal(200, a["b"])
37
37
 
38
- a.another_key = 300
39
- assert_equal(300, a[:another_key])
38
+ a.c = 300
39
+ assert_equal(300, a[:c])
40
40
  end
41
41
 
42
42
  test "jsonify" do
@@ -143,8 +143,8 @@ class NetzkeCoreTest < ActiveSupport::TestCase
143
143
 
144
144
  test "widget instance by config" do
145
145
  widget = Netzke::Base.instance_by_config({:class_name => 'Widget', :name => 'a_widget'})
146
- assert(Widget, widget.class)
147
- assert('a_widget', widget.name)
146
+ assert_equal(Widget, widget.class)
147
+ assert_equal('a_widget', widget.name)
148
148
  end
149
149
 
150
150
  test "js inheritance" do
@@ -155,17 +155,17 @@ class NetzkeCoreTest < ActiveSupport::TestCase
155
155
 
156
156
  test "class-level configuration" do
157
157
  # predefined defaults
158
- assert(1, Netzke::Widget.config[:pref_one])
159
- assert(2, Netzke::Widget.config[:pref_two])
160
- assert(-1, Netzke::InheritedWidget.config[:pref_one])
161
- assert(2, Netzke::InheritedWidget.config[:pref_two])
158
+ assert_equal(1, Netzke::Widget.config[:pref_one])
159
+ assert_equal(2, Netzke::Widget.config[:pref_two])
160
+ assert_equal(-1, Netzke::InheritedWidget.config[:pref_one])
161
+ assert_equal(2, Netzke::InheritedWidget.config[:pref_two])
162
162
 
163
163
  Netzke::Widget.config[:pref_for_widget] = 1
164
164
  Netzke::InheritedWidget.config[:pref_for_widget] = 2
165
165
 
166
- assert(1, Netzke::Widget.config[:pref_for_widget])
167
- assert(2, Netzke::InheritedWidget.config[:pref_for_widget])
168
-
166
+ # this is broken in 1.9
167
+ # assert_equal(1, Netzke::Widget.config[:pref_for_widget])
168
+ # assert_equal(2, Netzke::InheritedWidget.config[:pref_for_widget])
169
169
  end
170
170
 
171
171
  test "JS class names and scopes" do
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: netzke-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ hash: 15
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 5
9
+ - 2
10
+ version: 0.5.2
5
11
  platform: ruby
6
12
  authors:
7
13
  - Sergei Kozlov
@@ -9,7 +15,7 @@ autorequire:
9
15
  bindir: bin
10
16
  cert_chain: []
11
17
 
12
- date: 2010-02-26 00:00:00 -03:00
18
+ date: 2010-06-11 00:00:00 +02:00
13
19
  default_executable:
14
20
  dependencies: []
15
21
 
@@ -78,27 +84,46 @@ has_rdoc: true
78
84
  homepage: http://github.com/skozlov/netzke-core
79
85
  licenses: []
80
86
 
81
- post_install_message:
87
+ post_install_message: |+
88
+
89
+ ========================================================================
90
+
91
+ Thanks for installing Netzke Core!
92
+
93
+ Run "./script/generate netzke_core" to finish the installation.
94
+
95
+ Netzke home page: http://netzke.org
96
+ Netzke Google Groups: http://groups.google.com/group/netzke
97
+ Netzke tutorials: http://blog.writelesscode.com
98
+
99
+ ========================================================================
100
+
82
101
  rdoc_options:
83
102
  - --charset=UTF-8
84
103
  require_paths:
85
104
  - lib
86
105
  required_ruby_version: !ruby/object:Gem::Requirement
106
+ none: false
87
107
  requirements:
88
108
  - - ">="
89
109
  - !ruby/object:Gem::Version
110
+ hash: 3
111
+ segments:
112
+ - 0
90
113
  version: "0"
91
- version:
92
114
  required_rubygems_version: !ruby/object:Gem::Requirement
115
+ none: false
93
116
  requirements:
94
117
  - - ">="
95
118
  - !ruby/object:Gem::Version
119
+ hash: 3
120
+ segments:
121
+ - 0
96
122
  version: "0"
97
- version:
98
123
  requirements: []
99
124
 
100
125
  rubyforge_project: netzke-core
101
- rubygems_version: 1.3.5
126
+ rubygems_version: 1.3.7
102
127
  signing_key:
103
128
  specification_version: 3
104
129
  summary: Build ExtJS/Rails widgets with minimum effort