netzke-core 0.1.1.1

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.
Files changed (40) hide show
  1. data/CHANGELOG +13 -0
  2. data/LICENSE +20 -0
  3. data/Manifest +39 -0
  4. data/README.mdown +11 -0
  5. data/Rakefile +14 -0
  6. data/generators/netzke_core/USAGE +8 -0
  7. data/generators/netzke_core/netzke_core_generator.rb +13 -0
  8. data/generators/netzke_core/templates/create_netzke_layouts.rb +14 -0
  9. data/generators/netzke_core/templates/create_netzke_preferences.rb +18 -0
  10. data/generators/netzke_core/templates/netzke.html.erb +10 -0
  11. data/init.rb +1 -0
  12. data/install.rb +1 -0
  13. data/javascripts/core.js +124 -0
  14. data/lib/app/controllers/netzke_controller.rb +16 -0
  15. data/lib/app/models/netzke_layout.rb +75 -0
  16. data/lib/app/models/netzke_preference.rb +66 -0
  17. data/lib/netzke-core.rb +28 -0
  18. data/lib/netzke/base.rb +210 -0
  19. data/lib/netzke/controller_extensions.rb +95 -0
  20. data/lib/netzke/core_ext.rb +77 -0
  21. data/lib/netzke/js_class_builder.rb +114 -0
  22. data/lib/vendor/facets/hash/recursive_merge.rb +28 -0
  23. data/netzke-core.gemspec +32 -0
  24. data/tasks/netzke_core_tasks.rake +4 -0
  25. data/test/app_root/app/controllers/application.rb +2 -0
  26. data/test/app_root/config/boot.rb +114 -0
  27. data/test/app_root/config/database.yml +21 -0
  28. data/test/app_root/config/environment.rb +13 -0
  29. data/test/app_root/config/environments/in_memory.rb +0 -0
  30. data/test/app_root/config/environments/mysql.rb +0 -0
  31. data/test/app_root/config/environments/postgresql.rb +0 -0
  32. data/test/app_root/config/environments/sqlite.rb +0 -0
  33. data/test/app_root/config/environments/sqlite3.rb +0 -0
  34. data/test/app_root/config/routes.rb +4 -0
  35. data/test/app_root/script/console +6 -0
  36. data/test/core_ext_test.rb +35 -0
  37. data/test/netzke_core_test.rb +133 -0
  38. data/test/test_helper.rb +20 -0
  39. data/uninstall.rb +1 -0
  40. metadata +109 -0
