netzke-basepack 0.7.7 → 0.8.0
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/.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)
|