netzke-basepack 0.6.2 → 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. data/CHANGELOG.rdoc +27 -2
  2. data/TODO.rdoc +1 -5
  3. data/app/models/netzke_persistent_array_auto_model.rb +0 -1
  4. data/features/components_in_view.feature +11 -0
  5. data/features/form_panel.feature +49 -0
  6. data/features/grid_panel.feature +32 -1
  7. data/features/i18n.feature +18 -0
  8. data/features/nested_attributes.feature +23 -0
  9. data/features/search_in_grid.feature +9 -9
  10. data/features/simple_app.feature +10 -0
  11. data/features/step_definitions/grid_panel_steps.rb +23 -0
  12. data/features/support/paths.rb +6 -0
  13. data/features/support/pickle.rb +0 -1
  14. data/features/virtual_attributes.feature +20 -0
  15. data/javascripts/basepack.js +166 -243
  16. data/lib/netzke-basepack.rb +3 -3
  17. data/lib/netzke/active_record.rb +6 -7
  18. data/lib/netzke/active_record/attributes.rb +214 -143
  19. data/lib/netzke/active_record/combobox_options.rb +12 -10
  20. data/lib/netzke/basepack.rb +6 -3
  21. data/lib/netzke/basepack/accordion_panel.rb +4 -2
  22. data/lib/netzke/basepack/auth_app.rb +152 -0
  23. data/lib/netzke/basepack/basic_app.rb +2 -262
  24. data/lib/netzke/basepack/form_panel.rb +35 -27
  25. data/lib/netzke/basepack/form_panel/fields.rb +35 -17
  26. data/lib/netzke/basepack/form_panel/javascripts/comma_list_cbg.js +59 -0
  27. data/lib/netzke/basepack/form_panel/javascripts/display_mode.js +62 -0
  28. data/lib/netzke/basepack/form_panel/javascripts/main.js +138 -0
  29. data/lib/netzke/basepack/form_panel/javascripts/n_radio_group.js +25 -0
  30. data/lib/netzke/basepack/form_panel/services.rb +12 -9
  31. data/lib/netzke/basepack/grid_panel.rb +87 -53
  32. data/lib/netzke/basepack/grid_panel/columns.rb +60 -15
  33. data/lib/netzke/basepack/grid_panel/javascripts/advanced_search.js +2 -64
  34. data/lib/netzke/basepack/grid_panel/javascripts/edit_in_form.js +2 -2
  35. data/lib/netzke/basepack/grid_panel/javascripts/{pre.js → main.js} +35 -17
  36. data/lib/netzke/basepack/grid_panel/javascripts/misc.js +4 -0
  37. data/lib/netzke/basepack/grid_panel/services.rb +17 -14
  38. data/lib/netzke/basepack/paging_form_panel.rb +92 -0
  39. data/lib/netzke/basepack/simple_app.rb +71 -0
  40. data/lib/netzke/basepack/simple_app/javascripts/main.js +53 -0
  41. data/lib/netzke/basepack/{basic_app → simple_app/javascripts}/statusbar_ext.js +0 -0
  42. data/lib/netzke/basepack/tab_panel.rb +2 -12
  43. data/lib/netzke/basepack/tab_panel/javascripts/main.js +11 -0
  44. data/lib/netzke/basepack/version.rb +2 -2
  45. data/lib/netzke/basepack/window.rb +6 -7
  46. data/lib/netzke/basepack/wrap_lazy_loaded.rb +3 -1
  47. data/lib/netzke/data_accessor.rb +25 -14
  48. data/lib/netzke/ext.rb +1 -1
  49. data/locales/en.yml +22 -0
  50. data/netzke-basepack.gemspec +66 -12
  51. data/spec/active_record/attributes_spec.rb +31 -2
  52. data/spec/factories.rb +16 -1
  53. data/test/rails_app/Gemfile +2 -2
  54. data/test/rails_app/Gemfile.lock +76 -77
  55. data/test/rails_app/app/components/author_grid.rb +7 -0
  56. data/test/rails_app/app/components/book_form.rb +24 -0
  57. data/test/rails_app/app/components/book_grid.rb +6 -1
  58. data/test/rails_app/app/components/book_grid_with_default_values.rb +11 -0
  59. data/test/rails_app/app/components/book_grid_with_nested_attributes.rb +13 -0
  60. data/test/rails_app/app/components/book_grid_with_virtual_attributes.rb +22 -0
  61. data/test/rails_app/app/components/book_paging_form_panel.rb +20 -0
  62. data/test/rails_app/app/components/book_presentation.rb +18 -0
  63. data/test/rails_app/app/components/books_bound_to_author.rb +10 -0
  64. data/test/rails_app/app/components/form_without_model.rb +19 -0
  65. data/test/rails_app/app/components/lockable_book_form.rb +17 -0
  66. data/test/rails_app/app/components/lockable_user_form.rb +7 -0
  67. data/test/rails_app/app/components/simple_window.rb +10 -0
  68. data/test/rails_app/app/components/some_accordion_panel.rb +22 -0
  69. data/test/rails_app/app/components/{simple_basic_app.rb → some_auth_app.rb} +3 -3
  70. data/test/rails_app/app/components/some_border_layout.rb +10 -7
  71. data/test/rails_app/app/components/some_simple_app.rb +34 -0
  72. data/test/rails_app/app/components/some_tab_panel.rb +16 -11
  73. data/test/rails_app/app/components/user_form.rb +11 -4
  74. data/test/rails_app/app/components/user_grid.rb +7 -1
  75. data/test/rails_app/app/components/window_component_loader.rb +1 -0
  76. data/test/rails_app/app/controllers/application_controller.rb +6 -0
  77. data/test/rails_app/app/controllers/components_controller.rb +3 -3
  78. data/test/rails_app/app/controllers/welcome_controller.rb +2 -2
  79. data/test/rails_app/app/helpers/embedded_components_helper.rb +2 -0
  80. data/test/rails_app/app/models/address.rb +3 -0
  81. data/test/rails_app/app/models/author.rb +2 -0
  82. data/test/rails_app/app/models/book.rb +1 -0
  83. data/test/rails_app/app/models/user.rb +1 -2
  84. data/test/rails_app/app/views/components/simple_panel.html.erb +1 -0
  85. data/test/rails_app/app/views/layouts/nested.html.erb +5 -0
  86. data/test/rails_app/config/application.rb +1 -1
  87. data/test/rails_app/config/initializers/netzke.rb +0 -4
  88. data/test/rails_app/config/locales/es.yml +16 -0
  89. data/test/rails_app/config/routes.rb +4 -1
  90. data/test/rails_app/db/development_structure.sql +33 -4
  91. data/test/rails_app/db/migrate/20101026190021_create_books.rb +2 -0
  92. data/test/rails_app/db/migrate/20110101143818_create_addresses.rb +17 -0
  93. data/test/rails_app/db/schema.rb +33 -1
  94. data/test/rails_app/spec/controllers/embedded_components_controller_spec.rb +12 -0
  95. data/test/rails_app/spec/helpers/embedded_components_helper_spec.rb +15 -0
  96. data/test/rails_app/spec/models/address_spec.rb +5 -0
  97. data/test/rails_app/spec/views/embedded_components/index.html.erb_spec.rb +5 -0
  98. metadata +67 -13
  99. data/features/basic_app.feature +0 -12
  100. data/lib/netzke/active_record/association_attributes.rb +0 -102
  101. data/lib/netzke/basepack/form_panel/javascripts/pre.js +0 -76
  102. data/lib/netzke/basepack/form_panel/javascripts/xcheckbox.js +0 -82
  103. data/lib/netzke/basepack/grid_panel/javascript.rb +0 -69
  104. data/locale/en.yml +0 -16
