netzke-basepack 0.6.0 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. data/CHANGELOG.rdoc +14 -6
  2. data/README.rdoc +16 -31
  3. data/Rakefile +22 -16
  4. data/TODO.rdoc +1 -1
  5. data/app/models/netzke_field_list.rb +29 -29
  6. data/app/models/netzke_model_attr_list.rb +4 -4
  7. data/app/models/netzke_persistent_array_auto_model.rb +9 -9
  8. data/config/database.yml +2 -35
  9. data/features/accordion_panel.feature +1 -1
  10. data/features/form_panel.feature +2 -2
  11. data/features/grid_panel.feature +15 -3
  12. data/features/search_in_grid.feature +4 -4
  13. data/features/simple_panel.feature +4 -4
  14. data/features/step_definitions/pickle_steps.rb +2 -2
  15. data/features/step_definitions/web_steps.rb +5 -5
  16. data/features/support/env.rb +6 -6
  17. data/features/tab_panel.feature +1 -1
  18. data/javascripts/basepack.js +28 -28
  19. data/lib/netzke-basepack.rb +5 -5
  20. data/lib/netzke/active_record.rb +1 -1
  21. data/lib/netzke/active_record/association_attributes.rb +9 -9
  22. data/lib/netzke/active_record/attributes.rb +24 -23
  23. data/lib/netzke/active_record/combobox_options.rb +3 -3
  24. data/lib/netzke/active_record/relation_extensions.rb +4 -4
  25. data/lib/netzke/basepack.rb +4 -4
  26. data/{app/components → lib}/netzke/basepack/accordion_panel.rb +7 -7
  27. data/{app/components → lib}/netzke/basepack/basic_app.rb +18 -18
  28. data/{app/components → lib}/netzke/basepack/basic_app/statusbar_ext.js +0 -0
  29. data/lib/netzke/basepack/border_layout_panel.rb +101 -0
  30. data/{app/components → lib}/netzke/basepack/form_panel.rb +21 -21
  31. data/{app/components → lib}/netzke/basepack/form_panel/fields.rb +29 -36
  32. data/{app/components → lib}/netzke/basepack/form_panel/javascripts/netzkefileupload.js +0 -0
  33. data/{app/components → lib}/netzke/basepack/form_panel/javascripts/pre.js +9 -9
  34. data/{app/components → lib}/netzke/basepack/form_panel/javascripts/xcheckbox.js +1 -1
  35. data/{app/components → lib}/netzke/basepack/form_panel/services.rb +11 -11
  36. data/{app/components → lib}/netzke/basepack/grid_panel.rb +74 -92
  37. data/{app/components → lib}/netzke/basepack/grid_panel/columns.rb +34 -36
  38. data/{app/components → lib}/netzke/basepack/grid_panel/javascript.rb +7 -7
  39. data/{app/components → lib}/netzke/basepack/grid_panel/javascripts/advanced_search.js +10 -10
  40. data/{app/components → lib}/netzke/basepack/grid_panel/javascripts/edit_in_form.js +2 -2
  41. data/{app/components → lib}/netzke/basepack/grid_panel/javascripts/pre.js +31 -31
  42. data/{app/components → lib}/netzke/basepack/grid_panel/javascripts/rows-dd.js +1 -1
  43. data/{app/components → lib}/netzke/basepack/grid_panel/multi_edit_form.rb +2 -2
  44. data/{app/components → lib}/netzke/basepack/grid_panel/record_form_window.rb +3 -3
  45. data/{app/components → lib}/netzke/basepack/grid_panel/search_window.rb +11 -11
  46. data/{app/components → lib}/netzke/basepack/grid_panel/services.rb +28 -28
  47. data/{app/components → lib}/netzke/basepack/panel.rb +0 -0
  48. data/{app/components → lib}/netzke/basepack/search_panel.rb +11 -11
  49. data/{app/components → lib}/netzke/basepack/tab_panel.rb +7 -7
  50. data/lib/netzke/basepack/version.rb +1 -1
  51. data/{app/components → lib}/netzke/basepack/window.rb +14 -14
  52. data/{app/components → lib}/netzke/basepack/wrapper.rb +6 -6
  53. data/lib/netzke/data_accessor.rb +18 -18
  54. data/lib/netzke/fields_configurator.rb +30 -30
  55. data/lib/netzke/json_array_editor.rb +9 -9
  56. data/lib/netzke/masquerade_selector.rb +5 -5
  57. data/locale/en.yml +1 -1
  58. data/netzke-basepack.gemspec +252 -240
  59. data/spec/active_record/attributes_spec.rb +6 -1
  60. data/spec/active_record/relation_extensions_spec.rb +11 -11
  61. data/spec/components/form_panel_spec.rb +13 -19
  62. data/spec/components/grid_panel_spec.rb +1 -1
  63. data/test/rails_app/Gemfile +4 -3
  64. data/test/rails_app/Gemfile.lock +42 -50
  65. data/test/rails_app/app/components/book_grid.rb +4 -0
  66. data/test/rails_app/app/components/generic_user_form.rb +2 -2
  67. data/test/rails_app/app/components/simple_basic_app.rb +3 -3
  68. data/test/rails_app/app/components/simple_panel.rb +1 -1
  69. data/test/rails_app/app/components/some_border_layout.rb +12 -11
  70. data/test/rails_app/app/components/some_search_panel.rb +5 -5
  71. data/test/rails_app/app/components/user_form.rb +1 -1
  72. data/test/rails_app/app/components/window_component_loader.rb +2 -2
  73. data/test/rails_app/app/models/author.rb +7 -0
  74. data/test/rails_app/app/models/book.rb +3 -0
  75. data/test/rails_app/app/models/user.rb +1 -1
  76. data/test/rails_app/config/locales/es.yml +0 -1
  77. data/test/rails_app/config/routes.rb +2 -2
  78. data/test/rails_app/db/development_structure.sql +28 -3
  79. data/test/rails_app/db/migrate/20101026185816_create_authors.rb +14 -0
  80. data/test/rails_app/db/migrate/20101026190021_create_books.rb +17 -0
  81. data/test/rails_app/db/schema.rb +18 -1
  82. data/test/rails_app/public/javascripts/effects.js +1 -1
  83. data/test/rails_app/spec/models/author_spec.rb +5 -0
  84. data/test/rails_app/spec/models/book_spec.rb +5 -0
  85. data/test/test_helper.rb +1 -1
  86. data/test/unit/accordion_panel_test.rb +2 -2
  87. data/test/unit/active_record_basepack_test.rb +9 -9
  88. data/test/unit/fields_configuration_test.rb +4 -4
  89. data/test/unit/grid_panel_test.rb +8 -8
  90. data/test/unit/tab_panel_test.rb +2 -2
  91. metadata +49 -36
  92. data/.gitignore +0 -10
  93. data/app/components/netzke/basepack/border_layout_panel.rb +0 -39
