netzke-basepack 0.5.8 → 0.5.9
Sign up to get free protection for your applications and to get access to all the features.
- 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
|