data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,28 @@
1
+ = v0.6.3 - 2011-01-14
2
+ * compatibility with netzke-core 0.6.5
3
+
4
+ * refactoring
5
+ * GridPanel code restructured, using the new +js_mixin+ method
6
+
7
+ * bug fix
8
+ * GridPanel respects strong_default_attrs
9
+ * TabPanel doesn't fire multiple load requests per tab in case of lazy-loaded tabs and fast clicking
10
+ * Filtering/sorting on virtual columns is now disabled by default
11
+ * Filtering on date columns
12
+
13
+ * enhancements
14
+ * I18n for Grid/FormPanel
15
+ * new +getter+ config option for columns/fields, a lambda receiving the record as parameter
16
+ * new +setter+ config option for columns/fields, a lambda receiving the record as first parameter, new value as the second
17
+ * GridPanel passes columns' default values to the "Add in form" form
18
+ * FormPanel can now be used without specifying a model
19
+ * New +commalistcbg+ form field for checkboxes, where boxLabels of selected checkboxes are serialized into comma-separated string (the separator is configurable)
20
+ * New +nradiogroup+ form field for radio buttons, where the value is defined by the boxLabel of the selected radio button
21
+ * New +no_binding+ option for configuring a form field. Set it to "true" when you don't want Netzke to expand the field configuration based on the +name+ property. May be needed in some cases, e.g. when using checkboxes/radio buttons in the form.
22
+ * New +nested_attribute+ option for configuring data attributes (thus applicable for a column, a field, or a +netzke_attribute+ in the model). When set to true for an association attribute (e.g. author__name), assigning a value to it will change the association's attribute, *not* trying to find an association by name and reassign it if found (default behavior).
23
+ * FormPanel shows the "Updating..." mask while sending values to the server (configurable with updateMask option/property)
24
+ * FormPanel now can be used in the "lockable" mode (:config => :lockable), which makes it load initially in "display mode", then "unlock" it, change the values, and "lock" it again (updating the values on the server)
25
+
1
26
  = v0.6.2 - 2010-11-05
2
27
  * compatibility with netzke-core 0.6.4
3
28
  * bug fix
@@ -7,7 +32,7 @@
7
32
  * enhancements
8
33
  * BorderLayoutPanel persistence: remembers region sizes and collapsed/expanded states
9
34
  * tooltips for grid buttons
10
-
35
+
11
36
  * bug fix
