netzke-basepack 0.5.4 → 0.5.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -1
- data/CHANGELOG.rdoc +13 -0
- data/README.rdoc +18 -9
- data/Rakefile +6 -7
- data/TODO.rdoc +4 -2
- data/javascripts/basepack.js +32 -1
- data/lib/app/models/netzke_auto_column.rb +2 -2
- data/lib/netzke-basepack.rb +2 -1
- data/lib/netzke/accordion_panel.rb +6 -4
- data/lib/netzke/basic_app.rb +222 -231
- data/lib/netzke/border_layout_panel.rb +4 -2
- data/lib/netzke/fields_configurator.rb +2 -2
- data/lib/netzke/form_panel.rb +6 -4
- data/lib/netzke/form_panel_api.rb +20 -16
- data/lib/netzke/form_panel_extras/javascripts/netzkefileupload.js +5 -0
- data/lib/netzke/form_panel_js.rb +26 -7
- data/lib/netzke/grid_panel.rb +31 -10
- data/lib/netzke/grid_panel_api.rb +46 -40
- data/lib/netzke/grid_panel_extras/record_form_window.rb +46 -0
- data/lib/netzke/grid_panel_js.rb +9 -32
- data/lib/netzke/property_editor.rb +1 -1
- data/lib/netzke/property_editor_extras/helper_model.rb +2 -6
- data/lib/netzke/tab_panel.rb +5 -4
- data/lib/netzke/table_editor.rb +1 -1
- data/lib/netzke/tree_panel.rb +1 -1
- data/lib/netzke/window.rb +77 -0
- data/lib/netzke/wrapper.rb +1 -1
- data/test/unit/accordion_panel_test.rb +1 -1
- data/test/unit/grid_panel_test.rb +11 -2
- data/test/unit/tab_panel_test.rb +1 -1
- metadata +8 -6
- data/VERSION +0 -1
data/.gitignore
CHANGED
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
= v0.5.5.1 - 2009-11-09
|
2
|
+
* Compatibility with latest netzke-core
|
3
|
+
|
4
|
+
= v0.5.5 - 2009-11-09
|
5
|
+
* Compatibility with latest netzke-core
|
6
|
+
* Regression: pressing "enter" was not submitting the form (FormPanel)
|
7
|
+
* Regression: "Restore defaults" button was not working in FieldsConfigurator and PropertyEditor
|
8
|
+
* Fix: excluding columns in FieldConfigurator was causing inconsistent column behavior (move/hide/resize)
|
9
|
+
* Fix: resolving conflicts with Ext.form.FormPanel's <tt>submit</tt> and <tt>load</tt> methods
|
10
|
+
* New: rudimentary FileUploadField support in FormPanel (it will do a normal, non-AJAX, form submit)
|
11
|
+
* New: Netzke::Window widget, supports persistent moving/resizing.
|
12
|
+
* New: (experimental) GridPanel's "Add in form" button now opens the new Window widget. Later all other windows will be slowly rewritten to do the same.
|
13
|
+
|
1
14
|
= v0.5.4 - 2009-10-12
|
2
15
|
* Dependencies updated
|
3
16
|
|
data/README.rdoc
CHANGED
@@ -5,35 +5,44 @@ Note that if you would like to modify this code or experiment with it, you may b
|
|
5
5
|
|
6
6
|
= Prerequisites
|
7
7
|
1. Rails >= 2.2
|
8
|
-
2. Ext JS >= 3.0: its root
|
8
|
+
2. Ext JS >= 3.0: its root by default must be accessible as RAILS_ROOT/public/extjs. You may symlink your Ext JS library here like this (from your app folder):
|
9
|
+
|
9
10
|
cd public && ln -s ~/Developer/extjs/ext-3.0 extjs
|
10
11
|
|
11
12
|
3. acts_as_list plugin must be installed:
|
12
|
-
./script/plugin install git://github.com/rails/acts_as_list.git
|
13
13
|
|
14
|
-
|
15
|
-
gem sources -a http://gems.github.com/
|
16
|
-
sudo gem install mislav-will_paginate
|
14
|
+
./script/plugin install git://github.com/rails/acts_as_list.git
|
17
15
|
|
18
16
|
= Installation
|
19
|
-
|
17
|
+
The gem is hosted on gemcutter. If you haven't yet enabled gemcutter, run the following:
|
18
|
+
|
19
|
+
sudo gem install gemcutter && gem tumble
|
20
|
+
|
21
|
+
Install the gem:
|
22
|
+
|
20
23
|
gem install netzke-basepack
|
21
24
|
|
22
25
|
Include it into environment.rb:
|
26
|
+
|
23
27
|
config.gem "netzke-basepack"
|
24
28
|
|
25
29
|
Include mapping for Netzke controller providing *.js and *.css (in routes.rb):
|
30
|
+
|
26
31
|
map.netzke
|
27
32
|
|
28
33
|
= Usage
|
29
34
|
First, run the generators to have the necessary migrations:
|
35
|
+
|
30
36
|
./script/generate netzke_core
|
31
37
|
|
32
38
|
Do the migrations:
|
39
|
+
|
33
40
|
rake db:migrate
|
34
41
|
|
35
42
|
The following example will provide you with a grid-based scaffold for ActiveRecord-model called Book. You may generate it like this:
|
43
|
+
|
36
44
|
./script/generate model Book title:string amount:integer
|
45
|
+
|
37
46
|
(don't forget to re-run the migrations after it)
|
38
47
|
|
39
48
|
In the controller declare the widget:
|
@@ -57,7 +66,7 @@ Declaring a widget in the controller provides you with a couple of helpers that
|
|
57
66
|
|
58
67
|
1. books_class_definition will contain the JavaScript code defining the code for the JS class.
|
59
68
|
2. books_widget_instance will declare a local JavaScript variable called 'book'.
|
60
|
-
3. books_widget_render will provide the JavaScript code that calls the "render" method on the variable declared by books_widget_instance.
|
69
|
+
3. books_widget_render will provide the JavaScript code that calls the "render" method on the variable declared by books_widget_instance; the widget will be rendered into a div with id "books-div".
|
61
70
|
|
62
71
|
Use these helpers inside of the script-tag like the following (in the view):
|
63
72
|
|
@@ -68,7 +77,7 @@ Use these helpers inside of the script-tag like the following (in the view):
|
|
68
77
|
<%= books_widget_render %>
|
69
78
|
})
|
70
79
|
</script>
|
71
|
-
<div id="books">the widget will be rendered in this div</div>
|
80
|
+
<div id="books-div">the widget will be rendered in this div</div>
|
72
81
|
|
73
82
|
If your layout already calls yield :javascripts wrapped in the <script>-tag, you can have all javascript-code in one place on the page:
|
74
83
|
|
@@ -80,7 +89,7 @@ If your layout already calls yield :javascripts wrapped in the <script>-tag, you
|
|
80
89
|
})
|
81
90
|
<% end %>
|
82
91
|
<p>... your page content here ...</p>
|
83
|
-
<div id="books">the widget will be rendered in this div</div>
|
92
|
+
<div id="books-div">the widget will be rendered in this div</div>
|
84
93
|
|
85
94
|
== Dynamic loading of widgets
|
86
95
|
TODO: this part will be covered later
|
data/Rakefile
CHANGED
@@ -1,22 +1,21 @@
|
|
1
1
|
begin
|
2
2
|
require 'jeweler'
|
3
3
|
Jeweler::Tasks.new do |gemspec|
|
4
|
+
gemspec.version = "0.5.5"
|
4
5
|
gemspec.name = "netzke-basepack"
|
5
|
-
gemspec.summary = "Pre-built
|
6
|
-
gemspec.description = "
|
6
|
+
gemspec.summary = "Pre-built Rails + ExtJS widgets for your RIA"
|
7
|
+
gemspec.description = "A set of full-featured extendible Netzke widgets (such as FormPanel, GridPanel, Window, BorderLayoutPanel, etc) which can be used as building block for your RIA"
|
7
8
|
gemspec.email = "sergei@playcode.nl"
|
8
9
|
gemspec.homepage = "http://github.com/skozlov/netzke-basepack"
|
9
10
|
gemspec.rubyforge_project = "netzke-basepack"
|
10
11
|
gemspec.authors = ["Sergei Kozlov"]
|
11
|
-
gemspec.add_dependency("netzke-core", ">=0.4.
|
12
|
+
gemspec.add_dependency("netzke-core", ">=0.4.5.2")
|
12
13
|
gemspec.add_dependency("searchlogic", ">=2.0.0")
|
13
14
|
gemspec.add_dependency("will_paginate", ">=2.0.0")
|
14
15
|
end
|
15
|
-
Jeweler::
|
16
|
-
rubyforge.doc_task = "rdoc"
|
17
|
-
end
|
16
|
+
Jeweler::GemcutterTasks.new
|
18
17
|
rescue LoadError
|
19
|
-
puts "Jeweler not available. Install it with: sudo gem install
|
18
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
20
19
|
end
|
21
20
|
|
22
21
|
require 'rake/rdoctask'
|
data/TODO.rdoc
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
== Priority
|
2
|
-
* Make column/fields configuration fool-proof
|
3
2
|
* Introduce three-state checkbox for SearchPanel
|
4
3
|
* Add icons to buttons to actions (toolbars/menus)
|
5
4
|
* On grid refresh, reset the dirty fields, so that the "Apply" button doesn't do anything
|
6
5
|
|
6
|
+
== Foolproof
|
7
|
+
* Should not be possible delete the "ID" field from grids/forms
|
8
|
+
|
7
9
|
== Optimizations
|
8
|
-
*
|
10
|
+
* Check persistent_config-related queries (aren't they too many?)
|
9
11
|
|
10
12
|
== One day
|
11
13
|
* Replace xcheckbox with checkbox in FormPanel
|
data/javascripts/basepack.js
CHANGED
@@ -794,4 +794,35 @@ Ext.grid.HeaderDropZone.prototype.onNodeDrop = function(n, dd, e, data){
|
|
794
794
|
return true;
|
795
795
|
}
|
796
796
|
return false;
|
797
|
-
}
|
797
|
+
}
|
798
|
+
|
799
|
+
// Feedback Ghost
|
800
|
+
Netzke.FeedbackGhost = function(){};
|
801
|
+
Ext.apply(Netzke.FeedbackGhost.prototype, {
|
802
|
+
showFeedback: function(msg){
|
803
|
+
var createBox = function(s, l){
|
804
|
+
return ['<div class="msg">',
|
805
|
+
'<div class="x-box-tl"><div class="x-box-tr"><div class="x-box-tc"></div></div></div>',
|
806
|
+
'<div class="x-box-ml"><div class="x-box-mr"><div class="x-box-mc">', s, '</div></div></div>',
|
807
|
+
'<div class="x-box-bl"><div class="x-box-br"><div class="x-box-bc"></div></div></div>',
|
808
|
+
'</div>'].join('');
|
809
|
+
}
|
810
|
+
|
811
|
+
var showBox = function(msg, lvl){
|
812
|
+
if (!lvl) {lvl = 'notice'};
|
813
|
+
var msgCt = Ext.DomHelper.insertFirst(document.body, {'class':'netzke-feedback'}, true);
|
814
|
+
var m = Ext.DomHelper.append(msgCt, {html:createBox(msg,lvl)}, true);
|
815
|
+
m.slideIn('t').pause(2).ghost("b", {remove:true});
|
816
|
+
}
|
817
|
+
|
818
|
+
if (typeof msg != 'string') {
|
819
|
+
var compoundMsg = "";
|
820
|
+
Ext.each(msg, function(m){
|
821
|
+
compoundMsg += m.msg + '<br>';
|
822
|
+
});
|
823
|
+
if (compoundMsg != "") showBox(compoundMsg, null); // the second parameter will be level
|
824
|
+
} else {
|
825
|
+
showBox(msg);
|
826
|
+
}
|
827
|
+
}
|
828
|
+
});
|
@@ -48,9 +48,9 @@ class NetzkeAutoColumn < ActiveRecord::Base
|
|
48
48
|
|
49
49
|
def self.widget=(widget)
|
50
50
|
@@widget = widget
|
51
|
-
if Netzke::Base.session["netzke_auto_column_last_widget"] != @@widget.
|
51
|
+
if Netzke::Base.session["netzke_auto_column_last_widget"] != @@widget.global_id
|
52
52
|
rebuild_table
|
53
|
-
Netzke::Base.session["netzke_auto_column_last_widget"] = @@widget.
|
53
|
+
Netzke::Base.session["netzke_auto_column_last_widget"] = @@widget.global_id
|
54
54
|
end
|
55
55
|
end
|
56
56
|
end
|
data/lib/netzke-basepack.rb
CHANGED
@@ -19,4 +19,5 @@ ActiveSupport::Dependencies.load_once_paths.delete(File.join(File.dirname(__FILE
|
|
19
19
|
# Include javascript & styles required by all basepack widgets.
|
20
20
|
# These files will get loaded at the initial load of the framework (along with Ext and Netzke-core).
|
21
21
|
Netzke::Base.config[:javascripts] << "#{File.dirname(__FILE__)}/../javascripts/basepack.js"
|
22
|
-
Netzke::Base.config[:stylesheets] << "#{File.dirname(__FILE__)}/../stylesheets/basepack.css"
|
22
|
+
Netzke::Base.config[:stylesheets] << "#{File.dirname(__FILE__)}/../stylesheets/basepack.css"
|
23
|
+
Netzke::Base.config[:stylesheets] << Netzke::Base.config[:ext_location] + "/examples/form/file-upload.css"
|
@@ -16,7 +16,7 @@ module Netzke
|
|
16
16
|
:defaults => {:layout => 'fit'},
|
17
17
|
:init_component => <<-END_OF_JAVASCRIPT.l,
|
18
18
|
function(){
|
19
|
-
|
19
|
+
#{js_full_class_name}.superclass.initComponent.call(this);
|
20
20
|
|
21
21
|
// Set events
|
22
22
|
this.items.each(function(i){
|
@@ -26,7 +26,8 @@ module Netzke
|
|
26
26
|
// If not collapsed, add the active aggregatee (item) into it
|
27
27
|
if (!i.collapsed) {
|
28
28
|
var preloadedItemConfig = this[i.widget.camelize(true) + "Config"];
|
29
|
-
|
29
|
+
var klass = this.classifyScopedName(preloadedItemConfig.scopedClassName);
|
30
|
+
i.add(new klass(preloadedItemConfig));
|
30
31
|
i.doLayout(); // always needed after adding a component
|
31
32
|
}
|
32
33
|
}, this);
|
@@ -41,7 +42,8 @@ module Netzke
|
|
41
42
|
|
42
43
|
if (preloadedItemConfig){
|
43
44
|
// preloaded widget only needs to be instantiated, as its class and configuration have already been loaded
|
44
|
-
|
45
|
+
var klass = this.classifyScopedName(preloadedItemConfig.scopedClassName);
|
46
|
+
panel.add(new klass(preloadedItemConfig));
|
45
47
|
panel.doLayout(); // always needed after adding a component
|
46
48
|
} else {
|
47
49
|
// load the widget from the server
|
@@ -89,7 +91,7 @@ module Netzke
|
|
89
91
|
res = []
|
90
92
|
config[:items].each_with_index do |item, i|
|
91
93
|
res << {
|
92
|
-
# :id => item[:active] &&
|
94
|
+
# :id => item[:active] && global_id + '_active', # to mark the fit-panel which will contain the active widget
|
93
95
|
:title => item[:title] || (item[:name] && item[:name].to_s.humanize),
|
94
96
|
:widget => item[:name], # to know which fit panel will load which widget
|
95
97
|
:collapsed => !(item[:active] || false)
|
data/lib/netzke/basic_app.rb
CHANGED
@@ -11,233 +11,246 @@ module Netzke
|
|
11
11
|
# * masquerade support
|
12
12
|
# * AJAX activity indicator
|
13
13
|
class BasicApp < Base
|
14
|
-
|
14
|
+
def self.include_js
|
15
|
+
res = []
|
16
|
+
ext_examples = Netzke::Base.config[:ext_location] + "/examples/"
|
17
|
+
res << ext_examples + "ux/StatusBar.js"
|
18
|
+
res << "#{File.dirname(__FILE__)}/basic_app_extras/statusbar_ext.js"
|
19
|
+
end
|
15
20
|
|
16
|
-
|
17
|
-
|
18
|
-
|
21
|
+
def self.js_base_class
|
22
|
+
"Ext.Viewport"
|
23
|
+
end
|
19
24
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
#
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
masq = %Q{user "#{user.login}"}
|
45
|
-
elsif session[:masq_role]
|
46
|
-
role = Role.find(session[:masq_role])
|
47
|
-
masq = %Q{role "#{role.name}"}
|
48
|
-
elsif session[:masq_world]
|
49
|
-
masq = %Q{World}
|
50
|
-
end
|
51
|
-
|
52
|
-
[{
|
53
|
-
:id => 'main-panel',
|
54
|
-
:region => 'center',
|
55
|
-
:layout => 'fit'
|
56
|
-
},{
|
57
|
-
:id => 'main-toolbar',
|
58
|
-
:xtype => 'toolbar',
|
59
|
-
:region => 'north',
|
60
|
-
:height => 25
|
61
|
-
# :items => ["-"]
|
62
|
-
},{
|
63
|
-
:id => 'main-statusbar',
|
64
|
-
:xtype => 'statusbar',
|
65
|
-
:region => 'south',
|
66
|
-
:height => 22,
|
67
|
-
:statusAlign => 'right',
|
68
|
-
:busyText => 'Busy...',
|
69
|
-
:default_text => masq.nil? ? "Ready #{"(config mode)" if session[:config_mode]}" : "Masquerading as #{masq}",
|
70
|
-
:default_icon_cls => ""
|
71
|
-
}]
|
25
|
+
# Global BasicApp configuration
|
26
|
+
def self.config
|
27
|
+
set_default_config({
|
28
|
+
:logout_url => "/logout" # default logout url
|
29
|
+
})
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
# def self.include_css
|
34
|
+
# res = []
|
35
|
+
# res << Netzke::Base.config[:ext_location] + "/examples/ux/css/StatusBar.css"
|
36
|
+
# res
|
37
|
+
# end
|
38
|
+
|
39
|
+
def self.js_panels
|
40
|
+
# In status bar we want to show what we are masquerading as
|
41
|
+
if session[:masq_user]
|
42
|
+
user = User.find(session[:masq_user])
|
43
|
+
masq = %Q{user "#{user.login}"}
|
44
|
+
elsif session[:masq_role]
|
45
|
+
role = Role.find(session[:masq_role])
|
46
|
+
masq = %Q{role "#{role.name}"}
|
47
|
+
elsif session[:masq_world]
|
48
|
+
masq = %Q{World}
|
72
49
|
end
|
73
|
-
|
74
|
-
def js_extend_properties
|
75
|
-
{
|
76
|
-
:layout => 'border',
|
77
|
-
|
78
|
-
:panels => js_panels,
|
79
|
-
|
80
|
-
:init_component => <<-END_OF_JAVASCRIPT.l,
|
81
|
-
function(){
|
82
|
-
this.items = this.panels; // a bit weird, but working; can't assign it straight
|
83
50
|
|
84
|
-
|
51
|
+
[{
|
52
|
+
:id => 'main-panel',
|
53
|
+
:region => 'center',
|
54
|
+
:layout => 'fit'
|
55
|
+
},{
|
56
|
+
:id => 'main-toolbar',
|
57
|
+
:xtype => 'toolbar',
|
58
|
+
:region => 'north',
|
59
|
+
:height => 25
|
60
|
+
# :items => ["-"]
|
61
|
+
},{
|
62
|
+
:id => 'main-statusbar',
|
63
|
+
:xtype => 'statusbar',
|
64
|
+
:region => 'south',
|
65
|
+
:height => 22,
|
66
|
+
:statusAlign => 'right',
|
67
|
+
:busyText => 'Busy...',
|
68
|
+
:default_text => masq.nil? ? "Ready #{"(config mode)" if session[:config_mode]}" : "Masquerading as #{masq}",
|
69
|
+
:default_icon_cls => ""
|
70
|
+
}]
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.js_extend_properties
|
74
|
+
{
|
75
|
+
:layout => 'border',
|
85
76
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
}
|
77
|
+
:panels => js_panels,
|
78
|
+
|
79
|
+
:init_component => <<-END_OF_JAVASCRIPT.l,
|
80
|
+
function(){
|
81
|
+
this.items = this.panels; // a bit weird, but working; can't assign it straight
|
82
|
+
|
83
|
+
#{js_full_class_name}.superclass.initComponent.call(this);
|
94
84
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
this.
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
Ext.Ajax.on('requestcomplete', function(){this.findById('main-statusbar').hideBusy()}, this);
|
103
|
-
Ext.Ajax.on('requestexception', function(){this.findById('main-statusbar').hideBusy()}, this);
|
85
|
+
// If we are given a token, load the corresponding widget, otherwise load the last loaded widget
|
86
|
+
var currentToken = Ext.History.getToken();
|
87
|
+
if (currentToken != "") {
|
88
|
+
this.processHistory(currentToken);
|
89
|
+
} else {
|
90
|
+
var lastLoaded = this.initialConfig.widgetToLoad; // passed from the server
|
91
|
+
if (lastLoaded) Ext.History.add(lastLoaded);
|
104
92
|
}
|
105
|
-
END_OF_JAVASCRIPT
|
106
|
-
|
107
|
-
:host_menu => <<-END_OF_JAVASCRIPT.l,
|
108
|
-
function(menu, owner){
|
109
|
-
var toolbar = this.findById('main-toolbar');
|
110
|
-
if (!this.menus[owner.id]) this.menus[owner.id] = [];
|
111
|
-
Ext.each(menu, function(item) {
|
112
|
-
// var newMenu = new Ext.Toolbar.Button(item);
|
113
|
-
// var position = toolbar.items.getCount() - 2;
|
114
|
-
// position = position < 0 ? 0 : position;
|
115
|
-
// toolbar.insertButton(position, newMenu);
|
116
93
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
94
|
+
Ext.History.on('change', this.processHistory, this);
|
95
|
+
|
96
|
+
// Hosted menus
|
97
|
+
this.menus = {};
|
98
|
+
|
99
|
+
// Setting the "busy" indicator for Ajax requests
|
100
|
+
Ext.Ajax.on('beforerequest', function(){this.findById('main-statusbar').showBusy()}, this);
|
101
|
+
Ext.Ajax.on('requestcomplete', function(){this.findById('main-statusbar').hideBusy()}, this);
|
102
|
+
Ext.Ajax.on('requestexception', function(){this.findById('main-statusbar').hideBusy()}, this);
|
103
|
+
|
104
|
+
// Initialize history
|
105
|
+
Ext.History.init();
|
106
|
+
}
|
107
|
+
END_OF_JAVASCRIPT
|
108
|
+
|
109
|
+
:host_menu => <<-END_OF_JAVASCRIPT.l,
|
110
|
+
function(menu, owner){
|
111
|
+
var toolbar = this.findById('main-toolbar');
|
112
|
+
if (!this.menus[owner.id]) this.menus[owner.id] = [];
|
113
|
+
Ext.each(menu, function(item) {
|
114
|
+
// var newMenu = new Ext.Toolbar.Button(item);
|
115
|
+
// var position = toolbar.items.getCount() - 2;
|
116
|
+
// position = position < 0 ? 0 : position;
|
117
|
+
// toolbar.insertButton(position, newMenu);
|
122
118
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
// toolbar.items.remove(menu); // remove the item from the toolbar
|
129
|
-
// menu.destroy(); // ... and destroy it
|
130
|
-
// });
|
131
|
-
// }
|
132
|
-
}
|
133
|
-
END_OF_JAVASCRIPT
|
119
|
+
toolbar.add(item);
|
120
|
+
// this.menus[owner.id].push(newMenu); // TODO: remember the menus from this owner in some other way
|
121
|
+
}, this);
|
122
|
+
}
|
123
|
+
END_OF_JAVASCRIPT
|
134
124
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
125
|
+
:unhost_menu => <<-END_OF_JAVASCRIPT.l,
|
126
|
+
function(owner){
|
127
|
+
// var toolbar = this.findById('main-toolbar');
|
128
|
+
// if (this.menus[owner.id]) {
|
129
|
+
// Ext.each(this.menus[owner.id], function(menu){
|
130
|
+
// toolbar.items.remove(menu); // remove the item from the toolbar
|
131
|
+
// menu.destroy(); // ... and destroy it
|
132
|
+
// });
|
133
|
+
// }
|
134
|
+
}
|
135
|
+
END_OF_JAVASCRIPT
|
140
136
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
function(config){
|
153
|
-
this.findById('main-panel').instantiateChild(config);
|
154
|
-
}
|
155
|
-
END_OF_JAVASCRIPT
|
156
|
-
|
157
|
-
# Loads widget by name
|
158
|
-
:app_load_widget => <<-END_OF_JAVASCRIPT.l,
|
159
|
-
function(name){
|
160
|
-
Ext.History.add(name);
|
161
|
-
}
|
162
|
-
END_OF_JAVASCRIPT
|
137
|
+
:on_login => <<-END_OF_JAVASCRIPT.l,
|
138
|
+
function(){
|
139
|
+
window.location = "/login"
|
140
|
+
}
|
141
|
+
END_OF_JAVASCRIPT
|
142
|
+
|
143
|
+
:on_logout => <<-END_OF_JAVASCRIPT.l,
|
144
|
+
function(){
|
145
|
+
window.location = "#{config[:logout_url]}"
|
146
|
+
}
|
147
|
+
END_OF_JAVASCRIPT
|
163
148
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
149
|
+
# Event handler for history change
|
150
|
+
:process_history => <<-END_OF_JAVASCRIPT.l,
|
151
|
+
function(token){
|
152
|
+
if (token){
|
153
|
+
this.loadAggregatee({id:token, container:'main-panel'});
|
154
|
+
} else {
|
155
|
+
Ext.getCmp('main-panel').removeChild();
|
168
156
|
}
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
157
|
+
}
|
158
|
+
END_OF_JAVASCRIPT
|
159
|
+
|
160
|
+
:instantiate_aggregatee => <<-END_OF_JAVASCRIPT.l,
|
161
|
+
function(config){
|
162
|
+
this.findById('main-panel').instantiateChild(config);
|
163
|
+
}
|
164
|
+
END_OF_JAVASCRIPT
|
165
|
+
|
166
|
+
# Loads widget by name
|
167
|
+
:app_load_widget => <<-END_OF_JAVASCRIPT.l,
|
168
|
+
function(name){
|
169
|
+
Ext.History.add(name);
|
170
|
+
}
|
171
|
+
END_OF_JAVASCRIPT
|
172
|
+
|
173
|
+
# Loads widget by action
|
174
|
+
:load_widget_by_action => <<-END_OF_JAVASCRIPT.l,
|
175
|
+
function(action){
|
176
|
+
this.appLoadWidget(action.widget || action.name);
|
177
|
+
}
|
178
|
+
END_OF_JAVASCRIPT
|
179
|
+
|
180
|
+
:on_toggle_config_mode => <<-END_OF_JAVASCRIPT.l,
|
181
|
+
function(){
|
182
|
+
this.toggleConfigMode();
|
183
|
+
}
|
184
|
+
END_OF_JAVASCRIPT
|
185
|
+
|
186
|
+
|
187
|
+
# Masquerade selector window
|
188
|
+
:show_masquerade_selector => <<-END_OF_JAVASCRIPT.l
|
189
|
+
function(){
|
190
|
+
var w = new Ext.Window({
|
191
|
+
title: 'Masquerade as',
|
192
|
+
modal: true,
|
193
|
+
width: Ext.lib.Dom.getViewWidth() * 0.6,
|
194
|
+
height: Ext.lib.Dom.getViewHeight() * 0.6,
|
195
|
+
layout: 'fit',
|
196
|
+
closeAction :'destroy',
|
197
|
+
buttons: [{
|
198
|
+
text: 'Select',
|
199
|
+
handler : function(){
|
200
|
+
if (role = w.getWidget().masquerade.role) {
|
201
|
+
Ext.Msg.confirm("Masquerading as a role", "Individual preferences for all users with this role will get overwritten as you make changes. Continue?", function(btn){
|
202
|
+
if (btn === 'yes') {
|
201
203
|
w.close();
|
202
204
|
}
|
203
|
-
}
|
204
|
-
}
|
205
|
-
scope:this
|
206
|
-
},{
|
207
|
-
text:'No masquerading',
|
208
|
-
handler:function(){
|
209
|
-
this.masquerade = {};
|
205
|
+
});
|
206
|
+
} else {
|
210
207
|
w.close();
|
211
|
-
}
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
208
|
+
}
|
209
|
+
},
|
210
|
+
scope:this
|
211
|
+
},{
|
212
|
+
text:'As World',
|
213
|
+
handler:function(){
|
214
|
+
Ext.Msg.confirm("Masquerading as World", "Caution! All settings that you will modify will be overwritten for all roles and all users. Are you sure you know what you're doing?", function(btn){
|
215
|
+
if (btn === "yes") {
|
216
|
+
this.masquerade = {world:true};
|
217
|
+
w.close();
|
218
|
+
}
|
219
|
+
}, this);
|
220
|
+
},
|
221
|
+
scope:this
|
222
|
+
},{
|
223
|
+
text:'No masquerading',
|
224
|
+
handler:function(){
|
225
|
+
this.masquerade = {};
|
226
|
+
w.close();
|
227
|
+
},
|
228
|
+
scope:this
|
229
|
+
},{
|
230
|
+
text:'Cancel',
|
231
|
+
handler:function(){
|
232
|
+
w.hide();
|
233
|
+
},
|
234
|
+
scope:this
|
235
|
+
}],
|
236
|
+
listeners : {close: {fn: function(){
|
237
|
+
this.masqueradeAs(this.masquerade || w.getWidget().masquerade || {});
|
238
|
+
}, scope: this}}
|
239
|
+
});
|
224
240
|
|
225
|
-
|
226
|
-
|
227
|
-
|
241
|
+
w.show(null, function(){
|
242
|
+
this.loadAggregatee({id:"masqueradeSelector", container:w.id})
|
243
|
+
}, this);
|
228
244
|
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
end
|
245
|
+
}
|
246
|
+
END_OF_JAVASCRIPT
|
247
|
+
}
|
233
248
|
end
|
234
249
|
|
235
|
-
extend ClassMethods
|
236
|
-
|
237
250
|
# Set the Logout button if Netzke::Base.user is set
|
238
251
|
def menu
|
239
252
|
res = []
|
240
|
-
user =
|
253
|
+
user = User.find_by_id(session[:netzke_user_id])
|
241
254
|
if !user.nil?
|
242
255
|
user_name = user.respond_to?(:name) ? user.name : user.login # try to display user's name, fallback to login
|
243
256
|
res << "->" <<
|
@@ -246,22 +259,13 @@ module Netzke
|
|
246
259
|
:menu => user_menu
|
247
260
|
}
|
248
261
|
else
|
249
|
-
res << "->" <<
|
250
|
-
{
|
251
|
-
:text => "Login",
|
252
|
-
:handler => <<-END_OF_JAVASCRIPT.l,
|
253
|
-
function(){
|
254
|
-
window.location = "/login"
|
255
|
-
}
|
256
|
-
END_OF_JAVASCRIPT
|
257
|
-
:scope => this
|
258
|
-
}
|
262
|
+
res << "->" << :login
|
259
263
|
end
|
260
264
|
res
|
261
265
|
end
|
262
266
|
|
263
267
|
def user_menu
|
264
|
-
[
|
268
|
+
[:logout]
|
265
269
|
end
|
266
270
|
|
267
271
|
def initialize(*args)
|
@@ -281,8 +285,9 @@ module Netzke
|
|
281
285
|
def actions
|
282
286
|
{
|
283
287
|
:masquerade_selector => {:text => "Masquerade as ...", :fn => "showMasqueradeSelector"},
|
284
|
-
:toggle_config_mode => {:text => "#{session[:config_mode] ? "Leave" : "Enter"} config mode"
|
285
|
-
:
|
288
|
+
:toggle_config_mode => {:text => "#{session[:config_mode] ? "Leave" : "Enter"} config mode"},
|
289
|
+
:login => {:text => "Login"},
|
290
|
+
:logout => {:text => "Logout"}
|
286
291
|
}
|
287
292
|
end
|
288
293
|
|
@@ -297,20 +302,6 @@ module Netzke
|
|
297
302
|
}
|
298
303
|
end
|
299
304
|
|
300
|
-
# We rely on the FeedbackGhost (to not need to implement our own feedback management)
|
301
|
-
def initial_aggregatees
|
302
|
-
{:feedback_ghost => {:widget_class_name => "FeedbackGhost"}}
|
303
|
-
end
|
304
|
-
|
305
|
-
# Besides instantiating ourselves, also instantiate the FeedbackGhost
|
306
|
-
def js_widget_instance
|
307
|
-
<<-END_OF_JAVASCRIPT << super
|
308
|
-
new Ext.netzke.cache['FeedbackGhost']({id:'feedback_ghost'})
|
309
|
-
// Initialize history (can't say why it's not working well inside the appLoaded handler)
|
310
|
-
Ext.History.init();
|
311
|
-
END_OF_JAVASCRIPT
|
312
|
-
end
|
313
|
-
|
314
305
|
#
|
315
306
|
# Interface section
|
316
307
|
#
|