@@ -9,21 +9,21 @@ module Netzke::ActiveRecord
9
9
  module InstanceMethods
10
10
  # Allow nested association access (assocs separated by "." or "__"), e.g.: proxy_service.asset__gui_folder__name
11
11
  # Example:
12
- #
12
+ #
13
13
  # Book.first.genre__name = 'Fantasy'
14
- #
14
+ #
15
15
  # is the same as:
16
- #
16
+ #
17
17
  # Book.first.genre = Genre.find_by_name('Fantasy')
18
18
  #
19
19
  # The result - easier forms and grids that handle nested models: simply specify column/field name as "genre__name".
20
20
  def method_missing_with_basepack(method, *args, &block)
21
21
  # if refering to a column, just pass it to the original method_missing
22
22
  return method_missing_without_basepack(method, *args, &block) if self.class.column_names.include?(method.to_s)
23
-
23
+
24
24
  split = method.to_s.split(/\.|__/)
25
25
  if split.size > 1
26
- if split.last =~ /=$/
26
+ if split.last =~ /=$/
27
27
  if split.size == 2
28
28
  # search for association and assign it to self
29
29
  assoc = self.class.reflect_on_association(split.first.to_sym)
@@ -61,12 +61,12 @@ module Netzke::ActiveRecord
61
61
  method_missing_without_basepack(method, *args, &block)
62
62
  end
63
63
  end
64
-
64
+
65
65
  # Make respond_to? return true for association assignment method, like "genre__name="
66
66
  def respond_to_with_basepack?(method, include_private = false)
67
67
  split = method.to_s.split(/__/)
68
68
  if split.size > 1
69
- if split.last =~ /=$/
69
+ if split.last =~ /=$/
70
70
  if split.size == 2
71
71
  # search for association and assign it to self
72
72
  assoc = self.class.reflect_on_association(split.first.to_sym)
@@ -91,12 +91,12 @@ module Netzke::ActiveRecord
91
91
 
