netzke-core 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,15 @@
1
+ v0.2.0
2
+ * Some re-factoring and redesign. Now simple compound widgets can be created on the fly in the controller
3
+ * Added ext_widget[:quiet] configuration option to suppress widget's feedback
4
+ * Support for extra CSS sources, similar to JS
5
+ * NETZKE_BOOT_CONFIG introduced to specify which Netzke functionality should be disabled to reduce the size of /netzke/netzke.[js|css]
6
+ * FeedbackGhost widget added - invisible widget providing feedback to the user
7
+ * netzke_widget controller class-method renamed into netzke
8
+ * JS-comments now get stripped also from the extra files that get included in the netzke-* gems.
9
+ * Permissions joined js_config
10
+
11
+ Bug fixes
12
+
1
13
  v0.1.4
2
14
  Helpers added to facilitate ExtJS/netzke.js inclusion
3
15
  The route defined for netzke_controller
data/Manifest CHANGED
@@ -1,4 +1,5 @@
1
1
  CHANGELOG
2
+ css/core.css
2
3
  generators/netzke_core/netzke_core_generator.rb
3
4
  generators/netzke_core/templates/create_netzke_layouts.rb
4
5
  generators/netzke_core/templates/create_netzke_preferences.rb
@@ -13,6 +14,7 @@ lib/netzke/action_view_ext.rb
13
14
  lib/netzke/base.rb
14
15
  lib/netzke/controller_extensions.rb
15
16
  lib/netzke/core_ext.rb
17
+ lib/netzke/feedback_ghost.rb
16
18
  lib/netzke/js_class_builder.rb
17
19
  lib/netzke/routing.rb
18
20
  lib/netzke-core.rb
data/css/core.css ADDED
@@ -0,0 +1,8 @@
1
+ /* feedback */
2
+ .netzke-feedback {
3
+ position:absolute;
4
+ left:25%;
5
+ top:0;
6
+ width:300px;
7
+ z-index:20000;
8
+ }
@@ -6,7 +6,7 @@ class CreateNetzkePreferences < ActiveRecord::Migration
6
6
  t.string :value
7
7
  t.integer :user_id
8
8
  t.integer :role_id
9
- t.string :custom_field
9
+ t.string :widget_name
10
10
 
11
11
  t.timestamps
12
12
  end
