netzke-core 0.4.5.2 → 0.5.0
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.
- data/CHANGELOG.rdoc +12 -0
- data/README.rdoc +33 -8
- data/Rakefile +1 -1
- data/javascripts/core.js +85 -21
- data/lib/app/controllers/netzke_controller.rb +13 -63
- data/lib/netzke/action_view_ext.rb +49 -12
- data/lib/netzke/base.rb +24 -16
- data/lib/netzke/base_js.rb +35 -11
- data/lib/netzke/controller_extensions.rb +0 -108
- metadata +3 -2
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
= v0.5.0
|
2
|
+
* Compatibility with Ext 3.1.0
|
3
|
+
* API change: Netzke widget's now should be declared directly in the views instead of controllers.
|
4
|
+
* API change: all ExtJS and Netzke JavaScript and styles are now loaded with the help of <tt>netzke_init</tt> helper.
|
5
|
+
* API change: <tt>persistence_key</tt> option replaces <tt>persistent_config_id</tt> option.
|
6
|
+
* Impr: headers in panels in the "config" mode now show the widget's global ID.
|
7
|
+
* New: required ExtJS version check introduced at initial Netzke load.
|
8
|
+
* Depr: :widget_class_name option is deprecated, use :class_name.
|
9
|
+
* DRY: now there's no need to always define "actions" method, use it to override the defaults, which are automatically calculated based on configuration for toolbars/menu.
|
10
|
+
* Impr: each generated JS class now has its unique xtype, e.g. "netzkegridpanel".
|
11
|
+
* Fix: FeedbackGhost moved over from netzke-basepack.
|
12
|
+
|
1
13
|
= v0.4.5.2 - 2009-11-09
|
2
14
|
* Fix: Hash#convert_keys and Array#convert_keys in core extensions are now renamed into deep_convert_keys, and now always plainly do what they're expected to do: recursively convert keys according to given block.
|
3
15
|
|
data/README.rdoc
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
= netzke-core
|
2
2
|
Create Ext JS + Rails reusable components (widgets) with minimum effort.
|
3
3
|
|
4
|
-
This is the bare bones of the Netzke framework. Use it to build your own widgets from scratch. For pre-built widgets (like panels, grids, forms, trees, applications), see the netzke-basepack project.
|
4
|
+
This is the bare bones of the Netzke framework. Use it to build your own widgets from scratch. For pre-built widgets (like panels, grids, forms, trees, applications), see the netzke-basepack (http://github.com/skozlov/netzke-basepack) project.
|
5
5
|
|
6
6
|
The idea behind the Netzke framework is that it allows you write reusable client/server code. Create a widget, and then embed it (or load it dynamically) into your Ext-based applications or HTML pages. For more info, see the links below.
|
7
7
|
|
8
8
|
== Instalation
|
9
|
-
|
9
|
+
For the latest ("edge") stuff, install as plugin (recommended!):
|
10
|
+
|
11
|
+
./script/plugin install git://github.com/skozlov/netzke-core.git
|
12
|
+
|
13
|
+
Otherwise, install as gem. The gem is hosted on gemcutter. If you haven't yet enabled gemcutter, run the following:
|
10
14
|
|
11
15
|
sudo gem install gemcutter && gem tumble
|
12
16
|
|
@@ -14,17 +18,38 @@ Install the gem
|
|
14
18
|
|
15
19
|
sudo gem install netzke-core
|
16
20
|
|
17
|
-
|
21
|
+
Generate the migrations for Netzke persistent storage:
|
18
22
|
|
19
|
-
script/
|
23
|
+
./script/generate netzke_core
|
20
24
|
|
25
|
+
Run the migrations.
|
26
|
+
|
27
|
+
Netzke assumes that your ExtJS library is in public/extjs (which may be a symbolic link).
|
28
|
+
|
21
29
|
== Usage
|
22
|
-
|
30
|
+
Here's how to embed a Netzke widget into your Rails view.
|
31
|
+
|
32
|
+
1. In your layout, within the "head" tag, use the <tt>netzke_init</tt> helper to include all the necessary JavaScript and styles.
|
33
|
+
|
34
|
+
<%= netzke_init %>
|
35
|
+
|
36
|
+
2. In your view use the <tt>netzke</tt> helper wherever you want to insert a widget.
|
37
|
+
|
38
|
+
<%= netzke :grid_panel, :data_class_name => "User", :columns => [:id, :name, :created_at] %>
|
39
|
+
|
40
|
+
(here we use the GridPanel widget from the netzke-basepack project)
|
41
|
+
|
42
|
+
== More info
|
43
|
+
Introduction to Netzke framework and wiki: http://github.com/skozlov/netzke
|
44
|
+
|
45
|
+
Twitter: <http://twitter.com/skozlov>
|
46
|
+
|
47
|
+
Tutorials: <http://blog.writelesscode.com>
|
23
48
|
|
24
|
-
|
49
|
+
Live-demo: <http://netzke-demo.writelesscode.com>
|
25
50
|
|
26
|
-
|
51
|
+
The netzke-basepack project (pre-built full-featured widgets): <http://github.com/skozlov/netzke-basepack>
|
27
52
|
|
28
|
-
|
53
|
+
---
|
29
54
|
|
30
55
|
Copyright (c) 2009 Sergei Kozlov, released under the MIT license
|
data/Rakefile
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
begin
|
2
2
|
require 'jeweler'
|
3
3
|
Jeweler::Tasks.new do |gemspec|
|
4
|
-
gemspec.version = "0.
|
4
|
+
gemspec.version = "0.5.0"
|
5
5
|
gemspec.name = "netzke-core"
|
6
6
|
gemspec.summary = "Build ExtJS/Rails widgets with minimum effort"
|
7
7
|
gemspec.description = "Allows building ExtJS/Rails reusable code in a DRY way"
|
data/javascripts/core.js
CHANGED
@@ -2,18 +2,20 @@
|
|
2
2
|
This file gets loaded along with the rest of Ext library at the initial load
|
3
3
|
*/
|
4
4
|
|
5
|
+
// Check Ext JS version
|
6
|
+
var requiredExtVersion = "3.1.0";
|
7
|
+
var currentExtVersion = Ext.version;
|
8
|
+
if (requiredExtVersion !== currentExtVersion) {
|
9
|
+
alert("Netzke needs Ext " + requiredExtVersion + ". You have " + currentExtVersion + ".");
|
10
|
+
}
|
11
|
+
|
12
|
+
// Initial stuff
|
5
13
|
Ext.BLANK_IMAGE_URL = "/extjs/resources/images/default/s.gif";
|
6
14
|
Ext.ns('Ext.netzke'); // namespace for extensions that depend on Ext
|
7
15
|
Ext.ns('Netzke'); // Netzke namespace
|
8
|
-
Netzke.cache = {}; // empty Netzke cache at the moment of loading
|
9
16
|
|
10
17
|
Ext.QuickTips.init();
|
11
18
|
|
12
|
-
// To comply with Rails' forgery protection
|
13
|
-
Ext.Ajax.extraParams = {
|
14
|
-
authenticity_token : Ext.authenticityToken
|
15
|
-
};
|
16
|
-
|
17
19
|
// Type detection functions
|
18
20
|
Netzke.isObject = function(o) {
|
19
21
|
return (o != null && typeof o == "object" && o.constructor.toString() == Object.toString());
|
@@ -100,10 +102,33 @@ Ext.widgetMixIn = {
|
|
100
102
|
|
101
103
|
// build the cached widgets list to send it to the server
|
102
104
|
var cachedWidgetNames = "";
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
105
|
+
|
106
|
+
// recursive function that checks the properties of the caller ("this") and returns the list of those that look like constructor, i.e. have an "xtype" property themselves
|
107
|
+
var classesList = function(pref){
|
108
|
+
var res = [];
|
109
|
+
for (name in this) {
|
110
|
+
if (this[name].xtype) {
|
111
|
+
res.push(pref + name);
|
112
|
+
this[name].classesList = classesList; // define the same function on each property on the fly
|
113
|
+
res = res.concat(this[name].classesList(pref + name + ".")); // ... and call it, providing our name along with the scope
|
114
|
+
}
|
115
|
+
}
|
116
|
+
return res;
|
117
|
+
};
|
118
|
+
|
119
|
+
// assign this function to Netzke.classes and call it
|
120
|
+
Netzke.classes.classesList = classesList;
|
121
|
+
var cl = Netzke.classes.classesList("");
|
122
|
+
|
123
|
+
// join the classes into a coma-separated list
|
124
|
+
var cache = "";
|
125
|
+
Ext.each(cl, function(c){cache += c + ",";});
|
126
|
+
|
127
|
+
// for (name in Netzke.classes) {
|
128
|
+
// cachedWidgetNames += name + ",";
|
129
|
+
// }
|
130
|
+
// apiParams.cache = cachedWidgetNames;
|
131
|
+
apiParams.cache = cache;
|
107
132
|
|
108
133
|
// remember the passed callback for the future
|
109
134
|
if (params.callback) {
|
@@ -291,13 +316,18 @@ Ext.widgetMixIn = {
|
|
291
316
|
}
|
292
317
|
},
|
293
318
|
|
319
|
+
// Returns API url based on provided API point
|
320
|
+
buildApiUrl: function(apip){
|
321
|
+
return "/netzke/" + this.id + "__" + apip;
|
322
|
+
},
|
323
|
+
|
294
324
|
// Does the call to the server and processes the response
|
295
325
|
callServer : function(intp, params, callback, scope){
|
296
326
|
if (!params) params = {};
|
297
|
-
|
298
|
-
params
|
299
|
-
url
|
300
|
-
callback
|
327
|
+
Ext.Ajax.request({
|
328
|
+
params: params,
|
329
|
+
url: this.buildApiUrl(intp),
|
330
|
+
callback: function(options, success, response){
|
301
331
|
if (success) {
|
302
332
|
// execute commands from server
|
303
333
|
this.bulkExecute(Ext.decode(response.responseText));
|
@@ -404,11 +434,15 @@ Ext.widgetMixIn = {
|
|
404
434
|
}
|
405
435
|
|
406
436
|
// Set title
|
407
|
-
if (
|
408
|
-
config.title
|
437
|
+
if (config.mode === "config"){
|
438
|
+
if (!config.title) {
|
439
|
+
config.title = '[' + config.id + ']';
|
440
|
+
} else {
|
441
|
+
config.title = config.title + ' [' + config.id + ']';
|
442
|
+
}
|
409
443
|
} else {
|
410
|
-
if (config.
|
411
|
-
config.title = config.
|
444
|
+
if (!config.title) {
|
445
|
+
config.title = config.id.humanize();
|
412
446
|
}
|
413
447
|
}
|
414
448
|
},
|
@@ -525,8 +559,6 @@ Ext.override(Ext.Container, {
|
|
525
559
|
Ext.each(n.split("."), function(s){
|
526
560
|
klass = klass[s];
|
527
561
|
});
|
528
|
-
// Caching the class
|
529
|
-
Netzke.cache[n] = true;
|
530
562
|
return klass;
|
531
563
|
},
|
532
564
|
|
@@ -542,4 +574,36 @@ Ext.override(Ext.Container, {
|
|
542
574
|
this.doLayout();
|
543
575
|
}
|
544
576
|
}
|
545
|
-
});
|
577
|
+
});
|
578
|
+
|
579
|
+
|
580
|
+
// Feedback Ghost
|
581
|
+
Netzke.FeedbackGhost = function(){};
|
582
|
+
Ext.apply(Netzke.FeedbackGhost.prototype, {
|
583
|
+
showFeedback: function(msg){
|
584
|
+
var createBox = function(s, l){
|
585
|
+
return ['<div class="msg">',
|
586
|
+
'<div class="x-box-tl"><div class="x-box-tr"><div class="x-box-tc"></div></div></div>',
|
587
|
+
'<div class="x-box-ml"><div class="x-box-mr"><div class="x-box-mc">', s, '</div></div></div>',
|
588
|
+
'<div class="x-box-bl"><div class="x-box-br"><div class="x-box-bc"></div></div></div>',
|
589
|
+
'</div>'].join('');
|
590
|
+
}
|
591
|
+
|
592
|
+
var showBox = function(msg, lvl){
|
593
|
+
if (!lvl) {lvl = 'notice'};
|
594
|
+
var msgCt = Ext.DomHelper.insertFirst(document.body, {'class':'netzke-feedback'}, true);
|
595
|
+
var m = Ext.DomHelper.append(msgCt, {html:createBox(msg,lvl)}, true);
|
596
|
+
m.slideIn('t').pause(2).ghost("b", {remove:true});
|
597
|
+
}
|
598
|
+
|
599
|
+
if (typeof msg != 'string') {
|
600
|
+
var compoundMsg = "";
|
601
|
+
Ext.each(msg, function(m){
|
602
|
+
compoundMsg += m.msg + '<br>';
|
603
|
+
});
|
604
|
+
if (compoundMsg != "") showBox(compoundMsg, null); // the second parameter will be level
|
605
|
+
} else {
|
606
|
+
showBox(msg);
|
607
|
+
}
|
608
|
+
}
|
609
|
+
});
|
@@ -1,5 +1,4 @@
|
|
1
|
-
class NetzkeController <
|
2
|
-
|
1
|
+
class NetzkeController < ApplicationController
|
3
2
|
def index
|
4
3
|
redirect_to :action => :test_widgets
|
5
4
|
end
|
@@ -27,68 +26,19 @@ class NetzkeController < ActionController::Base
|
|
27
26
|
end
|
28
27
|
end
|
29
28
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
# FormPanel
|
35
|
-
netzke :form_panel, :persistent_config => false, :label_align => "top", :columns => [
|
36
|
-
{:name => 'field_one', :xtype => 'textarea'},
|
37
|
-
{:name => 'field_two', :xtype => 'textarea'}
|
38
|
-
]
|
39
|
-
|
40
|
-
# BorderLayoutPanel
|
41
|
-
netzke :border_layout_panel, :regions => {
|
42
|
-
:west => {
|
43
|
-
:widget_class_name => "Panel",
|
44
|
-
:region_config => {:width => 300, :split => true}
|
45
|
-
},
|
46
|
-
:center => {
|
47
|
-
:widget_class_name => "Panel"
|
48
|
-
}
|
49
|
-
}
|
50
|
-
|
51
|
-
# TabPanel
|
52
|
-
netzke :tab_panel, :items => [{
|
53
|
-
:widget_class_name => "Panel",
|
54
|
-
:ext_config => {
|
55
|
-
:html => "Panel 1",
|
56
|
-
},
|
57
|
-
# :active => true
|
58
|
-
},{
|
59
|
-
:widget_class_name => "Panel",
|
60
|
-
:ext_config => {
|
61
|
-
:html => "Panel 2",
|
62
|
-
}
|
63
|
-
}]
|
64
|
-
|
65
|
-
# AccordionPanel
|
66
|
-
netzke :accordion_panel, :items => [{
|
67
|
-
:widget_class_name => "Panel",
|
68
|
-
:ext_config => {
|
69
|
-
:html => "Panel 1",
|
70
|
-
},
|
71
|
-
:active => true
|
72
|
-
},{
|
73
|
-
:widget_class_name => "Panel",
|
74
|
-
:ext_config => {
|
75
|
-
:html => "Panel 2",
|
76
|
-
}
|
77
|
-
}]
|
29
|
+
def method_missing(method_name)
|
30
|
+
widget_name, *action = method_name.to_s.split('__')
|
31
|
+
widget_name = widget_name.to_sym
|
32
|
+
action = !action.empty? && action.join("__").to_sym
|
78
33
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
self.class.widget_config_storage.each_key.map(&:to_s).sort.each do |w|
|
88
|
-
html << "<a href='#{w}_test'>#{w.to_s.humanize}</a><br/>\n"
|
34
|
+
if action
|
35
|
+
w_instance = Netzke::Base.instance_by_config(Netzke::Base.session[:netzke_widgets][widget_name])
|
36
|
+
# only widget's actions starting with "api_" are accessible from outside (security)
|
37
|
+
api_action = action.to_s.index('__') ? action : "api_#{action}"
|
38
|
+
render :text => w_instance.send(api_action, params), :layout => false
|
39
|
+
else
|
40
|
+
super
|
89
41
|
end
|
90
|
-
|
91
|
-
render :text => html
|
92
42
|
end
|
93
|
-
|
43
|
+
|
94
44
|
end
|
@@ -1,26 +1,63 @@
|
|
1
1
|
module Netzke
|
2
2
|
module ActionViewExt
|
3
|
-
|
3
|
+
# Include JavaScript
|
4
4
|
def netzke_js_include
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
res << javascript_include_tag("/extjs/adapter/ext/ext-base.js", "/extjs/ext-all-debug.js")
|
9
|
-
else
|
10
|
-
res << javascript_include_tag("/extjs/adapter/ext/ext-base.js", "/extjs/ext-all.js")
|
11
|
-
end
|
12
|
-
res << javascript_tag( "Ext.authenticityToken = '#{form_authenticity_token}'") # forgery protection
|
5
|
+
# ExtJS
|
6
|
+
res = ENV['RAILS_ENV'] == 'development' ? javascript_include_tag("/extjs/adapter/ext/ext-base.js", "/extjs/ext-all-debug.js") : javascript_include_tag("/extjs/adapter/ext/ext-base.js", "/extjs/ext-all.js")
|
7
|
+
# Netzke (dynamically generated)
|
13
8
|
res << javascript_include_tag("/netzke/netzke.js")
|
14
|
-
|
15
|
-
res
|
16
9
|
end
|
17
10
|
|
11
|
+
# Include CSS
|
18
12
|
def netzke_css_include(theme_name = :default)
|
13
|
+
# ExtJS base
|
19
14
|
res = stylesheet_link_tag("/extjs/resources/css/ext-all.css")
|
15
|
+
# ExtJS theming
|
20
16
|
res << stylesheet_link_tag("/extjs/resources/css/xtheme-#{theme_name}.css") unless theme_name == :default
|
21
|
-
|
17
|
+
# Netzke (dynamically generated)
|
18
|
+
res << stylesheet_link_tag("/netzke/netzke.css")
|
22
19
|
res
|
23
20
|
end
|
21
|
+
|
22
|
+
# JavaScript for all Netzke classes in this view, and Ext.onReady which renders all Netzke widgets in this view
|
23
|
+
def netzke_js
|
24
|
+
javascript_tag <<-END_OF_JAVASCRIPT
|
25
|
+
Ext.Ajax.extraParams = {authenticity_token: '#{form_authenticity_token}'}; // Rails' forgery protection... effective?
|
26
|
+
#{@content_for_netzke_js_classes}
|
27
|
+
Ext.onReady(function(){
|
28
|
+
#{@content_for_netzke_on_ready}
|
29
|
+
});
|
30
|
+
END_OF_JAVASCRIPT
|
31
|
+
end
|
32
|
+
|
33
|
+
# Wrapper for all the above. Use it in your layout.
|
34
|
+
# Params: <tt>:ext_theme</tt> - the name of ExtJS theme to apply (optional)
|
35
|
+
# E.g.:
|
36
|
+
# <%= netzke_init :ext_theme => "grey" %>
|
37
|
+
def netzke_init(params = {})
|
38
|
+
theme = params[:ext_theme] || :default
|
39
|
+
[netzke_css_include(theme), netzke_js_include, netzke_js].join("\n")
|
40
|
+
end
|
41
|
+
|
42
|
+
# Use this helper in your views to embed Netzke widgets. E.g.:
|
43
|
+
# netzke :my_grid, :widget_class_name => "GridPanel", :columns => [:id, :name, :created_at]
|
44
|
+
# On how to configure a widget, see documentation for Netzke::Base or/and specific widget
|
45
|
+
def netzke(name, config = {})
|
46
|
+
::ActiveSupport::Deprecation.warn("widget_class_name option is deprecated. Use class_name instead", caller) if config[:widget_class_name]
|
47
|
+
class_name = config[:class_name] ||= config[:widget_class_name] || name.to_s.camelcase
|
48
|
+
config[:name] = name
|
49
|
+
Netzke::Base.reg_widget(config)
|
50
|
+
w = Netzke::Base.instance_by_config(config)
|
51
|
+
content_for :netzke_js_classes, w.js_missing_code(@rendered_classes ||= [])
|
52
|
+
content_for :netzke_on_ready, w.js_widget_instance
|
53
|
+
content_for :netzke_on_ready, w.js_widget_render
|
54
|
+
|
55
|
+
# Now mark this widget's class as rendered, so that we only generate it once per view
|
56
|
+
@rendered_classes << class_name unless @rendered_classes.include?(class_name)
|
57
|
+
|
58
|
+
# Return the html for this widget
|
59
|
+
w.js_widget_html
|
60
|
+
end
|
24
61
|
end
|
25
62
|
end
|
26
63
|
|
data/lib/netzke/base.rb
CHANGED
@@ -42,7 +42,7 @@ module Netzke
|
|
42
42
|
|
43
43
|
include Netzke::BaseJs # javascript (client-side)
|
44
44
|
|
45
|
-
attr_accessor :parent, :name, :global_id
|
45
|
+
attr_accessor :parent, :name, :global_id #, :permissions, :session
|
46
46
|
|
47
47
|
# Class-level Netzke::Base configuration. The defaults also get specified here.
|
48
48
|
def self.config
|
@@ -152,7 +152,8 @@ module Netzke
|
|
152
152
|
|
153
153
|
# Instance of widget by config
|
154
154
|
def self.instance_by_config(config)
|
155
|
-
|
155
|
+
::ActiveSupport::Deprecation.warn("widget_class_name option is deprecated. Use class_name instead", caller) if config[:widget_class_name]
|
156
|
+
widget_class = "Netzke::#{config[:class_name] || config[:widget_class_name]}".constantize
|
156
157
|
widget_class.new(config)
|
157
158
|
end
|
158
159
|
|
@@ -163,24 +164,22 @@ module Netzke
|
|
163
164
|
nil
|
164
165
|
end
|
165
166
|
|
166
|
-
# Return persistent config class
|
167
|
-
# def self.persistent_config
|
168
|
-
# # if the class is not present, fake it (it will not store anything, and always return nil)
|
169
|
-
# persistent_config_manager_class || {}
|
170
|
-
# end
|
171
|
-
|
172
167
|
# Widget initialization process
|
173
168
|
# * the config hash is available to the widget after the "super" call in the initializer
|
174
169
|
# * override/add new default configuration options into the "default_config" method
|
175
170
|
# (the config hash is not yet available)
|
176
171
|
def initialize(config = {}, parent = nil)
|
177
|
-
@session = Netzke::Base.session
|
172
|
+
# @session = Netzke::Base.session
|
178
173
|
@passed_config = config # configuration passed at the moment of instantiation
|
179
174
|
@parent = parent
|
180
175
|
@name = config[:name].nil? ? short_widget_class_name.underscore : config[:name].to_s
|
181
176
|
@global_id = parent.nil? ? @name : "#{parent.global_id}__#{@name}"
|
182
177
|
@flash = []
|
183
178
|
end
|
179
|
+
|
180
|
+
def session
|
181
|
+
Netzke::Base.session
|
182
|
+
end
|
184
183
|
|
185
184
|
#
|
186
185
|
# Configuration
|
@@ -215,7 +214,7 @@ module Netzke
|
|
215
214
|
def persistent_config(global = false)
|
216
215
|
if persistent_config_enabled? || global
|
217
216
|
config_class = self.class.persistent_config_manager_class
|
218
|
-
config_class.widget_name = global ? nil :
|
217
|
+
config_class.widget_name = global ? nil : persistence_key.to_s # pass to the config class our unique name
|
219
218
|
config_class
|
220
219
|
else
|
221
220
|
# if we can't use presistent config, all the calls to it will always return nil,
|
@@ -225,9 +224,11 @@ module Netzke
|
|
225
224
|
end
|
226
225
|
end
|
227
226
|
|
228
|
-
# A string which will identify
|
229
|
-
|
230
|
-
|
227
|
+
# A string which will identify NetzkePreference records for this widget.
|
228
|
+
# If <tt>persistence_key</tt> is passed, use it. Otherwise use global widget's id.
|
229
|
+
def persistence_key #:nodoc:
|
230
|
+
# initial_config[:persistence_key] ? parent.try(:persistence_key) ? "#{parent.persistence_key}__#{initial_config[:persistence_key]}".to_sym : initial_config[:persistence_key] : global_id.to_sym
|
231
|
+
initial_config[:persistence_key] ? initial_config[:persistence_key] : global_id.to_sym
|
231
232
|
end
|
232
233
|
|
233
234
|
def update_persistent_ext_config(hsh)
|
@@ -281,9 +282,9 @@ module Netzke
|
|
281
282
|
# this method will return the following hash:
|
282
283
|
# {:enabled => true, :layout => {:width => 100, :header => {:height => 20}}}
|
283
284
|
def persistent_config_hash
|
284
|
-
return {} if !initial_config[:persistent_config]
|
285
|
+
return {} if !initial_config[:persistent_config] || Netzke::Base.persistent_config_manager_class.nil?
|
285
286
|
|
286
|
-
prefs = NetzkePreference.find_all_for_widget(
|
287
|
+
prefs = NetzkePreference.find_all_for_widget(persistence_key.to_s)
|
287
288
|
res = {}
|
288
289
|
prefs.each do |p|
|
289
290
|
hsh_levels = p.name.split("__").map(&:to_sym)
|
@@ -412,7 +413,8 @@ module Netzke
|
|
412
413
|
aggr = aggr.to_sym
|
413
414
|
aggregatee_config = aggregator.aggregatees[aggr]
|
414
415
|
raise ArgumentError, "No aggregatee '#{aggr}' defined for widget '#{aggregator.global_id}'" if aggregatee_config.nil?
|
415
|
-
|
416
|
+
::ActiveSupport::Deprecation.warn("widget_class_name option is deprecated. Use class_name instead", caller) if aggregatee_config[:widget_class_name]
|
417
|
+
short_class_name = aggregatee_config[:class_name] || aggregatee_config[:widget_class_name]
|
416
418
|
raise ArgumentError, "No widget_class_name specified for aggregatee #{aggr} of #{aggregator.global_id}" if short_class_name.nil?
|
417
419
|
widget_class = "Netzke::#{short_class_name}".constantize
|
418
420
|
|
@@ -539,6 +541,12 @@ module Netzke
|
|
539
541
|
super
|
540
542
|
end
|
541
543
|
end
|
544
|
+
|
545
|
+
# Register the configuration for the widget in the session, and also remember that the code for it has been rendered
|
546
|
+
def self.reg_widget(config)
|
547
|
+
session[:netzke_widgets] ||= {}
|
548
|
+
session[:netzke_widgets][config[:name]] = config
|
549
|
+
end
|
542
550
|
|
543
551
|
end
|
544
552
|
end
|
data/lib/netzke/base_js.rb
CHANGED
@@ -45,7 +45,6 @@ module Netzke
|
|
45
45
|
res.merge!(:netzke_api => api_points) unless api_points.empty?
|
46
46
|
|
47
47
|
# Widget class name. Needed for dynamic instantiation in javascript.
|
48
|
-
# res.merge!(:widget_class_name => short_widget_class_name)
|
49
48
|
res.merge!(:scoped_class_name => self.class.js_scoped_class_name)
|
50
49
|
|
51
50
|
# Actions, toolbars and menus
|
@@ -94,17 +93,42 @@ module Netzke
|
|
94
93
|
|
95
94
|
# container for rendering
|
96
95
|
def js_widget_html
|
97
|
-
%Q{<div id="#{name.to_s.split('_').join('-')}-div"
|
96
|
+
%Q{<div id="#{name.to_s.split('_').join('-')}-div"></div>}
|
98
97
|
end
|
99
98
|
|
100
99
|
#
|
101
|
-
#
|
102
|
-
#
|
103
|
-
|
104
100
|
# Widget's actions, tools and menus that are loaded at the moment of instantiation
|
105
|
-
|
101
|
+
|
102
|
+
private
|
103
|
+
# Extract action names from menus and toolbars.
|
104
|
+
# E.g.:
|
105
|
+
# collect_actions(["->", {:text => "Menu", :menu => [{:text => "Submenu", :menu => [:another_button]}, "-", :a_button]}])
|
106
|
+
# => {:a_button => {:text => "A button"}, :another_button => {:text => "Another button"}}
|
107
|
+
def collect_actions(arry)
|
108
|
+
res = {}
|
109
|
+
arry.each do |item|
|
110
|
+
if item.is_a?(Hash) && menu = item[:menu]
|
111
|
+
res.merge!(collect_actions(item[:menu]))
|
112
|
+
elsif item.is_a?(Symbol)
|
113
|
+
# it's an action
|
114
|
+
res.merge!(item => {:text => item.to_s.humanize})
|
115
|
+
elsif item.is_a?(String)
|
116
|
+
# it's a string item (or maybe JS code)
|
117
|
+
else
|
118
|
+
end
|
119
|
+
end
|
120
|
+
res
|
121
|
+
end
|
122
|
+
|
123
|
+
public
|
124
|
+
# Create default actions from bbar, tbar, and fbar, which are passed in the configuration
|
125
|
+
def actions
|
126
|
+
bar_items = (ext_config[:bbar] || []) + (ext_config[:tbar] || []) + (ext_config[:fbar] || [])
|
127
|
+
bar_items.uniq!
|
128
|
+
collect_actions(bar_items)
|
129
|
+
end
|
130
|
+
|
106
131
|
def menu; nil; end
|
107
|
-
# def tools; nil; end
|
108
132
|
|
109
133
|
# Little helpers
|
110
134
|
def this; "this".l; end
|
@@ -179,11 +203,11 @@ module Netzke
|
|
179
203
|
# Declaration of widget's class (stored in the cache storage (Ext.netzke.cache) at the client side
|
180
204
|
# to be reused at the moment of widget instantiation)
|
181
205
|
def js_class(cached = [])
|
182
|
-
#
|
183
|
-
# TODO: invent an easy and error-prove way to check if adding this scope is necessary.
|
184
|
-
# For now setting it each and every time (very save and not really bothering).
|
206
|
+
# Defining the scope if it isn't known yet
|
185
207
|
res = %Q{
|
186
|
-
|
208
|
+
if (!#{js_full_scope}) {
|
209
|
+
Ext.ns("#{js_full_scope}");
|
210
|
+
}
|
187
211
|
}
|
188
212
|
|
189
213
|
if js_inheritance?
|
@@ -1,14 +1,12 @@
|
|
1
1
|
module Netzke
|
2
2
|
module ControllerExtensions
|
3
3
|
def self.included(base)
|
4
|
-
base.extend ControllerClassMethods
|
5
4
|
base.send(:before_filter, :set_session_data)
|
6
5
|
end
|
7
6
|
|
8
7
|
def set_session_data
|
9
8
|
Netzke::Base.session = session
|
10
9
|
session[:netzke_user_id] = defined?(current_user) ? current_user.try(:id) : nil
|
11
|
-
|
12
10
|
# set netzke_just_logged_in and netzke_just_logged_out states (may be used by Netzke widgets)
|
13
11
|
if session[:_netzke_next_request_is_first_after_login]
|
14
12
|
session[:netzke_just_logged_in] = true
|
@@ -24,111 +22,5 @@ module Netzke
|
|
24
22
|
session[:netzke_just_logged_out] = false
|
25
23
|
end
|
26
24
|
end
|
27
|
-
|
28
|
-
def method_missing(method_name)
|
29
|
-
if self.class.widget_config_storage == {}
|
30
|
-
super
|
31
|
-
else
|
32
|
-
widget, *action = method_name.to_s.split('__')
|
33
|
-
widget = widget.to_sym
|
34
|
-
action = !action.empty? && action.join("__").to_sym
|
35
|
-
|
36
|
-
# only widget's actions starting with "api_" are accessible from outside (security)
|
37
|
-
if action
|
38
|
-
api_action = action.to_s.index('__') ? action : "api_#{action}"
|
39
|
-
|
40
|
-
# widget module
|
41
|
-
widget_class = "Netzke::#{self.class.widget_config_storage[widget][:widget_class_name]}".constantize
|
42
|
-
|
43
|
-
# instantiate the server part of the widget
|
44
|
-
widget_instance = widget_class.new(self.class.widget_config_storage[widget])
|
45
|
-
|
46
|
-
render :text => widget_instance.send(api_action, params), :layout => false
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
module ControllerClassMethods
|
52
|
-
|
53
|
-
# widget_config_storage for all widgets
|
54
|
-
def widget_config_storage
|
55
|
-
@@widget_config_storage ||= {}
|
56
|
-
@@widget_config_storage[self.name] ||= {} # specific for controller
|
57
|
-
end
|
58
|
-
|
59
|
-
#
|
60
|
-
# Use this method to declare a widget in the controller
|
61
|
-
#
|
62
|
-
def netzke(name, config={})
|
63
|
-
# which module is the widget?
|
64
|
-
config[:widget_class_name] ||= name.to_s.classify
|
65
|
-
config[:name] ||= name
|
66
|
-
|
67
|
-
# register the widget config in the storage
|
68
|
-
widget_config_storage[name] = config
|
69
|
-
|
70
|
-
# provide widget helpers
|
71
|
-
ActionView::Base.module_eval <<-END_EVAL, __FILE__, __LINE__
|
72
|
-
def #{name}_server_instance(config = {})
|
73
|
-
default_config = controller.class.widget_config_storage[:#{name}]
|
74
|
-
if config.empty?
|
75
|
-
# only cache when the config is empty (which means that config specified in controller is used)
|
76
|
-
@widget_instance_cache ||= {}
|
77
|
-
@widget_instance_cache[:#{name}] ||= Netzke::Base.instance_by_config(default_config)
|
78
|
-
else
|
79
|
-
# if helper is called with parameters - always return a fresh instance of widget, no caching
|
80
|
-
Netzke::Base.instance_by_config(default_config.deep_merge(config))
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def #{name}_widget_instance(config = {})
|
85
|
-
#{name}_server_instance(config).js_widget_instance
|
86
|
-
end
|
87
|
-
|
88
|
-
def #{name}_class_definition
|
89
|
-
@generated_widget_classes ||= []
|
90
|
-
res = #{name}_server_instance.js_missing_code(@generated_widget_classes)
|
91
|
-
|
92
|
-
# prevent duplication of javascript when multiple homogeneous widgets are on the same page
|
93
|
-
@generated_widget_classes += #{name}_server_instance.dependencies
|
94
|
-
@generated_widget_classes.uniq!
|
95
|
-
res
|
96
|
-
end
|
97
|
-
|
98
|
-
def #{name}_widget_html
|
99
|
-
#{name}_server_instance.js_widget_html
|
100
|
-
end
|
101
|
-
|
102
|
-
def #{name}_widget_render
|
103
|
-
#{name}_server_instance.js_widget_render
|
104
|
-
end
|
105
|
-
|
106
|
-
END_EVAL
|
107
|
-
|
108
|
-
# add controller action which will render a simple HTML page containing the widget
|
109
|
-
define_method("#{name}_test") do
|
110
|
-
@widget_name = name
|
111
|
-
render :inline => <<-HTML
|
112
|
-
<head>
|
113
|
-
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
114
|
-
<title><%= @widget_name %></title>
|
115
|
-
<%= netzke_js_include %>
|
116
|
-
<%= netzke_css_include %>
|
117
|
-
<script type="text/javascript" charset="utf-8">
|
118
|
-
<%= #{name}_class_definition %>
|
119
|
-
Ext.onReady(function(){
|
120
|
-
<%= #{name}_widget_instance %>
|
121
|
-
<%= #{name}_widget_render %>
|
122
|
-
});
|
123
|
-
</script>
|
124
|
-
</head>
|
125
|
-
<body>
|
126
|
-
<%= #{name}_widget_html %>
|
127
|
-
</body>
|
128
|
-
HTML
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
25
|
end
|
133
|
-
|
134
26
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: netzke-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sergei Kozlov
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2010-01-20 00:00:00 -03:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -22,6 +22,7 @@ extensions: []
|
|
22
22
|
extra_rdoc_files:
|
23
23
|
- LICENSE
|
24
24
|
- README.rdoc
|
25
|
+
- TODO
|
25
26
|
files:
|
26
27
|
- .autotest
|
27
28
|
- .gitignore
|