data/CHANGELOG ADDED
@@ -0,0 +1,13 @@
1
+ v0.1.1.1
2
+ Meta: moving from GitHub to RubyForge
3
+
4
+ v0.1.1
5
+ Inter-widget dependencies code reworked
6
+ JS-class code generation code slightly reworked
7
+
8
+ v0.1.0.2
9
+ Meta: fix outdated Manifest
10
+
11
+ v0.1.0.1 Meta work: replacing underscore with dash in the name
12
+
13
+ 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,39 @@
1
+ CHANGELOG
2
+ generators/netzke_core/netzke_core_generator.rb
3
+ generators/netzke_core/templates/create_netzke_layouts.rb
4
+ generators/netzke_core/templates/create_netzke_preferences.rb
5
+ generators/netzke_core/templates/netzke.html.erb
6
+ generators/netzke_core/USAGE
7
+ init.rb
8
+ install.rb
9
+ javascripts/core.js
10
+ lib/app/controllers/netzke_controller.rb
11
+ lib/app/models/netzke_layout.rb
12
+ lib/app/models/netzke_preference.rb
13
+ lib/netzke/base.rb
14
+ lib/netzke/controller_extensions.rb
15
+ lib/netzke/core_ext.rb
16
+ lib/netzke/js_class_builder.rb
17
+ lib/netzke-core.rb
18
+ lib/vendor/facets/hash/recursive_merge.rb
19
+ LICENSE
20
+ Manifest
21
+ netzke-core.gemspec
22
+ Rakefile
23
+ README.mdown
24
+ tasks/netzke_core_tasks.rake
25
+ test/app_root/app/controllers/application.rb
26
+ test/app_root/config/boot.rb
27
+ test/app_root/config/database.yml
28
+ test/app_root/config/environment.rb
29
+ test/app_root/config/environments/in_memory.rb
30
+ test/app_root/config/environments/mysql.rb
31
+ test/app_root/config/environments/postgresql.rb
32
+ test/app_root/config/environments/sqlite.rb
33
+ test/app_root/config/environments/sqlite3.rb
34
+ test/app_root/config/routes.rb
35
+ test/app_root/script/console
36
+ test/core_ext_test.rb
37
+ test/netzke_core_test.rb
38
+ test/test_helper.rb
39
+ uninstall.rb
data/README.mdown ADDED
@@ -0,0 +1,11 @@
1
+ netzke-core
2
+ ==========
3
+
4
+ Create ExtJS/Rails reusable components (widgets) with minimum effort.
5
+
6
+ Example
7
+ =======
8
+
9
+ See the tutorials on http://blog.writelesscode.com
10
+
11
+ Copyright (c) 2008 Sergei Kozlov, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,14 @@
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 = "Build ExtJS/Rails widgets with minimum effort"
7
+ p.url = "http://writelesscode.com"
8
+ p.development_dependencies = []
9
+ p.test_pattern = 'test/**/*_test.rb'
10
+ p.retain_gemspec = true
11
+
12
+ # fixing the problem with lib/*-* files being removed while doing manifest
13
+ p.clean_pattern = ["pkg", "doc", 'build/*', '**/coverage', '**/*.o', '**/*.so', '**/*.a', '**/*.log', "{ext,lib}/*.{bundle,so,obj,pdb,lib,def,exp}", "ext/Makefile", "{ext,lib}/**/*.{bundle,so,obj,pdb,lib,def,exp}", "ext/**/Makefile", "pkg", "*.gem", ".config"]
14
+ end
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Explain the generator
3
+
4
+ Example:
5
+ ./script/generate netzke-core Thing
6
+
7
+ This will create:
8
+ what/will/it/create
@@ -0,0 +1,13 @@
1
+ # class NetzkeCoreGenerator < Rails::Generator::NamedBase
2
+ class NetzkeCoreGenerator < Rails::Generator::Base
3
+ def manifest
4
+ record do |m|
5
+ # m.directory "public/javascripts/netzke"
6
+ # m.file 'netzke.js', "public/javascripts/netzke/netzke.js"
7
+ m.file 'netzke.html.erb', "app/views/layouts/netzke.html.erb"
8
+ m.migration_template 'create_netzke_preferences.rb', "db/migrate", {:migration_file_name => "create_netzke_preferences"}
9
+ # FIXME: how do we avoid getting the same migration IDs?
10
+ m.migration_template 'create_netzke_layouts.rb', "db/migrate", {:migration_file_name => "create_netzke_layouts"}
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ class CreateNetzkeLayouts < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :netzke_layouts do |t|
4
+ t.string :widget_name
5
+ t.string :items_class
6
+ t.integer :user_id
7
+ t.timestamps
8
+ end
9
+ end
10
+
11
+ def self.down
12
+ drop_table :netzke_layouts
13
+ end
14
+ end
@@ -0,0 +1,18 @@
1
+ class CreateNetzkePreferences < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :netzke_preferences do |t|
4
+ t.string :name
5
+ t.string :pref_type
6
+ t.string :value
7
+ t.integer :user_id
8
+ t.integer :role_id
9
+ t.string :custom_field
10
+
11
+ t.timestamps
12
+ end
13
+ end
14
+
15
+ def self.down
16
+ drop_table :netzke_preferences
17
+ end
18
+ end
@@ -0,0 +1,10 @@
1
+ <head>
2
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8">
3
+ <title><%= @widget_name %></title>
4
+ <%= javascript_include_tag("/extjs/adapter/ext/ext-base.js", "/extjs/ext-all-debug.js") %>
5
+ <%= javascript_include_tag("/netzke/netzke.js") %>
6
+ <%= stylesheet_link_tag("/extjs/resources/css/ext-all.css") %>
7
+ </head>
8
+ <body id="">
9
+ <%= yield %>
10
+ </body>
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ # require 'netzke-core'
data/install.rb ADDED
@@ -0,0 +1 @@
1
+ # Install hook code here
@@ -0,0 +1,124 @@
1
+ Ext.BLANK_IMAGE_URL = "/extjs/resources/images/default/s.gif";
2
+ Ext.componentCache = {};
3
+
4
+ Ext.namespace('Ext.netzke');
5
+
6
+ // helper method to do multiple Ext.apply's
7
+ Ext.chainApply = function(objectArray){
8
+ var res = {};
9
+ Ext.each(objectArray, function(obj){Ext.apply(res, obj)});
10
+ return res;
11
+ };
12
+
13
+ // implementation of totalProperty, successProperty and root configuration options for ArrayReader
14
+ Ext.data.ArrayReader = Ext.extend(Ext.data.JsonReader, {
15
+ readRecords : function(o){
16
+ var sid = this.meta ? this.meta.id : null;
17
+ var recordType = this.recordType, fields = recordType.prototype.fields;
18
+ var records = [];
19
+ // console.info(this.meta);
20
+ var root = o[this.meta.root] || o, totalRecords = o[this.meta.totalProperty], success = o[this.meta.successProperty];
21
+ for(var i = 0; i < root.length; i++){
22
+ var n = root[i];
23
+ var values = {};
24
+ var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
25
+ for(var j = 0, jlen = fields.length; j < jlen; j++){
26
+ var f = fields.items[j];
27
+ var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
28
+ var v = n[k] !== undefined ? n[k] : f.defaultValue;
29
+ v = f.convert(v, n);
30
+ values[f.name] = v;
31
+ }
32
+ var record = new recordType(values, id);
33
+ record.json = n;
34
+ records[records.length] = record;
35
+ }
36
+ return {
37
+ records : records,
38
+ totalRecords : totalRecords,
39
+ success : success
40
+ };
41
+ }
42
+ });
43
+
44
+ // Methods common to all widget classes
45
+ Ext.widgetMixIn = {
46
+ widgetInit:function(config){
47
+ this.app = Ext.getCmp('application');
48
+ if (config.tools) Ext.each(config.tools, function(i){i.on.click = this[i.on.click].createDelegate(this)}, this);
49
+ if (config.actions) Ext.each(config.actions, function(i){i.handler = this[i.handler].createDelegate(this);}, this);
50
+ },
51
+
52
+ setEvents: function(){
53
+ this.on('beforedestroy', function(){
54
+ // clean-up menus
55
+ if (this.app && !!this.app.unhostMenus) {
56
+ // alert('beforedestroy');
57
+ this.app.unhostMenus(this)
58
+ }
59
+ }, this);
60
+
61
+ this.on('render', this.onWidgetLoad, this);
62
+ },
63
+
64
+ feedback:function(msg){
65
+ if (this.app && !!this.app.showFeedback) {
66
+ this.app.showFeedback(msg)
67
+ } else {
68
+ // there's no application to show the feedback - so, we do it ourselves
69
+ if (typeof msg == 'string'){
70
+ alert(msg)
71
+ } else {
72
+ var compoundResponse = ""
73
+ Ext.each(msg, function(m){
74
+ compoundResponse += m.msg + "\n"
75
+ })
76
+ if (compoundResponse != "") alert(compoundResponse);
77
+ }
78
+ };
79
+ },
80
+
81
+ addMenus:function(menus){
82
+ if (this.app && !!this.app.hostMenu) {
83
+ Ext.each(menus, function(menu){this.app.hostMenu(menu, this)}, this)
84
+ }
85
+ },
86
+
87
+ onWidgetLoad:Ext.emptyFn // gets overridden
88
+ };
89
+
90
+ // Make Panel with layout 'fit' capable to dynamically load widgets
91
+ Ext.override(Ext.Panel, {
92
+ getWidget: function(){
93
+ return this.items.get(0)
94
+ },
95
+
96
+ loadWidget: function(url, params){
97
+ if (!params) params = {}
98
+
99
+ this.remove(this.getWidget()); // first delete previous widget
100
+
101
+ // we will let the server know which components we have cached
102
+ var cachedComponentNames = [];
103
+ for (name in Ext.componentCache) {
104
+ cachedComponentNames.push(name);
105
+ }
106
+
107
+ this.disable(); // to visually emphasize loading
108
+
109
+ Ext.Ajax.request(
110
+ {url:url, params:Ext.apply(params, {components_cache:Ext.encode(cachedComponentNames)}), script:false, callback:function(panel, success, response){
111
+ var response = Ext.decode(response.responseText);
112
+ if (response['classDefinition']) eval(response['classDefinition']); // evaluate widget's class if it was sent
113
+
114
+ response.config.parent = this // we might want to know the parent panel in advance (e.g. to know its size)
115
+ var instance = new Ext.componentCache[response.config.widgetClassName](response.config)
116
+
117
+ this.add(instance);
118
+ this.doLayout();
119
+ this.enable();
120
+ }, scope:this}
121
+ )
122
+
123
+ }
124
+ });
@@ -0,0 +1,16 @@
1
+ class NetzkeController < ActionController::Base
2
+
3
+ # collect javascripts from all plugins that registered it in Netzke::Base.config[:javascripts]
4
+ def netzke
5
+ respond_to do |format|
6
+ format.js {
7
+ res = ""
8
+ Netzke::Base.config[:javascripts].each do |path|
9
+ f = File.new(path)
10
+ res << f.read
11
+ end
12
+ render :text => res
13
+ }
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,75 @@
1
+ class NetzkeLayout < ActiveRecord::Base
2
+ # has_many :layout_items#, :class_name => "ExtWidget::LayoutItem", :order => :position
3
+ # has_many :objects, :class_name => "Objects", :foreign_key => "class_name_id"
4
+ # belongs_to :role
5
+ # belongs_to :user
6
+
7
+ UNRELATED_ATTRS = %w(created_at updated_at position layout_id)
8
+
9
+ def self.user_id
10
+ @@user_id ||= nil
11
+ end
12
+
13
+ def layout_items
14
+ items_class.constantize.find_all_by_layout_id(id, :order => 'position')
15
+ end
16
+
17
+ #
18
+ # def self.user_id=(user_id)
19
+ # @@user_id = user_id
20
+ # end
21
+ #
22
+ # def self.layout_items(widget_name)
23
+ # layout = self.layout(widget_name)
24
+ # layout.nil? ? nil : layout.layout_items.map(&:attributes).map{|item| item.delete_if{|k,v| UNRELATED_ATTRS.include?(k)}}
25
+ # end
26
+ #
27
+ def self.by_widget(widget_name)
28
+ self.find(:first, :conditions => {:widget_name => widget_name, :user_id => self.user_id})
29
+ end
30
+
31
+ def move_item(old_index, new_index)
32
+ layout_item = layout_items[old_index]
33
+ layout_item.remove_from_list
34
+ layout_item.insert_at(new_index + 1)
35
+ end
36
+
37
+ # def self.layout_items(widget_name)
38
+ # layout = self.by_widget(widget_name)
39
+ # if layout
40
+ # layout.layout_items
41
+ # else
42
+ # # create new layout and fill it out with default values
43
+ # layout = Layout.create({:widget_name => widget_name, :user_id => self.user_id})
44
+ # end
45
+ # end
46
+
47
+ def items_hash
48
+ layout_items.map(&:attributes).map{|item| item.delete_if{|k,v| UNRELATED_ATTRS.include?(k)}}.map{ |i| i.convert_keys{ |k| k.to_sym } }
49
+ end
50
+
51
+ # if layout items are provided, use them instead of defaults (exsposed) layout items, but merge their configs with the default
52
+ # def self.create_layout_for_widget(widget_name, data_class_name, layout_item_class_name, items = nil)
53
+ # layout = self.create(:widget_name => widget_name, :items_class => layout_item_class_name, :user_id => self.user_id)
54
+ # data_class = data_class_name.constantize
55
+ # layout_item_class = layout_item_class_name.constantize
56
+ #
57
+ #
58
+ # if items.nil?
59
+ # complete_items = data_class.exposed_columns
60
+ # else
61
+ # # normalize columns
62
+ # columns = columns.
63
+ # default_columns = data_class.exposed_columns.map{|c| c.is_a?(Symbol) ? {:name => c} : c}
64
+ # columns.each
65
+ #
66
+ # complete_columns = columns.nil? ? : columns
67
+ # complete_columns.each do |c|
68
+ # config = c.is_a?(Hash) ? c : {:name => c}
69
+ # # we have to merge layout_id in order to have :position set up properly
70
+ # item = layout_item_class.create_with_defaults(config.merge({:layout_id => layout.id}), data_class)
71
+ # end
72
+ # layout
73
+ # end
74
+
75
+ end
@@ -0,0 +1,66 @@
1
+ class NetzkePreference < ActiveRecord::Base
2
+ CONVERTION_METHODS= {'Fixnum' => 'to_i', 'String' => 'to_s', 'Float' => 'to_f', 'Symbol' => 'to_sym'}
3
+
4
+ def self.user=(user)
5
+ @@user = user
6
+ end
7
+
8
+ def self.user
9
+ @@user ||= nil
10
+ end
11
+
12
+ def self.custom_field=(value)
13
+ @@custom_field = value
14
+ end
15
+
16
+ def self.custom_field
17
+ @@custom_field ||= nil
18
+ end
19
+
20
+ def normalized_value
21
+ klass = read_attribute(:pref_type)
22
+ norm_value = read_attribute(:value)
23
+ if klass.nil?
24
+ # do not cast
25
+ r = norm_value
26
+ elsif klass == 'Boolean'
27
+ r = norm_value == 'false' ? false : (norm_value == 'true' || norm_value)
28
+ elsif klass == 'NilClass'
29
+ r = nil
30
+ elsif klass == 'Array'
31
+ r = JSON.parse(norm_value)
32
+ else
33
+ r = norm_value.send(CONVERTION_METHODS[klass])
34
+ end
35
+ r
36
+ end
37
+
38
+ def normalized_value=(new_value)
39
+ # norm_value = (new_value.to_s if new_value == true or new_value == false) || new_value
40
+ case new_value.class.to_s
41
+ when "Array"
42
+ write_attribute(:value, new_value.to_json)
43
+ else
44
+ write_attribute(:value, new_value.to_s)
45
+ end
46
+ write_attribute(:pref_type, [TrueClass, FalseClass].include?(new_value.class) ? 'Boolean' : new_value.class.to_s)
47
+ end
48
+
49
+ def self.[](pref_name)
50
+ pref_name = pref_name.to_s
51
+ conditions = {:name => pref_name, :user_id => self.user, :custom_field => self.custom_field}
52
+ pref = self.find(:first, :conditions => conditions)
53
+ # pref = @@user.nil? ? self.find_by_name(pref_name) : self.find_by_name_and_user_id(pref_name, @@user.id)
54
+ pref && pref.normalized_value
55
+ end
56
+
57
+ def self.[]=(pref_name, new_value)
58
+ pref_name = pref_name.to_s
59
+ conditions = {:name => pref_name, :user_id => self.user, :custom_field => self.custom_field}
60
+ pref = self.find(:first, :conditions => conditions) || self.create(conditions)
61
+ # pref = self.user.nil? ? self.find_or_create_by_name(pref_name) : self.find_or_create_by_name_and_user_id(pref_name, self.user.id)
62
+ pref.normalized_value = new_value
63
+ pref.save!
64
+ end
65
+
66
+ end