data/javascripts/core.js CHANGED
@@ -49,7 +49,8 @@ Ext.data.ArrayReader = Ext.extend(Ext.data.JsonReader, {
49
49
  // Methods common to all widget classes
50
50
  Ext.widgetMixIn = {
51
51
  widgetInit:function(config){
52
- this.app = Ext.getCmp('application');
52
+ this.app = Ext.getCmp('feedback_ghost');
53
+ // this.app = Ext.getCmp('application');
53
54
  if (config.tools) Ext.each(config.tools, function(i){i.on.click = this[i.on.click].createDelegate(this)}, this);
54
55
  if (config.actions) Ext.each(config.actions, function(i){i.handler = this[i.handler].createDelegate(this);}, this);
55
56
  },
@@ -67,6 +68,7 @@ Ext.widgetMixIn = {
67
68
  },
68
69
 
69
70
  feedback:function(msg){
71
+ if (this.initialConfig.quiet) return false;
70
72
  if (this.app && !!this.app.showFeedback) {
71
73
  this.app.showFeedback(msg)
72
74
  } else {
@@ -127,3 +129,21 @@ Ext.override(Ext.Panel, {
127
129
 
128
130
  }
129
131
  });
132
+
133
+ // Some Rubyish String extensions
134
+ // from http://code.google.com/p/inflection-js/
135
+ String.prototype.capitalize=function()
136
+ {
137
+ var str=this.toLowerCase();
138
+ str=str.substring(0,1).toUpperCase()+str.substring(1);
139
+ return str;
140
+ };
141
+
142
+ String.prototype.humanize=function(lowFirstLetter)
143
+ {
144
+ var str=this.toLowerCase();
145
+ str=str.replace(new RegExp('_id','g'),'');
146
+ str=str.replace(new RegExp('_','g'),' ');
147
+ if(!lowFirstLetter)str=str.capitalize();
148
+ return str;
149
+ };
@@ -9,6 +9,15 @@ class NetzkeController < ActionController::Base
9
9
  f = File.new(path)
10
10
  res << f.read
11
11
  end
12
+ render :text => res.strip_js_comments
13
+ }
14
+
15
+ format.css {
16
+ res = ""
17
+ Netzke::Base.config[:css].each do |path|
18
+ f = File.new(path)
19
+ res << f.read
20
+ end
12
21
  render :text => res
13
22
  }
14
23
  end
@@ -1,9 +1,4 @@
1
1
  class NetzkeLayout < ActiveRecord::Base
2
- # has_many :layout_items#, :class_name => "ExtWidget::LayoutItem", :order => :position
3
- # has_many :objects, :class_name => "Objects", :foreign_key => "class_name_id"
4
- # belongs_to :role
5
- # belongs_to :user
6
-
7
2
  UNRELATED_ATTRS = %w(created_at updated_at position layout_id)
8
3
 
9
4
  def self.user_id
@@ -14,16 +9,6 @@ class NetzkeLayout < ActiveRecord::Base
14
9
  items_class.constantize.find_all_by_layout_id(id, :order => 'position')
15
10
  end
16
11
 
17
- #
18
- # def self.user_id=(user_id)
19
- # @@user_id = user_id
20
- # end
21
- #
22
- # def self.layout_items(widget_name)
23
- # layout = self.layout(widget_name)
24
- # layout.nil? ? nil : layout.layout_items.map(&:attributes).map{|item| item.delete_if{|k,v| UNRELATED_ATTRS.include?(k)}}
25
- # end
26
- #
27
12
  def self.by_widget(widget_name)
28
13
  self.find(:first, :conditions => {:widget_name => widget_name, :user_id => self.user_id})
29
14
  end
@@ -34,42 +19,8 @@ class NetzkeLayout < ActiveRecord::Base
34
19
  layout_item.insert_at(new_index + 1)
35
20
  end
36
21
 
37
- # def self.layout_items(widget_name)
38
- # layout = self.by_widget(widget_name)
39
- # if layout
40
- # layout.layout_items
41
- # else
42
- # # create new layout and fill it out with default values
43
- # layout = Layout.create({:widget_name => widget_name, :user_id => self.user_id})
44
- # end
45
- # end
46
-
47
22
  def items_hash
48
23
  layout_items.map(&:attributes).map{|item| item.delete_if{|k,v| UNRELATED_ATTRS.include?(k)}}.map{ |i| i.convert_keys{ |k| k.to_sym } }
49
24
  end
50
-
51
- # if layout items are provided, use them instead of defaults (exsposed) layout items, but merge their configs with the default
52
- # def self.create_layout_for_widget(widget_name, data_class_name, layout_item_class_name, items = nil)
53
- # layout = self.create(:widget_name => widget_name, :items_class => layout_item_class_name, :user_id => self.user_id)
54
- # data_class = data_class_name.constantize
55
- # layout_item_class = layout_item_class_name.constantize
56
- #
57
- #
58
- # if items.nil?
59
- # complete_items = data_class.exposed_columns
60
- # else
61
- # # normalize columns
62
- # columns = columns.
63
- # default_columns = data_class.exposed_columns.map{|c| c.is_a?(Symbol) ? {:name => c} : c}
64
- # columns.each
65
- #
66
- # complete_columns = columns.nil? ? : columns
67
- # complete_columns.each do |c|
68
- # config = c.is_a?(Hash) ? c : {:name => c}
69
- # # we have to merge layout_id in order to have :position set up properly
70
- # item = layout_item_class.create_with_defaults(config.merge({:layout_id => layout.id}), data_class)
71
- # end
72
- # layout
73
- # end
74
25
 
75
26
  end
@@ -9,12 +9,12 @@ class NetzkePreference < ActiveRecord::Base
9
9
  @@user ||= nil
10
10
  end
11
11
 
12
- def self.custom_field=(value)
13
- @@custom_field = value
12
+ def self.widget_name=(value)
13
+ @@widget_name = value
14
14
  end
15
15
 
16
- def self.custom_field
17
- @@custom_field ||= nil
16
+ def self.widget_name
17
+ @@widget_name ||= nil
18
18
  end
19
19
 
20
20
  def normalized_value
@@ -48,7 +48,7 @@ class NetzkePreference < ActiveRecord::Base
48
48
 
49
49
  def self.[](pref_name)
50
50
  pref_name = pref_name.to_s
51
- conditions = {:name => pref_name, :user_id => self.user, :custom_field => self.custom_field}
51
+ conditions = {:name => pref_name, :user_id => self.user, :widget_name => self.widget_name}
52
52
  pref = self.find(:first, :conditions => conditions)
53
53
  # pref = @@user.nil? ? self.find_by_name(pref_name) : self.find_by_name_and_user_id(pref_name, @@user.id)
54
54
  pref && pref.normalized_value
@@ -56,7 +56,7 @@ class NetzkePreference < ActiveRecord::Base
56
56
 
57
57
  def self.[]=(pref_name, new_value)
58
58
  pref_name = pref_name.to_s
59
- conditions = {:name => pref_name, :user_id => self.user, :custom_field => self.custom_field}
59
+ conditions = {:name => pref_name, :user_id => self.user, :widget_name => self.widget_name}
60
60
  pref = self.find(:first, :conditions => conditions) || self.create(conditions)
61
61
  # pref = self.user.nil? ? self.find_or_create_by_name(pref_name) : self.find_or_create_by_name_and_user_id(pref_name, self.user.id)
62
62
  pref.normalized_value = new_value
@@ -18,6 +18,7 @@ module Netzke
18
18
  def netzke_css_include(theme_name = :default)
19
19
  res = stylesheet_link_tag("/extjs/resources/css/ext-all.css")
20
20
  res << stylesheet_link_tag("/extjs/resources/css/xtheme-#{theme_name}.css") unless theme_name == :default
21
+ res << stylesheet_link_tag("/netzke/netzke.css") # CSS from Netzke
21
22
  res
22
23
  end
23
24
  end
data/lib/netzke/base.rb CHANGED
@@ -1,35 +1,78 @@
1
1
  require 'json'
2
2
 
3
3
  module Netzke
4
+ #
5
+ # Configuration:
6
+ # * Define NETZKE_BOOT_CONFIG in environment.rb to specify which Netzke functionality should be disabled
7
+ # to reduce the size of /netzke/netzke.[js|css]. Those Netzke gems that use additional JS-code
8
+ # should be aware of this constant.
9
+ #
4
10
  class Base
5
- # client-side code (generates JS-classes of the widgets)
6
- include Netzke::JsClassBuilder
7
-
8
- # Global Netzke configuration
9
- def self.config
10
- @@config ||= {
11
- :javascripts => ["#{File.dirname(__FILE__)}/../../javascripts/core.js"] # locations of javascript files (which automatically will be collected into one file and sent as netzke.js)
12
- }
13
- end
14
-
15
- def self.js_class_code(cached_dependencies = [])
16
- self.new(:js_class => true).js_missing_code(cached_dependencies)
17
- end
18
-
19
11
  # Helper class to read/write from/to widget's persistent preferences. TODO: rework it.
20
12
  class Config
21
13
  def initialize(widget_name)
22
14
  @widget_name = widget_name
23
15
  end
24
16
  def []=(k,v)
25
- NetzkePreference.custom_field = @widget_name
17
+ NetzkePreference.widget_name = @widget_name
26
18
  NetzkePreference[k] = v
27
19
  end
28
20
  def [](k)
29
- NetzkePreference.custom_field = @widget_name
21
+ NetzkePreference.widget_name = @widget_name
30
22
  NetzkePreference[k]
31
23
  end
32
24
  end
25
+
26
+ # Client-side code (generates JS-class of the widget)
27
+ include Netzke::JsClassBuilder
28
+
29
+ # Class methods
30
+ class << self
31
+ # Global Netzke configuration
32
+ def config
33
+ @@config ||= {
34
+ # locations of javascript and css files (which will be automatically collected into one file and sent as /netzke/netzke.js and /netzke/netzke.css respectively)
35
+ :javascripts => [],
36
+ :css => []
37
+ }
38
+ end
39
+
40
+ def short_widget_class_name
41
+ name.split("::").last
42
+ end
43
+
44
+ #
45
+ # Use this class method to declare connection points between client side of a widget and its server side. A method in a widget class with the same name will be (magically) called by the client side of the widget. See Grid widget for an example
46
+ #
47
+ def interface(*interface_points)
48
+ interfacep = read_inheritable_attribute(:interface_points) || []
49
+ interface_points.each{|p| interfacep << p}
50
+ write_inheritable_attribute(:interface_points, interfacep)
51
+
52
+ interface_points.each do |interfacep|
53
+ module_eval <<-END, __FILE__, __LINE__
54
+ def interface_#{interfacep}(*args)
55
+ #{interfacep}(*args).to_js
56
+ end
57
+ # FIXME: commented out because otherwise ColumnOperations stop working
58
+ # def #{interfacep}(*args)
59
+ # flash :warning => "API point '#{interfacep}' is not implemented for widget '#{short_widget_class_name}'"
60
+ # {:flash => @flash}
61
+ # end
62
+ END
63
+ end
64
+ end
65
+
66
+ def interface_points
67
+ read_inheritable_attribute(:interface_points)
68
+ end
69
+
70
+ # returns an instance of a widget defined in the config
71
+ def instance_by_config(config)
72
+ widget_class = "Netzke::#{config[:widget_class_name]}".constantize
73
+ widget_class.new(config)
74
+ end
75
+ end
33
76
 
34
77
  attr_accessor :config, :server_confg, :parent, :logger, :id_name, :permissions
35
78
  attr_reader :pref
@@ -57,47 +100,13 @@ module Netzke
57
100
  self.class.short_widget_class_name
58
101
  end
59
102
 
60
- def self.short_widget_class_name
61
- name.split("::").last
62
- end
63
-
64
- #
65
- # Use this class-method to declare connection points between client side of a widget and its server side. A method in a widget class with the same name will be (magically) called by the client-side of the widget. See Grid widget for an example
66
- #
67
- def self.interface(*interface_points)
68
- interfacep = read_inheritable_attribute(:interface_points) || []
69
- interface_points.each{|p| interfacep << p}
70
- write_inheritable_attribute(:interface_points, interfacep)
71
-
72
- interface_points.each do |interfacep|
73
- module_eval <<-END, __FILE__, __LINE__
74
- def interface_#{interfacep}(*args)
75
- #{interfacep}(*args).to_js
76
- end
77
- # FIXME: commented out because otherwise ColumnOperations stop working
78
- # def #{interfacep}(*args)
79
- # flash :warning => "API point '#{interfacep}' is not implemented for widget '#{short_widget_class_name}'"
80
- # {:flash => @flash}
81
- # end
82
- END
83
- end
84
- end
85
-
86
- def self.interface_points
87
- read_inheritable_attribute(:interface_points)
88
- end
89
-
90
- def interface_points
91
- self.class.interface_points
92
- end
93
-
94
- interface :get_widget # default
103
+ interface :get_widget # every widget gets this
95
104
 
96
105
  ## Dependencies
97
106
  def dependencies
98
107
  @dependencies ||= begin
99
- non_late_aggregatees_widget_classes = aggregatees.values.map{|v| v[:widget_class_name]}
100
- (initial_dependencies + non_late_aggregatees_widget_classes).uniq
108
+ non_late_aggregatees_widget_classes = non_late_aggregatees.values.map{|v| v[:widget_class_name]}
109
+ (initial_dependencies + non_late_aggregatees_widget_classes << self.class.short_widget_class_name).uniq
101
110
  end
102
111
  end
103
112
 
@@ -123,7 +132,7 @@ module Netzke
123
132
  aggregatees.merge!(aggr)
124
133
  end
125
134
 
126
- # The difference between aggregatees and late aggregatees is the following: the former gets instantiated together with its aggregator and is normally instantly visible as a part of it. While a late aggregatee doesn't get instantiated along with its aggregator. Until it gets requested, it doesn't take any part in its aggregator's lifecycle. An example of late aggregatee could be a widget that is loaded by an application widget on user's request, or a preferences window that only gets instantiated when user wants to edit widget's preferences. An example of a normal aggregatee is any widget (like a grid) within a BorderLayout-based widget (i.e. aggregator) - it should get instantiated and shown along with its aggregator.
135
+ # The difference between aggregatees and late aggregatees is the following: the former gets instantiated together with its aggregator and is normally *instantly* visible as a part of it (for example, the widget in the initially expanded panel in an Accordion). A late aggregatee doesn't get instantiated along with its aggregator. Until it gets requested from the server, it doesn't take any part in its aggregator's life. An example of late aggregatee could be a widget that is loaded dynamically into a previously collapsed panel of an Accordion, or a preferences window (late aggregatee) for a widget (aggregator) that only gets shown when user wants to edit widget's preferences.
127
136
  def initial_late_aggregatees
128
137
  {}
129
138
  end
@@ -145,7 +154,6 @@ module Netzke
145
154
  aggregator
146
155
  end
147
156
 
148
-
149
157
  def full_widget_class_name(short_name)
150
158
  "Netzke::#{short_name}"
151
159
  end
@@ -178,7 +186,7 @@ module Netzke
178
186
  config[:allow] && config[:allow].each{|p| @permissions.merge!(p.to_sym => true)} # allow
179
187
 
180
188
  # ... and then merge it with NetzkePreferences (if not instantiated to only generate JS-class code)
181
- !config[:js_class] && available_permissions.each do |p|
189
+ available_permissions.each do |p|
182
190
  @permissions[p.to_sym] = @pref["permissions.#{p}"] if !@pref["permissions.#{p}"].nil?
183
191
  end
184
192
  end
@@ -36,7 +36,7 @@ module Netzke
36
36
  #
37
37
  # Use this method to declare a widget in the controller
38
38
  #
39
- def netzke_widget(name, config={})
39
+ def netzke(name, config={})
40
40
  # which module is the widget?
41
41
  config[:widget_class_name] ||= name.to_s.classify
42
42
  config[:name] ||= name
@@ -61,7 +61,7 @@ module Netzke
61
61
  widget_instance.js_widget_instance
62
62
  end
63
63
 
64
- def #{name}_class_definition
64
+ def #{name}_class_definition_old
65
65
  result = ""
66
66
  config = controller.class.widget_config_storage[:#{name}]
67
67
  @generated_widget_classes ||= []
@@ -72,6 +72,16 @@ module Netzke
72
72
  end
73
73
  result
74
74
  end
75
+
76
+ def #{name}_class_definition
77
+ @generated_widget_classes ||= []
78
+ config = controller.class.widget_config_storage[:#{name}]
79
+ widget_instance = Netzke::#{config[:widget_class_name]}.new(config)
80
+ res = widget_instance.js_missing_code(@generated_widget_classes)
81
+ @generated_widget_classes += widget_instance.dependencies
82
+ @generated_widget_classes.uniq!
83
+ res
84
+ end
75
85
  END_EVAL
76
86
 
77
87
  # add controller action which will render a simple HTML page containing the widget
@@ -0,0 +1,43 @@
1
+ module Netzke
2
+ #
3
+ # An invisible component that provides feedback service for all Netzke widgets
4
+ #
5
+ class FeedbackGhost < Base
6
+ class << self
7
+ def js_base_class
8
+ "Ext.Component" # yes, invisible
9
+ end
10
+
11
+ def js_extend_properties
12
+ {
13
+ :show_feedback => <<-JS.l,
14
+ function(msg){
15
+ var createBox = function(s, l){
16
+ return ['<div class="msg">',
17
+ '<div class="x-box-tl"><div class="x-box-tr"><div class="x-box-tc"></div></div></div>',
18
+ '<div class="x-box-ml"><div class="x-box-mr"><div class="x-box-mc">', s, '</div></div></div>',
19
+ '<div class="x-box-bl"><div class="x-box-br"><div class="x-box-bc"></div></div></div>',
20
+ '</div>'].join('');
21
+ }
22
+
23
+ var showBox = function(msg, lvl){
24
+ if (!lvl) lvl = 'notice';
25
+ var msgCt = Ext.DomHelper.insertFirst(document.body, {class:'netzke-feedback'}, true);
26
+ var m = Ext.DomHelper.append(msgCt, {html:createBox(msg,lvl)}, true);
27
+ m.slideIn('t').pause(2).ghost("b", {remove:true});
28
+ }
29
+
30
+ if (typeof msg != 'string') {
31
+ Ext.each(msg, function(m){
32
+ showBox(m.msg, m.level)
33
+ })
34
+ } else {
35
+ showBox(msg)
36
+ }
37
+ }
38
+ JS
39
+ }
40
+ end
41
+ end
42
+ end
43
+ end
@@ -5,110 +5,150 @@ module Netzke
5
5
  # Most of the methods below are meant to be overwritten by a concrete widget class.
6
6
  #
7
7
  module JsClassBuilder
8
- # the JS (Ext) class that we inherit from
9
- def js_base_class; "Ext.Panel"; end
10
-
11
- # widget's actions that are loaded at the moment of instantiating a widget
12
- def actions; null; end
13
-
14
- # widget's tools that are loaded at the moment of instantiating a widget see (js_config method)
15
- def tools; []; end
16
-
17
- def tbar; null; end
18
-
19
- def bbar; null; end
20
-
21
- # functions and properties that will be used to extend the functionality of (Ext) JS-class specified in js_base_class
22
- def js_extend_properties; {}; end
23
-
24
- # code executed before and after the constructor
25
- def js_before_constructor; ""; end
26
- def js_after_constructor; ""; end
27
-
28
- # widget's listeners
29
- def js_listeners; {}; end
30
-
31
- # widget's menus
32
- def js_menus; []; end
33
-
34
- # items
35
- def js_items; null; end
36
-
37
- # default config that is passed into the constructor
38
- def js_default_config
39
- {
40
- :title => short_widget_class_name,
41
- :listeners => js_listeners,
42
- :tools => "config.tools".l,
43
- :actions => "config.actions".l,
44
- :tbar => "config.tbar".l,
45
- :bbar => "config.bbar".l,
46
- :items => js_items,
47
- :height => 400,
48
- :width => 800,
49
- :border => false
50
- }
8
+ def self.included(base)
9
+ base.extend ClassMethods
51
10
  end
52
11
 
53
- # declaration of widget's class (stored directly in the cache storage at the client side to be reused at the moment of widget instantiation)
54
- def js_class
55
- <<-JS
56
- Ext.componentCache['#{short_widget_class_name}'] = Ext.extend(#{js_base_class}, Ext.chainApply([Ext.widgetMixIn, {
57
- constructor: function(config){
58
- this.widgetInit(config);
59
- #{js_before_constructor}
60
- Ext.componentCache['#{short_widget_class_name}'].superclass.constructor.call(this, Ext.apply(#{js_default_config.to_js}, config));
61
- #{js_after_constructor}
62
- this.setEvents();
63
- this.addMenus(#{js_menus.to_js});
64
- }
65
- }, #{js_extend_properties.to_js}]))
66
- JS
67
- end
12
+ #
13
+ # Instance methods
14
+ #
68
15
 
69
- # generate instantiating - used when a widget is generated stand-alone (as a part of a HTML page)
70
- def js_widget_instance
71
- %Q(var #{config[:name].to_js} = new Ext.componentCache['#{short_widget_class_name}'](#{js_config.to_js});)
72
- end
73
-
74
- # the config that is send from the server and is used for instantiating a widget
16
+ # The config that is sent from the server and is used for instantiating a widget
75
17
  def js_config
76
18
  res = {}
77
-
78
- # recursively include configs of all (non-late) aggregatees, so that the widget can instantiate them, too
19
+
20
+ # recursively include configs of all (non-late) aggregatees, so that the widget can instantiate them
79
21
  aggregatees.each_pair do |aggr_name, aggr_config|
80
22
  next if aggr_config[:late_aggregation]
81
23
  res["#{aggr_name}_config".to_sym] = aggregatee_instance(aggr_name.to_sym).js_config
82
24
  end
83
-
25
+
84
26
  # interface
85
- interface = interface_points.inject({}){|h,interfacep| h.merge(interfacep => widget_action(interfacep))}
27
+ interface = self.class.interface_points.inject({}){|h,interfacep| h.merge(interfacep => widget_action(interfacep))}
86
28
  res.merge!(:interface => interface)
87
-
29
+
88
30
  res.merge!(:widget_class_name => short_widget_class_name)
89
31
 
90
32
  res.merge!(config[:ext_config])
91
33
  res.merge!(:id => @id_name)
92
-
34
+
93
35
  # include tools and actions
94
- res.merge!(:tools => tools)
95
- res.merge!(:actions => actions)
36
+ res.merge!(:tools => tools) if tools
37
+ res.merge!(:actions => actions) if actions
38
+ res.merge!(:bbar => tbar) if tbar
39
+ res.merge!(:tbar => bbar) if bbar
40
+
41
+ # include permissions
42
+ res.merge!(:permissions => permissions) unless available_permissions.empty?
43
+
44
+ # include eventual region_config
45
+ res.merge!(:region_config => config[:region_config])
96
46
  res
97
47
  end
48
+
49
+ # Generate instantiating - used when a widget is generated stand-alone (as a part of a HTML page)
50
+ def js_widget_instance
51
+ %Q(var #{config[:name].to_js} = new Ext.componentCache['#{short_widget_class_name}'](#{js_config.to_js});)
52
+ end
98
53
 
99
- # class definition of the widget plus that of all the dependencies, minus those that are specified as dependencies_to_exclude
54
+ # All the JS-code required by this *instance* of the widget. It includes the JS-class for the widget
55
+ # itself, as well as JS-classes for all widgets (non-late) aggregatees.
100
56
  def js_missing_code(cached_dependencies = [])
101
57
  result = ""
102
58
  dependencies.each do |dep_name|
103
- dependency_class = "Netzke::#{dep_name}".constantize
104
- result << dependency_class.js_class_code(cached_dependencies)
59
+ unless cached_dependencies.include?(dep_name)
60
+ dependency_class = "Netzke::#{dep_name}".constantize
61
+ result << dependency_class.js_class
62
+ end
105
63
  end
106
- result << js_class.strip_js_comments unless cached_dependencies.include?(short_widget_class_name) && !config[:no_caching]
107
64
  result
108
65
  end
109
66
 
67
+ # widget's actions, tools and toolbars that are loaded at the moment of instantiating a widget
68
+ def actions; nil; end
69
+ def tools; nil; end
70
+ def tbar; nil; end
71
+ def bbar; nil; end
72
+
110
73
  # little helpers
111
74
  def this; "this".l; end
112
75
  def null; "null".l; end
76
+
77
+
78
+ # Methods used to create the javascript class (only once per widget class).
79
+ # The generated code gets cached at the browser, and the widget intstances (at the browser side)
80
+ # get instantiated from it.
81
+ # All these methods can be overwritten in case you want to extend the functionality of some pre-built widget
82
+ # instead of using it as is (using both would cause JS-code duplication)
83
+ module ClassMethods
84
+ # the JS (Ext) class that we inherit from on JS-level
85
+ def js_base_class; "Ext.Panel"; end
86
+
87
+ # functions and properties that will be used to extend the functionality of (Ext) JS-class specified in js_base_class
88
+ def js_extend_properties; {}; end
89
+
90
+ # code executed before and after the constructor
91
+ def js_before_constructor; ""; end
92
+ def js_after_constructor; ""; end
93
+
94
+ # widget's listeners
95
+ def js_listeners; {}; end
96
+
97
+ # widget's menus
98
+ def js_menus; []; end
99
+
100
+ # items
101
+ def js_items; null; end
102
+
103
+ # default config that is always passed into the constructor
104
+ def js_default_config
105
+ {
106
+ :title => "config.id.humanize()".l,
107
+ :listeners => js_listeners,
108
+ :tools => "config.tools".l,
109
+ :actions => "config.actions".l,
110
+ :tbar => "config.tbar".l,
111
+ :bbar => "config.bbar".l,
112
+ # :items => "config.items".l,
113
+ # :items => js_items,
114
+ :height => 400,
115
+ :width => 800,
116
+ :border => false
117
+ }
118
+ end
119
+
120
+ # Declaration of widget's class (stored in the cache storage (Ext.componentCache) at the client side
121
+ # to be reused at the moment of widget instantiation)
122
+ def js_class
123
+ <<-JS
124
+ Ext.componentCache['#{short_widget_class_name}'] = Ext.extend(#{js_base_class}, Ext.chainApply([Ext.widgetMixIn, {
125
+ constructor: function(config){
126
+ this.widgetInit(config);
127
+ #{js_before_constructor}
128
+ Ext.componentCache['#{short_widget_class_name}'].superclass.constructor.call(this, Ext.apply(#{js_default_config.to_js}, config));
129
+ #{js_after_constructor}
130
+ this.setEvents();
131
+ this.addMenus(#{js_menus.to_js});
132
+ }
133
+ }, #{js_extend_properties.to_js}]))
134
+ JS
135
+ end
136
+
137
+ # class definition of the widget plus that of all the dependencies, minus those that are specified as cached_dependencies
138
+ def js_missing_code(cached_dependencies = [])
139
+ result = ""
140
+ dependencies.each do |dep_name|
141
+ dependency_class = "Netzke::#{dep_name}".constantize
142
+ result << dependency_class.js_class_code(cached_dependencies)
143
+ end
144
+ result << js_class.strip_js_comments unless cached_dependencies.include?(short_widget_class_name) && !config[:no_caching]
145
+ result
146
+ end
147
+
148
+ def this; "this".l; end
149
+ def null; "null".l; end
150
+
151
+ end
152
+
113
153
  end
114
154
  end
data/lib/netzke-core.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # NetzkeCore
2
2
  require 'netzke/js_class_builder'
3
3
  require 'netzke/base'
4
+ require 'netzke/feedback_ghost'
4
5
  require 'netzke/action_view_ext'
5
6
  require 'netzke/controller_extensions'
6
7
  require 'netzke/core_ext'
@@ -17,19 +18,26 @@ require 'vendor/facets/hash/recursive_merge'
17
18
  ActiveSupport::Dependencies.load_once_paths.delete(path)
18
19
  end
19
20
 
20
- # Provide controllers with netzke_widget class method
21
- ActionController::Base.class_eval do
22
- include Netzke::ControllerExtensions
21
+ if defined? ActionController
22
+ # Provide controllers with netzke class method
23
+ ActionController::Base.class_eval do
24
+ include Netzke::ControllerExtensions
25
+ end
26
+
27
+ # Include the route to netzke controller
28
+ ActionController::Routing::RouteSet::Mapper.send :include, Netzke::Routing::MapperExtensions
23
29
  end
24
30
 
31
+ if defined? ActionView
32
+ # Helpers to be put into layouts
33
+ ActionView::Base.send :include, Netzke::ActionViewExt
34
+ end
35
+
25
36
  # Make this plugin auto-reloaded for easier development
26
37
  ActiveSupport::Dependencies.load_once_paths.delete(File.join(File.dirname(__FILE__)))
27
38
 
28
39
  # Include the javascript
29
40
  Netzke::Base.config[:javascripts] << "#{File.dirname(__FILE__)}/../javascripts/core.js"
30
41
 
31
- # Include the route to netzke controller
32
- ActionController::Routing::RouteSet::Mapper.send :include, Netzke::Routing::MapperExtensions
33
-
34
- # Helpers to be put into layouts
35
- ActionView::Base.send :include, Netzke::ActionViewExt
42
+ # Include CSS
43
+ Netzke::Base.config[:css] << "#{File.dirname(__FILE__)}/../css/core.css"
data/netzke-core.gemspec CHANGED
@@ -2,15 +2,15 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{netzke-core}
5
- s.version = "0.1.4"
5
+ s.version = "0.2.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Sergei Kozlov"]
9
- s.date = %q{2009-01-02}
9
+ s.date = %q{2009-01-07}
10
10
  s.description = %q{Build ExtJS/Rails widgets with minimum effort}
11
11
  s.email = %q{sergei@writelesscode.com}
12
- s.extra_rdoc_files = ["CHANGELOG", "lib/app/controllers/netzke_controller.rb", "lib/app/models/netzke_layout.rb", "lib/app/models/netzke_preference.rb", "lib/netzke/action_view_ext.rb", "lib/netzke/base.rb", "lib/netzke/controller_extensions.rb", "lib/netzke/core_ext.rb", "lib/netzke/js_class_builder.rb", "lib/netzke/routing.rb", "lib/netzke-core.rb", "lib/vendor/facets/hash/recursive_merge.rb", "LICENSE", "README.mdown", "tasks/netzke_core_tasks.rake"]
13
- s.files = ["CHANGELOG", "generators/netzke_core/netzke_core_generator.rb", "generators/netzke_core/templates/create_netzke_layouts.rb", "generators/netzke_core/templates/create_netzke_preferences.rb", "generators/netzke_core/USAGE", "init.rb", "install.rb", "javascripts/core.js", "lib/app/controllers/netzke_controller.rb", "lib/app/models/netzke_layout.rb", "lib/app/models/netzke_preference.rb", "lib/netzke/action_view_ext.rb", "lib/netzke/base.rb", "lib/netzke/controller_extensions.rb", "lib/netzke/core_ext.rb", "lib/netzke/js_class_builder.rb", "lib/netzke/routing.rb", "lib/netzke-core.rb", "lib/vendor/facets/hash/recursive_merge.rb", "LICENSE", "Manifest", "netzke-core.gemspec", "Rakefile", "README.mdown", "tasks/netzke_core_tasks.rake", "test/app_root/app/controllers/application.rb", "test/app_root/config/boot.rb", "test/app_root/config/database.yml", "test/app_root/config/environment.rb", "test/app_root/config/environments/in_memory.rb", "test/app_root/config/environments/mysql.rb", "test/app_root/config/environments/postgresql.rb", "test/app_root/config/environments/sqlite.rb", "test/app_root/config/environments/sqlite3.rb", "test/app_root/config/routes.rb", "test/app_root/script/console", "test/core_ext_test.rb", "test/netzke_core_test.rb", "test/test_helper.rb", "uninstall.rb"]
12
+ s.extra_rdoc_files = ["CHANGELOG", "lib/app/controllers/netzke_controller.rb", "lib/app/models/netzke_layout.rb", "lib/app/models/netzke_preference.rb", "lib/netzke/action_view_ext.rb", "lib/netzke/base.rb", "lib/netzke/controller_extensions.rb", "lib/netzke/core_ext.rb", "lib/netzke/feedback_ghost.rb", "lib/netzke/js_class_builder.rb", "lib/netzke/routing.rb", "lib/netzke-core.rb", "lib/vendor/facets/hash/recursive_merge.rb", "LICENSE", "README.mdown", "tasks/netzke_core_tasks.rake"]
13
+ s.files = ["CHANGELOG", "css/core.css", "generators/netzke_core/netzke_core_generator.rb", "generators/netzke_core/templates/create_netzke_layouts.rb", "generators/netzke_core/templates/create_netzke_preferences.rb", "generators/netzke_core/USAGE", "init.rb", "install.rb", "javascripts/core.js", "lib/app/controllers/netzke_controller.rb", "lib/app/models/netzke_layout.rb", "lib/app/models/netzke_preference.rb", "lib/netzke/action_view_ext.rb", "lib/netzke/base.rb", "lib/netzke/controller_extensions.rb", "lib/netzke/core_ext.rb", "lib/netzke/feedback_ghost.rb", "lib/netzke/js_class_builder.rb", "lib/netzke/routing.rb", "lib/netzke-core.rb", "lib/vendor/facets/hash/recursive_merge.rb", "LICENSE", "Manifest", "netzke-core.gemspec", "Rakefile", "README.mdown", "tasks/netzke_core_tasks.rake", "test/app_root/app/controllers/application.rb", "test/app_root/config/boot.rb", "test/app_root/config/database.yml", "test/app_root/config/environment.rb", "test/app_root/config/environments/in_memory.rb", "test/app_root/config/environments/mysql.rb", "test/app_root/config/environments/postgresql.rb", "test/app_root/config/environments/sqlite.rb", "test/app_root/config/environments/sqlite3.rb", "test/app_root/config/routes.rb", "test/app_root/script/console", "test/core_ext_test.rb", "test/netzke_core_test.rb", "test/test_helper.rb", "uninstall.rb"]
14
14
  s.has_rdoc = true
15
15
  s.homepage = %q{http://writelesscode.com}
16
16
  s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Netzke-core", "--main", "README.mdown"]
@@ -13,10 +13,6 @@ module Netzke
13
13
  }
14
14
  end
15
15
 
16
- # def initial_dependencies
17
- # %w{NestedWidgetOne NestedWidgetTwo DeepNestedWidget}
18
- # end
19
-
20
16
  def available_permissions
21
17
  %w(read update)
22
18
  end
@@ -123,11 +119,16 @@ class NetzkeCoreTest < ActiveSupport::TestCase
123
119
  assert(!widget.dependencies.include?('DeepNestedWidget'))
124
120
  end
125
121
 
126
- test "dependencies in JS class generators" do
127
- js_code = Widget.js_class_code
128
- assert(js_code.index("Ext.componentCache['NestedWidgetOne']"))
129
- assert(js_code.index("Ext.componentCache['NestedWidgetTwo']"))
130
- assert(js_code.index("Ext.componentCache['DeepNestedWidget']"))
122
+ # test "dependencies in JS class generators" do
123
+ # js_code = Widget.js_class
124
+ # assert(js_code.index("Ext.componentCache['NestedWidgetOne']"))
125
+ # assert(js_code.index("Ext.componentCache['NestedWidgetTwo']"))
126
+ # assert(js_code.index("Ext.componentCache['DeepNestedWidget']"))
127
+ # end
128
+
129
+ test "widget instance by config" do
130
+ widget = Netzke::Base.instance_by_config({:widget_class_name => 'Widget', :name => 'a_widget'})
131
+ assert(Widget, widget.class)
132
+ assert('a_widget', widget.config[:name])
131
133
  end
132
-
133
134
  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.1.4
4
+ version: 0.2.0
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-01-02 00:00:00 -06:00
12
+ date: 2009-01-07 00:00:00 -06:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -28,6 +28,7 @@ extra_rdoc_files:
28
28
  - lib/netzke/base.rb
29
29
  - lib/netzke/controller_extensions.rb
30
30
  - lib/netzke/core_ext.rb
31
+ - lib/netzke/feedback_ghost.rb
31
32
  - lib/netzke/js_class_builder.rb
32
33
  - lib/netzke/routing.rb
33
34
  - lib/netzke-core.rb
@@ -37,6 +38,7 @@ extra_rdoc_files:
37
38
  - tasks/netzke_core_tasks.rake
38
39
  files:
39
40
  - CHANGELOG
41
+ - css/core.css
40
42
  - generators/netzke_core/netzke_core_generator.rb
41
43
  - generators/netzke_core/templates/create_netzke_layouts.rb
42
44
  - generators/netzke_core/templates/create_netzke_preferences.rb
@@ -51,6 +53,7 @@ files:
51
53
  - lib/netzke/base.rb
52
54
  - lib/netzke/controller_extensions.rb
53
55
  - lib/netzke/core_ext.rb
56
+ - lib/netzke/feedback_ghost.rb
54
57
  - lib/netzke/js_class_builder.rb
55
58
  - lib/netzke/routing.rb
56
59
  - lib/netzke-core.rb