12
37
  * auto-detection of association's method when the latter is virtual was broken in 1.9.2
13
38
 
@@ -321,4 +346,4 @@
321
346
  * Meta work: replacing underscore with dash in the name
322
347
 
323
348
  = v0.1.0 - 2008-12-20
324
- * Initial release
349
+ * Initial release
data/TODO.rdoc CHANGED
@@ -1,6 +1,5 @@
1
1
  == Priority
2
- * Fix :meta => true config in columns work
3
- * On grid refresh, reset the dirty fields, so that the "Apply" button doesn't do anything
2
+ * Make GridPanel show the mask straight after pressing "Apply"
4
3
  * DataAccessor#to_array should not rescue exceptions, but rather check the availability of the attributes; `respond_to_with_basepack?` should be extended to also return true for association columns
5
4
  * GridPanel's read_only vs editable (doesn't work now) options
6
5
  * Find a way to print the grid nicely (along with the column and rows that don't fit on the screen)
@@ -10,6 +9,3 @@
10
9
 
11
10
  == Optimizations
12
11
  * Check persistent_config-related queries (aren't they too many?)
13
-
14
- == One day
15
- * Replace xcheckbox with checkbox in FormPanel
@@ -41,7 +41,6 @@ class NetzkePersistentArrayAutoModel < ActiveRecord::Base
41
41
  # only select those attributes that were provided to us as columns. The rest is ignored.
42
42
  column_names = config[:columns].map{ |c| c[:name] }
43
43
  clean_data = data.collect{ |c| c.reject{ |k,v| !column_names.include?(k.to_s) } }
44
- Rails.logger.debug "!!! clean_data: #{clean_data.inspect}\n"
45
44
  self.delete_all
46
45
  self.create(clean_data)
47
46
  end
@@ -0,0 +1,11 @@
1
+ Feature: Components in view
2
+ In order to value
3
+ As a role
4
+ I want feature
5
+
6
+ @javascript
7
+ Scenario: Components configured in the view should render properly
8
+ When I go to the "simple panel" view
9
+ Then I should see "Simple Panel content"
10
+ When I press "Update html"
11
+ Then I should see "HTML received from server"
@@ -38,3 +38,52 @@ Scenario: UserFormWithDefaultFields should render properly
38
38
  And I should see "Castaneda"
39
39
  And I should see "writer"
40
40
 
41
+ @javascript
42
+ Scenario: FormPanel should be functional without model provided
43
+ Given I am on the FormWithoutModel test page
44
+ When I fill in "Text field:" with "Some text"
45
+ And I fill in "Number field:" with "42"
46
+ And I check "Boolean field:"
47
+ And I press "Apply"
48
+
49
+ Then I should see "Text field: Some text"
50
+ And I should see "Number field: 42"
51
+ And I should see "Boolean field: true"
52
+
53
+ @javascript
54
+ Scenario: Checkbox field should work properly
55
+ Given an author exists with first_name: "Carlos"
56
+ And a book exists with author: that author, digitized: false, exemplars: 2, title: "Some Title"
57
+ When I go to the BookForm test page
58
+ And I fill in "Exemplars:" with "4"
59
+ And I check "Digitized:"
60
+ And I press "Apply"
61
+ Then I should see "YES"
62
+ And a book should exist with digitized: true, author: that author, exemplars: 4
63
+ And a book should not exist with digitized: false, author: that author
64
+
65
+ @javascript
66
+ Scenario: Checkbox group for tags should work properly
67
+ Given a book exists with title: "Some Title"
68
+ When I go to the BookForm test page
69
+ And I check "recommend"
70
+ And I check "cool"
71
+ And I press "Apply"
72
+ Then the "cool" checkbox should be checked
73
+ And the "recommend" checkbox should be checked
74
+ But the "read" checkbox should not be checked
75
+ And a book should exist with tags: "cool,recommend"
76
+
77
+ # Needs cleaner check whether AJAX request was completed
78
+ # @javascript
79
+ # Scenario: Validations
80
+ # Given a book exists with title: "Some Title"
81
+ # When I go to the BookForm test page
82
+ # And I fill in "Title:" with ""
83
+ # And I press "Apply"
84
+ # And I sleep 1 second
85
+ # Then I should see "Title can't be blank"
86
+ # When I fill in "Title:" with ""
87
+ # And I press "Apply"
88
+ # And I sleep 1 second
89
+ # Then I should not see "Title can't be blank"
@@ -57,7 +57,8 @@ Scenario: Multi-editing records
57
57
  And I press "Edit in form"
58
58
  And I fill in "First name:" with "Maxim"
59
59
  And I press "OK"
60
- Then the following users should exist:
60
+ Then I should see "Updated 2 records."
61
+ And the following users should exist:
61
62
  | first_name | last_name |
62
63
  | Maxim | Castaneda |
63
64
  | Maxim | Hesse |
@@ -71,4 +72,34 @@ Scenario: Filling out association column with association's virtual method
71
72
  Then I should see "Nabokov, Vladimir"
72
73
  And I should see "Lolita"
73
74
 
75
+ @javascript
76
+ Scenario: Grid with strong_default_attrs
77
+ Given an author exists with first_name: "Vladimir", last_name: "Nabokov"
78
+ And a book exists with title: "Lolita", author: that author
79
+ And a book exists with title: "Unknown"
80
+ When I go to the BooksBoundToAuthor test page
81
+ And I press "Add in form"
82
+ And I fill in "Title:" with "The Luzhin Defence"
83
+ And I press "OK"
84
+ And I should see "The Luzhin Defence"
85
+ And I should see "Lolita"
86
+ But I should not see "Unknown"
74
87
 
88
+ @javascript
89
+ Scenario: Grid with columns with default values
90
+ Given I am on the BookGridWithDefaultValues test page
91
+ When I press "Add in form"
92
+ And I press "OK"
93
+ And I sleep 1 second
94
+ Then a book should exist with title: "Lolita", exemplars: 100
95
+
96
+ @javascript
97
+ Scenario: Inline editing
98
+ Given a book exists with title: "Magus", exemplars: 100
99
+ When I go to the BookGrid test page
100
+ And I edit row 1 of the grid with title: "Collector", exemplars: 200
101
+ And I press "Apply"
102
+ And I sleep 1 second
103
+ Then the grid should have 0 modified records
104
+ And a book should exist with title: "Collector", exemplars: 200
105
+ But a book should not exist with title: "Magus"
@@ -0,0 +1,18 @@
1
+ Feature: I18n
2
+ In order to value
3
+ As a role
4
+ I want feature
5
+
6
+ Scenario: A grid with localized column headers
7
+ When I go to the "es" version of the BookGrid page
8
+ Then I should see "Autor"
9
+ And I should see "Creado en"
10
+ But I should not see "Author"
11
+ And I should not see "Created at"
12
+
13
+ Scenario: A form with localized field labels
14
+ When I go to the "es" version of the BookForm page
15
+ Then I should see "Autor"
16
+ And I should see "En abundancia"
17
+ But I should not see "Author"
18
+ And I should not see "In abundance"
@@ -0,0 +1,23 @@
1
+ Feature: Nested attributes
2
+ In order to value
3
+ As a role
4
+ I want feature
5
+
6
+ @javascript
7
+ Scenario: Grid with nested attributes
8
+ Given an author exists with first_name: "Vlad", last_name: "Nabokoff"
9
+ And a book exists with title: "Lola", author: that author
10
+ When I go to the BookGridWithNestedAttributes test page
11
+ And I select first row in the grid
12
+ And I press "Edit in form"
13
+ And I fill in "Author first name:" with "Vladimir"
14
+ And I fill in "Author last name:" with "Nabokov"
15
+ And I fill in "Title:" with "Lolita"
16
+ And I press "OK"
17
+
18
+ Then I should see "Nabokov"
19
+ Then an author should exist with first_name: "Vladimir", last_name: "Nabokov"
20
+ And a book should exist with title: "Lolita", author: that author
21
+
22
+ But an author should not exist with first_name: "Vlad"
23
+ And a book should not exist with title: "Lola"
@@ -6,17 +6,17 @@ Feature: Search
6
6
  @javascript
7
7
  Scenario: Search via Search window
8
8
  Given the following roles exist:
9
- | name |
10
- | admin |
11
- | superadmin |
12
- | user |
9
+ | id | name |
10
+ | 1 | admin |
11
+ | 2 | superadmin |
12
+ | 3 | user |
13
13
 
14
14
  And the following users exist:
15
- | first_name | last_name | role__name |
16
- | Paul | Bley | admin |
17
- | Dalai | Lama | user |
18
- | Taisha | Abelar | superadmin |
19
- | Florinda | Donner | admin |
15
+ | first_name | last_name | role_id |
16
+ | Paul | Bley | 1 |
17
+ | Dalai | Lama | 3 |
18
+ | Taisha | Abelar | 2 |
19
+ | Florinda | Donner | 1 |
20
20
 
21
21
  When I go to the UserGrid test page
22
22
  Then the grid should show 4 records
@@ -0,0 +1,10 @@
1
+ Feature: Basic application
2
+ In order to value
3
+ As a role
4
+ I want feature
5
+
6
+ @javascript
7
+ Scenario: SimpleApp should load its components dynamically
8
+ Given I am on the SomeSimpleApp test page
9
+ When I press "Simple accordion"
10
+ Then I should see "Some simple app simple accordion"
@@ -24,3 +24,26 @@ Then /^the grid should show (\d+) records$/ do |arg1|
24
24
  return grid.getStore().getCount();
25
25
  JS
26
26
  end
27
+
28
+ When /^I edit row (\d+) of the grid with #{capture_fields}$/ do |rowIndex, fields|
29
+ fields = ActiveSupport::JSON.decode("{#{fields}}")
30
+ js_set_fields = fields.each_pair.map do |k,v|
31
+ "r.set('#{k}', '#{v}');"
32
+ end.join
33
+ page.driver.browser.execute_script <<-JS
34
+ var components = [];
35
+ for (var cmp in Netzke.page) { components.push(cmp); }
36
+ var grid = Netzke.page[components[0]];
37
+ var r = grid.getStore().getAt(#{rowIndex.to_i-1});
38
+ #{js_set_fields}
39
+ JS
40
+ end
41
+
42
+ Then /^the grid should have (\d+) modified records$/ do |n|
43
+ page.driver.browser.execute_script(<<-JS).should == n.to_i
44
+ var components = [];
45
+ for (var cmp in Netzke.page) { components.push(cmp); }
46
+ var grid = Netzke.page[components[0]];
47
+ return grid.getStore().getModifiedRecords().length;
48
+ JS
49
+ end
@@ -40,9 +40,15 @@ module NavigationHelpers
40
40
  when /the component loader page/
41
41
  '/panel/component_loader'
42
42
 
43
+ when /the "(.*)" view/
44
+ embedded_components_path(:action => $1.gsub(" ", "_"))
45
+
43
46
  when /the (.*) test page/
44
47
  components_path(:component => $1)
45
48
 
49
+ when /the "(.+)" version of the (.*) page/
50
+ components_path(:component => $2, :locale => $1)
51
+
46
52
  else
47
53
  begin
48
54
  page_name =~ /the (.*) page/
@@ -22,4 +22,3 @@ require 'pickle/world'
22
22
  # config.adapters = [:machinist]
23
23
  # config.map 'I', 'myself', 'me', 'my', :to => 'user: "me"'
24
24
  # end
25
- require 'pickle/path/world'
@@ -0,0 +1,20 @@
1
+ Feature: Window component loader
2
+ In order to value
3
+ As a role
4
+ I want feature
5
+
6
+ @javascript
7
+ Scenario: Columns and fields with custom setter/getter methods should work as expected
8
+ Given an author exists with first_name: "Victor"
9
+ And a book exists with title: "Lolita", exemplars: "5", author: that author
10
+ And I am on the BookGridWithVirtualAttributes test page
11
+ Then I should see "Victor"
12
+ And I should see "YES"
13
+
14
+ When I select first row in the grid
15
+ And I press "Edit in form"
16
+ And I fill in "Author first name" with "Vladimir"
17
+ And I fill in "Exemplars" with "3"
18
+ And I press "OK"
19
+ Then I should see "Vladimir"
20
+ And I should see "NO"
@@ -1,4 +1,5 @@
1
1
  Ext.ns("Netzke.pre");
2
+ Ext.ns("Netzke.pre.Basepack");
2
3
  Ext.ns("Ext.ux.grid");
3
4
 
4
5
  Ext.apply(Ext.History, new Ext.util.Observable());
@@ -38,12 +39,12 @@ Ext.netzke.ComboBox = Ext.extend(Ext.form.ComboBox, {
38
39
  });
39
40
 
40
41
  var parent = Ext.getCmp(this.parentId);
41
- // Is parent a grid?
42
- if (parent.getSelectionModel) {
43
- this.on('beforequery',function(qe) {
44
- delete qe.combo.lastQuery;
45
- },this);
46
- }
42
+ // Is parent a grid?
43
+ if (parent.getSelectionModel) {
44
+ this.on('beforequery',function(qe) {
45
+ delete qe.combo.lastQuery;
46
+ },this);
47
+ }
47
48
 
48
49
  // A not-so-clean approach to submit the current record id
49
50
  store.on('beforeload',function(store, options){
@@ -53,7 +54,7 @@ Ext.netzke.ComboBox = Ext.extend(Ext.form.ComboBox, {
53
54
  } else {
54
55
  // TODO: also for the FormPanel
55
56
  }
56
- },this)
57
+ }, this);
57
58
  }
58
59
  });
