netzke-basepack 0.5.8 → 0.5.9
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 +18 -0
- data/README.rdoc +11 -4
- data/Rakefile +19 -3
- data/TODO.rdoc +1 -1
- data/generators/netzke_basepack/netzke_basepack_generator.rb +13 -0
- data/generators/netzke_basepack/templates/create_netzke_field_lists.rb +18 -0
- data/generators/netzke_basepack/templates/public_assets/ts-checkbox.gif +0 -0
- data/install.rb +1 -1
- data/javascripts/basepack.js +124 -30
- data/lib/app/models/netzke_field_list.rb +261 -0
- data/lib/app/models/netzke_model_attr_list.rb +21 -0
- data/lib/app/models/netzke_persistent_array_auto_model.rb +58 -0
- data/lib/netzke-basepack.rb +17 -2
- data/lib/netzke/active_record.rb +10 -0
- data/lib/netzke/active_record/association_attributes.rb +102 -0
- data/lib/netzke/active_record/attributes.rb +100 -0
- data/lib/netzke/active_record/combobox_options.rb +43 -0
- data/lib/netzke/active_record/data_accessor.rb +9 -12
- data/lib/netzke/attributes_configurator.rb +195 -0
- data/lib/netzke/basic_app.rb +47 -4
- data/lib/netzke/configuration_panel.rb +1 -1
- data/lib/netzke/data_accessor.rb +7 -30
- data/lib/netzke/fields_configurator.rb +106 -41
- data/lib/netzke/form_panel.rb +28 -125
- data/lib/netzke/form_panel/form_panel_api.rb +2 -3
- data/lib/netzke/form_panel/form_panel_fields.rb +147 -0
- data/lib/netzke/form_panel/form_panel_js.rb +35 -15
- data/lib/netzke/grid_panel.rb +130 -213
- data/lib/netzke/grid_panel/grid_panel_api.rb +254 -257
- data/lib/netzke/grid_panel/grid_panel_columns.rb +226 -0
- data/lib/netzke/grid_panel/grid_panel_js.rb +126 -119
- data/lib/netzke/grid_panel/record_form_window.rb +7 -1
- data/lib/netzke/json_array_editor.rb +61 -0
- data/lib/netzke/plugins/configuration_tool.rb +1 -1
- data/lib/netzke/property_editor.rb +3 -3
- data/lib/netzke/search_panel.rb +164 -27
- data/lib/netzke/tab_panel.rb +14 -12
- data/stylesheets/basepack.css +43 -2
- data/test/app_root/app/models/book.rb +1 -1
- data/test/app_root/app/models/role.rb +3 -0
- data/test/app_root/app/models/user.rb +3 -0
- data/test/app_root/config/database.yml +1 -1
- data/test/app_root/db/migrate/20090102223630_create_netzke_field_lists.rb +18 -0
- data/test/app_root/db/migrate/20090423214303_create_roles.rb +11 -0
- data/test/app_root/db/migrate/20090423222114_create_users.rb +12 -0
- data/test/fixtures/books.yml +4 -2
- data/test/fixtures/categories.yml +2 -2
- data/test/fixtures/genres.yml +6 -6
- data/test/fixtures/roles.yml +8 -0
- data/test/fixtures/users.yml +11 -0
- data/test/test_helper.rb +2 -0
- data/test/unit/active_record_basepack_test.rb +2 -2
- data/test/unit/fields_configuration_test.rb +18 -0
- data/test/unit/grid_panel_test.rb +29 -27
- metadata +41 -16
- data/lib/app/models/netzke_auto_column.rb +0 -4
- data/lib/app/models/netzke_auto_field.rb +0 -4
- data/lib/app/models/netzke_auto_table.rb +0 -61
- data/lib/netzke/active_record/basepack.rb +0 -134
- data/lib/netzke/grid_panel/javascripts/filters.js +0 -7
- data/test/app_root/db/migrate/20090102223630_create_netzke_layouts.rb +0 -14
- data/test/unit/helper_model_test.rb +0 -30
@@ -0,0 +1,21 @@
|
|
1
|
+
# Holds attribute lists for application models.
|
2
|
+
# Is used to configure attributes in the layer between a model and its representation in the Netzke application, thus providing default attributes
|
3
|
+
# for grids and panels.
|
4
|
+
class NetzkeModelAttrList < NetzkeFieldList
|
5
|
+
|
6
|
+
# Updates attributes for all lists owned by owner_id and below the current authority level
|
7
|
+
def self.update_fields(owner_id, attrs_hash)
|
8
|
+
super
|
9
|
+
|
10
|
+
NetzkeFieldList.find_all_lists_under_current_authority(owner_id).each do |list|
|
11
|
+
list.update_attrs(attrs_hash)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.add_attrs(attrs)
|
16
|
+
NetzkeFieldList.find_all_lists_under_current_authority(owner_id).each do |list|
|
17
|
+
attrs.each{ |attr_hash| list.append_attr(attr_hash) }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'acts_as_list'
|
2
|
+
class NetzkePersistentArrayAutoModel < ActiveRecord::Base
|
3
|
+
set_table_name "netzke_temp_table"
|
4
|
+
connection.create_table(table_name){} if !connection.table_exists?(table_name)
|
5
|
+
|
6
|
+
acts_as_list
|
7
|
+
default_scope :order => "position"
|
8
|
+
|
9
|
+
cattr_accessor :config
|
10
|
+
|
11
|
+
def self.all_columns
|
12
|
+
self.all.map{ |c| c.attributes.reject{ |k,v| k == 'id' || k == 'position' } }
|
13
|
+
end
|
14
|
+
|
15
|
+
# Configuration
|
16
|
+
def self.configure(config)
|
17
|
+
self.config = config
|
18
|
+
if NetzkePreference.first(:conditions => {:name => "netzke_persistent_array_refresh_token"}).try(:value) != refresh_token || !connection.table_exists?(table_name)
|
19
|
+
rebuild_table#(:columns => config[:columns], :initial_data => config[:initial_data])
|
20
|
+
end
|
21
|
+
NetzkePreference.find_or_create_by_name("netzke_persistent_array_refresh_token").update_attribute(:value, refresh_token)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.rebuild_table#(config)
|
25
|
+
connection.drop_table(table_name) if connection.table_exists?(table_name)
|
26
|
+
# create the table with the fields
|
27
|
+
self.connection.create_table(table_name) do |t|
|
28
|
+
config[:columns].each do |c|
|
29
|
+
c = c.dup # to make next line shorter
|
30
|
+
t.column c.delete(:name), c.delete(:type), c
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
self.reset_column_information
|
35
|
+
|
36
|
+
# self.create config[:initial_data]
|
37
|
+
self.replace_data(config[:initial_data])
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.replace_data(data)
|
41
|
+
# only select those attributes that were provided to us as columns. The rest is ignored.
|
42
|
+
column_names = config[:columns].map{ |c| c[:name] }
|
43
|
+
clean_data = data.collect{ |c| c.reject{ |k,v| !column_names.include?(k.to_s) } }
|
44
|
+
|
45
|
+
self.delete_all
|
46
|
+
self.create(clean_data)
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def self.refresh_token
|
52
|
+
@@refresh_token ||= begin
|
53
|
+
session = Netzke::Base.session
|
54
|
+
config[:owner] + (session[:masq_user] || session[:masq_role] || session[:masq_world] || session[:netzke_user_id]).to_s
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
data/lib/netzke-basepack.rb
CHANGED
@@ -4,6 +4,7 @@ require 'netzke-core'
|
|
4
4
|
|
5
5
|
# ExtJS-related constants
|
6
6
|
require 'netzke/ext'
|
7
|
+
require 'netzke/active_record'
|
7
8
|
|
8
9
|
# Make widget classes auto-loadable with help of ActiveSupport
|
9
10
|
path = File.dirname(__FILE__)
|
@@ -25,5 +26,19 @@ end
|
|
25
26
|
Netzke::Base.config[:javascripts] << "#{File.dirname(__FILE__)}/../javascripts/basepack.js"
|
26
27
|
Netzke::Base.config[:stylesheets] << "#{File.dirname(__FILE__)}/../stylesheets/basepack.css"
|
27
28
|
|
28
|
-
|
29
|
-
|
29
|
+
|
30
|
+
# FIXME: The following stylesheet inclusion doesn't *really* belong here, being widget-specific,
|
31
|
+
# but I don't see any other solution for now. The problem is that these stylesheets come straight from
|
32
|
+
# Ext JS, having *relative* URLs to the images, which doesn't allow us to include them all together as those stylesheets
|
33
|
+
# from Netzke.
|
34
|
+
|
35
|
+
# Used by FormPanel (file upload field)
|
36
|
+
Netzke::Base.config[:external_css] << "/extjs/examples/ux/fileuploadfield/css/fileuploadfield"
|
37
|
+
|
38
|
+
# Used by GridPanel
|
39
|
+
Netzke::Base.config[:external_css] << "/extjs/examples/ux/gridfilters/css/RangeMenu"
|
40
|
+
Netzke::Base.config[:external_css] << "/extjs/examples/ux/gridfilters/css/GridFilters"
|
41
|
+
|
42
|
+
if Netzke::Base.config[:with_icons].nil? && defined?(RAILS_ROOT)
|
43
|
+
Netzke::Base.config[:with_icons] = File.exists?("#{RAILS_ROOT}/public#{Netzke::Base.config[:icons_uri]}")
|
44
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require "active_record"
|
2
|
+
|
3
|
+
module Netzke::ActiveRecord
|
4
|
+
# Provides extensions to all ActiveRecord-based classes
|
5
|
+
module AssociationAttributes
|
6
|
+
module ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
module InstanceMethods
|
10
|
+
# Allow nested association access (assocs separated by "." or "__"), e.g.: proxy_service.asset__gui_folder__name
|
11
|
+
# Example:
|
12
|
+
#
|
13
|
+
# Book.first.genre__name = 'Fantasy'
|
14
|
+
#
|
15
|
+
# is the same as:
|
16
|
+
#
|
17
|
+
# Book.first.genre = Genre.find_by_name('Fantasy')
|
18
|
+
#
|
19
|
+
# The result - easier forms and grids that handle nested models: simply specify column/field name as "genre__name".
|
20
|
+
def method_missing_with_basepack(method, *args, &block)
|
21
|
+
# if refering to a column, just pass it to the original method_missing
|
22
|
+
return method_missing_without_basepack(method, *args, &block) if self.class.column_names.include?(method.to_s)
|
23
|
+
|
24
|
+
split = method.to_s.split(/\.|__/)
|
25
|
+
if split.size > 1
|
26
|
+
if split.last =~ /=$/
|
27
|
+
if split.size == 2
|
28
|
+
# search for association and assign it to self
|
29
|
+
assoc = self.class.reflect_on_association(split.first.to_sym)
|
30
|
+
assoc_method = split.last.chop
|
31
|
+
if assoc
|
32
|
+
begin
|
33
|
+
assoc_instance = assoc.klass.send("find_by_#{assoc_method}", *args)
|
34
|
+
rescue NoMethodError
|
35
|
+
assoc_instance = nil
|
36
|
+
logger.debug "!!! no find_by_#{assoc_method} method for class #{assoc.klass.name}\n"
|
37
|
+
end
|
38
|
+
if (assoc_instance)
|
39
|
+
self.send("#{split.first}=", assoc_instance)
|
40
|
+
else
|
41
|
+
logger.debug "!!! Couldn't find association #{split.first} by #{assoc_method} '#{args.first}'"
|
42
|
+
end
|
43
|
+
else
|
44
|
+
method_missing_without_basepack(method, *args, &block)
|
45
|
+
end
|
46
|
+
else
|
47
|
+
method_missing_without_basepack(method, *args, &block)
|
48
|
+
end
|
49
|
+
else
|
50
|
+
res = self
|
51
|
+
split.each do |m|
|
52
|
+
if res.respond_to?(m)
|
53
|
+
res = res.send(m) unless res.nil?
|
54
|
+
else
|
55
|
+
res.nil? ? nil : method_missing_without_basepack(method, *args, &block)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
res
|
59
|
+
end
|
60
|
+
else
|
61
|
+
method_missing_without_basepack(method, *args, &block)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Make respond_to? return true for association assignment method, like "genre__name="
|
66
|
+
def respond_to_with_basepack?(method, include_private = false)
|
67
|
+
split = method.to_s.split(/__/)
|
68
|
+
if split.size > 1
|
69
|
+
if split.last =~ /=$/
|
70
|
+
if split.size == 2
|
71
|
+
# search for association and assign it to self
|
72
|
+
assoc = self.class.reflect_on_association(split.first.to_sym)
|
73
|
+
assoc_method = split.last.chop
|
74
|
+
if assoc
|
75
|
+
assoc.klass.respond_to?("find_by_#{assoc_method}")
|
76
|
+
else
|
77
|
+
respond_to_without_basepack?(method, include_private)
|
78
|
+
end
|
79
|
+
else
|
80
|
+
respond_to_without_basepack?(method, include_private)
|
81
|
+
end
|
82
|
+
else
|
83
|
+
# self.respond_to?(split.first) ? self.send(split.first).respond_to?(split[1..-1].join("__")) : false
|
84
|
+
respond_to_without_basepack?(method, include_private)
|
85
|
+
end
|
86
|
+
else
|
87
|
+
respond_to_without_basepack?(method, include_private)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.included(receiver)
|
93
|
+
receiver.extend ClassMethods
|
94
|
+
|
95
|
+
receiver.send :include, InstanceMethods
|
96
|
+
receiver.alias_method_chain :method_missing, :basepack
|
97
|
+
receiver.alias_method_chain :respond_to?, :basepack
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module Netzke::ActiveRecord::Attributes
|
2
|
+
module ClassMethods
|
3
|
+
|
4
|
+
# Define or configure an attribute.
|
5
|
+
# Example:
|
6
|
+
# netzke_attribute :recent, :type => :boolean, :read_only => true
|
7
|
+
def netzke_attribute(name, options = {})
|
8
|
+
name = name.to_s
|
9
|
+
options[:attr_type] = options.delete(:type) || :string
|
10
|
+
declared_attrs = read_inheritable_attribute(:netzke_declared_attributes) || []
|
11
|
+
# if the attr was declared already, simply merge it with the new options
|
12
|
+
existing = declared_attrs.detect{ |va| va[:name] == name }
|
13
|
+
if existing
|
14
|
+
existing.merge!(options)
|
15
|
+
else
|
16
|
+
declared_attrs << {:name => name}.merge(options)
|
17
|
+
end
|
18
|
+
write_inheritable_attribute(:netzke_declared_attributes, declared_attrs)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Exclude attributes from being picked up by grids and forms.
|
22
|
+
# Accepts an array of attribute names (as symbols).
|
23
|
+
# Example:
|
24
|
+
# netzke_expose_attributes :created_at, :updated_at, :crypted_password
|
25
|
+
def netzke_exclude_attributes(*args)
|
26
|
+
write_inheritable_attribute(:netzke_excluded_attributes, args.map(&:to_s))
|
27
|
+
end
|
28
|
+
|
29
|
+
# Explicitly expose attributes that should be picked up by grids and forms.
|
30
|
+
# Accepts an array of attribute names (as symbols).
|
31
|
+
# Takes precedence over <tt>netzke_exclude_attributes</tt>.
|
32
|
+
# Example:
|
33
|
+
# netzke_expose_attributes :name, :role__name
|
34
|
+
def netzke_expose_attributes(*args)
|
35
|
+
write_inheritable_attribute(:netzke_exposed_attributes, args.map(&:to_s))
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns the attributes that will be picked up by grids and forms.
|
39
|
+
def netzke_attributes
|
40
|
+
exposed = read_inheritable_attribute(:netzke_exposed_attributes)
|
41
|
+
exposed ? netzke_attrs_in_forced_order(exposed) : netzke_attrs_in_natural_order
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
def netzke_declared_attributes
|
46
|
+
read_inheritable_attribute(:netzke_declared_attributes) || []
|
47
|
+
end
|
48
|
+
|
49
|
+
def netzke_excluded_attributes
|
50
|
+
read_inheritable_attribute(:netzke_excluded_attributes) || []
|
51
|
+
end
|
52
|
+
|
53
|
+
def netzke_attrs_in_forced_order(attrs)
|
54
|
+
attrs.collect do |attr_name|
|
55
|
+
declared = netzke_declared_attributes.detect { |va| va[:name] == attr_name } || {}
|
56
|
+
in_columns_hash = columns_hash[attr_name] && {:name => attr_name, :attr_type => columns_hash[attr_name].type, :default_value => columns_hash[attr_name].default} || {} # {:virtual => true} # if nothing found in columns, mark it as "virtual" or not?
|
57
|
+
if in_columns_hash.empty?
|
58
|
+
# If not among the model columns, it's either virtual, or an association
|
59
|
+
merged = association_attr?(attr_name) ? {:name => attr_name} : declared.merge(:virtual => true)
|
60
|
+
else
|
61
|
+
# .. otherwise merge with what's declared
|
62
|
+
merged = in_columns_hash.merge(declared)
|
63
|
+
end
|
64
|
+
|
65
|
+
# We didn't find it among declared, nor among the model columns, nor does it seem association attribute
|
66
|
+
merged[:name].nil? && raise(ArgumentError, "Unknown attribute '#{attr_name}' for model #{self.name}", caller)
|
67
|
+
|
68
|
+
merged
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def netzke_attrs_in_natural_order
|
73
|
+
(
|
74
|
+
declared_attrs = netzke_declared_attributes
|
75
|
+
column_names.map do |name|
|
76
|
+
c = {:name => name, :attr_type => columns_hash[name].type}
|
77
|
+
# auto set up the default value from the column settings
|
78
|
+
c.merge!(:default_value => columns_hash[name].default) if columns_hash[name].default
|
79
|
+
|
80
|
+
# if there's a declared attr with the same name, simply merge it with what's taken from the model's columns
|
81
|
+
if declared = declared_attrs.detect{ |va| va[:name] == name }
|
82
|
+
c.merge!(declared)
|
83
|
+
declared_attrs.delete(declared)
|
84
|
+
end
|
85
|
+
c
|
86
|
+
end +
|
87
|
+
declared_attrs
|
88
|
+
).reject { |attr| netzke_excluded_attributes.include?(attr[:name]) }
|
89
|
+
end
|
90
|
+
|
91
|
+
def association_attr?(attr_name)
|
92
|
+
!!attr_name.index("__") # probably we can't do much better than this, as we don't know at this moment if the associated model has a specific attribute, and we don't really want to find it out
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.included(receiver)
|
98
|
+
receiver.extend ClassMethods
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Netzke::ActiveRecord::ComboboxOptions
|
2
|
+
module ClassMethods
|
3
|
+
# TODO: rename to netzke_options_for (to avoid polluting the namespace)
|
4
|
+
def options_for(column, query = "")
|
5
|
+
# First, check if we have options for this class and column defined in persistent storage
|
6
|
+
# NetzkePreference.widget_name = self.name
|
7
|
+
# options = NetzkePreference[:combobox_options] || {}
|
8
|
+
# if options[column]
|
9
|
+
# options[column].select{ |o| o.index(/^#{query}/) }
|
10
|
+
if respond_to?("#{column}_combobox_options")
|
11
|
+
# AR model provides the choices itself
|
12
|
+
send("#{column}_combobox_options", query)
|
13
|
+
else
|
14
|
+
# Returns all unique values for a column, filtered with <tt>query</tt>
|
15
|
+
if (assoc_name, *assoc_method = column.split('__')).size > 1
|
16
|
+
# column is an association column
|
17
|
+
assoc_method = assoc_method.join('__') # in case we get something like country__continent__name
|
18
|
+
association = reflect_on_association(assoc_name.to_sym) || raise(NameError, "Association #{assoc_name} not known for class #{name}")
|
19
|
+
association.klass.options_for(assoc_method, query)
|
20
|
+
else
|
21
|
+
column = assoc_name
|
22
|
+
if self.column_names.include?(column)
|
23
|
+
# it's simply a column in the table
|
24
|
+
records = query.empty? ? find_by_sql("select distinct #{column} from #{table_name}") : find_by_sql("select distinct #{column} from #{table_name} where #{column} like '#{query}%'")
|
25
|
+
records.map{|r| r.send(column)}
|
26
|
+
else
|
27
|
+
# it's a "virtual" column - the least effective search
|
28
|
+
records = self.find(:all).map{|r| r.send(column)}.uniq
|
29
|
+
query.empty? ? records : records.select{|r| r.index(/^#{query}/)}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
module InstanceMethods
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.included(receiver)
|
40
|
+
receiver.extend ClassMethods
|
41
|
+
receiver.send :include, InstanceMethods
|
42
|
+
end
|
43
|
+
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'netzke/active_record/basepack'
|
2
|
-
|
3
1
|
module Netzke::ActiveRecord
|
4
2
|
# Provides extensions to those ActiveRecord-based models that provide data to the "data accessor" widgets,
|
5
3
|
# like GridPanel, FormPanel, etc
|
@@ -7,22 +5,21 @@ module Netzke::ActiveRecord
|
|
7
5
|
|
8
6
|
# Allow specify the netzke widget that requires this data. Virtual attributes may be using it to produce
|
9
7
|
# widget-dependent result.
|
10
|
-
def netzke_widget=(widget)
|
11
|
-
|
12
|
-
end
|
13
|
-
|
14
|
-
def netzke_widget
|
15
|
-
|
16
|
-
end
|
8
|
+
# def netzke_widget=(widget)
|
9
|
+
# @netzke_widget = widget
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# def netzke_widget
|
13
|
+
# @netzke_widget
|
14
|
+
# end
|
17
15
|
|
18
16
|
# Transforms a record to array of values according to the passed columns.
|
19
17
|
def to_array(columns, widget = nil)
|
20
|
-
self.netzke_widget = widget
|
18
|
+
# self.netzke_widget = widget
|
21
19
|
res = []
|
22
20
|
for c in columns
|
23
|
-
nc = c.is_a?(Symbol) ? {:name => c} : c
|
24
21
|
begin
|
25
|
-
res << send(
|
22
|
+
res << send(c[:name]) unless c[:included] == false
|
26
23
|
rescue
|
27
24
|
# So that we don't crash at a badly configured column
|
28
25
|
res << "UNDEF"
|
@@ -0,0 +1,195 @@
|
|
1
|
+
module Netzke
|
2
|
+
# == AttributesConfigurator
|
3
|
+
# Provides dynamic configuring of attributes for a specific model. This will be picked up by Grid/FormPanels as defaults.
|
4
|
+
# Configuration parameters:
|
5
|
+
# * <tt>:model</tt> - model to configure attributes for
|
6
|
+
class AttributesConfigurator < JsonArrayEditor
|
7
|
+
api :load_defaults
|
8
|
+
|
9
|
+
def default_columns
|
10
|
+
[{
|
11
|
+
:name => "id",
|
12
|
+
:attr_type => :integer
|
13
|
+
},{
|
14
|
+
:name => "included",
|
15
|
+
:attr_type => :boolean,
|
16
|
+
:default_value => true
|
17
|
+
},{
|
18
|
+
:name => "name",
|
19
|
+
:attr_type => :string,
|
20
|
+
:width => 200,
|
21
|
+
:editor => {
|
22
|
+
:xtype => :combo,
|
23
|
+
:store => config[:model].constantize.netzke_attributes.map{ |attr| attr[:name] },
|
24
|
+
:force_selection => true
|
25
|
+
}
|
26
|
+
},{
|
27
|
+
:name => "label",
|
28
|
+
:attr_type => :string,
|
29
|
+
:width => 200
|
30
|
+
},{
|
31
|
+
:name => "default_value",
|
32
|
+
:attr_type => :string,
|
33
|
+
:width => 200
|
34
|
+
},{
|
35
|
+
:name => "combobox_options",
|
36
|
+
:attr_type => :string,
|
37
|
+
:width => 200,
|
38
|
+
:editor => :textarea
|
39
|
+
},{
|
40
|
+
:name => "read_only",
|
41
|
+
:attr_type => :boolean,
|
42
|
+
:default_value => false,
|
43
|
+
:header => "R/O"
|
44
|
+
},{
|
45
|
+
:name => "position",
|
46
|
+
:attr_type => :integer,
|
47
|
+
:included => false
|
48
|
+
},{
|
49
|
+
:name => "attr_type",
|
50
|
+
:attr_type => :string,
|
51
|
+
:meta => :true
|
52
|
+
}]
|
53
|
+
end
|
54
|
+
|
55
|
+
def default_config
|
56
|
+
super.deep_merge({
|
57
|
+
:name => 'columns',
|
58
|
+
:ext_config => {
|
59
|
+
:header => false,
|
60
|
+
:enable_extended_search => false,
|
61
|
+
:enable_edit_in_form => false,
|
62
|
+
:enable_pagination => false,
|
63
|
+
:enable_rows_reordering => GridPanel.config[:rows_reordering_available]
|
64
|
+
}
|
65
|
+
})
|
66
|
+
end
|
67
|
+
|
68
|
+
def config_tool_needed?
|
69
|
+
false
|
70
|
+
end
|
71
|
+
|
72
|
+
def actions
|
73
|
+
super.merge(
|
74
|
+
:defaults => {:text => 'Restore defaults', :icon => Netzke::Base.config[:with_icons] && (Netzke::Base.config[:icons_uri] + "wand.png")}
|
75
|
+
)
|
76
|
+
end
|
77
|
+
|
78
|
+
def default_bbar
|
79
|
+
%w{ add edit apply del - defaults }
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.js_extend_properties
|
83
|
+
{
|
84
|
+
:init_component => <<-END_OF_JAVASCRIPT.l,
|
85
|
+
function(){
|
86
|
+
#{js_full_class_name}.superclass.initComponent.call(this);
|
87
|
+
|
88
|
+
// Automatically set the correct editor for the default_value column
|
89
|
+
this.on('beforeedit', function(e){
|
90
|
+
var column = this.getColumnModel().getColumnById(this.getColumnModel().getColumnId(e.column));
|
91
|
+
var record = this.getStore().getAt(e.row);
|
92
|
+
|
93
|
+
if (column.dataIndex === "default_value") {
|
94
|
+
if (record.get("name") === this.pri) {
|
95
|
+
// Don't allow setting default value for the primary key
|
96
|
+
column.setEditor(null);
|
97
|
+
} else {
|
98
|
+
// Auto set the editor, dependent on the field type
|
99
|
+
var attrType = record.get("attr_type");
|
100
|
+
column.setEditor(Ext.create({xtype: this.attrTypeEditorMap[attrType] || "textfield"}));
|
101
|
+
}
|
102
|
+
}
|
103
|
+
}, this);
|
104
|
+
|
105
|
+
// Add push menu item to column context menus
|
106
|
+
this.on("viewready", this.extendColumnMenu, this);
|
107
|
+
}
|
108
|
+
END_OF_JAVASCRIPT
|
109
|
+
|
110
|
+
:extend_column_menu => <<-END_OF_JAVASCRIPT.l,
|
111
|
+
function(){
|
112
|
+
this.getView().hmenu.add("-", {text: "Propagate", handler: this.onPushToViews, scope: this});
|
113
|
+
}
|
114
|
+
END_OF_JAVASCRIPT
|
115
|
+
|
116
|
+
:on_push_to_views => <<-END_OF_JAVASCRIPT.l,
|
117
|
+
function(){
|
118
|
+
var columnIndex = this.getView().hdCtxIndex,
|
119
|
+
dataIndex = this.getColumnModel().getDataIndex(columnIndex);
|
120
|
+
|
121
|
+
this.pushDefaultsForAttr({name: dataIndex});
|
122
|
+
}
|
123
|
+
END_OF_JAVASCRIPT
|
124
|
+
|
125
|
+
:on_defaults => <<-END_OF_JAVASCRIPT.l,
|
126
|
+
function(){
|
127
|
+
Ext.Msg.confirm('Confirm', 'Are you sure?', function(btn){
|
128
|
+
if (btn == 'yes') {
|
129
|
+
this.loadDefaults();
|
130
|
+
}
|
131
|
+
}, this);
|
132
|
+
}
|
133
|
+
END_OF_JAVASCRIPT
|
134
|
+
}
|
135
|
+
end
|
136
|
+
|
137
|
+
api :push_defaults_for_attr
|
138
|
+
def push_defaults_for_attr(params)
|
139
|
+
NetzkeFieldList.update_children_on_attr(config[:model], params[:name])
|
140
|
+
{:feedback => "Done."}
|
141
|
+
end
|
142
|
+
|
143
|
+
def load_defaults(params)
|
144
|
+
data_class.replace_data(default_model_attrs)
|
145
|
+
on_data_changed
|
146
|
+
{:load_store_data => get_data}
|
147
|
+
end
|
148
|
+
|
149
|
+
private
|
150
|
+
# An override
|
151
|
+
def process_data(data, operation)
|
152
|
+
if operation == :update
|
153
|
+
meta_attrs_to_update = data.inject({}) do |r,el|
|
154
|
+
r.merge({
|
155
|
+
data_class.find(el["id"]).name => el.reject{ |k,v| k == "id" }
|
156
|
+
})
|
157
|
+
end
|
158
|
+
|
159
|
+
res = super
|
160
|
+
NetzkeModelAttrList.update_fields(config[:model], meta_attrs_to_update)
|
161
|
+
# NetzkeFieldList.update_children(config[:model], meta_attrs_to_update)
|
162
|
+
res
|
163
|
+
else
|
164
|
+
# NetzkeModelAttrList.add_attrs(config[:model], data.reject{ |k,v| k == "id" })
|
165
|
+
super
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# An override
|
170
|
+
def store_data(data)
|
171
|
+
NetzkeModelAttrList.update_list_for_current_authority(config[:model], data)
|
172
|
+
# Let's try to do it through process_data
|
173
|
+
# NetzkeFieldList.write_attrs_for_model(config[:model], data)
|
174
|
+
end
|
175
|
+
|
176
|
+
# An override
|
177
|
+
def initial_data
|
178
|
+
# NetzkeModelAttrList.attrs_for_model(config[:model])
|
179
|
+
NetzkeModelAttrList.read_list(config[:model]) || default_model_attrs
|
180
|
+
# NetzkeModelAttrList.read_attrs_for_model(config[:model]) || default_model_attrs
|
181
|
+
end
|
182
|
+
|
183
|
+
# Default model attributes, along with their defaults meta-attributes (like :label)
|
184
|
+
def default_model_attrs
|
185
|
+
@default_model_attrs ||= begin
|
186
|
+
config[:model].constantize.netzke_attributes.map do |attr|
|
187
|
+
attr.merge(
|
188
|
+
:label => attr[:label] || attr[:name].humanize,
|
189
|
+
:attr_type => attr[:attr_type].to_s
|
190
|
+
)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|