92
92
  def self.included(receiver)
93
93
  receiver.extend ClassMethods
94
-
94
+
95
95
  receiver.send :include, InstanceMethods
96
96
  receiver.alias_method_chain :method_missing, :basepack
97
97
  receiver.alias_method_chain :respond_to?, :basepack
98
98
  end
99
-
99
+
100
100
  end
101
101
  end
102
102
 
@@ -1,6 +1,6 @@
1
1
  module Netzke::ActiveRecord::Attributes
2
2
  extend ActiveSupport::Concern
3
-
3
+
4
4
  module ClassMethods
5
5
  # Define or configure an attribute.
6
6
  # Example:
@@ -24,7 +24,7 @@ module Netzke::ActiveRecord::Attributes
24
24
  end
25
25
  write_inheritable_attribute(:netzke_declared_attributes, declared_attrs)
26
26
  end
27
-
27
+
28
28
  # Exclude attributes from being picked up by grids and forms.
29
29
  # Accepts an array of attribute names (as symbols).
30
30
  # Example:
@@ -32,7 +32,7 @@ module Netzke::ActiveRecord::Attributes
32
32
  def netzke_exclude_attributes(*args)
33
33
  write_inheritable_attribute(:netzke_excluded_attributes, args.map(&:to_s))
34
34
  end
35
-
35
+
36
36
  # Explicitly expose attributes that should be picked up by grids and forms.
37
37
  # Accepts an array of attribute names (as symbols).
38
38
  # Takes precedence over <tt>netzke_exclude_attributes</tt>.
@@ -41,13 +41,13 @@ module Netzke::ActiveRecord::Attributes
41
41
  def netzke_expose_attributes(*args)
42
42
  write_inheritable_attribute(:netzke_exposed_attributes, args.map(&:to_s))
43
43
  end
44
-
44
+
45
45
  # Returns the attributes that will be picked up by grids and forms.
46
46
  def netzke_attributes
47
47
  exposed = netzke_exposed_attributes
48
48
  exposed ? netzke_attrs_in_forced_order(exposed) : netzke_attrs_in_natural_order
49
49
  end
50
-
50
+
51
51
  def netzke_exposed_attributes
52
52
  exposed = read_inheritable_attribute(:netzke_exposed_attributes)
53
53
  if exposed && !exposed.include?(self.primary_key)
@@ -57,12 +57,12 @@ module Netzke::ActiveRecord::Attributes
57
57
  end
58
58
  exposed
59
59
  end
60
-
60
+
61
61
  private
62
62
  def netzke_declared_attributes
63
63
  read_inheritable_attribute(:netzke_declared_attributes) || []
64
64
  end
65
-
65
+
66
66
  def netzke_excluded_attributes
67
67
  read_inheritable_attribute(:netzke_excluded_attributes) || []
68
68
  end
@@ -78,37 +78,38 @@ module Netzke::ActiveRecord::Attributes
78
78
  # .. otherwise merge with what's declared
79
79
  merged = in_columns_hash.merge(declared)
80
80
  end
81
-
81
+
82
82
  # We didn't find it among declared, nor among the model columns, nor does it seem association attribute
83
83
  merged[:name].nil? && raise(ArgumentError, "Unknown attribute '#{attr_name}' for model #{self.name}", caller)
84
-
84
+
85
85
  merged
86
86
  end
87
87
  end
88
-
88
+
89
89
  # Returns netzke attributes in the order of columns in the table, followed by extra declared attributes
90
90
  # Detects one-to-many association columns and replaces the name of the column with association column name (Netzke style), e.g.:
91
- #
91
+ #
92
92
  # role_id => role__name
93
93
  def netzke_attrs_in_natural_order