59
60
 
@@ -63,65 +64,6 @@ Ext.util.Format.mask = function(v){
63
64
  return "********";
64
65
  };
65
66
 
66
- // Implementation of totalProperty, successProperty and root configuration options for ArrayReader
67
- Ext.data.ArrayReader = Ext.extend(Ext.data.JsonReader, {
68
- readRecords : function(o){
69
- var sid = this.meta ? this.meta.id : null;
70
- var recordType = this.recordType, fields = recordType.prototype.fields;
71
- var records = [];
72
- var root = o[this.meta.root] || o, totalRecords = o[this.meta.totalProperty], success = o[this.meta.successProperty];
73
- for(var i = 0; i < root.length; i++){
74
- var n = root[i];
75
- var values = {};
76
- var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
77
- for(var j = 0, jlen = fields.length; j < jlen; j++){
78
- var f = fields.items[j];
79
- var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
80
- var v = n[k] !== undefined ? n[k] : f.defaultValue;
81
- v = f.convert(v, n);
82
- values[f.name] = v;
83
- }
84
- var record = new recordType(values, id);
85
- record.json = n;
86
- records[records.length] = record;
87
- }
88
- return {
89
- records : records,
90
- totalRecords : totalRecords,
91
- success : success
92
- };
93
- }
94
- });
95
-
96
-
97
- Ext.data.RecordArrayReader = Ext.extend(Ext.data.JsonReader, {
98
- /**
99
- * Create a data block containing Ext.data.Records from an Array.
100
- * @param {Object} o An Array of row objects which represents the dataset.
101
- * @return {Object} data A data block which is used by an Ext.data.Store object as
102
- * a cache of Ext.data.Records.
103
- */
104
- readRecord : function(o){
105
- var sid = this.meta ? this.meta.id : null;
106
- var recordType = this.recordType, fields = recordType.prototype.fields;
107
- var records = [];
108
- var root = o;
109
- var n = root;
110
- var values = {};
111
- var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
112
- for(var j = 0, jlen = fields.length; j < jlen; j++){
113
- var f = fields.items[j];
114
- var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
115
- var v = n[k] !== undefined ? n[k] : f.defaultValue;
116
- v = f.convert(v, n);
117
- values[f.name] = v;
118
- }
119
- var record = new recordType(values, id);
120
- record.json = n;
121
- return record;
122
- }
123
- });
124
-
125
67
  Ext.netzke.JsonField = Ext.extend(Ext.form.TextField, {
126
68
  validator: function(value) {
127
69
  try{
@@ -794,185 +736,166 @@ Ext.grid.HeaderDropZone.prototype.onNodeDrop = function(n, dd, e, data){
794
736
  return false;
795
737
  };
796
738
 
797
- // Temporary fix for Ext 3.1 resize problem:
798
- Ext.override(Ext.Panel, {
799
-
800
- // private
801
- onResize : function(w, h, rw, rh){
802
- if(Ext.isDefined(w) || Ext.isDefined(h)){
803
- if(!this.collapsed){
804
- // First, set the the Panel's body width.
805
- // If we have auto-widthed it, get the resulting full offset width so we can size the Toolbars to match
806
- // The Toolbars must not buffer this resize operation because we need to know their heights.
807
-
808
- if(Ext.isNumber(w)){
809
- this.body.setWidth(w = this.adjustBodyWidth(w - this.getFrameWidth()));
810
- } else if (w == 'auto') {
811
- w = this.body.setWidth('auto').dom.offsetWidth;
812
- } else {
813
- w = this.body.dom.offsetWidth;
814
- }
739
+ Ext.ns('Ext.ux.form');
740
+ Ext.ux.form.TriCheckbox = Ext.extend(Ext.form.Checkbox, {
741
+ checked: null,
742
+ valueList: [null, false, true],
743
+ stateClassList: ['x-checkbox-undef', null, 'x-checkbox-checked'],
744
+ overClass: 'x-form-check-over',
745
+ clickClass: 'x-form-check-down',
746
+ triState: true,
747
+ defaultAutoCreate: {tag: 'input', type: 'hidden', autocomplete: 'off'},
748
+ initComponent: function() {
749
+ this.value = this.checked;
750
+ Ext.ux.form.TriCheckbox.superclass.initComponent.apply(this, arguments);
751
+ // make a copy before modifying valueList and stateClassList arrays
752
+ this.vList = this.valueList.slice(0);
753
+ this.cList = this.stateClassList.slice(0);
754
+ if(this.triState !== true) {
755
+ // consider 'undefined' value and its class go first in arrays
756
+ this.vList.shift();
757
+ this.cList.shift();
758
+ }
759
+ if(this.overCls !== undefined) {
760
+ this.overClass = this.overCls;
761
+ delete this.overCls;
762
+ }
763
+ this.value = this.normalizeValue(this.value);
764
+ },
765
+ onRender : function(ct, position){
766
+ Ext.form.Checkbox.superclass.onRender.call(this, ct, position);
767
+
768
+ this.innerWrap = this.el.wrap({tag: 'span', cls: 'x-form-check-innerwrap'});
769
+ this.wrap = this.innerWrap.wrap({cls: 'x-form-check-wrap'});
770
+
771
+ this.currCls = this.getCls(this.value);
772
+ this.wrap.addClass(this.currCls);
773
+ if(this.clickClass && !this.disabled && !this.readOnly)
774
+ this.innerWrap.addClassOnClick(this.clickClass);
775
+ if(this.overClass && !this.disabled && !this.readOnly)
776
+ this.innerWrap.addClassOnOver(this.overClass);
777
+
778
+ this.imageEl = this.innerWrap.createChild({
779
+ tag: 'img',
780
+ src: Ext.BLANK_IMAGE_URL,
781
+ cls: 'x-form-tscheckbox'
782
+ }, this.el);
783
+ if(this.fieldClass) this.imageEl.addClass(this.fieldClass);
784
+
785
+ if(this.boxLabel){
786
+ this.innerWrap.createChild({
787
+ tag: 'label',
788
+ htmlFor: this.el.id,
789
+ cls: 'x-form-cb-label',
790
+ html: this.boxLabel
791
+ });
792
+ }
815
793
 
816
- if(this.tbar){
817
- this.tbar.setWidth(w);
818
- if(this.topToolbar){
819
- this.topToolbar.setSize(w);
820
- }
821
- }
822
- if(this.bbar){
823
- this.bbar.setWidth(w);
824
- if(this.bottomToolbar){
825
- this.bottomToolbar.setSize(w);
826
- // The bbar does not move on resize without this.
827
- if (Ext.isIE) {
828
- this.bbar.setStyle('position', 'static');
829
- this.bbar.setStyle('position', '');
830
- }
831
- }
832
- }
833
- if(this.footer){
834
- this.footer.setWidth(w);
835
- if(this.fbar){
836
- this.fbar.setSize(Ext.isIE ? (w - this.footer.getFrameWidth('lr')) : 'auto');
837
- }
838
- }
794
+ // Need to repaint for IE, otherwise positioning is broken
795
+ if(Ext.isIE){
796
+ this.wrap.repaint();
797
+ }
798
+ this.resizeEl = this.positionEl = this.wrap;
799
+ },
800
+ onResize : function(){
801
+ Ext.form.Checkbox.superclass.onResize.apply(this, arguments);
802
+ if(!this.boxLabel && !this.fieldLabel && this.imageEl){
803
+ this.imageEl.alignTo(this.wrap, 'c-c');
804
+ }
805
+ },
806
+ initEvents : function(){
807
+ Ext.form.Checkbox.superclass.initEvents.call(this);
808
+ this.mon(this.innerWrap, {
809
+ scope: this,
810
+ click: this.onClick
811
+ });
812
+ },
813
+ onClick : function(){
814
+ if (!this.disabled && !this.readOnly) {
815
+ this.setValue(this.vList[(this.vList.indexOf(this.value) + 1) % this.vList.length]);
816
+ }
817
+ },
818
+ getValue : function(){
819
+ return this.value;
820
+ },
821
+ setValue : function(v){
822
+ var value = this.value;
823
+ this.value = this.normalizeValue(v);
824
+ if(this.rendered) this.el.dom.value = this.value;
825
+
826
+ if(value !== this.value){
827
+ this.updateView();
828
+ this.fireEvent('check', this, this.value);
829
+ if(this.handler) this.handler.call(this.scope || this, this, this.value);
830
+ }
831
+ return this;
832
+ },
833
+ normalizeValue: function(v) {
834
+ return (v === null || v === undefined) && this.triState ? null :
835
+ (v === true || (['true', 'yes', 'on', '1']).indexOf(String(v).toLowerCase()) != -1);
836
+ },
837
+ getCls: function(v) {
838
+ var idx = this.vList.indexOf(this.value);
839
+ return idx > -1 ? this.cList[idx] : undefined;
840
+ },
841
+ updateView: function() {
842
+ var cls = this.getCls(this.value);
843
+ if (!this.wrap || cls === undefined) return;
844
+
845
+ this.wrap.replaceClass(this.currCls, cls);
846
+ this.currCls = cls;
847
+ }
848
+ });
849
+ Ext.reg('tricheckbox', Ext.ux.form.TriCheckbox);
839
850
 
840
- // At this point, the Toolbars must be layed out for getFrameHeight to find a result.
841
- if(Ext.isNumber(h)){
842
- h = Math.max(0, this.adjustBodyHeight(h - this.getFrameHeight()));
843
- this.body.setHeight(h);
844
- }else if(h == 'auto'){
845
- this.body.setHeight(h);
846
- }
847
851
 
848
- if(this.disabled && this.el._mask){
849
- this.el._mask.setSize(this.el.dom.clientWidth, this.el.getHeight());
850
- }
851
- }else{
852
- this.queuedBodySize = {width: w, height: h};
853
- if(!this.queuedExpand && this.allowQueuedExpand !== false){
854
- this.queuedExpand = true;
855
- this.on('expand', function(){
856
- delete this.queuedExpand;
857
- this.onResize(this.queuedBodySize.width, this.queuedBodySize.height);
858
- }, this, {single:true});
859
- }
860
- }
861
- this.onBodyResize(w, h);
852
+ // Enabling checkbox submission when unchecked
853
+ (function() {
854
+ origCheckboxRender = Ext.form.Checkbox.prototype.onRender;
855
+ origCheckboxSetValue = Ext.form.Checkbox.prototype.setValue;
856
+
857
+ Ext.override(Ext.form.Checkbox, {
858
+ onRender: function() {
859
+ // call the original onRender() function
860
+ origCheckboxRender.apply(this, arguments);
861
+
862
+ if (this.getXType() === 'radio') return;
863
+
864
+ // Handle initial case based on this.checked
865
+ if (this.checked == false) {
866
+ this.noValEl = Ext.DomHelper.insertAfter(this.el, {
867
+ tag: 'input',
868
+ type: 'hidden',
869
+ value: false,
870
+ name: this.getName()
871
+ }, true);
872
+ }
873
+ else {
874
+ this.noValEl = null;
875
+ }
876
+ },
877
+ setValue: function() {
878
+ // call original setValue() function
879
+ origCheckboxSetValue.apply(this, arguments);
880
+
881
+ if (this.getXType() === 'radio') return;
882
+
883
+ if (this.checked) {
884
+ if (this.noValEl != null) {
885
+ // Remove the extra hidden element
886
+ this.noValEl.remove();
887
+ this.noValEl = null;
862
888
  }
863
- this.syncShadow();
864
- Ext.Panel.superclass.onResize.call(this, w, h, rw, rh);
889
+ }
890
+ else {
891
+ // Add our hidden element for (unchecked) value
892
+ if (this.noValEl == null) this.noValEl = Ext.DomHelper.insertAfter(this.el, {
893
+ tag: 'input',
894
+ type: 'hidden',
895
+ value: false,
896
+ name: this.getName()
897
+ }, true);
898
+ }
865
899
  }
866
- });
867
-
868
- Ext.ns('Ext.ux.form');
869
- Ext.ux.form.TriCheckbox = Ext.extend(Ext.form.Checkbox, {
870
- checked: null,
871
- valueList: [null, false, true],
872
- stateClassList: ['x-checkbox-undef', null, 'x-checkbox-checked'],
873
- overClass: 'x-form-check-over',
874
- clickClass: 'x-form-check-down',
875
- triState: true,
876
- defaultAutoCreate: {tag: 'input', type: 'hidden', autocomplete: 'off'},
877
- initComponent: function() {
878
- this.value = this.checked;
879
- Ext.ux.form.TriCheckbox.superclass.initComponent.apply(this, arguments);
880
- // make a copy before modifying valueList and stateClassList arrays
881
- this.vList = this.valueList.slice(0);
882
- this.cList = this.stateClassList.slice(0);
883
- if(this.triState !== true) {
884
- // consider 'undefined' value and its class go first in arrays
885
- this.vList.shift();
886
- this.cList.shift();
887
- }
888
- if(this.overCls !== undefined) {
889
- this.overClass = this.overCls;
890
- delete this.overCls;
891
- }
892
- this.value = this.normalizeValue(this.value);
893
- },
894
- onRender : function(ct, position){
895
- Ext.form.Checkbox.superclass.onRender.call(this, ct, position);
896
-
897
- this.innerWrap = this.el.wrap({tag: 'span', cls: 'x-form-check-innerwrap'});
898
- this.wrap = this.innerWrap.wrap({cls: 'x-form-check-wrap'});
899
-
900
- this.currCls = this.getCls(this.value);
901
- this.wrap.addClass(this.currCls);
902
- if(this.clickClass && !this.disabled && !this.readOnly)
903
- this.innerWrap.addClassOnClick(this.clickClass);
904
- if(this.overClass && !this.disabled && !this.readOnly)
905
- this.innerWrap.addClassOnOver(this.overClass);
906
-
907
- this.imageEl = this.innerWrap.createChild({
908
- tag: 'img',
909
- src: Ext.BLANK_IMAGE_URL,
910
- cls: 'x-form-tscheckbox'
911
- }, this.el);
912
- if(this.fieldClass) this.imageEl.addClass(this.fieldClass);
913
-
914
- if(this.boxLabel){
915
- this.innerWrap.createChild({
916
- tag: 'label',
917
- htmlFor: this.el.id,
918
- cls: 'x-form-cb-label',
919
- html: this.boxLabel
920
- });
921
- }
922
-
923
- // Need to repaint for IE, otherwise positioning is broken
924
- if(Ext.isIE){
925
- this.wrap.repaint();
926
- }
927
- this.resizeEl = this.positionEl = this.wrap;
928
- },
929
- onResize : function(){
930
- Ext.form.Checkbox.superclass.onResize.apply(this, arguments);
931
- if(!this.boxLabel && !this.fieldLabel && this.imageEl){
932
- this.imageEl.alignTo(this.wrap, 'c-c');
933
- }
934
- },
935
- initEvents : function(){
936
- Ext.form.Checkbox.superclass.initEvents.call(this);
937
- this.mon(this.innerWrap, {
938
- scope: this,
939
- click: this.onClick
940
- });
941
- },
942
- onClick : function(){
943
- if (!this.disabled && !this.readOnly) {
944
- this.setValue(this.vList[(this.vList.indexOf(this.value) + 1) % this.vList.length]);
945
- }
946
- },
947
- getValue : function(){
948
- return this.value;
949
- },
950
- setValue : function(v){
951
- var value = this.value;
952
- this.value = this.normalizeValue(v);
953
- if(this.rendered) this.el.dom.value = this.value;
954
-
955
- if(value !== this.value){
956
- this.updateView();
957
- this.fireEvent('check', this, this.value);
958
- if(this.handler) this.handler.call(this.scope || this, this, this.value);
959
- }
960
- return this;
961
- },
962
- normalizeValue: function(v) {
963
- return (v === null || v === undefined) && this.triState ? null :
964
- (v === true || (['true', 'yes', 'on', '1']).indexOf(String(v).toLowerCase()) != -1);
965
- },
966
- getCls: function(v) {
967
- var idx = this.vList.indexOf(this.value);
968
- return idx > -1 ? this.cList[idx] : undefined;
969
- },
970
- updateView: function() {
971
- var cls = this.getCls(this.value);
972
- if (!this.wrap || cls === undefined) return;
973
-
974
- this.wrap.replaceClass(this.currCls, cls);
975
- this.currCls = cls;
976
- }
977
- });
978
- Ext.reg('tricheckbox', Ext.ux.form.TriCheckbox);
900
+ });
901
+ })();