skozlov-netzke_core 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +1 -0
- data/LICENSE +20 -0
- data/Manifest +64 -0
- data/README.mdown +18 -0
- data/Rakefile +11 -0
- data/generators/netzke_basepack/USAGE +8 -0
- data/generators/netzke_basepack/netzke_basepack_generator.rb +8 -0
- data/generators/netzke_basepack/netzke_grid_generator.rb +7 -0
- data/generators/netzke_basepack/templates/create_netzke_grid_columns.rb +21 -0
- data/init.rb +2 -0
- data/install.rb +1 -0
- data/javascripts/basepack.js +41 -0
- data/lib/app/models/netzke_grid_column.rb +23 -0
- data/lib/netzke/accordion.rb +11 -0
- data/lib/netzke/ar_ext.rb +163 -0
- data/lib/netzke/column.rb +43 -0
- data/lib/netzke/container.rb +81 -0
- data/lib/netzke/grid.rb +132 -0
- data/lib/netzke/grid_interface.rb +132 -0
- data/lib/netzke/grid_js_builder.rb +249 -0
- data/lib/netzke/preference_grid.rb +43 -0
- data/lib/netzke/properties_tool.rb +66 -0
- data/lib/netzke/property_grid.rb +60 -0
- data/lib/netzke_basepack.rb +14 -0
- data/netzke_core.gemspec +38 -0
- data/tasks/netzke_basepack_tasks.rake +4 -0
- data/test/app_root/app/controllers/application.rb +2 -0
- data/test/app_root/app/models/book.rb +9 -0
- data/test/app_root/app/models/category.rb +2 -0
- data/test/app_root/app/models/city.rb +3 -0
- data/test/app_root/app/models/continent.rb +2 -0
- data/test/app_root/app/models/country.rb +3 -0
- data/test/app_root/app/models/genre.rb +3 -0
- data/test/app_root/config/boot.rb +114 -0
- data/test/app_root/config/database.yml +21 -0
- data/test/app_root/config/environment.rb +13 -0
- data/test/app_root/config/environments/in_memory.rb +0 -0
- data/test/app_root/config/environments/mysql.rb +0 -0
- data/test/app_root/config/environments/postgresql.rb +0 -0
- data/test/app_root/config/environments/sqlite.rb +0 -0
- data/test/app_root/config/environments/sqlite3.rb +0 -0
- data/test/app_root/config/routes.rb +4 -0
- data/test/app_root/db/migrate/20081222033343_create_books.rb +15 -0
- data/test/app_root/db/migrate/20081222033440_create_genres.rb +14 -0
- data/test/app_root/db/migrate/20081222035855_create_netzke_preferences.rb +18 -0
- data/test/app_root/db/migrate/20081223024935_create_categories.rb +13 -0
- data/test/app_root/db/migrate/20081223025635_create_countries.rb +14 -0
- data/test/app_root/db/migrate/20081223025653_create_continents.rb +13 -0
- data/test/app_root/db/migrate/20081223025732_create_cities.rb +15 -0
- data/test/app_root/script/console +7 -0
- data/test/ar_ext_test.rb +39 -0
- data/test/column_test.rb +27 -0
- data/test/console_with_fixtures.rb +4 -0
- data/test/fixtures/books.yml +9 -0
- data/test/fixtures/categories.yml +7 -0
- data/test/fixtures/cities.yml +21 -0
- data/test/fixtures/continents.yml +7 -0
- data/test/fixtures/countries.yml +9 -0
- data/test/fixtures/genres.yml +9 -0
- data/test/grid_test.rb +43 -0
- data/test/netzke_basepack_test.rb +8 -0
- data/test/schema.rb +10 -0
- data/test/test_helper.rb +20 -0
- data/uninstall.rb +1 -0
- metadata +159 -0
data/CHANGELOG
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
v0.1.0 Initial release
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Sergei Kozlov
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Manifest
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
CHANGELOG
|
2
|
+
generators/netzke_basepack/netzke_basepack_generator.rb
|
3
|
+
generators/netzke_basepack/netzke_grid_generator.rb
|
4
|
+
generators/netzke_basepack/templates/create_netzke_grid_columns.rb
|
5
|
+
generators/netzke_basepack/USAGE
|
6
|
+
init.rb
|
7
|
+
install.rb
|
8
|
+
javascripts/basepack.js
|
9
|
+
lib/app/models/netzke_grid_column.rb
|
10
|
+
lib/netzke/accordion.rb
|
11
|
+
lib/netzke/ar_ext.rb
|
12
|
+
lib/netzke/column.rb
|
13
|
+
lib/netzke/container.rb
|
14
|
+
lib/netzke/grid.rb
|
15
|
+
lib/netzke/grid_interface.rb
|
16
|
+
lib/netzke/grid_js_builder.rb
|
17
|
+
lib/netzke/preference_grid.rb
|
18
|
+
lib/netzke/properties_tool.rb
|
19
|
+
lib/netzke/property_grid.rb
|
20
|
+
lib/netzke_basepack.rb
|
21
|
+
LICENSE
|
22
|
+
Manifest
|
23
|
+
netzke_core.gemspec
|
24
|
+
Rakefile
|
25
|
+
README.mdown
|
26
|
+
tasks/netzke_basepack_tasks.rake
|
27
|
+
test/app_root/app/controllers/application.rb
|
28
|
+
test/app_root/app/models/book.rb
|
29
|
+
test/app_root/app/models/category.rb
|
30
|
+
test/app_root/app/models/city.rb
|
31
|
+
test/app_root/app/models/continent.rb
|
32
|
+
test/app_root/app/models/country.rb
|
33
|
+
test/app_root/app/models/genre.rb
|
34
|
+
test/app_root/config/boot.rb
|
35
|
+
test/app_root/config/database.yml
|
36
|
+
test/app_root/config/environment.rb
|
37
|
+
test/app_root/config/environments/in_memory.rb
|
38
|
+
test/app_root/config/environments/mysql.rb
|
39
|
+
test/app_root/config/environments/postgresql.rb
|
40
|
+
test/app_root/config/environments/sqlite.rb
|
41
|
+
test/app_root/config/environments/sqlite3.rb
|
42
|
+
test/app_root/config/routes.rb
|
43
|
+
test/app_root/db/migrate/20081222033343_create_books.rb
|
44
|
+
test/app_root/db/migrate/20081222033440_create_genres.rb
|
45
|
+
test/app_root/db/migrate/20081222035855_create_netzke_preferences.rb
|
46
|
+
test/app_root/db/migrate/20081223024935_create_categories.rb
|
47
|
+
test/app_root/db/migrate/20081223025635_create_countries.rb
|
48
|
+
test/app_root/db/migrate/20081223025653_create_continents.rb
|
49
|
+
test/app_root/db/migrate/20081223025732_create_cities.rb
|
50
|
+
test/app_root/script/console
|
51
|
+
test/ar_ext_test.rb
|
52
|
+
test/column_test.rb
|
53
|
+
test/console_with_fixtures.rb
|
54
|
+
test/fixtures/books.yml
|
55
|
+
test/fixtures/categories.yml
|
56
|
+
test/fixtures/cities.yml
|
57
|
+
test/fixtures/continents.yml
|
58
|
+
test/fixtures/countries.yml
|
59
|
+
test/fixtures/genres.yml
|
60
|
+
test/grid_test.rb
|
61
|
+
test/netzke_basepack_test.rb
|
62
|
+
test/schema.rb
|
63
|
+
test/test_helper.rb
|
64
|
+
uninstall.rb
|
data/README.mdown
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
NetzkeBasepack
|
2
|
+
==============
|
3
|
+
|
4
|
+
Introduction goes here.
|
5
|
+
|
6
|
+
|
7
|
+
Example
|
8
|
+
=======
|
9
|
+
|
10
|
+
Example goes here.
|
11
|
+
|
12
|
+
|
13
|
+
Credentials
|
14
|
+
===========
|
15
|
+
|
16
|
+
Testing with the help of http://github.com/pluginaweek/plugin_test_helper
|
17
|
+
|
18
|
+
Copyright (c) 2008 Sergei Kozlov, released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'echoe'
|
2
|
+
|
3
|
+
Echoe.new("netzke_core") do |p|
|
4
|
+
p.author = "Sergei Kozlov"
|
5
|
+
p.email = "sergei@writelesscode.com"
|
6
|
+
p.summary = "Base Netzke widgets - grid, form, tree, and more"
|
7
|
+
p.url = "http://writelesscode.com"
|
8
|
+
p.runtime_dependencies = ["searchlogic >=1.6.2", "netzke_core >= 0.1.0"]
|
9
|
+
p.development_dependencies = []
|
10
|
+
p.test_pattern = 'test/**/*_test.rb'
|
11
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class CreateNetzkeGridColumns < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :netzke_grid_columns do |t|
|
4
|
+
t.string :name
|
5
|
+
t.string :label
|
6
|
+
t.boolean :read_only
|
7
|
+
t.integer :position
|
8
|
+
t.boolean :hidden
|
9
|
+
t.integer :width
|
10
|
+
t.string :shows_as, :limit => 32
|
11
|
+
|
12
|
+
t.integer :layout_id
|
13
|
+
|
14
|
+
t.timestamps
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.down
|
19
|
+
drop_table :netzke_grid_columns
|
20
|
+
end
|
21
|
+
end
|
data/init.rb
ADDED
data/install.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# Install hook code here
|
@@ -0,0 +1,41 @@
|
|
1
|
+
// Editors for grid cells and form fields
|
2
|
+
Ext.netzke.editors = {
|
3
|
+
combo_box: function(c, config){
|
4
|
+
var row = Ext.data.Record.create([{name:'id'}])
|
5
|
+
var store = new Ext.data.Store({
|
6
|
+
proxy: new Ext.data.HttpProxy({url:config.interface.getCbChoices, jsonData:{column:c.name}}),
|
7
|
+
reader: new Ext.data.ArrayReader({root:'data', id:0}, row)
|
8
|
+
})
|
9
|
+
return new Ext.form.ComboBox({
|
10
|
+
mode: 'remote',
|
11
|
+
displayField:'id',
|
12
|
+
valueField:'id',
|
13
|
+
triggerAction:'all',
|
14
|
+
store: store
|
15
|
+
})
|
16
|
+
},
|
17
|
+
|
18
|
+
text_field: function(c, config){
|
19
|
+
return new Ext.form.TextField({
|
20
|
+
selectOnFocus:true
|
21
|
+
})
|
22
|
+
},
|
23
|
+
|
24
|
+
checkbox: function(c, config){
|
25
|
+
return new Ext.form.TextField({
|
26
|
+
selectOnFocus:true
|
27
|
+
})
|
28
|
+
},
|
29
|
+
|
30
|
+
number_field: function(c, config){
|
31
|
+
return new Ext.form.NumberField({
|
32
|
+
selectOnFocus:true
|
33
|
+
})
|
34
|
+
},
|
35
|
+
|
36
|
+
datetime: function(c, config){
|
37
|
+
return new Ext.form.TextField({
|
38
|
+
selectOnFocus:true
|
39
|
+
})
|
40
|
+
}
|
41
|
+
}
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class NetzkeGridColumn < ActiveRecord::Base
|
2
|
+
belongs_to :layout, :class_name => "NetzkeLayout"
|
3
|
+
|
4
|
+
acts_as_list :scope => :layout
|
5
|
+
|
6
|
+
# old?
|
7
|
+
# def self.create_with_defaults(column_config, klass)
|
8
|
+
# create(klass.default_column_config(column_config).stringify_values!)
|
9
|
+
# end
|
10
|
+
|
11
|
+
def self.create_layout_for_widget(widget)
|
12
|
+
layout = NetzkeLayout.create(:widget_name => widget.id_name, :items_class => self.name, :user_id => NetzkeLayout.user_id)
|
13
|
+
|
14
|
+
columns = Netzke::Column.default_columns_for_widget(widget)
|
15
|
+
|
16
|
+
for c in columns
|
17
|
+
config_for_create = c.merge(:layout_id => layout.id).stringify_values!
|
18
|
+
create(config_for_create)
|
19
|
+
end
|
20
|
+
|
21
|
+
layout
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
module Netzke
|
2
|
+
module ActiveRecordExtensions
|
3
|
+
def self.included(base)
|
4
|
+
base.extend ActiveRecordClassMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
#
|
8
|
+
# Allow nested association acces (assocs separated by "." or "__"), e.g.: proxy_service.send('asset__gui_folder__name')
|
9
|
+
# Example:
|
10
|
+
# b = Book.first
|
11
|
+
# b.genre__name = 'Fantasy' => b.genre = Genre.find_by_name('Fantasy')
|
12
|
+
# NOT IMPLEMENTED: ANY USE? b.genre__catalog__name = 'Best sellers' => b.genre_id = b.genre.find_by_catalog_id(Catalog.find_by_name('Best sellers')).id
|
13
|
+
#
|
14
|
+
|
15
|
+
def method_missing(method, *args, &block)
|
16
|
+
# if refering to a column, just pass it to the originar method_missing
|
17
|
+
return super if self.class.column_names.include?(method.to_s)
|
18
|
+
|
19
|
+
split = method.to_s.split(/\.|__/)
|
20
|
+
if split.size > 1
|
21
|
+
if split.last =~ /=$/
|
22
|
+
if split.size == 2
|
23
|
+
# search for association and assign it to self
|
24
|
+
assoc = self.class.reflect_on_association(split.first.to_sym)
|
25
|
+
assoc_method = split.last.chop
|
26
|
+
if assoc
|
27
|
+
assoc_instance = assoc.klass.send("find_by_#{assoc_method}", *args)
|
28
|
+
raise ArgumentError, "Couldn't find association #{split.first} by #{assoc_method} '#{args.first}'" unless assoc_instance
|
29
|
+
self.send("#{split.first}=", assoc_instance)
|
30
|
+
else
|
31
|
+
super
|
32
|
+
end
|
33
|
+
else
|
34
|
+
super
|
35
|
+
end
|
36
|
+
else
|
37
|
+
res = self
|
38
|
+
split.each do |m|
|
39
|
+
if res.respond_to?(m)
|
40
|
+
res = res.send(m) unless res.nil?
|
41
|
+
else
|
42
|
+
res.nil? ? nil : super
|
43
|
+
end
|
44
|
+
end
|
45
|
+
res
|
46
|
+
end
|
47
|
+
else
|
48
|
+
super
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
module ActiveRecordClassMethods
|
54
|
+
def choices_for(column, query = nil)
|
55
|
+
if respond_to?("#{column}_choices", query)
|
56
|
+
# AR class provides the choices itself
|
57
|
+
send("#{column}_choices")
|
58
|
+
else
|
59
|
+
if (assoc_name, *assoc_method = column.split('__')).size > 1
|
60
|
+
# column is an association column
|
61
|
+
assoc_method = assoc_method.join('__') # in case we get something like country__continent__name
|
62
|
+
association = reflect_on_association(assoc_name.to_sym) || raise(NameError, "Association #{assoc_name} not known for class #{name}")
|
63
|
+
association.klass.choices_for(assoc_method, query)
|
64
|
+
else
|
65
|
+
column = assoc_name
|
66
|
+
if self.column_names.include?(column)
|
67
|
+
# it's just a column
|
68
|
+
records = query.nil? ? find_by_sql("select distinct #{column} from #{table_name}") : find_by_sql("select distinct #{column} from #{table_name} where #{column} like '#{query}%'")
|
69
|
+
records.map{|r| r.send(column)}
|
70
|
+
else
|
71
|
+
# it's a "virtual" column - the least effective search
|
72
|
+
records = self.find(:all).map{|r| r.send(column)}.uniq
|
73
|
+
query.nil? ? records : records.select{|r| r.send(column).index(/^#{query}/)}
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# which columns are to be picked up by grids and forms
|
80
|
+
def expose_columns(columns, *args)
|
81
|
+
if columns == :all
|
82
|
+
write_inheritable_attribute(:exposed_columns, self.column_names.map(&:to_sym))
|
83
|
+
else
|
84
|
+
write_inheritable_attribute(:exposed_columns, columns)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def exposed_columns
|
89
|
+
read_inheritable_attribute(:exposed_columns) || write_inheritable_attribute(:exposed_columns, expose_columns(:all) + virtual_columns)
|
90
|
+
end
|
91
|
+
|
92
|
+
# virtual "columns" that simply correspond to instance methods of an ActiveRecord class
|
93
|
+
def virtual_column(config)
|
94
|
+
if config.is_a?(Symbol)
|
95
|
+
config = {:name => config}
|
96
|
+
else
|
97
|
+
config = {:name => config.keys.first}.merge(config.values.first)
|
98
|
+
end
|
99
|
+
write_inheritable_attribute(:virtual_columns, (read_inheritable_attribute(:virtual_columns) || []) << config)
|
100
|
+
end
|
101
|
+
|
102
|
+
def virtual_columns
|
103
|
+
read_inheritable_attribute(:virtual_columns) || []
|
104
|
+
end
|
105
|
+
|
106
|
+
def is_virtual_column?(column)
|
107
|
+
read_inheritable_attribute(:virtual_columns).keys.include?(column)
|
108
|
+
end
|
109
|
+
|
110
|
+
#
|
111
|
+
# Used by Netzke::Grid
|
112
|
+
#
|
113
|
+
|
114
|
+
DEFAULT_COLUMN_WIDTH = 100
|
115
|
+
|
116
|
+
def default_column_config(config)
|
117
|
+
config = {:name => config} if config.is_a?(Symbol) # optionally we may get only a column name (as Symbol)
|
118
|
+
type = (columns_hash[config[:name].to_s] && columns_hash[config[:name].to_s].type) || :virtual
|
119
|
+
|
120
|
+
# general config
|
121
|
+
res = {
|
122
|
+
:name => config[:name].to_s || "unnamed",
|
123
|
+
:label => config[:label] || config[:name].to_s.humanize,
|
124
|
+
:read_only => config[:name] == :id, # make "id" column read-only by default
|
125
|
+
:hidden => config[:name] == :id, # hide "id" column by default
|
126
|
+
:width => DEFAULT_COLUMN_WIDTH,
|
127
|
+
:shows_as => :text_field
|
128
|
+
}
|
129
|
+
|
130
|
+
case type
|
131
|
+
when :integer
|
132
|
+
res[:shows_as] = :number_field
|
133
|
+
when :boolean
|
134
|
+
res[:shows_as] = :checkbox
|
135
|
+
res[:width] = 50
|
136
|
+
when :date
|
137
|
+
res[:shows_as] = :date_field
|
138
|
+
when :datetime
|
139
|
+
res[:shows_as] = :datetime
|
140
|
+
when :string
|
141
|
+
res[:shows_as] = :text_field
|
142
|
+
end
|
143
|
+
|
144
|
+
res.merge(config) # merge with custom confg (it has the priority)
|
145
|
+
end
|
146
|
+
|
147
|
+
#
|
148
|
+
# Used by Netzke::Form
|
149
|
+
#
|
150
|
+
|
151
|
+
DEFAULT_FIELD_WIDTH = 100
|
152
|
+
DEFAULT_FIELD_HEIGHT = 50
|
153
|
+
def default_field_config(config)
|
154
|
+
# TODO
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
ActiveRecord::Base.class_eval do
|
162
|
+
include Netzke::ActiveRecordExtensions
|
163
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Netzke
|
2
|
+
class Column
|
3
|
+
def self.default_columns_for_widget(widget)
|
4
|
+
raise ArgumentError, "No data_class_name specified for widget #{widget.config[:name]}" if widget.config[:data_class_name].nil?
|
5
|
+
|
6
|
+
# layout = NetzkeLayout.create(:widget_name => widget.id_name, :items_class => self.name, :user_id => NetzkeLayout.user_id)
|
7
|
+
|
8
|
+
data_class = widget.config[:data_class_name].constantize
|
9
|
+
|
10
|
+
exposed_columns = normalize_columns(data_class.exposed_columns) # columns exposed from the data class
|
11
|
+
|
12
|
+
columns_from_config = widget.config[:columns] && normalize_columns(widget.config[:columns]) # columns specified in widget's config
|
13
|
+
|
14
|
+
if columns_from_config
|
15
|
+
# reverse-merge each column hash from config with each column hash from exposed_columns (columns from config have higher priority)
|
16
|
+
for c in columns_from_config
|
17
|
+
corresponding_exposed_column = exposed_columns.find{ |k| k[:name] == c[:name] }
|
18
|
+
c.reverse_merge!(corresponding_exposed_column) if corresponding_exposed_column
|
19
|
+
end
|
20
|
+
columns_for_create = columns_from_config
|
21
|
+
else
|
22
|
+
# we didn't have columns configured in widget's config, so, use the columns from the data class
|
23
|
+
columns_for_create = exposed_columns
|
24
|
+
end
|
25
|
+
|
26
|
+
res = []
|
27
|
+
for c in columns_for_create
|
28
|
+
# finally reverse-merge them with the defaults from the data_class
|
29
|
+
res << data_class.default_column_config(c)
|
30
|
+
end
|
31
|
+
|
32
|
+
res
|
33
|
+
end
|
34
|
+
|
35
|
+
protected
|
36
|
+
|
37
|
+
# like this: [:col1, {:name => :col2}, :col3] => [{:name => :col1}, {:name => :col2}, {:name => :col3}]
|
38
|
+
def self.normalize_columns(items)
|
39
|
+
items.map{|c| c.is_a?(Symbol) ? {:name => c} : c}
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|