netzke-core 0.6.5 → 0.6.6
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 +7 -0
- data/TODO +2 -0
- data/app/controllers/netzke_controller.rb +72 -20
- data/features/actions.feature +1 -1
- data/features/component_loader.feature +13 -1
- data/features/ext.direct.feature +32 -0
- data/features/i18n.feature +32 -0
- data/features/inheritance.feature +2 -2
- data/features/step_definitions/generic_steps.rb +21 -5
- data/features/step_definitions/touch_steps.rb +3 -0
- data/features/support/env.rb +4 -0
- data/features/support/paths.rb +6 -0
- data/features/touch.feature +10 -0
- data/javascripts/core.js +10 -15
- data/javascripts/ext.js +92 -1
- data/javascripts/touch.js +11 -0
- data/lib/netzke/actions.rb +13 -8
- data/lib/netzke/base.rb +32 -45
- data/lib/netzke/configuration.rb +53 -0
- data/lib/netzke/core/options_hash.rb +27 -0
- data/lib/netzke/core/version.rb +1 -1
- data/lib/netzke/core.rb +15 -5
- data/lib/netzke/core_ext/hash.rb +10 -8
- data/lib/netzke/inheritance.rb +31 -0
- data/lib/netzke/javascript.rb +45 -2
- data/lib/netzke/railz/action_view_ext.rb +8 -0
- data/lib/netzke/railz/controller_extensions.rb +1 -1
- data/lib/netzke/railz/engine.rb +27 -0
- data/lib/netzke/railz.rb +1 -0
- data/lib/netzke/session.rb +4 -0
- data/lib/netzke/state.rb +6 -6
- data/lib/netzke-core.rb +0 -23
- data/netzke-core.gemspec +27 -4
- data/spec/component/actions_spec.rb +2 -2
- data/spec/component/configuration_spec.rb +61 -0
- data/test/rails_app/Gemfile +1 -1
- data/test/rails_app/Gemfile.lock +48 -46
- data/test/rails_app/app/components/component_loader.rb +34 -1
- data/test/rails_app/app/components/ext_direct/composite.rb +48 -0
- data/test/rails_app/app/components/ext_direct/details.rb +13 -0
- data/test/rails_app/app/components/ext_direct/selector.rb +31 -0
- data/test/rails_app/app/components/ext_direct/statistics.rb +13 -0
- data/test/rails_app/app/components/extended_localized_panel.rb +2 -0
- data/test/rails_app/app/components/extended_server_caller.rb +0 -1
- data/test/rails_app/app/components/localized_panel.rb +28 -0
- data/test/rails_app/app/components/server_caller.rb +1 -0
- data/test/rails_app/app/components/server_counter.rb +123 -0
- data/test/rails_app/app/controllers/application_controller.rb +7 -0
- data/test/rails_app/config/initializers/backtrace_silencers.rb +1 -1
- data/test/rails_app/config/initializers/netzke.rb +1 -1
- data/test/rails_app/config/locales/en.yml +9 -2
- data/test/rails_app/config/locales/es.yml +11 -0
- data/test/rails_app/config/routes.rb +2 -2
- metadata +28 -16
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
= v0.6.6 - 2011-02-26
|
2
|
+
* enhancements
|
3
|
+
* Client-server communication is updated to use Ext.Direct (many thanks to @pschyska)
|
4
|
+
* Introduced +js_translate+ class method that allows specifying i18n properties used in the JavaScript class
|
5
|
+
* Better handling of actions i18n
|
6
|
+
* New `Netzke::Base.class_config_option` method to specify a class-level configuration options for a component, e.g. (in GridPanel): `class_config_option :column_filters_available, true`. This option then can be set in Rails application configuration, e.g.: `config.netzke.basepack.grid_panel.column_filters_available = false`, or directly on `Netzke::Core.config`, e.g.: `Netzke::Core.config.netzke.basepack.grid_panel.column_filters_available = false`.
|
7
|
+
|
1
8
|
= v0.6.5 - 2011-01-14
|
2
9
|
* enhancements
|
3
10
|
* Various fixes for IE
|
data/TODO
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
+
Make :items option understand also a hash.
|
1
2
|
Caching for netzke_controller-provided JS and CSS.
|
2
3
|
Caching - investigate reusing (fragment?) caching of Rails.
|
3
4
|
Use Ext.Direct in the Netzke controller.
|
4
5
|
Let specify per API point if it will use a GET or a POST request.
|
5
6
|
|
6
7
|
|
8
|
+
|
7
9
|
= Ideas that didn't work out
|
8
10
|
|
9
11
|
== Making value from super-class accessible in the block parameters in endpoints, e.g.:
|
@@ -1,8 +1,5 @@
|
|
1
1
|
class NetzkeController < ApplicationController
|
2
2
|
|
3
|
-
# Collect javascripts and stylesheets from all plugins that registered it in Netzke::Core.javascripts
|
4
|
-
# TODO: caching
|
5
|
-
# caches_action :netzke
|
6
3
|
def ext
|
7
4
|
respond_to do |format|
|
8
5
|
format.js {
|
@@ -69,33 +66,88 @@ class NetzkeController < ApplicationController
|
|
69
66
|
end
|
70
67
|
end
|
71
68
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
69
|
+
# Action for Ext.Direct RPC calls
|
70
|
+
def direct
|
71
|
+
result=""
|
72
|
+
error=false
|
73
|
+
if params['_json'] # this is a batched request
|
74
|
+
params['_json'].each do |batch|
|
75
|
+
result+= result.blank? ? '[' : ', '
|
76
|
+
begin
|
77
|
+
result+=invoke_endpoint batch[:act], batch[:method].underscore, batch[:data], batch[:tid]
|
78
|
+
rescue Exception => e
|
79
|
+
Rails.logger.error "!!! Netzke: Error invoking endpoint: #{batch[:act]} #{batch[:method].underscore} #{batch[:data].inspect} #{batch[:tid]}\n"
|
80
|
+
Rails.logger.error e.message
|
81
|
+
Rails.logger.error e.backtrace
|
82
|
+
error=true
|
83
|
+
break;
|
84
|
+
end
|
85
|
+
end
|
86
|
+
result+=']'
|
87
|
+
else # this is a single request
|
88
|
+
result=invoke_endpoint params[:act], params[:method].underscore, params[:data], params[:tid]
|
88
89
|
end
|
90
|
+
render :text => result, :layout => false, :status => error ? 500 : 200
|
89
91
|
end
|
90
92
|
|
91
|
-
|
93
|
+
# Action used by non-Ext.Direct (Touch) components
|
94
|
+
def dispatcher
|
95
|
+
endpoint_dispatch(params[:address])
|
96
|
+
end
|
97
|
+
|
98
|
+
protected
|
99
|
+
|
100
|
+
def invoke_endpoint component_name, action, data, tid
|
101
|
+
data=data[0] || {} # we get data as an array, extract the single argument if available
|
102
|
+
|
103
|
+
root_component_name, *sub_components = component_name.split('__')
|
104
|
+
root_component = Netzke::Base.instance_by_config Netzke::Core.session[:netzke_components][root_component_name.to_sym]
|
105
|
+
if sub_components.empty?
|
106
|
+
# we need to dispatch to root component, send it _#{action}_ep_wrapper
|
107
|
+
endpoint_action = "_#{action}_ep_wrapper"
|
108
|
+
else
|
109
|
+
# we need to dispatch to one or more sub_components, send subcomp__subsubcomp__endpoint to root component
|
110
|
+
endpoint_action = sub_components.join('__')+'__'+action
|
111
|
+
end
|
112
|
+
# send back JSON as specified in Ext.direct spec
|
113
|
+
# => type: rpc
|
114
|
+
# => tid, action, method as in the request, so that the client can mark the transaction and won't retry it
|
115
|
+
# => result: JavaScript code from he endpoint result which gets applied to the client-side component instance
|
116
|
+
result = root_component.send(endpoint_action, data)
|
117
|
+
|
118
|
+
{:type => "rpc", :tid => tid, :action => component_name, :method => action, :result => result.present? && result.l || {}}.to_json
|
119
|
+
end
|
120
|
+
|
121
|
+
# Main dispatcher of old-style (Sencha Touch) HTTP requests. The URL contains the name of the component,
|
122
|
+
# as well as the method of this component to be called, according to the double underscore notation.
|
123
|
+
# E.g.: some_grid__post_grid_data.
|
124
|
+
def endpoint_dispatch(method_name)
|
125
|
+
component_name, *action = method_name.to_s.split('__')
|
126
|
+
component_name = component_name.to_sym
|
127
|
+
action = !action.empty? && action.join("__").to_sym
|
128
|
+
|
129
|
+
if action
|
130
|
+
w_instance = Netzke::Base.instance_by_config(Netzke::Core.session[:netzke_components][component_name])
|
131
|
+
# only component's actions starting with "endpoint_" are accessible from outside (security)
|
132
|
+
endpoint_action = action.to_s.index('__') ? action : "_#{action}_ep_wrapper"
|
133
|
+
render :text => w_instance.send(endpoint_action, params), :layout => false
|
134
|
+
else
|
135
|
+
super
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
92
139
|
# Generates initial javascript code that is dependent on Rails environement
|
93
140
|
def initial_dynamic_javascript
|
94
141
|
res = []
|
95
142
|
res << %(Ext.Ajax.extraParams = {authenticity_token: '#{form_authenticity_token}'}; // Rails' forgery protection)
|
96
143
|
res << %{Ext.ns('Netzke');}
|
144
|
+
res << %{Ext.ns('Netzke.core');}
|
97
145
|
res << %{Netzke.RelativeUrlRoot = '#{ActionController::Base.config.relative_url_root}';}
|
98
146
|
res << %{Netzke.RelativeExtUrl = '#{ActionController::Base.config.relative_url_root}/extjs';}
|
147
|
+
|
148
|
+
# TODO: this will needs some DRYing
|
149
|
+
res << %{Netzke.core.directMaxRetries = '#{Netzke::Core.js_direct_max_retries}';}
|
150
|
+
|
99
151
|
res.join("\n")
|
100
152
|
end
|
101
153
|
|
data/features/actions.feature
CHANGED
@@ -9,5 +9,5 @@ Scenario: Pressing button should result in corresponding actions
|
|
9
9
|
Then I should see "Disabled action"
|
10
10
|
And button "Disabled action" should be disabled
|
11
11
|
|
12
|
-
When I press "Some
|
12
|
+
When I press "Some Cool Action"
|
13
13
|
Then I should see "Some action was triggered"
|
@@ -14,11 +14,23 @@ Feature: Component loader
|
|
14
14
|
Then I should see "Component loaded in window"
|
15
15
|
|
16
16
|
@selenium
|
17
|
-
Scenario: Component loader should invoke a callback
|
17
|
+
Scenario: Component loader should invoke a callback in loadComponent
|
18
18
|
Given I am on the ComponentLoader test page
|
19
19
|
When I press "Load with feedback"
|
20
20
|
Then I should see "Callback invoked!"
|
21
21
|
|
22
|
+
@selenium
|
23
|
+
Scenario: Component loader should invoke a generic endpoint callback
|
24
|
+
Given I am on the ComponentLoader test page
|
25
|
+
When I press "Load with generic callback"
|
26
|
+
Then I should see "Generic callback invoked!"
|
27
|
+
|
28
|
+
@selenium
|
29
|
+
Scenario: Component loader should invoke a generic endpoint callback
|
30
|
+
Given I am on the ComponentLoader test page
|
31
|
+
When I press "Load with generic callback and scope"
|
32
|
+
Then I should see "Fancy title set!"
|
33
|
+
|
22
34
|
@selenium
|
23
35
|
Scenario: Component loader should load a window component with another component in it
|
24
36
|
Given I am on the ComponentLoader test page
|
@@ -0,0 +1,32 @@
|
|
1
|
+
Feature: Actions
|
2
|
+
In order to value
|
3
|
+
As a role
|
4
|
+
I want feature
|
5
|
+
|
6
|
+
@javascript
|
7
|
+
Scenario: Making seven consecutive endpoint calls within 10ms batches to one XHR
|
8
|
+
When I go to the ServerCounter test page
|
9
|
+
And I press "Count seven times"
|
10
|
+
Then total requests made should be 1
|
11
|
+
|
12
|
+
@javascript
|
13
|
+
Scenario: Doing two calls to different endpoints preserves the order in request and response
|
14
|
+
When I go to the ServerCounter test page
|
15
|
+
And I press "Do ordered"
|
16
|
+
# "Second." is the indication that the result was applied to the client in the right order
|
17
|
+
# "2" is the indication that the request were processed in the right order on the server side
|
18
|
+
Then I should see "Second. 2"
|
19
|
+
|
20
|
+
@javascript
|
21
|
+
Scenario: 2 out of 5 requests fail, but the retry mechanism should recover, and process them in order
|
22
|
+
Given I go to the ServerCounter test page
|
23
|
+
When I press "Fail two out of five"
|
24
|
+
Then I should see "1,2,3,4,5"
|
25
|
+
|
26
|
+
@javascript
|
27
|
+
Scenario: Updating 3 components (in one request)
|
28
|
+
Given I go to the ExtDirect::Composite test page
|
29
|
+
When I fill in "User:" with "Power User"
|
30
|
+
And I press "Update"
|
31
|
+
Then I should see "Details for user Power User"
|
32
|
+
And I should see "Statistics for user Power User"
|
@@ -0,0 +1,32 @@
|
|
1
|
+
Feature: I18n
|
2
|
+
In order to value
|
3
|
+
As a role
|
4
|
+
I want feature
|
5
|
+
|
6
|
+
@javascript
|
7
|
+
Scenario: LocalizedPanel should be available in 2 languages
|
8
|
+
When I go to the LocalizedPanel test page
|
9
|
+
Then I should see "Localized Panel"
|
10
|
+
And I should see "First property, Second property"
|
11
|
+
And I should see "First action"
|
12
|
+
And I should see "Second action"
|
13
|
+
|
14
|
+
When I go to the "es" version of the LocalizedPanel page
|
15
|
+
Then I should see "Panel Localizada"
|
16
|
+
And I should see "Primera propriedad, Segunda propriedad"
|
17
|
+
And I should see "Primera acción"
|
18
|
+
And I should see "Segunda acción"
|
19
|
+
|
20
|
+
When I go to the "es" version of the ExtendedLocalizedPanel page
|
21
|
+
Then I should see "Panel Localizada"
|
22
|
+
And I should see "Primera propriedad, Segunda propriedad"
|
23
|
+
And I should see "Action one"
|
24
|
+
And I should see "Segunda acción"
|
25
|
+
|
26
|
+
When I go to the "en" version of the ExtendedLocalizedPanel page
|
27
|
+
Then I should see "Localized Panel"
|
28
|
+
And I should see "First property, Second property"
|
29
|
+
And I should see "Action one"
|
30
|
+
And I should see "Second action"
|
31
|
+
|
32
|
+
# NOTE: make sure that the locale is restored to "en" in the end!
|
@@ -5,9 +5,9 @@ Feature: Inheritance
|
|
5
5
|
|
6
6
|
@javascript
|
7
7
|
Scenario: Inherited component should successfully call parent methods in Ruby and JavaScript
|
8
|
-
When I go to the ExtendedServerCaller
|
8
|
+
When I go to the "en" version of the ExtendedServerCaller page
|
9
9
|
Then I should see "Extended Server Caller"
|
10
|
-
When I press "Call server"
|
10
|
+
When I press "Call server extensively"
|
11
11
|
Then I should see "All quiet here on the server, shiny weather"
|
12
12
|
And I should see "Added by extended Server Caller"
|
13
13
|
|
@@ -6,10 +6,26 @@ When /^I execute "([^\"]*)"$/ do |script|
|
|
6
6
|
page.driver.browser.execute_script(script)
|
7
7
|
end
|
8
8
|
|
9
|
-
Then /^button "([
|
10
|
-
|
9
|
+
Then /^button "([^"]*)" should be enabled$/ do |arg1|
|
10
|
+
page.driver.browser.execute_script(<<-JS).should == true
|
11
|
+
var btn = Ext.ComponentMgr.all.filter('text', '#{arg1}').filter('type','button').first();
|
12
|
+
return typeof(btn)!='undefined' ? !btn.disabled : false
|
13
|
+
JS
|
11
14
|
end
|
12
15
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
+
Then /^button "([^"]*)" should be disabled$/ do |arg1|
|
17
|
+
page.driver.browser.execute_script(<<-JS).should == true
|
18
|
+
var btn = Ext.ComponentMgr.all.filter('text', '#{arg1}').filter('type','button').first();
|
19
|
+
return typeof(btn)!='undefined' ? btn.disabled : false
|
20
|
+
JS
|
21
|
+
end
|
22
|
+
|
23
|
+
When /^total requests made should be (\d+)$/ do |count|
|
24
|
+
page.driver.browser.execute_script(<<-JS).should == true
|
25
|
+
return Netzke.connectionCount == #{count};
|
26
|
+
JS
|
27
|
+
end
|
28
|
+
|
29
|
+
When /I sleep (\d+) seconds?/ do |arg1|
|
30
|
+
sleep arg1.to_i
|
31
|
+
end
|
data/features/support/env.rb
CHANGED
@@ -27,6 +27,10 @@ require 'cucumber/rails/capybara_javascript_emulation' # Lets you click links wi
|
|
27
27
|
# steps to use the XPath syntax.
|
28
28
|
Capybara.default_selector = :css
|
29
29
|
|
30
|
+
# Capybara.register_driver :selenium do |app|
|
31
|
+
# Capybara::Driver::Selenium.new(app, {:browser => :chrome } )
|
32
|
+
# end
|
33
|
+
|
30
34
|
# If you set this to false, any error raised from within your app will bubble
|
31
35
|
# up to your step definition and out to cucumber unless you catch it somewhere
|
32
36
|
# on the way. You can make Rails rescue errors and render error pages on a
|
data/features/support/paths.rb
CHANGED
@@ -32,6 +32,12 @@ module NavigationHelpers
|
|
32
32
|
when /the (.*) test page/
|
33
33
|
components_path(:component => $1)
|
34
34
|
|
35
|
+
when /the (.*) page for touch/
|
36
|
+
touch_components_path(:component => $1)
|
37
|
+
|
38
|
+
when /the "(.+)" version of the (.*) page/
|
39
|
+
components_path(:component => $2, :locale => $1)
|
40
|
+
|
35
41
|
else
|
36
42
|
begin
|
37
43
|
page_name =~ /the (.*) page/
|
@@ -0,0 +1,10 @@
|
|
1
|
+
Feature: Touch - to be run in Chrome only
|
2
|
+
In order to value
|
3
|
+
As a role
|
4
|
+
I want feature
|
5
|
+
|
6
|
+
@javascript
|
7
|
+
Scenario: Client-server communication
|
8
|
+
Given I am on the ServerCaller page for touch
|
9
|
+
When I press button "Bug server"
|
10
|
+
Then I should see "Hello from the server!"
|
data/javascripts/core.js
CHANGED
@@ -11,9 +11,9 @@ Ext.BLANK_IMAGE_URL = Netzke.RelativeExtUrl + "/resources/images/default/s.gif";
|
|
11
11
|
Ext.ns('Ext.netzke'); // namespace for extensions that depend on Ext
|
12
12
|
|
13
13
|
Netzke.isLoading=function () {
|
14
|
-
return Netzke.runningRequests!=0;
|
14
|
+
return Netzke.runningRequests != 0;
|
15
15
|
}
|
16
|
-
Netzke.runningRequests=0
|
16
|
+
Netzke.runningRequests = 0;
|
17
17
|
|
18
18
|
Netzke.deprecationWarning = function(msg){
|
19
19
|
if (typeof console == 'undefined') {
|
@@ -108,17 +108,6 @@ Netzke.componentMixin = Ext.applyIf(Netzke.classes.Core.Mixin, {
|
|
108
108
|
// receiver.superclass.constructor.call(this, config);
|
109
109
|
// },
|
110
110
|
|
111
|
-
/*
|
112
|
-
Dynamically creates methods for api points, so that we could later call them like: this.myEndpointMethod()
|
113
|
-
*/
|
114
|
-
processEndpoints: function(){
|
115
|
-
var endpoints = this.endpoints || [];
|
116
|
-
endpoints.push('deliver_component'); // all Netzke components get this endpoint
|
117
|
-
Ext.each(endpoints, function(intp){
|
118
|
-
this[intp.camelize(true)] = function(args, callback, scope){ this.callServer(intp, args, callback, scope); }
|
119
|
-
}, this);
|
120
|
-
},
|
121
|
-
|
122
111
|
/*
|
123
112
|
Detects component placeholders in the passed object (typically, "items"),
|
124
113
|
and merges them with the corresponding config from this.components.
|
@@ -217,8 +206,14 @@ Netzke.componentMixin = Ext.applyIf(Netzke.classes.Core.Mixin, {
|
|
217
206
|
return this.endpointUrl(endpoint);
|
218
207
|
},
|
219
208
|
|
209
|
+
// endpointUrl: function(endpoint){
|
210
|
+
// Netzke.deprecationWarning("endpointUrl() is deprecated. Use Ext.direct counterparts instead.\nFor example, specify a DirectProxy instead of HttpProxy ( proxy: new Ext.data.DirectProxy({directFn: Netzke.providers[this.id].endPoint}) ),\nor specify api instead of url config option for BasicForm ( api: { load: Netzke.providers[this.id].loadEndPoint, submit: Netzke.providers[this.id].submitEndPoint} )");
|
211
|
+
// return Netzke.RelativeUrlRoot + "/netzke/" + this.id + "__" + endpoint;
|
212
|
+
// },
|
213
|
+
|
214
|
+
// Used by Touch components
|
220
215
|
endpointUrl: function(endpoint){
|
221
|
-
return Netzke.RelativeUrlRoot + "/netzke/" + this.id + "__" + endpoint;
|
216
|
+
return Netzke.RelativeUrlRoot + "/netzke/dispatcher?address=" + this.id + "__" + endpoint;
|
222
217
|
},
|
223
218
|
|
224
219
|
// Does the call to the server and processes the response
|
@@ -239,10 +234,10 @@ Netzke.componentMixin = Ext.applyIf(Netzke.classes.Core.Mixin, {
|
|
239
234
|
callback.apply(scope, [this.latestResult]);
|
240
235
|
}
|
241
236
|
}
|
237
|
+
Netzke.runningRequests--;
|
242
238
|
},
|
243
239
|
scope : this
|
244
240
|
});
|
245
|
-
Netzke.runningRequests--;
|
246
241
|
},
|
247
242
|
|
248
243
|
setResult: function(result) {
|
data/javascripts/ext.js
CHANGED
@@ -15,6 +15,65 @@ Ext.state.Provider.prototype.set = function(){};
|
|
15
15
|
}
|
16
16
|
})();
|
17
17
|
|
18
|
+
Netzke.classes.NetzkeRemotingProvider=Ext.extend(Ext.direct.RemotingProvider,{
|
19
|
+
getCallData: function(t){
|
20
|
+
return {
|
21
|
+
act: t.action, // rails doesn't really support having a parameter named "action"
|
22
|
+
method: t.method,
|
23
|
+
data: t.data,
|
24
|
+
type: 'rpc',
|
25
|
+
tid: t.tid
|
26
|
+
}
|
27
|
+
},
|
28
|
+
|
29
|
+
addAction: function(action, methods) {
|
30
|
+
var cls = this.namespace[action] || (this.namespace[action] = {});
|
31
|
+
for(var i = 0, len = methods.length; i < len; i++){
|
32
|
+
var m = methods[i];
|
33
|
+
cls[m.name] = this.createMethod(action, m);
|
34
|
+
}
|
35
|
+
},
|
36
|
+
|
37
|
+
// process response regardess of status
|
38
|
+
// i.e. in a batch request,
|
39
|
+
// - we request tids 1,2,3.
|
40
|
+
// - server is able to process 1 but not 2
|
41
|
+
// - server will stop and *not* process 3, because it could be dependant on 2 (this best possible approach to this
|
42
|
+
// situation, as we don't have transactions)
|
43
|
+
// - server will respond with status 500, indicating a fault
|
44
|
+
// - in the response, server will respond with the result from tid 1
|
45
|
+
// - client marks tid 1 as success (deletes the transaction from pending), and will retry 2 and 3 - this is the
|
46
|
+
// change in Ext.direct.RemotingProvider's default behaviour
|
47
|
+
onData: function(opt, success, xhr){
|
48
|
+
var events=this.getEvents(xhr);
|
49
|
+
|
50
|
+
for(var i = 0, len = events.length; i < len; i++){
|
51
|
+
var e = events[i],
|
52
|
+
t = this.getTransaction(e);
|
53
|
+
this.fireEvent('data', this, e);
|
54
|
+
if(t){
|
55
|
+
this.doCallback(t, e, true);
|
56
|
+
Ext.Direct.removeTransaction(t);
|
57
|
+
}
|
58
|
+
}
|
59
|
+
|
60
|
+
Netzke.classes.NetzkeRemotingProvider.superclass.onData.call(this, opt, success, xhr);
|
61
|
+
}
|
62
|
+
|
63
|
+
});
|
64
|
+
|
65
|
+
Netzke.directProvider = new Netzke.classes.NetzkeRemotingProvider({
|
66
|
+
"type": "remoting", // create a Ext.direct.RemotingProvider
|
67
|
+
"url": Netzke.RelativeUrlRoot + "/netzke/direct/", // url to connect to the Ext.Direct server-side router.
|
68
|
+
"namespace": "Netzke.providers", // namespace to create the Remoting Provider in
|
69
|
+
"actions": {},
|
70
|
+
"maxRetries": Netzke.core.directMaxRetries,
|
71
|
+
"enableBuffer": true, // buffer/batch requests within 10ms timeframe
|
72
|
+
"timeout": 30000 // 30s timeout per request
|
73
|
+
});
|
74
|
+
|
75
|
+
Ext.Direct.addProvider(Netzke.directProvider);
|
76
|
+
|
18
77
|
Ext.apply(Netzke.classes.Core.Mixin, {
|
19
78
|
height: 400,
|
20
79
|
border: false,
|
@@ -63,6 +122,38 @@ Ext.apply(Netzke.classes.Core.Mixin, {
|
|
63
122
|
this.initComponentWithoutNetzke();
|
64
123
|
},
|
65
124
|
|
125
|
+
/*
|
126
|
+
Dynamically creates methods for endpoints, so that we could later call them like: this.myEndpointMethod() (using Ext.Direct)
|
127
|
+
*/
|
128
|
+
processEndpoints: function(){
|
129
|
+
var endpoints = this.endpoints || [];
|
130
|
+
endpoints.push('deliver_component'); // all Netzke components get this endpoint
|
131
|
+
var directActions = [];
|
132
|
+
var that=this;
|
133
|
+
|
134
|
+
Ext.each(endpoints, function(intp){
|
135
|
+
directActions.push({"name":intp.camelize(true), "len":1});
|
136
|
+
//this[intp.camelize(true)] = function(args, callback, scope){ this.callServer(intp, args, callback, scope); }
|
137
|
+
this[intp.camelize(true)] = function(arg, callback, scope) {
|
138
|
+
Netzke.runningRequests++;
|
139
|
+
scope=scope || that;
|
140
|
+
Netzke.providers[this.id][intp.camelize(true)].call(typeof scope != 'undefined' ? scope : that, arg, function(result, remotingEvent) {
|
141
|
+
if(remotingEvent.message) {
|
142
|
+
console.error("RPC event indicates an error: ", remotingEvent);
|
143
|
+
throw new Error(remotingEvent.message);
|
144
|
+
}
|
145
|
+
that.bulkExecute(result); // invoke the endpoint result on the calling component
|
146
|
+
if(typeof callback == "function") {
|
147
|
+
callback.call(scope, that.latestResult); // invoke the callback on the provided scope, or on the calling component if no scope set. Pass latestResult to callback
|
148
|
+
}
|
149
|
+
Netzke.runningRequests--;
|
150
|
+
});
|
151
|
+
}
|
152
|
+
}, this);
|
153
|
+
|
154
|
+
Netzke.directProvider.addAction(this.id, directActions);
|
155
|
+
},
|
156
|
+
|
66
157
|
normalizeTools: function() {
|
67
158
|
if (this.tools) {
|
68
159
|
var normTools = [];
|
@@ -87,7 +178,7 @@ Ext.apply(Netzke.classes.Core.Mixin, {
|
|
87
178
|
this.addEvents(name+'click');
|
88
179
|
|
89
180
|
// Configure the action
|
90
|
-
var actionConfig = this.actions[name];
|
181
|
+
var actionConfig = Ext.apply({}, this.actions[name]); // do not modify original this.actions
|
91
182
|
actionConfig.customHandler = actionConfig.handler;
|
92
183
|
actionConfig.handler = this.actionHandler.createDelegate(this); // handler common for all actions
|
93
184
|
actionConfig.name = name;
|
data/javascripts/touch.js
CHANGED
@@ -15,6 +15,17 @@ Ext.apply(Netzke.classes.Core.Mixin, {
|
|
15
15
|
this.initComponentWithoutNetzke();
|
16
16
|
},
|
17
17
|
|
18
|
+
/*
|
19
|
+
Dynamically creates methods for api points, so that we could later call them like: this.myEndpointMethod()
|
20
|
+
*/
|
21
|
+
processEndpoints: function(){
|
22
|
+
var endpoints = this.endpoints || [];
|
23
|
+
endpoints.push('deliver_component'); // all Netzke components get this endpoint
|
24
|
+
Ext.each(endpoints, function(intp){
|
25
|
+
this[intp.camelize(true)] = function(args, callback, scope){ this.callServer(intp, args, callback, scope); }
|
26
|
+
}, this);
|
27
|
+
},
|
28
|
+
|
18
29
|
/*
|
19
30
|
Detects action configs in the passed object, and replaces them with instances of Ext.Action created by normalizeActions().
|
20
31
|
This detects action in arbitrary level of nesting, which means you can put any other components in your toolbar, and inside of them specify menus/items or even toolbars.
|
data/lib/netzke/actions.rb
CHANGED
@@ -85,16 +85,21 @@ module Netzke
|
|
85
85
|
private
|
86
86
|
|
87
87
|
def normalize_action_config(config)
|
88
|
-
|
89
|
-
|
90
|
-
|
88
|
+
config.tap do |c|
|
89
|
+
if c[:icon].is_a?(Symbol)
|
90
|
+
c[:icon] = uri_to_icon(c[:icon])
|
91
|
+
end
|
91
92
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
config[:tooltip] ||= I18n.t(i18n_id + ".actions." + config[:name] + "_tooltip", :default => default_text)
|
93
|
+
# Default text and tooltip
|
94
|
+
c[:text] ||= c[:name].humanize
|
95
|
+
c[:tooltip] ||= c[:name].humanize
|
96
96
|
|
97
|
-
|
97
|
+
# If we have an I18n for it, use it
|
98
|
+
default_text = I18n.t(i18n_id + ".actions." + c[:name], :default => "")
|
99
|
+
c[:text] = default_text if default_text.present?
|
100
|
+
default_tooltip = I18n.t(i18n_id + ".actions." + c[:name] + "_tooltip", :default => default_text)
|
101
|
+
c[:tooltip] = default_tooltip if default_tooltip.present?
|
102
|
+
end
|
98
103
|
end
|
99
104
|
|
100
105
|
def uri_to_icon(icon)
|
data/lib/netzke/base.rb
CHANGED
@@ -3,6 +3,7 @@ require 'active_support/memoizable'
|
|
3
3
|
require 'netzke/core_ext'
|
4
4
|
require 'netzke/javascript'
|
5
5
|
require 'netzke/stylesheets'
|
6
|
+
require 'netzke/inheritance'
|
6
7
|
require 'netzke/services'
|
7
8
|
require 'netzke/composition'
|
8
9
|
require 'netzke/configuration'
|
@@ -15,29 +16,32 @@ module Netzke
|
|
15
16
|
# The base for every Netzke component
|
16
17
|
#
|
17
18
|
# == Class-level configuration
|
18
|
-
# You can configure
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
19
|
+
# You can configure component classes in Rails Application, e.g.:
|
20
|
+
#
|
21
|
+
# config.netzke.basepack.grid_panel.column_filters_available = false
|
22
|
+
#
|
23
|
+
# Optionally, when used outside of Rails, you can also set the values directly on Netzke::Core.config (the Engine does it for you):
|
24
|
+
#
|
25
|
+
# Netzke::Core.config.netzke.basepack.grid_panel.column_filters_available = false
|
26
|
+
#
|
27
|
+
# If both default and overriding values are hashes, the default value gets deep-merged with the overriding value.
|
23
28
|
#
|
24
29
|
# Netzke::Base provides the following class-level configuration options:
|
25
|
-
# * default_instance_config - a hash that will be used as default configuration for this component's instances
|
30
|
+
# * default_instance_config - a hash that will be used as default configuration for ALL of this component's instances.
|
26
31
|
class Base
|
27
|
-
|
28
|
-
class_attribute :default_instance_config
|
29
|
-
self.default_instance_config = {}
|
30
|
-
|
31
32
|
include Session
|
32
33
|
include State
|
33
34
|
include Configuration
|
34
35
|
include Javascript
|
36
|
+
include Inheritance
|
35
37
|
include Services
|
36
38
|
include Composition
|
37
39
|
include Stylesheets
|
38
40
|
include Embedding
|
39
41
|
include Actions
|
40
42
|
|
43
|
+
class_config_option :default_instance_config, {}
|
44
|
+
|
41
45
|
# Parent component
|
42
46
|
attr_reader :parent
|
43
47
|
|
@@ -73,42 +77,11 @@ module Netzke
|
|
73
77
|
(config[:klass] || constantize_class_name(config[:class_name])).new(config)
|
74
78
|
end
|
75
79
|
|
76
|
-
#
|
77
|
-
def
|
78
|
-
|
79
|
-
[]
|
80
|
-
else
|
81
|
-
superclass.class_ancestors + [self]
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
# Same as +read_inheritable_attribute+ returning a hash, but returns empty hash when it's equal to superclass's
|
86
|
-
def read_clean_inheritable_hash(attr_name)
|
87
|
-
res = read_inheritable_attribute(attr_name) || {}
|
88
|
-
# We don't want here any values from the superclass (which is the consequence of using inheritable attributes).
|
89
|
-
res == self.superclass.read_inheritable_attribute(attr_name) ? {} : res
|
90
|
-
end
|
91
|
-
|
92
|
-
# Same as +read_inheritable_attribute+ returning a hash, but returns empty hash when it's equal to superclass's
|
93
|
-
def read_clean_inheritable_array(attr_name)
|
94
|
-
res = read_inheritable_attribute(attr_name) || []
|
95
|
-
# We don't want here any values from the superclass (which is the consequence of using inheritable attributes).
|
96
|
-
res == self.superclass.read_inheritable_attribute(attr_name) ? [] : res
|
80
|
+
# The ID used to locate this component's block in locale files
|
81
|
+
def i18n_id
|
82
|
+
name.split("::").map{|c| c.underscore}.join(".")
|
97
83
|
end
|
98
|
-
end
|
99
|
-
|
100
84
|
|
101
|
-
def self.total_instances
|
102
|
-
@@instances || 0
|
103
|
-
end
|
104
|
-
|
105
|
-
def self.reset_total_instances
|
106
|
-
@@instances = 0
|
107
|
-
end
|
108
|
-
|
109
|
-
def self.increase_total_instances
|
110
|
-
@@instances ||= 0
|
111
|
-
@@instances += 1
|
112
85
|
end
|
113
86
|
|
114
87
|
# Instantiates a component instance. A parent can optionally be provided.
|
@@ -147,7 +120,21 @@ module Netzke
|
|
147
120
|
end
|
148
121
|
|
149
122
|
def i18n_id
|
150
|
-
self.class.
|
123
|
+
self.class.i18n_id
|
124
|
+
end
|
125
|
+
|
126
|
+
# Used for performance measurments
|
127
|
+
def self.total_instances
|
128
|
+
@@instances || 0
|
129
|
+
end
|
130
|
+
|
131
|
+
def self.reset_total_instances
|
132
|
+
@@instances = 0
|
133
|
+
end
|
134
|
+
|
135
|
+
def self.increase_total_instances
|
136
|
+
@@instances ||= 0
|
137
|
+
@@instances += 1
|
151
138
|
end
|
152
139
|
|
153
140
|
private
|