94
94
  (
95
95
  declared_attrs = netzke_declared_attributes
96
-
96
+
97
97
  column_names.map do |name|
98
98
  c = {:name => name, :attr_type => columns_hash[name].type}
99
-
99
+
100
100
  # If it's named as foreign key of some association, then it's an association column
101
101
  assoc = reflect_on_all_associations.detect{|a| a.primary_key_name == c[:name]}
102
102
 
103
103
  if assoc && !assoc.options[:polymorphic]
104
- assoc_method = %w{name title label id}.detect{|m| (assoc.klass.instance_methods + assoc.klass.column_names).include?(m) } || assoc.klass.primary_key
104
+ candidates = %w{name title label} << assoc.primary_key_name
105
+ assoc_method = candidates.detect{|m| (assoc.klass.instance_methods.map(&:to_s) + assoc.klass.column_names).include?(m) }
105
106
  c[:name] = "#{assoc.name}__#{assoc_method}"
106
- c[:attr_type] = assoc.klass.columns_hash[assoc_method].type
107
+ c[:attr_type] = assoc.klass.columns_hash[assoc_method].try(:type) || :string # when it's an instance method rather than a column, fall back to :string
107
108
  end
108
-
109
+
109
110
  # auto set up the default value from the column settings
110
111
  c.merge!(:default_value => columns_hash[name].default) if columns_hash[name].default
111
-
112
+
112
113
  # if there's a declared attr with the same name, simply merge it with what's taken from the model's columns
113
114
  if declared = declared_attrs.detect{ |va| va[:name] == c[:name] }
114
115
  c.merge!(declared)
@@ -119,13 +120,13 @@ module Netzke::ActiveRecord::Attributes
119
120
  declared_attrs
120
121
  ).reject { |attr| netzke_excluded_attributes.include?(attr[:name]) }
121
122
  end
122
-
123
+
123
124
  def association_attr?(attr_name)
124
125
  !!attr_name.index("__") # probably we can't do much better than this, as we don't know at this moment if the associated model has a specific attribute, and we don't really want to find it out
125
126
  end
126
-
127
+
127
128
  end
128
-
129
+
129
130
  # Transforms a record to array of values according to the passed attributes
130
131
  def to_array(attributes)
131
132
  res = []
@@ -143,7 +144,7 @@ module Netzke::ActiveRecord::Attributes
143
144
  end
144
145
  res
145
146
  end
146
-
147
+
147
148
  # Accepts both hash and array of attributes
148
149
  def to_hash(attributes)
149
150
  res = {}
@@ -153,7 +154,7 @@ module Netzke::ActiveRecord::Attributes
153
154
  end
154
155
  res
155
156
  end
156
-
157
+
157
158
  def value_for_attribute(a)
158
159
  begin
159
160
  v = send(a[:name])
@@ -165,5 +166,5 @@ module Netzke::ActiveRecord::Attributes
165
166
  "UNDEF"
166
167
  end
167
168
  end
168
-
169
+
169
170
  end
@@ -1,13 +1,13 @@
1
1
  module Netzke::ActiveRecord::ComboboxOptions
2
2
  module ClassMethods
3
-
3
+
4
4
  def netzke_combo_options_for(column, query = "")
5
5
  records = query.empty? ? find_by_sql("select distinct #{column} from #{table_name}") : find_by_sql("select distinct #{column} from #{table_name} where #{column} like '#{query}%'")
6
6
  records.map{|r| r.send(column)}
7
7
  end
8
-
8
+
9
9
  end
10
-
10
+
11
11
  def self.included(receiver)
12
12
  receiver.extend ClassMethods
13
13
  end
@@ -1,7 +1,7 @@
1
1
  module Netzke
2
2
  module ActiveRecord
3
3
  module RelationExtensions
4
-
4
+
5
5
  def extend_with(*params)
6
6
  scope = params.shift
7
7
  case scope.class.name
@@ -19,8 +19,8 @@ module Netzke
19
19
  raise ArgumentError, "Wrong parameter type for ActiveRecord::Relation#extend_with"
20
20
  end
21
21
  end
22
-
23
- # Non-destructively extends itself whith a hash of double-underscore'd conditions,
22
+
23
+ # Non-destructively extends itself whith a hash of double-underscore'd conditions,
24
24
  # where the last part "__" is MetaWhere operator (which is required), e.g.:
25
25
  # {:role__name__like => "%admin"}
26
26
  def extend_with_netzke_conditions(cond)
@@ -29,7 +29,7 @@ module Netzke
29
29
  operator.empty? ? r.where(assoc.to_sym.send(method) => v) : r.where(assoc.to_sym => {method.to_sym.send(operator.last) => v}).joins(assoc.to_sym)
30
30
  end
31
31
  end
32
-
32
+
33
33
  end
34
34
  end
35
35
  end
@@ -4,18 +4,18 @@ require 'netzke/active_record'
4
4
  module Netzke
5
5
  module Basepack
6
6
  mattr_accessor :with_icons
7
-
7
+
8
8
  mattr_accessor :icons_uri
9
-
9
+
10
10
  class << self
11
11
  # Called from netzke-basepack.rb
12
12
  def init
