netzke-core 0.3.1 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +1 -0
- data/.gitignore +4 -0
- data/CHANGELOG +21 -0
- data/Manifest +9 -11
- data/README.rdoc +12 -0
- data/Rakefile +17 -13
- data/TODO +2 -1
- data/VERSION +1 -0
- data/generators/netzke_core/templates/create_netzke_preferences.rb +1 -1
- data/javascripts/core.js +271 -113
- data/lib/app/controllers/netzke_controller.rb +66 -9
- data/lib/app/models/netzke_preference.rb +39 -32
- data/lib/netzke-core.rb +0 -3
- data/lib/netzke/base.rb +318 -140
- data/lib/netzke/base_js.rb +249 -0
- data/lib/netzke/controller_extensions.rb +29 -40
- data/lib/netzke/core_ext.rb +40 -18
- data/lib/netzke/feedback_ghost.rb +2 -2
- data/netzke-core.gemspec +90 -11
- data/test/unit/core_ext_test.rb +28 -7
- data/test/unit/netzke_core_test.rb +57 -29
- data/test/unit/netzke_preference_test.rb +7 -7
- metadata +35 -38
- data/README.mdown +0 -15
- data/lib/netzke/base_extras/interface.rb +0 -20
- data/lib/netzke/base_extras/js_builder.rb +0 -271
- data/lib/vendor/facets/hash/recursive_merge.rb +0 -28
data/README.mdown
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
# netzke-core
|
2
|
-
Create Ext JS + Rails reusable components (widgets) with minimum effort.
|
3
|
-
|
4
|
-
Note that if you would like to modify this code or experiment with it, you may be better off cloning this project into your app's vendor/plugin directory - it will then behave as a Rails plugin.
|
5
|
-
|
6
|
-
# Example
|
7
|
-
See the introduction to the Netzke framework at http://github.com/skozlov/netzke/tree/master
|
8
|
-
|
9
|
-
The tutorials: http://blog.writelesscode.com
|
10
|
-
|
11
|
-
Live-demo: http://netzke-demo.writelesscode.com
|
12
|
-
|
13
|
-
Also see the netzke-basepack project: http://github.com/skozlov/netzke-basepack/tree/master
|
14
|
-
|
15
|
-
Copyright (c) 2008-2009 Sergei Kozlov, released under LGPL 3.0
|
@@ -1,20 +0,0 @@
|
|
1
|
-
module Netzke
|
2
|
-
module BaseExtras
|
3
|
-
module Interface
|
4
|
-
def get_widget(params = {})
|
5
|
-
components_cache = (ActiveSupport::JSON.decode(params[:components_cache]) if params[:components_cache]) || []
|
6
|
-
|
7
|
-
js = js_missing_code(components_cache)
|
8
|
-
css = css_missing_code(components_cache)
|
9
|
-
|
10
|
-
css = nil if css.blank?
|
11
|
-
|
12
|
-
# if browser does not have our widget's (and all its dependencies') class and styles, send it over
|
13
|
-
{ :config => js_config,
|
14
|
-
:js => js,
|
15
|
-
:css => css
|
16
|
-
}
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,271 +0,0 @@
|
|
1
|
-
module Netzke
|
2
|
-
module BaseExtras
|
3
|
-
#
|
4
|
-
# Module which provides JS-class generation functionality for the widgets ("client-side"). This code is executed only once per widget class, and the results are cached at the server.
|
5
|
-
# Included into Netzke::Base class.
|
6
|
-
# Most of the methods below are meant to be overwritten.
|
7
|
-
#
|
8
|
-
module JsBuilder
|
9
|
-
def self.included(base)
|
10
|
-
base.extend ClassMethods
|
11
|
-
end
|
12
|
-
|
13
|
-
#
|
14
|
-
# Instance methods
|
15
|
-
#
|
16
|
-
|
17
|
-
# The config that is sent from the server and is used for instantiating a widget
|
18
|
-
def js_config
|
19
|
-
res = {}
|
20
|
-
|
21
|
-
# Unique id of the widget
|
22
|
-
res.merge!(:id => @id_name)
|
23
|
-
|
24
|
-
# Recursively include configs of all non-late aggregatees, so that the widget can instantiate them in
|
25
|
-
# in the browser immediately.
|
26
|
-
aggregatees.each_pair do |aggr_name, aggr_config|
|
27
|
-
next if aggr_config[:late_aggregation]
|
28
|
-
res["#{aggr_name}_config".to_sym] = aggregatee_instance(aggr_name.to_sym).js_config
|
29
|
-
end
|
30
|
-
|
31
|
-
# Interface
|
32
|
-
interface = self.class.interface_points.inject({}){|h,interfacep| h.merge(interfacep => widget_action(interfacep))}
|
33
|
-
res.merge!(:interface => interface)
|
34
|
-
|
35
|
-
# Widget class name
|
36
|
-
res.merge!(:widget_class_name => short_widget_class_name)
|
37
|
-
|
38
|
-
# Include
|
39
|
-
res.merge!(js_ext_config)
|
40
|
-
|
41
|
-
# Actions, toolbars and menus
|
42
|
-
tools && res.merge!(:tools => tools)
|
43
|
-
actions && res.merge!(:actions => actions)
|
44
|
-
tbar && res.merge!(:tbar => tbar)
|
45
|
-
bbar && res.merge!(:bbar => bbar)
|
46
|
-
menu && res.merge!(:menu => menu)
|
47
|
-
|
48
|
-
# Permissions
|
49
|
-
res.merge!(:permissions => permissions) unless available_permissions.empty?
|
50
|
-
|
51
|
-
res
|
52
|
-
end
|
53
|
-
|
54
|
-
def js_ext_config
|
55
|
-
config[:ext_config] || {}
|
56
|
-
end
|
57
|
-
|
58
|
-
# All the JS-code required by this instance of the widget to be instantiated in the browser.
|
59
|
-
# It includes the JS-class for the widget itself, as well as JS-classes for all widgets' (non-late) aggregatees.
|
60
|
-
def js_missing_code(cached_dependencies = [])
|
61
|
-
dependency_classes.inject("") do |r,k|
|
62
|
-
cached_dependencies.include?(k) ? r : r + "Netzke::#{k}".constantize.js_code(cached_dependencies).strip_js_comments
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def css_missing_code(cached_dependencies = [])
|
67
|
-
dependency_classes.inject("") do |r,k|
|
68
|
-
cached_dependencies.include?(k) ? r : r + "Netzke::#{k}".constantize.css_code(cached_dependencies)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
#
|
73
|
-
# The following methods are used when a widget is generated stand-alone (as a part of a HTML page)
|
74
|
-
#
|
75
|
-
|
76
|
-
# instantiating
|
77
|
-
def js_widget_instance
|
78
|
-
%Q{var #{config[:name].to_js} = new Ext.netzke.cache.#{short_widget_class_name}(#{js_config.to_js});}
|
79
|
-
end
|
80
|
-
|
81
|
-
# rendering
|
82
|
-
def js_widget_render
|
83
|
-
%Q{#{config[:name].to_js}.render("#{config[:name].to_s.split('_').join('-')}");}
|
84
|
-
end
|
85
|
-
|
86
|
-
# container for rendering
|
87
|
-
def js_widget_html
|
88
|
-
%Q{<div id="#{config[:name].to_s.split('_').join('-')}"></div>}
|
89
|
-
end
|
90
|
-
|
91
|
-
#
|
92
|
-
#
|
93
|
-
#
|
94
|
-
|
95
|
-
# widget's actions, tools and toolbars that are loaded at the moment of instantiating a widget
|
96
|
-
def actions; nil; end
|
97
|
-
def tbar; nil; end
|
98
|
-
def bbar; nil; end
|
99
|
-
def menu; nil; end
|
100
|
-
def tools; nil; end
|
101
|
-
|
102
|
-
# little helpers
|
103
|
-
def this; "this".l; end
|
104
|
-
def null; "null".l; end
|
105
|
-
|
106
|
-
|
107
|
-
# Methods used to create the javascript class (only once per widget class).
|
108
|
-
# The generated code gets cached at the browser, and the widget intstances (at the browser side)
|
109
|
-
# get instantiated from it.
|
110
|
-
# All these methods can be overwritten in case you want to extend the functionality of some pre-built widget
|
111
|
-
# instead of using it as is (using both would cause JS-code duplication)
|
112
|
-
module ClassMethods
|
113
|
-
# the JS (Ext) class that we inherit from on JS-level
|
114
|
-
def js_base_class; "Ext.Panel"; end
|
115
|
-
|
116
|
-
# default config that gets merged with Base#js_config
|
117
|
-
def js_default_config
|
118
|
-
{
|
119
|
-
# :header => user_has_role?(:configurator) ? true : nil,
|
120
|
-
:title => "config.id.humanize()".l,
|
121
|
-
:listeners => js_listeners,
|
122
|
-
:tools => "config.tools".l,
|
123
|
-
:actions => "config.actions".l,
|
124
|
-
:tbar => "config.tbar".l,
|
125
|
-
:bbar => "config.bbar".l,
|
126
|
-
# :items => "config.items".l,
|
127
|
-
# :items => js_items,
|
128
|
-
:height => 400,
|
129
|
-
:width => 800,
|
130
|
-
:border => false,
|
131
|
-
:is_netzke => true # to distinguish a Netzke widget from regular Ext components
|
132
|
-
}
|
133
|
-
end
|
134
|
-
|
135
|
-
# functions and properties that will be used to extend the functionality of (Ext) JS-class specified in js_base_class
|
136
|
-
def js_extend_properties; {}; end
|
137
|
-
|
138
|
-
# code executed before and after the constructor
|
139
|
-
def js_before_constructor; ""; end
|
140
|
-
def js_after_constructor; ""; end
|
141
|
-
|
142
|
-
# widget's listeners
|
143
|
-
def js_listeners; {}; end
|
144
|
-
|
145
|
-
# widget's menus
|
146
|
-
def js_menus; []; end
|
147
|
-
|
148
|
-
# items
|
149
|
-
def js_items; null; end
|
150
|
-
|
151
|
-
# are we using JS inheritance? for now, if js_base_class is a Netzke class - yes
|
152
|
-
def js_inheritance
|
153
|
-
js_base_class.is_a?(Class)
|
154
|
-
end
|
155
|
-
|
156
|
-
# Declaration of widget's class (stored in the cache storage (Ext.netzke.cache) at the client side
|
157
|
-
# to be reused at the moment of widget instantiation)
|
158
|
-
def js_class
|
159
|
-
if js_inheritance
|
160
|
-
<<-JS
|
161
|
-
Ext.netzke.cache.#{short_widget_class_name} = function(config){
|
162
|
-
Ext.netzke.cache.#{short_widget_class_name}.superclass.constructor.call(this, config);
|
163
|
-
};
|
164
|
-
Ext.extend(Ext.netzke.cache.#{short_widget_class_name}, Ext.netzke.cache.#{js_base_class.short_widget_class_name}, Ext.applyIf(#{js_extend_properties.to_js}, Ext.widgetMixIn));
|
165
|
-
|
166
|
-
JS
|
167
|
-
else
|
168
|
-
js_add_menus = "this.addMenus(#{js_menus.to_js});" unless js_menus.empty?
|
169
|
-
<<-JS
|
170
|
-
Ext.netzke.cache.#{short_widget_class_name} = function(config){
|
171
|
-
this.beforeConstructor(config);
|
172
|
-
#{js_before_constructor}
|
173
|
-
Ext.netzke.cache.#{short_widget_class_name}.superclass.constructor.call(this, Ext.apply(#{js_default_config.to_js}, config));
|
174
|
-
this.afterConstructor(config);
|
175
|
-
#{js_after_constructor}
|
176
|
-
#{js_add_menus}
|
177
|
-
};
|
178
|
-
Ext.extend(Ext.netzke.cache.#{short_widget_class_name}, #{js_base_class}, Ext.applyIf(#{js_extend_properties.to_js}, Ext.widgetMixIn));
|
179
|
-
JS
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
#
|
184
|
-
# Include extra code from Ext js library (e.g. examples)
|
185
|
-
#
|
186
|
-
def ext_js_include(*args)
|
187
|
-
included_ext_js = read_inheritable_attribute(:included_ext_js) || []
|
188
|
-
args.each {|f| included_ext_js << f}
|
189
|
-
write_inheritable_attribute(:included_ext_js, included_ext_js)
|
190
|
-
end
|
191
|
-
|
192
|
-
#
|
193
|
-
# Include extra Javascript code. This code will be loaded along with the widget's class and in front of it.
|
194
|
-
#
|
195
|
-
# Example usage:
|
196
|
-
# js_include "File.dirname(__FILE__)/form_panel_extras/javascripts/xdatetime.js",
|
197
|
-
# :ext_examples => ["grid-filtering/menu/EditableItem.js", "grid-filtering/menu/RangeMenu.js"],
|
198
|
-
# "File.dirname(__FILE__)/form_panel_extras/javascripts/xcheckbox.js"
|
199
|
-
#
|
200
|
-
def js_include(*args)
|
201
|
-
included_js = read_inheritable_attribute(:included_js) || []
|
202
|
-
args.each do |inclusion|
|
203
|
-
if inclusion.is_a?(Hash)
|
204
|
-
# we are signalized a non-default file location (e.g. Ext examples)
|
205
|
-
case inclusion.keys.first
|
206
|
-
when :ext_examples
|
207
|
-
location = Netzke::Base.config[:ext_location] + "/examples/"
|
208
|
-
end
|
209
|
-
files = inclusion.values.first
|
210
|
-
else
|
211
|
-
location = ""
|
212
|
-
files = inclusion
|
213
|
-
end
|
214
|
-
|
215
|
-
files = [files] if files.is_a?(String)
|
216
|
-
|
217
|
-
for f in files
|
218
|
-
included_js << location + f
|
219
|
-
end
|
220
|
-
end
|
221
|
-
write_inheritable_attribute(:included_js, included_js)
|
222
|
-
end
|
223
|
-
|
224
|
-
# returns all extra js-code (as string) required by this widget's class
|
225
|
-
def js_included
|
226
|
-
res = ""
|
227
|
-
|
228
|
-
included_js = read_inheritable_attribute(:included_js) || []
|
229
|
-
res << included_js.inject("") do |r, path|
|
230
|
-
f = File.new(path)
|
231
|
-
r << f.read
|
232
|
-
end
|
233
|
-
|
234
|
-
res
|
235
|
-
end
|
236
|
-
|
237
|
-
# all JS code needed for this class, including one from the ancestor widget
|
238
|
-
def js_code(cached_dependencies = [])
|
239
|
-
res = ""
|
240
|
-
|
241
|
-
# include the base-class javascript if doing JS inheritance
|
242
|
-
res << js_base_class.js_code << "\n" if js_inheritance && !cached_dependencies.include?(js_base_class.short_widget_class_name)
|
243
|
-
|
244
|
-
# include static javascripts
|
245
|
-
res << js_included << "\n"
|
246
|
-
|
247
|
-
# our own JS class definition
|
248
|
-
res << js_class
|
249
|
-
res
|
250
|
-
end
|
251
|
-
|
252
|
-
# all JS code needed for this class including the one from the ancestor widget
|
253
|
-
def css_code(cached_dependencies = [])
|
254
|
-
res = ""
|
255
|
-
|
256
|
-
# include the base-class javascript if doing JS inheritance
|
257
|
-
res << js_base_class.css_code << "\n" if js_inheritance && !cached_dependencies.include?(js_base_class.short_widget_class_name)
|
258
|
-
|
259
|
-
# res << css_included << "\n"
|
260
|
-
|
261
|
-
res
|
262
|
-
end
|
263
|
-
|
264
|
-
def this; "this".l; end
|
265
|
-
def null; "null".l; end
|
266
|
-
|
267
|
-
end
|
268
|
-
|
269
|
-
end
|
270
|
-
end
|
271
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
class Hash
|
2
|
-
# Same as Hash#merge but recursively merges sub-hashes.
|
3
|
-
def recursive_merge(other)
|
4
|
-
hash = self.dup
|
5
|
-
other.each do |key, value|
|
6
|
-
myval = self[key]
|
7
|
-
if value.is_a?(Hash) && myval.is_a?(Hash)
|
8
|
-
hash[key] = myval.recursive_merge(value)
|
9
|
-
else
|
10
|
-
hash[key] = value
|
11
|
-
end
|
12
|
-
end
|
13
|
-
hash
|
14
|
-
end
|
15
|
-
|
16
|
-
# Same as Hash#merge! but recursively merges sub-hashes.
|
17
|
-
def recursive_merge!(other)
|
18
|
-
other.each do |key, value|
|
19
|
-
myval = self[key]
|
20
|
-
if value.is_a?(Hash) && myval.is_a?(Hash)
|
21
|
-
myval.recursive_merge!(value)
|
22
|
-
else
|
23
|
-
self[key] = value
|
24
|
-
end
|
25
|
-
end
|
26
|
-
self
|
27
|
-
end
|
28
|
-
end
|