netzke-basepack 0.6.2 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.rdoc +27 -2
- data/TODO.rdoc +1 -5
- data/app/models/netzke_persistent_array_auto_model.rb +0 -1
- data/features/components_in_view.feature +11 -0
- data/features/form_panel.feature +49 -0
- data/features/grid_panel.feature +32 -1
- data/features/i18n.feature +18 -0
- data/features/nested_attributes.feature +23 -0
- data/features/search_in_grid.feature +9 -9
- data/features/simple_app.feature +10 -0
- data/features/step_definitions/grid_panel_steps.rb +23 -0
- data/features/support/paths.rb +6 -0
- data/features/support/pickle.rb +0 -1
- data/features/virtual_attributes.feature +20 -0
- data/javascripts/basepack.js +166 -243
- data/lib/netzke-basepack.rb +3 -3
- data/lib/netzke/active_record.rb +6 -7
- data/lib/netzke/active_record/attributes.rb +214 -143
- data/lib/netzke/active_record/combobox_options.rb +12 -10
- data/lib/netzke/basepack.rb +6 -3
- data/lib/netzke/basepack/accordion_panel.rb +4 -2
- data/lib/netzke/basepack/auth_app.rb +152 -0
- data/lib/netzke/basepack/basic_app.rb +2 -262
- data/lib/netzke/basepack/form_panel.rb +35 -27
- data/lib/netzke/basepack/form_panel/fields.rb +35 -17
- data/lib/netzke/basepack/form_panel/javascripts/comma_list_cbg.js +59 -0
- data/lib/netzke/basepack/form_panel/javascripts/display_mode.js +62 -0
- data/lib/netzke/basepack/form_panel/javascripts/main.js +138 -0
- data/lib/netzke/basepack/form_panel/javascripts/n_radio_group.js +25 -0
- data/lib/netzke/basepack/form_panel/services.rb +12 -9
- data/lib/netzke/basepack/grid_panel.rb +87 -53
- data/lib/netzke/basepack/grid_panel/columns.rb +60 -15
- data/lib/netzke/basepack/grid_panel/javascripts/advanced_search.js +2 -64
- data/lib/netzke/basepack/grid_panel/javascripts/edit_in_form.js +2 -2
- data/lib/netzke/basepack/grid_panel/javascripts/{pre.js → main.js} +35 -17
- data/lib/netzke/basepack/grid_panel/javascripts/misc.js +4 -0
- data/lib/netzke/basepack/grid_panel/services.rb +17 -14
- data/lib/netzke/basepack/paging_form_panel.rb +92 -0
- data/lib/netzke/basepack/simple_app.rb +71 -0
- data/lib/netzke/basepack/simple_app/javascripts/main.js +53 -0
- data/lib/netzke/basepack/{basic_app → simple_app/javascripts}/statusbar_ext.js +0 -0
- data/lib/netzke/basepack/tab_panel.rb +2 -12
- data/lib/netzke/basepack/tab_panel/javascripts/main.js +11 -0
- data/lib/netzke/basepack/version.rb +2 -2
- data/lib/netzke/basepack/window.rb +6 -7
- data/lib/netzke/basepack/wrap_lazy_loaded.rb +3 -1
- data/lib/netzke/data_accessor.rb +25 -14
- data/lib/netzke/ext.rb +1 -1
- data/locales/en.yml +22 -0
- data/netzke-basepack.gemspec +66 -12
- data/spec/active_record/attributes_spec.rb +31 -2
- data/spec/factories.rb +16 -1
- data/test/rails_app/Gemfile +2 -2
- data/test/rails_app/Gemfile.lock +76 -77
- data/test/rails_app/app/components/author_grid.rb +7 -0
- data/test/rails_app/app/components/book_form.rb +24 -0
- data/test/rails_app/app/components/book_grid.rb +6 -1
- data/test/rails_app/app/components/book_grid_with_default_values.rb +11 -0
- data/test/rails_app/app/components/book_grid_with_nested_attributes.rb +13 -0
- data/test/rails_app/app/components/book_grid_with_virtual_attributes.rb +22 -0
- data/test/rails_app/app/components/book_paging_form_panel.rb +20 -0
- data/test/rails_app/app/components/book_presentation.rb +18 -0
- data/test/rails_app/app/components/books_bound_to_author.rb +10 -0
- data/test/rails_app/app/components/form_without_model.rb +19 -0
- data/test/rails_app/app/components/lockable_book_form.rb +17 -0
- data/test/rails_app/app/components/lockable_user_form.rb +7 -0
- data/test/rails_app/app/components/simple_window.rb +10 -0
- data/test/rails_app/app/components/some_accordion_panel.rb +22 -0
- data/test/rails_app/app/components/{simple_basic_app.rb → some_auth_app.rb} +3 -3
- data/test/rails_app/app/components/some_border_layout.rb +10 -7
- data/test/rails_app/app/components/some_simple_app.rb +34 -0
- data/test/rails_app/app/components/some_tab_panel.rb +16 -11
- data/test/rails_app/app/components/user_form.rb +11 -4
- data/test/rails_app/app/components/user_grid.rb +7 -1
- data/test/rails_app/app/components/window_component_loader.rb +1 -0
- data/test/rails_app/app/controllers/application_controller.rb +6 -0
- data/test/rails_app/app/controllers/components_controller.rb +3 -3
- data/test/rails_app/app/controllers/welcome_controller.rb +2 -2
- data/test/rails_app/app/helpers/embedded_components_helper.rb +2 -0
- data/test/rails_app/app/models/address.rb +3 -0
- data/test/rails_app/app/models/author.rb +2 -0
- data/test/rails_app/app/models/book.rb +1 -0
- data/test/rails_app/app/models/user.rb +1 -2
- data/test/rails_app/app/views/components/simple_panel.html.erb +1 -0
- data/test/rails_app/app/views/layouts/nested.html.erb +5 -0
- data/test/rails_app/config/application.rb +1 -1
- data/test/rails_app/config/initializers/netzke.rb +0 -4
- data/test/rails_app/config/locales/es.yml +16 -0
- data/test/rails_app/config/routes.rb +4 -1
- data/test/rails_app/db/development_structure.sql +33 -4
- data/test/rails_app/db/migrate/20101026190021_create_books.rb +2 -0
- data/test/rails_app/db/migrate/20110101143818_create_addresses.rb +17 -0
- data/test/rails_app/db/schema.rb +33 -1
- data/test/rails_app/spec/controllers/embedded_components_controller_spec.rb +12 -0
- data/test/rails_app/spec/helpers/embedded_components_helper_spec.rb +15 -0
- data/test/rails_app/spec/models/address_spec.rb +5 -0
- data/test/rails_app/spec/views/embedded_components/index.html.erb_spec.rb +5 -0
- metadata +67 -13
- data/features/basic_app.feature +0 -12
- data/lib/netzke/active_record/association_attributes.rb +0 -102
- data/lib/netzke/basepack/form_panel/javascripts/pre.js +0 -76
- data/lib/netzke/basepack/form_panel/javascripts/xcheckbox.js +0 -82
- data/lib/netzke/basepack/grid_panel/javascript.rb +0 -69
- 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
|
-
*
|
|
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"
|
data/features/form_panel.feature
CHANGED
|
@@ -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"
|
data/features/grid_panel.feature
CHANGED
|
@@ -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
|
|
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
|
-
|
|
|
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 |
|
|
16
|
-
| Paul
|
|
17
|
-
| Dalai
|
|
18
|
-
| Taisha
|
|
19
|
-
| Florinda
|
|
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
|
data/features/support/paths.rb
CHANGED
|
@@ -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/
|
data/features/support/pickle.rb
CHANGED
|
@@ -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"
|
data/javascripts/basepack.js
CHANGED
|
@@ -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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
798
|
-
Ext.
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
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
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
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
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
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
|
-
|
|
864
|
-
|
|
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
|
+
})();
|