13
13
  Netzke::Core.javascripts << "#{File.dirname(__FILE__)}/../../javascripts/basepack.js"
14
14
  Netzke::Core.stylesheets << "#{File.dirname(__FILE__)}/../../stylesheets/basepack.css"
15
15
  end
16
-
16
+
17
17
  # Use it to confirure Basepack in the initializers, e.g.:
18
- #
18
+ #
19
19
  # Netzke::Basepack.setup do |config|
20
20
  # config.icons_uri = "/images/famfamfam/icons"
21
21
  # end
@@ -1,9 +1,9 @@
1
1
  module Netzke
2
2
  module Basepack
3
3
  # = AccordionPanel
4
- #
4
+ #
5
5
  # A panel with the 'accordion' layout. Can lazily load its nested components. For example:
6
- #
6
+ #
7
7
  # netzke :my_accordion, :items => [{
8
8
  # :html => "I'm a simple Ext.Panel",
9
9
  # :title => "Panel One"
@@ -14,24 +14,24 @@ module Netzke
14
14
  # :lazy_loading => true
15
15
  # }]
16
16
  class AccordionPanel < Netzke::Base
17
-
17
+
18
18
  include WrapLazyLoaded
19
-
19
+
20
20
  js_property :layout, 'accordion'
21
-
21
+
22
22
  js_method :init_component, <<-JS
