netzke-basepack 0.7.7 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +15 -10
- data/{CHANGELOG.rdoc → CHANGELOG.md} +146 -110
- data/LICENSE +7 -1
- data/README.md +47 -56
- data/Rakefile +5 -5
- data/config/before-travis.sh +10 -0
- data/javascripts/basepack.js +0 -130
- data/javascripts/netzkeremotecombo.js +59 -0
- data/lib/netzke/basepack.rb +9 -14
- data/lib/netzke/basepack/accordion.rb +45 -0
- data/lib/netzke/basepack/active_record.rb +12 -0
- data/lib/netzke/basepack/active_record/relation_extensions.rb +27 -0
- data/lib/netzke/basepack/columns.rb +309 -0
- data/lib/netzke/basepack/data_accessor.rb +22 -12
- data/lib/netzke/basepack/data_adapters/abstract_adapter.rb +75 -11
- data/lib/netzke/basepack/data_adapters/active_record_adapter.rb +154 -49
- data/lib/netzke/basepack/fields.rb +162 -0
- data/lib/netzke/basepack/form.rb +136 -0
- data/lib/netzke/basepack/{form_panel → form}/javascripts/comma_list_cbg.js +0 -1
- data/lib/netzke/basepack/{form_panel/javascripts/form_panel.js → form/javascripts/form.js} +20 -26
- data/lib/netzke/basepack/{form_panel → form}/javascripts/n_radio_group.js +0 -1
- data/lib/netzke/basepack/{form_panel → form}/javascripts/readonly_mode.js +0 -0
- data/lib/netzke/basepack/form/services.rb +115 -0
- data/lib/netzke/basepack/{form_panel → form}/stylesheets/readonly_mode.css +0 -0
- data/lib/netzke/basepack/grid.rb +355 -0
- data/lib/netzke/basepack/{grid_panel → grid}/javascripts/advanced_search.js +1 -1
- data/lib/netzke/basepack/{grid_panel → grid}/javascripts/check_column_fix.js +0 -0
- data/lib/netzke/basepack/{grid_panel → grid}/javascripts/edit_in_form.js +3 -3
- data/lib/netzke/basepack/{grid_panel → grid}/javascripts/event_handling.js +5 -2
- data/lib/netzke/basepack/{grid_panel/javascripts/grid_panel.js → grid/javascripts/grid.js} +120 -132
- data/lib/netzke/basepack/{grid_panel → grid}/javascripts/misc.js +0 -0
- data/lib/netzke/basepack/grid/services.rb +216 -0
- data/lib/netzke/basepack/item_persistence.rb +44 -0
- data/lib/netzke/basepack/item_persistence/events_plugin.rb +47 -0
- data/lib/netzke/basepack/{paging_form_panel.rb → paging_form.rb} +24 -30
- data/lib/netzke/basepack/{paging_form_panel/javascripts/paging_form_panel.js → paging_form/javascripts/paging_form.js} +2 -4
- data/lib/netzke/basepack/query_builder.rb +44 -73
- data/lib/netzke/basepack/query_builder/javascripts/query_builder.js +16 -2
- data/lib/netzke/basepack/record_form_window.rb +67 -0
- data/lib/netzke/basepack/search_panel.rb +22 -24
- data/lib/netzke/basepack/search_panel/javascripts/condition_field.js +2 -2
- data/lib/netzke/basepack/search_window.rb +47 -53
- data/lib/netzke/basepack/simple_app.rb +10 -13
- data/lib/netzke/basepack/simple_app/javascripts/simple_app.js +2 -8
- data/lib/netzke/basepack/tab_panel.rb +5 -4
- data/lib/netzke/basepack/tab_panel/javascripts/tab_panel.js +5 -5
- data/lib/netzke/basepack/version.rb +2 -2
- data/lib/netzke/basepack/viewport.rb +16 -0
- data/lib/netzke/basepack/window.rb +27 -18
- data/lib/netzke/basepack/window/javascripts/window.js +7 -1
- data/lib/netzke/basepack/wrap_lazy_loaded.rb +18 -18
- data/locales/en.yml +40 -24
- data/netzke-basepack.gemspec +51 -82
- data/stylesheets/basepack.css +0 -41
- data/test/basepack_test_app/Gemfile +9 -46
- data/test/basepack_test_app/Gemfile.lock +61 -96
- data/test/basepack_test_app/app/components/author_form.rb +8 -5
- data/test/basepack_test_app/app/components/author_grid.rb +2 -2
- data/test/basepack_test_app/app/components/book_form.rb +34 -31
- data/test/basepack_test_app/app/components/book_form_with_defaults.rb +6 -7
- data/test/basepack_test_app/app/components/book_form_with_file_upload.rb +10 -0
- data/test/basepack_test_app/app/components/book_form_with_nested_attributes.rb +5 -6
- data/test/basepack_test_app/app/components/book_grid.rb +19 -8
- data/test/basepack_test_app/app/components/book_grid_filtering.rb +4 -7
- data/test/basepack_test_app/app/components/book_grid_loader.rb +28 -15
- data/test/basepack_test_app/app/components/book_grid_with_custom_columns.rb +45 -21
- data/test/basepack_test_app/app/components/book_grid_with_default_values.rb +26 -8
- data/test/basepack_test_app/app/components/book_grid_with_excluded_columns.rb +11 -0
- data/test/basepack_test_app/app/components/book_grid_with_extra_feedback.rb +2 -2
- data/test/basepack_test_app/app/components/book_grid_with_extra_filters.rb +7 -6
- data/test/basepack_test_app/app/components/book_grid_with_mass_assignment_security.rb +9 -0
- data/test/basepack_test_app/app/components/book_grid_with_nested_attributes.rb +9 -9
- data/test/basepack_test_app/app/components/book_grid_with_overridden_columns.rb +5 -3
- data/test/basepack_test_app/app/components/book_grid_with_paging.rb +6 -8
- data/test/basepack_test_app/app/components/book_grid_with_persistence.rb +6 -4
- data/test/basepack_test_app/app/components/book_grid_with_scope.rb +6 -0
- data/test/basepack_test_app/app/components/book_grid_with_scoped_authors.rb +10 -7
- data/test/basepack_test_app/app/components/book_grid_with_virtual_attributes.rb +21 -13
- data/test/basepack_test_app/app/components/book_paging_form.rb +21 -0
- data/test/basepack_test_app/app/components/book_query_builder.rb +7 -6
- data/test/basepack_test_app/app/components/book_with_custom_primary_key_grid.rb +6 -7
- data/test/basepack_test_app/app/components/books_bound_to_author.rb +9 -7
- data/test/basepack_test_app/app/components/border_layout_panel_with_persistence.rb +12 -0
- data/test/basepack_test_app/app/components/double_book_grid.rb +19 -14
- data/test/basepack_test_app/app/components/form_without_model.rb +15 -16
- data/test/basepack_test_app/app/components/grid_with_initial_sorting.rb +7 -0
- data/test/basepack_test_app/app/components/grid_with_inline_data.rb +7 -0
- data/test/basepack_test_app/app/components/paging_form_with_search.rb +2 -2
- data/test/basepack_test_app/app/components/panel_with_persistent_regions.rb +35 -0
- data/test/basepack_test_app/app/components/query_builder.rb +7 -0
- data/test/basepack_test_app/app/components/simple_panel.rb +16 -11
- data/test/basepack_test_app/app/components/simple_window.rb +7 -6
- data/test/basepack_test_app/app/components/some_accordion.rb +18 -0
- data/test/basepack_test_app/app/components/some_auth_app.rb +5 -5
- data/test/basepack_test_app/app/components/some_border_layout.rb +20 -20
- data/test/basepack_test_app/app/components/some_search_panel.rb +6 -0
- data/test/basepack_test_app/app/components/some_simple_app.rb +30 -16
- data/test/basepack_test_app/app/components/some_tab_panel.rb +18 -15
- data/test/basepack_test_app/app/components/user_form.rb +18 -16
- data/test/basepack_test_app/app/components/user_form_with_default_fields.rb +5 -6
- data/test/basepack_test_app/app/components/user_grid.rb +11 -6
- data/test/basepack_test_app/app/components/user_grid_with_customized_form_fields.rb +5 -3
- data/test/basepack_test_app/app/components/window_component_loader.rb +25 -21
- data/test/basepack_test_app/app/models/address.rb +0 -26
- data/test/basepack_test_app/app/models/author.rb +0 -31
- data/test/basepack_test_app/app/models/book.rb +1 -42
- data/test/basepack_test_app/app/models/book_with_custom_primary_key.rb +1 -23
- data/test/basepack_test_app/app/models/role.rb +0 -21
- data/test/basepack_test_app/app/models/user.rb +0 -24
- data/test/basepack_test_app/app/views/layouts/components.html.erb +1 -1
- data/test/basepack_test_app/config/application.rb +1 -1
- data/test/basepack_test_app/config/database.yml.travis +2 -6
- data/test/basepack_test_app/config/initializers/netzke.rb +1 -6
- data/test/basepack_test_app/db/schema.rb +14 -14
- data/test/basepack_test_app/features/accordion_panel.feature +2 -2
- data/test/basepack_test_app/features/form_panel.feature +7 -7
- data/test/basepack_test_app/features/grid_panel.feature +93 -39
- data/test/basepack_test_app/features/grid_panel_with_custom_primary_key.feature +2 -1
- data/test/basepack_test_app/features/grid_sorting.feature +30 -6
- data/test/basepack_test_app/features/paging_form_panel.feature +7 -7
- data/test/basepack_test_app/features/persistent_regions.feature +30 -0
- data/test/basepack_test_app/features/search_in_grid.feature +5 -5
- data/test/basepack_test_app/features/simple_app.feature +6 -7
- data/test/basepack_test_app/features/step_definitions/form_panel_steps.rb +1 -1
- data/test/basepack_test_app/features/step_definitions/generic_steps.rb +109 -4
- data/test/basepack_test_app/features/step_definitions/grid_panel_steps.rb +8 -10
- data/test/basepack_test_app/features/step_definitions/window_steps.rb +27 -0
- data/test/basepack_test_app/features/tab_panel.feature +1 -1
- data/test/basepack_test_app/features/window.feature +17 -0
- data/test/unit/accordion_panel_test.rb +2 -2
- data/test/unit/grid_panel_test.rb +4 -4
- metadata +57 -83
- data/TODO.rdoc +0 -8
- data/lib/generators/netzke/basepack_generator.rb +0 -10
- data/lib/generators/netzke/templates/assets/ts-checkbox.gif +0 -0
- data/lib/generators/netzke/templates/create_netzke_field_lists.rb +0 -18
- data/lib/netzke/active_record.rb +0 -20
- data/lib/netzke/active_record/attributes.rb +0 -259
- data/lib/netzke/active_record/combobox_options.rb +0 -16
- data/lib/netzke/active_record/relation_extensions.rb +0 -37
- data/lib/netzke/basepack/accordion_panel.rb +0 -39
- data/lib/netzke/basepack/action_column.rb +0 -68
- data/lib/netzke/basepack/action_column/javascripts/action_column.js +0 -61
- data/lib/netzke/basepack/auth_app.rb +0 -159
- data/lib/netzke/basepack/basic_app.rb +0 -7
- data/lib/netzke/basepack/border_layout_panel.rb +0 -53
- data/lib/netzke/basepack/border_layout_panel/javascripts/border_layout_panel.js +0 -40
- data/lib/netzke/basepack/data_adapters/data_mapper_adapter.rb +0 -264
- data/lib/netzke/basepack/data_adapters/sequel_adapter.rb +0 -260
- data/lib/netzke/basepack/form_panel.rb +0 -144
- data/lib/netzke/basepack/form_panel/fields.rb +0 -208
- data/lib/netzke/basepack/form_panel/javascripts/misc.js +0 -4
- data/lib/netzke/basepack/form_panel/services.rb +0 -142
- data/lib/netzke/basepack/grid_panel.rb +0 -441
- data/lib/netzke/basepack/grid_panel/columns.rb +0 -400
- data/lib/netzke/basepack/grid_panel/javascripts/rows-dd.js +0 -281
- data/lib/netzke/basepack/grid_panel/record_form_window.rb +0 -41
- data/lib/netzke/basepack/grid_panel/services.rb +0 -235
- data/lib/netzke/basepack/panel.rb +0 -11
- data/lib/netzke/basepack/wrapper.rb +0 -28
- data/lib/netzke/data_mapper.rb +0 -18
- data/lib/netzke/data_mapper/attributes.rb +0 -273
- data/lib/netzke/data_mapper/combobox_options.rb +0 -11
- data/lib/netzke/data_mapper/relation_extensions.rb +0 -38
- data/lib/netzke/sequel.rb +0 -18
- data/lib/netzke/sequel/attributes.rb +0 -274
- data/lib/netzke/sequel/combobox_options.rb +0 -10
- data/lib/netzke/sequel/relation_extensions.rb +0 -40
- data/locales/zh-cn.yml +0 -79
- data/test/basepack_test_app/app/components/book_form_with_custom_fields.rb +0 -21
- data/test/basepack_test_app/app/components/book_grid_with_column_actions.rb +0 -15
- data/test/basepack_test_app/app/components/book_grid_with_defaults.rb +0 -6
- data/test/basepack_test_app/app/components/book_paging_form_panel.rb +0 -22
- data/test/basepack_test_app/app/components/generic_user_form.rb +0 -12
- data/test/basepack_test_app/app/components/simple_accordion.rb +0 -11
- data/test/basepack_test_app/app/components/simple_tab_panel.rb +0 -11
- data/test/basepack_test_app/app/components/simple_wrapper.rb +0 -7
- data/test/basepack_test_app/app/components/some_accordion_panel.rb +0 -22
- data/test/basepack_test_app/app/presenters/forms/generic_user.rb +0 -6
- data/test/basepack_test_app/app/views/components/loadable_window.html.erb +0 -9
- data/test/basepack_test_app/app/views/components/simple_panel.html.erb +0 -1
- data/test/basepack_test_app/features/components_in_view.feature +0 -11
- data/test/basepack_test_app/features/simple_panel.feature +0 -11
- data/test/basepack_test_app/features/validations_in_grid.feature +0 -13
- data/test/basepack_test_app/features/virtual_attributes.feature +0 -16
- data/test/basepack_test_app/spec/components/form_panel_spec.rb +0 -53
- data/test/basepack_test_app/spec/components/grid_panel_spec.rb +0 -10
- data/test/basepack_test_app/spec/data_adapter/adapter_spec.rb +0 -68
- data/test/basepack_test_app/spec/data_adapter/attributes_spec.rb +0 -56
- data/test/basepack_test_app/spec/data_adapter/relation_extensions_spec.rb +0 -125
- data/test/basepack_test_app/spec/factories.rb +0 -28
- data/test/basepack_test_app/spec/spec_helper.rb +0 -39
@@ -0,0 +1,27 @@
|
|
1
|
+
module Netzke
|
2
|
+
module Basepack
|
3
|
+
module ActiveRecord
|
4
|
+
module RelationExtensions
|
5
|
+
def extend_with(*params)
|
6
|
+
scope = params.shift
|
7
|
+
case scope.class.name
|
8
|
+
when "Symbol" # model's scope
|
9
|
+
self.send(scope, *params)
|
10
|
+
when "String" # SQL query or SQL query with params (e.g. ["created_at < ?", 1.day.ago])
|
11
|
+
params.empty? ? self.where(scope) : self.where([scope, *params])
|
12
|
+
when "Array"
|
13
|
+
self.extend_with(*scope)
|
14
|
+
when "Hash" # conditions hash
|
15
|
+
self.where(scope)
|
16
|
+
when "ActiveSupport::HashWithIndifferentAccess" # conditions hash
|
17
|
+
self.where(scope)
|
18
|
+
when "Proc" # receives a relation, must return a relation
|
19
|
+
scope.call(self)
|
20
|
+
else
|
21
|
+
raise ArgumentError, "Wrong parameter type for ActiveRecord::Relation#extend_with"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,309 @@
|
|
1
|
+
module Netzke
|
2
|
+
module Basepack
|
3
|
+
module Columns
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
COLUMN_METHOD_NAME = "%s_column"
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
# Overrides a column config, e.g.:
|
10
|
+
#
|
11
|
+
# column :title do |c|
|
12
|
+
# c.flex = 1
|
13
|
+
# end
|
14
|
+
def column(name, &block)
|
15
|
+
method_name = COLUMN_METHOD_NAME % name
|
16
|
+
define_method(method_name, &block)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns the list of (non-normalized) columns to be used. By default returns the list of model column names.
|
21
|
+
# Can be overridden.
|
22
|
+
def columns
|
23
|
+
config.columns || data_adapter.model_attributes
|
24
|
+
end
|
25
|
+
|
26
|
+
# An array of complete columns configs ready to be passed to the JS side.
|
27
|
+
# The +options+ hash can have the following keys:
|
28
|
+
# * :with_excluded - when true, include the columns that are marked as excluded
|
29
|
+
# * :with_meta - when true, include the meta column
|
30
|
+
def final_columns(options = {})
|
31
|
+
@_final_columns ||= {}
|
32
|
+
@_final_columns[options] ||= [].tap do |cols|
|
33
|
+
initial_columns(true).each do |c|
|
34
|
+
name = c.name
|
35
|
+
|
36
|
+
# merge with column declaration
|
37
|
+
send(:"#{name}_column", c) if respond_to?(:"#{name}_column")
|
38
|
+
|
39
|
+
# set the defaults as lowest priority
|
40
|
+
augment_column_config(c)
|
41
|
+
|
42
|
+
cols << c if options[:with_excluded] || !c.excluded
|
43
|
+
end
|
44
|
+
|
45
|
+
append_meta_column(cols) if options[:with_meta]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Columns as a hash, for easier access to a specific column
|
50
|
+
def final_columns_hash
|
51
|
+
@_final_columns_hash ||= final_columns.inject({}){|r,c| r.merge(c[:name].to_sym => c)}
|
52
|
+
end
|
53
|
+
|
54
|
+
# Columns from config.columns or the `columns` method, after normalization
|
55
|
+
def initial_columns(with_excluded = false)
|
56
|
+
@_initial_columns ||= {}
|
57
|
+
@_initial_columns[with_excluded] ||= [].tap do |cols|
|
58
|
+
has_primary_column = false
|
59
|
+
|
60
|
+
columns.each do |c|
|
61
|
+
# normalize:
|
62
|
+
# * :title => {name: 'title'}
|
63
|
+
# * {name: :some_column} => {name: 'some_column'}
|
64
|
+
c = ActiveSupport::OrderedOptions.new.replace(c.is_a?(Symbol) ? {name: c.to_s} : c.merge(name: c[:name].to_s))
|
65
|
+
|
66
|
+
cols << c if with_excluded || !c.excluded
|
67
|
+
|
68
|
+
# detect primary key column
|
69
|
+
has_primary_column ||= c.name == data_adapter.primary_key_name
|
70
|
+
end
|
71
|
+
|
72
|
+
# automatically add a column that reflects the primary key
|
73
|
+
cols.insert(0, ActiveSupport::OrderedOptions.new.replace(:name => data_adapter.primary_key_name)) unless has_primary_column
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def append_meta_column(cols)
|
78
|
+
cols << {}.tap do |c|
|
79
|
+
c.merge!(
|
80
|
+
:name => "meta",
|
81
|
+
:meta => true,
|
82
|
+
:getter => lambda do |r|
|
83
|
+
meta_data(r)
|
84
|
+
end
|
85
|
+
)
|
86
|
+
c[:default_value] = meta_default_data if meta_default_data.present?
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# default_value for the meta column; used when a new record is being created in the grid
|
91
|
+
def meta_default_data
|
92
|
+
default_association_values(final_columns_hash).present? ? { :association_values => default_association_values(final_columns_hash).literalize_keys } : {}
|
93
|
+
end
|
94
|
+
|
95
|
+
# Override it when you need extra meta data to be passed through the meta column
|
96
|
+
def meta_data(r)
|
97
|
+
{ :association_values => data_adapter.assoc_values(r, final_columns_hash).literalize_keys }
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
# Based on initial column config, e.g.:
|
103
|
+
#
|
104
|
+
# {:name=>"author__name", :attr_type=>:string}
|
105
|
+
#
|
106
|
+
# augment it with additional configuration params, e.g.:
|
107
|
+
#
|
108
|
+
# {:name=>"author__name", :attr_type=>:string, :editor=>{:xtype=>:netzkeremotecombo}, :assoc=>true, :virtual=>true, :header=>"Author name", :editable=>true, :sortable=>false, :filterable=>false}
|
109
|
+
#
|
110
|
+
# It may be handy to override it.
|
111
|
+
def augment_column_config(c)
|
112
|
+
set_default_attr_type(c)
|
113
|
+
set_default_xtype(c)
|
114
|
+
set_default_virtual(c)
|
115
|
+
set_default_text(c)
|
116
|
+
set_default_editable(c)
|
117
|
+
set_default_editor(c)
|
118
|
+
set_default_width(c)
|
119
|
+
set_default_hidden(c)
|
120
|
+
set_default_sortable(c)
|
121
|
+
set_default_filterable(c)
|
122
|
+
c[:assoc] = association_attr?(c) # needed on the JS side
|
123
|
+
end
|
124
|
+
|
125
|
+
def set_default_attr_type(c)
|
126
|
+
c[:attr_type] ||= association_attr?(c) ? :integer : data_adapter.attr_type(c.name)
|
127
|
+
end
|
128
|
+
|
129
|
+
def set_default_xtype(c)
|
130
|
+
return if c[:renderer] || c[:editor] # if user set those manually, we don't mess with column xtype
|
131
|
+
c[:xtype] ||= attr_type_to_xtype_map[c[:attr_type]]
|
132
|
+
end
|
133
|
+
|
134
|
+
def set_default_text(c)
|
135
|
+
c[:text] ||= c[:label] || data_adapter.human_attribute_name(c[:name])
|
136
|
+
end
|
137
|
+
|
138
|
+
def set_default_editor(c)
|
139
|
+
# if shouldn't be editable, don't set any default editor; also, specifying xtype takes care of the editor
|
140
|
+
return if c[:read_only] || c[:editable] == false
|
141
|
+
|
142
|
+
if association_attr?(c)
|
143
|
+
set_default_association_editor(c)
|
144
|
+
else
|
145
|
+
c[:editor] ||= editor_for_attr_type(c[:attr_type])
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
|
150
|
+
def set_default_width(c)
|
151
|
+
c[:width] ||= 50 if c[:attr_type] == :boolean
|
152
|
+
c[:width] ||= 150 if c[:attr_type] == :datetime
|
153
|
+
end
|
154
|
+
|
155
|
+
def set_default_hidden(c)
|
156
|
+
c[:hidden] = true if data_adapter.primary_key_attr?(c) && c[:hidden].nil?
|
157
|
+
end
|
158
|
+
|
159
|
+
def set_default_editable(c)
|
160
|
+
if c[:editable].nil?
|
161
|
+
c[:editable] = is_editable_column?(c)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def set_default_sortable(c)
|
166
|
+
# this *has* to be set to false if we don't want the column to be sortable (it's sortable by default in Ext)
|
167
|
+
c[:sortable] = !(c[:virtual] && !c[:sorting_scope]) if c[:sortable].nil?
|
168
|
+
end
|
169
|
+
|
170
|
+
def set_default_filterable(c)
|
171
|
+
c[:filterable] = !c[:virtual] if c[:filterable].nil?
|
172
|
+
end
|
173
|
+
|
174
|
+
|
175
|
+
# Detects an association column and sets up the proper editor.
|
176
|
+
def set_default_association_editor(c)
|
177
|
+
assoc, assoc_method = c[:name].split('__')
|
178
|
+
return unless assoc
|
179
|
+
|
180
|
+
assoc_method_type = data_adapter.get_assoc_property_type assoc, assoc_method
|
181
|
+
|
182
|
+
# if association column is boolean, display a checkbox (or alike), otherwise - a combobox (or alike)
|
183
|
+
if c[:nested_attribute]
|
184
|
+
c[:editor] ||= editor_for_attr_type(assoc_method_type)
|
185
|
+
else
|
186
|
+
c[:editor] ||= assoc_method_type == :boolean ? editor_for_attr_type(:boolean) : editor_for_association
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# If the column should be editable
|
191
|
+
def is_editable_column?(c)
|
192
|
+
not_editable_if = data_adapter.primary_key_attr?(c)
|
193
|
+
not_editable_if ||= c[:virtual] && !association_attr?(c[:name])
|
194
|
+
not_editable_if ||= c[:read_only]
|
195
|
+
|
196
|
+
editable_if = data_adapter.attribute_names.include?(c[:name])
|
197
|
+
editable_if ||= data_class.instance_methods.map(&:to_s).include?("#{c[:name]}=")
|
198
|
+
editable_if ||= association_attr?(c[:name])
|
199
|
+
|
200
|
+
editable_if && !not_editable_if
|
201
|
+
end
|
202
|
+
|
203
|
+
def initial_columns_order
|
204
|
+
final_columns.map do |c|
|
205
|
+
# copy the values that are not null
|
206
|
+
{name: c[:name]}.tap do |r|
|
207
|
+
r[:width] = c[:width] if c[:width]
|
208
|
+
r[:hidden] = c[:hidden] if c[:hidden]
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def columns_order
|
214
|
+
if config[:persistence]
|
215
|
+
state[:columns_order] = initial_columns_order if columns_have_changed?
|
216
|
+
state[:columns_order] || initial_columns_order
|
217
|
+
else
|
218
|
+
initial_columns_order
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def columns_have_changed?
|
223
|
+
init_column_names = initial_columns_order.map{ |c| c[:name].to_s }.sort
|
224
|
+
stored_column_names = (state[:columns_order] || initial_columns_order).map{ |c| c[:name].to_s }.sort
|
225
|
+
init_column_names != stored_column_names
|
226
|
+
end
|
227
|
+
|
228
|
+
# Column editor config for attribute type.
|
229
|
+
def editor_for_attr_type(type)
|
230
|
+
{:xtype => attr_type_to_editor_xtype_map[type] || :textfield}
|
231
|
+
end
|
232
|
+
|
233
|
+
# Column editor config for one-to-many association
|
234
|
+
def editor_for_association
|
235
|
+
{:xtype => :netzkeremotecombo}
|
236
|
+
end
|
237
|
+
|
238
|
+
# Hash that maps a column type to the editor xtype. Override if you want different editors.
|
239
|
+
def attr_type_to_editor_xtype_map
|
240
|
+
{
|
241
|
+
:integer => :numberfield,
|
242
|
+
:boolean => :checkbox,
|
243
|
+
:date => :datefield,
|
244
|
+
:datetime => :xdatetime,
|
245
|
+
:text => :textarea,
|
246
|
+
:string => :textfield
|
247
|
+
}
|
248
|
+
end
|
249
|
+
|
250
|
+
def attr_type_to_xtype_map
|
251
|
+
{
|
252
|
+
# :integer => :numbercolumn, # don't like the default formatter
|
253
|
+
:boolean => :checkcolumn,
|
254
|
+
:date => :datecolumn,
|
255
|
+
#:datetime => :datecolumn # TODO: replace with datetimepicker
|
256
|
+
}
|
257
|
+
end
|
258
|
+
|
259
|
+
# Default fields that will be displayed in the Add/Edit/Search forms
|
260
|
+
# When overriding this method, keep in mind that the fields inside the layout must be expanded (each field represented by a hash, not just a symbol)
|
261
|
+
def default_fields_for_forms
|
262
|
+
selected_columns = final_columns.select do |c|
|
263
|
+
data_adapter.attribute_names.include?(c[:name]) ||
|
264
|
+
data_class.instance_methods.include?("#{c[:name]}=") ||
|
265
|
+
association_attr?(c[:name])
|
266
|
+
end
|
267
|
+
|
268
|
+
selected_columns.map do |c|
|
269
|
+
field_config = {
|
270
|
+
:name => c[:name],
|
271
|
+
:field_label => c[:text] || c[:header]
|
272
|
+
}
|
273
|
+
|
274
|
+
# scopes for combobox options
|
275
|
+
field_config[:scopes] = c[:editor][:scopes] if c[:editor].is_a?(Hash)
|
276
|
+
|
277
|
+
field_config.merge!(c[:editor] || {})
|
278
|
+
|
279
|
+
field_config
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
def columns_default_values
|
284
|
+
final_columns.inject({}) do |r,c|
|
285
|
+
assoc_name, assoc_method = c[:name].split '__'
|
286
|
+
if c[:default_value].nil?
|
287
|
+
r
|
288
|
+
else
|
289
|
+
if assoc_method
|
290
|
+
r.merge(data_adapter.foreign_key_for(assoc_name) || data_adapter.foreign_key_for(assoc_name) => c[:default_value])
|
291
|
+
else
|
292
|
+
r.merge(c[:name] => c[:default_value])
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
# Recursively traversess items (an array) and yields each found field (a hash with :name set)
|
299
|
+
def each_attr_in(items)
|
300
|
+
items.each do |item|
|
301
|
+
if item.is_a?(Hash)
|
302
|
+
each_attr_in(item[:items]) if item[:items].is_a?(Array)
|
303
|
+
yield(item) if item[:name]
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
309
|
+
end
|
@@ -1,18 +1,14 @@
|
|
1
1
|
module Netzke
|
2
2
|
module Basepack
|
3
|
-
# This module is included into such data-driven components as
|
3
|
+
# This module is included into such data-driven components as Grid, Form, PagingForm, etc.
|
4
4
|
module DataAccessor
|
5
|
-
|
6
|
-
|
7
|
-
|
8
5
|
# Returns options for comboboxes in grids/forms
|
9
6
|
def combobox_options_for_column(column, method_options = {})
|
10
7
|
data_adapter.combobox_options_for_column column, method_options
|
11
8
|
end
|
12
9
|
|
13
10
|
# Normalize array of attributes
|
14
|
-
#
|
15
|
-
# [{:name => "col1"}, {:name => "col2"}, {:name => "col3"}]
|
11
|
+
# [:col1, "col2", {:name => :col3}] #=> [{:name => "col1"}, {:name => "col2"}, {:name => "col3"}]
|
16
12
|
def normalize_attrs(attrs)
|
17
13
|
attrs.map{ |a| normalize_attr(a) }
|
18
14
|
end
|
@@ -35,19 +31,33 @@ module Netzke
|
|
35
31
|
|
36
32
|
# Data adapter responsible for all DB-related operations
|
37
33
|
def data_adapter
|
38
|
-
@data_adapter ||= Netzke::Basepack::DataAdapters::AbstractAdapter.adapter_class(data_class).new(data_class)
|
34
|
+
@data_adapter ||= data_class && Netzke::Basepack::DataAdapters::AbstractAdapter.adapter_class(data_class).new(data_class)
|
39
35
|
end
|
40
36
|
|
41
|
-
# whether a column is bound to the primary_key
|
42
|
-
def primary_key_attr?(a)
|
43
|
-
|
44
|
-
end
|
37
|
+
# whether a column/field is bound to the primary_key
|
38
|
+
# def primary_key_attr?(a)
|
39
|
+
# data_class && a[:name].to_s == data_class.primary_key.to_s
|
40
|
+
# end
|
45
41
|
|
46
42
|
# Mark an attribute as "virtual" by default, when it doesn't reflect a model column, or a model column of an association
|
47
43
|
def set_default_virtual(c)
|
48
|
-
c[:virtual] = data_adapter.
|
44
|
+
c[:virtual] = data_adapter.virtual_attribute?(c) if c[:virtual].nil?
|
49
45
|
end
|
50
46
|
|
47
|
+
# Returns a hash of association attribute default values. Used when creating new records with association attributes that have a default value
|
48
|
+
def default_association_values(attr_hash) #:nodoc:
|
49
|
+
@_default_association_values ||= {}.tap do |values|
|
50
|
+
attr_hash.each_pair do |name,c|
|
51
|
+
next unless association_attr?(c) && c[:default_value]
|
52
|
+
|
53
|
+
assoc_name, assoc_method = c[:name].split '__'
|
54
|
+
assoc_class = data_adapter.class_for(assoc_name)
|
55
|
+
assoc_data_adapter = Netzke::Basepack::DataAdapters::AbstractAdapter.adapter_class(assoc_class).new(assoc_class)
|
56
|
+
assoc_instance = assoc_data_adapter.find_record c[:default_value]
|
57
|
+
values[name] = assoc_instance.send(assoc_method)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
51
61
|
end
|
52
62
|
end
|
53
63
|
end
|
@@ -2,6 +2,23 @@ module Netzke::Basepack::DataAdapters
|
|
2
2
|
# A concrete adapter should implement all the public instance methods of this adapter in order to support all the functionality of Basepack components.
|
3
3
|
class AbstractAdapter
|
4
4
|
|
5
|
+
# Returns primary key name of the model
|
6
|
+
def primary_key_name
|
7
|
+
"id"
|
8
|
+
end
|
9
|
+
|
10
|
+
# Returns a list of model attribute hashes, each containing `name`, `attr_type` and `default_value` (if set in the schema).
|
11
|
+
# For association columns the name can have the double-underscore format, e.g.: `author__first_name`.
|
12
|
+
# These attributes will be used by grids and forms to display default columns/fields.
|
13
|
+
def model_attributes
|
14
|
+
raise NotImplementedError
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns attribute type (as Symbol) given its name.
|
18
|
+
def attr_type(attr_name)
|
19
|
+
raise NotImplementedError
|
20
|
+
end
|
21
|
+
|
5
22
|
# Returns records based on passed params. Implements:
|
6
23
|
# * pagination
|
7
24
|
# * filtering
|
@@ -14,7 +31,7 @@ module Netzke::Basepack::DataAdapters
|
|
14
31
|
# * :direction - "asc" or "desc"
|
15
32
|
# * :limit - rows per page in pagination
|
16
33
|
# * :start - page number in pagination
|
17
|
-
# * :scope - the scope as described in Netzke::Basepack::
|
34
|
+
# * :scope - the scope as described in Netzke::Basepack::Grid
|
18
35
|
# * :filter - Ext filters
|
19
36
|
#
|
20
37
|
# The `columns` parameter may be used to use joins to address the n+1 query problem, and receives an array of column configurations
|
@@ -33,7 +50,7 @@ module Netzke::Basepack::DataAdapters
|
|
33
50
|
#
|
34
51
|
# `params` is a hash that contains the following keys:
|
35
52
|
#
|
36
|
-
# * :scope - the scope as described in Netzke::Basepack::
|
53
|
+
# * :scope - the scope as described in Netzke::Basepack::Grid
|
37
54
|
# * :filter - Ext filters
|
38
55
|
#
|
39
56
|
# The `columns` parameter may be used to use joins to address the n+1 query problem, and receives an array of column configurations
|
@@ -74,14 +91,18 @@ module Netzke::Basepack::DataAdapters
|
|
74
91
|
def get_property_type column
|
75
92
|
column.type
|
76
93
|
end
|
77
|
-
|
94
|
+
|
78
95
|
# should return true if column is virtual
|
79
|
-
def
|
96
|
+
def virtual_attribute? c
|
80
97
|
raise NotImplementedError
|
81
98
|
end
|
82
99
|
|
83
100
|
# Returns options for comboboxes in grids/forms
|
84
|
-
|
101
|
+
# +attr+ - column/field configuration; note that it will in its turn provide:
|
102
|
+
# * +name+ - attribute name
|
103
|
+
# * +scope+ - searching scope (optional)
|
104
|
+
# +query+ - whatever is entered in the combobox
|
105
|
+
def combo_data(attr, query = "")
|
85
106
|
raise NotImplementedError
|
86
107
|
end
|
87
108
|
|
@@ -99,6 +120,16 @@ module Netzke::Basepack::DataAdapters
|
|
99
120
|
def destroy(ids)
|
100
121
|
end
|
101
122
|
|
123
|
+
# Finds a record by id, return nil if not found
|
124
|
+
def find_record(id)
|
125
|
+
@model_class.find(id)
|
126
|
+
end
|
127
|
+
|
128
|
+
# Build a hash of foreign keys and the associated model
|
129
|
+
def hash_fk_model
|
130
|
+
raise NotImplementedError
|
131
|
+
end
|
132
|
+
|
102
133
|
# Changes records position (e.g. when acts_as_list is used in ActiveRecord).
|
103
134
|
#
|
104
135
|
# `params` is a hash with the following keys:
|
@@ -125,22 +156,55 @@ module Netzke::Basepack::DataAdapters
|
|
125
156
|
record.errors.to_a
|
126
157
|
end
|
127
158
|
|
128
|
-
#
|
129
|
-
def
|
130
|
-
|
159
|
+
# Whether an attribute is mass assignable. As second argument optionally takes the role.
|
160
|
+
def attribute_mass_assignable?(attr_name, role = :default)
|
161
|
+
true
|
131
162
|
end
|
132
163
|
|
133
|
-
#
|
134
|
-
def
|
135
|
-
|
164
|
+
# Whether an attribute (by name) is an association one
|
165
|
+
def association_attr?(attr_name)
|
166
|
+
!!attr_name.to_s.index("__")
|
167
|
+
end
|
168
|
+
|
169
|
+
# Transforms a record to an array of values according to the passed attributes
|
170
|
+
# +attrs+ - array of attribute config hashes
|
171
|
+
def record_to_array(r, attrs)
|
172
|
+
[]
|
136
173
|
end
|
137
174
|
|
175
|
+
# Transforms a record to a hash of values according to the passed attributes
|
176
|
+
# +attrs+ - array of attribute config hashes
|
177
|
+
def record_to_hash(r, attrs)
|
178
|
+
{}
|
179
|
+
end
|
138
180
|
|
181
|
+
# Returns a hash of association values for given record, e.g.:
|
182
|
+
#
|
183
|
+
# {author__first_name: "Michael"}
|
184
|
+
def assoc_values(r, attr_hash) #:nodoc:
|
185
|
+
{}.tap do |values|
|
186
|
+
attr_hash.each_pair do |name,c|
|
187
|
+
values[name] = record_value_for_attribute(r, c, true) if association_attr?(c)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
# Fetches the value specified by an (association) attribute
|
193
|
+
# If +through_association+ is true, get the value of the association by provided method, *not* the associated record's id
|
194
|
+
# E.g., author__name with through_association set to true may return "Vladimir Nabokov", while with through_association set to false, it'll return author_id for the current record
|
195
|
+
def record_value_for_attribute(r, a, through_association = false)
|
196
|
+
end
|
197
|
+
|
198
|
+
# Assigns new value to an (association) attribute in a given record
|
199
|
+
# +role+ - role provided for mass assignment protection
|
200
|
+
def set_record_value_for_attribute(record, attr, value, role = :default)
|
201
|
+
end
|
139
202
|
|
140
203
|
# -- End of overridable methods
|
141
204
|
|
142
205
|
# Abstract-adapter specifics
|
143
206
|
#
|
207
|
+
#
|
144
208
|
|
145
209
|
# Used to determine if the given adapter should be used for the passed in class.
|
146
210
|
def self.for_class?(member_class)
|