skozlov-netzke_core 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/CHANGELOG +1 -0
  2. data/LICENSE +20 -0
  3. data/Manifest +64 -0
  4. data/README.mdown +18 -0
  5. data/Rakefile +11 -0
  6. data/generators/netzke_basepack/USAGE +8 -0
  7. data/generators/netzke_basepack/netzke_basepack_generator.rb +8 -0
  8. data/generators/netzke_basepack/netzke_grid_generator.rb +7 -0
  9. data/generators/netzke_basepack/templates/create_netzke_grid_columns.rb +21 -0
  10. data/init.rb +2 -0
  11. data/install.rb +1 -0
  12. data/javascripts/basepack.js +41 -0
  13. data/lib/app/models/netzke_grid_column.rb +23 -0
  14. data/lib/netzke/accordion.rb +11 -0
  15. data/lib/netzke/ar_ext.rb +163 -0
  16. data/lib/netzke/column.rb +43 -0
  17. data/lib/netzke/container.rb +81 -0
  18. data/lib/netzke/grid.rb +132 -0
  19. data/lib/netzke/grid_interface.rb +132 -0
  20. data/lib/netzke/grid_js_builder.rb +249 -0
  21. data/lib/netzke/preference_grid.rb +43 -0
  22. data/lib/netzke/properties_tool.rb +66 -0
  23. data/lib/netzke/property_grid.rb +60 -0
  24. data/lib/netzke_basepack.rb +14 -0
  25. data/netzke_core.gemspec +38 -0
  26. data/tasks/netzke_basepack_tasks.rake +4 -0
  27. data/test/app_root/app/controllers/application.rb +2 -0
  28. data/test/app_root/app/models/book.rb +9 -0
  29. data/test/app_root/app/models/category.rb +2 -0
  30. data/test/app_root/app/models/city.rb +3 -0
  31. data/test/app_root/app/models/continent.rb +2 -0
  32. data/test/app_root/app/models/country.rb +3 -0
  33. data/test/app_root/app/models/genre.rb +3 -0
  34. data/test/app_root/config/boot.rb +114 -0
  35. data/test/app_root/config/database.yml +21 -0
  36. data/test/app_root/config/environment.rb +13 -0
  37. data/test/app_root/config/environments/in_memory.rb +0 -0
  38. data/test/app_root/config/environments/mysql.rb +0 -0
  39. data/test/app_root/config/environments/postgresql.rb +0 -0
  40. data/test/app_root/config/environments/sqlite.rb +0 -0
  41. data/test/app_root/config/environments/sqlite3.rb +0 -0
  42. data/test/app_root/config/routes.rb +4 -0
  43. data/test/app_root/db/migrate/20081222033343_create_books.rb +15 -0
  44. data/test/app_root/db/migrate/20081222033440_create_genres.rb +14 -0
  45. data/test/app_root/db/migrate/20081222035855_create_netzke_preferences.rb +18 -0
  46. data/test/app_root/db/migrate/20081223024935_create_categories.rb +13 -0
  47. data/test/app_root/db/migrate/20081223025635_create_countries.rb +14 -0
  48. data/test/app_root/db/migrate/20081223025653_create_continents.rb +13 -0
  49. data/test/app_root/db/migrate/20081223025732_create_cities.rb +15 -0
  50. data/test/app_root/script/console +7 -0
  51. data/test/ar_ext_test.rb +39 -0
  52. data/test/column_test.rb +27 -0
  53. data/test/console_with_fixtures.rb +4 -0
  54. data/test/fixtures/books.yml +9 -0
  55. data/test/fixtures/categories.yml +7 -0
  56. data/test/fixtures/cities.yml +21 -0
  57. data/test/fixtures/continents.yml +7 -0
  58. data/test/fixtures/countries.yml +9 -0
  59. data/test/fixtures/genres.yml +9 -0
  60. data/test/grid_test.rb +43 -0
  61. data/test/netzke_basepack_test.rb +8 -0
  62. data/test/schema.rb +10 -0
  63. data/test/test_helper.rb +20 -0
  64. data/uninstall.rb +1 -0
  65. metadata +159 -0
@@ -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.
@@ -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
@@ -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
@@ -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,8 @@
1
+ Description:
2
+ Explain the generator
3
+
4
+ Example:
5
+ ./script/generate netzke_basepack Thing
6
+
7
+ This will create:
8
+ what/will/it/create
@@ -0,0 +1,8 @@
1
+ class NetzkeBasepackGenerator < Rails::Generator::NamedBase
2
+ def manifest
3
+ record do |m|
4
+ # m.directory "lib"
5
+ # m.template 'README', "README"
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,7 @@
1
+ class NetzkeGridGenerator < Rails::Generator::Base
2
+ def manifest
3
+ record do |m|
4
+ m.migration_template 'create_netzke_grid_columns.rb', "db/migrate", {:migration_file_name => "create_netzke_grid_columns"}
5
+ end
6
+ end
7
+ 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
@@ -0,0 +1,2 @@
1
+ # Include hook code here
2
+ require 'netzke_basepack'
@@ -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,11 @@
1
+ module Netzke
2
+ class Accordion < Container
3
+
4
+ def js_default_config
5
+ super.merge({
6
+ :layout => 'accordion'
7
+ })
8
+ end
9
+
10
+ end
11
+ 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