23
23
  function(params){
24
24
  #{js_full_class_name}.superclass.initComponent.call(this);
25
25
  this.items.each(function(item){
26
26
  item.on('expand', function(i){
27
- if (i.wrappedComponent && !i.items.first()) {
27
+ if (i && i.wrappedComponent && !i.items.first()) {
28
28
  this.loadComponent({name: i.wrappedComponent, container: i.id});
29
29
  }
30
30
  }, this);
31
31
  }, this);
32
32
  }
33
33
  JS
34
-
34
+
35
35
  end
36
36
  end
37
37
  end
@@ -10,9 +10,9 @@ module Netzke
10
10
  # * (TODO) authentification support
11
11
  # * (TODO) masquerade support
12
12
  class BasicApp < Base
13
-
13
+
14
14
  js_base_class "Ext.Viewport"
15
-
15
+
16
16
  js_property :layout, :border
17
17
 
18
18
  def self.include_js
@@ -36,7 +36,7 @@ module Netzke
36
36
  elsif session[:masq_world]
37
37
  masq = %Q{World}
38
38
  end
39
-
39
+
40
40
  {
41
41
  :items => [{
42
42
  :id => 'main-panel',
@@ -75,29 +75,29 @@ module Netzke
75
75
  }
76
76
 
77
77
  Ext.History.on('change', this.processHistory, this);
78
-
78
+
79
79
  // Setting the "busy" indicator for Ajax requests
80
80
  Ext.Ajax.on('beforerequest', function(){this.findById('main-statusbar').showBusy()}, this);
81
81
  Ext.Ajax.on('requestcomplete', function(){this.findById('main-statusbar').hideBusy()}, this);
82
82
  Ext.Ajax.on('requestexception', function(){this.findById('main-statusbar').hideBusy()}, this);
83
-
83
+
84
84
  // Initialize history
85
85
  Ext.History.init();
86
86
  }
87
87
  JS
88
-
88
+
89
89
  js_method :on_login, <<-JS
90
90
  function(){
91
91
  window.location = "/login"
92
92
  }
93
93
  JS
94
-
94
+
95
95
  js_method :on_logout, <<-JS
96
96
  function(){
97
97
  window.location = "#{logout_url}"
98
98
  }
99
99
  JS
100
-
100
+
101
101
  js_method :process_history, <<-JS
102
102
  function(token){
103
103
  if (token){
@@ -107,13 +107,13 @@ module Netzke
107
107
  }
108
108
  }
109
109
  JS
110
-
110
+
111
111
  js_method :instantiate_component, <<-JS
112
112
  function(config){
113
113
  this.findById('main-panel').instantiateChild(config);
114
114
  }
115
115
  JS
116
-
116
+
117
117
  js_method :app_load_component, <<-JS
118
118
  function(name){
119
119
  Ext.History.add(name);
@@ -131,7 +131,7 @@ module Netzke
131
131
  this.toggleConfigMode();
132
132
  }
133
133
  JS
134
-
134
+
135
135
  js_method :show_masquerade_selector, <<-JS
136
136
  function(){
137
137
  var w = new Ext.Window({
@@ -223,18 +223,18 @@ module Netzke
223
223
 
224
224
  strong_children_config.deep_merge!(:mode => :config) if session[:config_mode]
225
225
  end
226
-
227
-
226
+
227
+
228
228
  action :masquerade_selector, :text => "Masquerade as ...", :handler => :show_masquerade_selector
229
-
230
- action :toggle_config_mode do
229
+
230
+ action :toggle_config_mode do
231
231
  {:text => "#{session[:config_mode] ? "Leave" : "Enter"} config mode"}
232
232
  end
233
-
233
+
234
234
  action :login, :icon => :door_in
235
-
235
+
236
236
  action :logout, :icon => :door_out
237
-
237
+
238
238
  # Html required for Ext.History to work
239
239
  def js_component_html
240
240
  super << %Q{
@@ -0,0 +1,101 @@
1
+ module Netzke
2
+ module Basepack
3
+ # Panel with border layout
4
+ # == Example configuration:
5
+ #
6
+ # :items => [
7
+ # {:title => "Item One", :class_name => "Basepack::Panel", :region => :center},
8
+ # {:title => "Item Two", :class_name => "Basepack::Panel", :region => :west, :width => 300, :split => true}
9
+ # ]
10
+ class BorderLayoutPanel < Netzke::Base
11
+ def items
12
+ @border_layout_items ||= begin
13
+ updated_items = super
14
+
15
+ if config[:persistence]
16
+ updated_items.each do |item|
17
+ region = item[:region] || components[item[:component]][:region]
18
+ item.merge!({
19
+ :width => state["#{region}_region_width"],
20
+ :height => state["#{region}_region_height"],
21
+ :collapsed => state["#{region}_region_collapsed"]
22
+ })
23
+ end
24
+ end
25
+
26
+ updated_items
27
+ end
28
+ end
29
+
30
+ js_property :layout, :border
31
+
32
+ js_method :init_component, <<-JS
33
+ function(){
34
+ Ext.each(['center', 'west', 'east', 'south', 'north'], function(r){
35
+ // A function to access a region component (even if the component gets reloaded, the function will work).
36
+ // E.g.: getEastComponent()
37
+ var methodName = 'get'+r.capitalize()+'Component';
38
+ this[methodName] = function(){
39
+ Netzke.deprecationWarning("Instead of '" + methodName + "' use getChildComponent('<name of your component>').");
40
+ return this.find('region', r)[0];
41
+ }.createDelegate(this);
42
+ }, this);
43
+
44
+ // Now let Ext.Panel do the rest
45
+ #{js_full_class_name}.superclass.initComponent.call(this);
46
+
47
+ // First time on "afterlayout", set resize events
48
+ if (this.persistence) {this.on('afterlayout', this.setRegionEvents, this, {single: true});}
49
+ }
50
+ JS
51
+
52
+ js_method :set_region_events, <<-JS
53
+ function(){
54
+ this.items.each(function(item, index, length){
55
+ if (!item.oldSize) item.oldSize = item.getSize(); // remember initial size
56
+
57
+ item.on('resize', function(panel, w, h){
58
+ if (panel.region !== 'center' && w && h) {
59
+ var params = {region:panel.region};
60
+
61
+ if (panel.oldSize.width != w) {
62
+ params.width = w;
63
+ } else {
64
+ params.height = h;
65
+ }
66
+
67
+ panel.oldSize = panel.getSize();
68
+ this.regionResized(params);
69
+ }
70
+ }, this);
71
+
72
+ item.on('collapse', function(panel){
73
+ this.regionCollapsed({region: panel.region});
74
+ }, this);
75
+
76
+ item.on('expand', function(panel){
77
+ this.regionExpanded({region: panel.region});
78
+ }, this);
79
+
80
+ }, this);
81
+ }
82
+ JS
83
+
84
+ endpoint :region_resized do |params|
85
+ size_state_hash = {}
86
+ size_state_hash[:"#{params[:region]}_region_width"] = params[:width] if params[:width]
87
+ size_state_hash[:"#{params[:region]}_region_height"] = params[:height] if params[:height]
88
+ update_state(size_state_hash)
89
+ end
90
+
91
+ endpoint :region_collapsed do |params|
92
+ update_state(:"#{params[:region]}_region_collapsed" => true)
93
+ end
94
+
95
+ endpoint :region_expanded do |params|
96
+ update_state(:"#{params[:region]}_region_collapsed" => false)
97
+ end
98
+
99
+ end
100
+ end
101
+ end