rsence 2.0.0.10.pre → 2.0.0.11
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +10 -0
- data/INSTALL.rdoc +52 -86
- data/{LICENSE → LICENSE.txt} +0 -0
- data/README.rdoc +52 -49
- data/VERSION +1 -1
- data/bin/rsence +4 -6
- data/conf/default_conf.yaml +314 -305
- data/conf/default_strings.yaml +70 -71
- data/docs/ExampleGuiPlugin.rdoc +193 -0
- data/{js/comm/comm/autosync/js.inc → docs/JavascriptBundles.rdoc} +0 -0
- data/docs/PluginBundleInfo.rdoc +173 -0
- data/docs/PluginBundles.rdoc +96 -0
- data/docs/Values.rdoc +163 -0
- data/js/comm/{comm/autosync → autosync}/autosync.js +1 -2
- data/js/comm/{comm → autosync}/js.inc +0 -0
- data/js/comm/{comm/comm.js → comm.js} +1 -0
- data/js/comm/{comm/queue/js.inc → js.inc} +0 -0
- data/js/comm/jsloader/jsloader.js +2 -4
- data/js/comm/{comm/session → queue}/js.inc +0 -0
- data/js/comm/{comm/queue → queue}/queue.js +1 -0
- data/js/comm/{comm/sessionwatcher → session}/js.inc +0 -0
- data/js/comm/{comm/session → session}/session.js +4 -3
- data/js/comm/{comm/transporter → sessionwatcher}/js.inc +0 -0
- data/js/comm/{comm/sessionwatcher → sessionwatcher}/sessionwatcher.js +1 -0
- data/js/comm/{comm/urlresponder → transporter}/js.inc +0 -0
- data/js/comm/{comm/transporter → transporter}/transporter.js +1 -0
- data/js/comm/{comm/values → urlresponder}/js.inc +0 -0
- data/js/comm/{comm/urlresponder → urlresponder}/urlresponder.js +1 -0
- data/js/comm/{reloadapp → values}/js.inc +0 -0
- data/js/comm/{comm/values → values}/values.js +1 -0
- data/js/controls/button/button.js +10 -1
- data/js/controls/checkbox/checkbox.js +2 -0
- data/js/controls/dialogs/alert_sheet/alert_sheet.js +1 -0
- data/js/controls/dialogs/confirm_sheet/confirm_sheet.js +1 -0
- data/js/controls/dialogs/sheet/sheet.js +1 -0
- data/js/controls/imageview/imageview.js +1 -0
- data/js/controls/passwordcontrol/passwordcontrol.js +1 -0
- data/js/controls/progress/progressbar/progressbar.js +1 -0
- data/js/controls/progress/progressindicator/progressindicator.js +1 -0
- data/js/controls/radiobutton/radiobutton.js +3 -1
- data/js/controls/sliders/slider/slider.js +1 -0
- data/js/controls/sliders/vslider/vslider.js +1 -0
- data/js/controls/stepper/stepper.js +1 -0
- data/js/controls/stringview/stringview.js +2 -2
- data/js/controls/tab/tab.js +7 -5
- data/js/controls/textarea/textarea.js +1 -0
- data/js/controls/textcontrol/textcontrol.js +3 -1
- data/js/controls/uploader/uploader.js +1 -0
- data/js/controls/validatorview/validatorview.js +62 -59
- data/js/controls/window/window.js +1 -0
- data/js/core/class/class.js +2 -1
- data/js/core/elem/elem.js +27 -27
- data/js/core/event/event.js +3 -874
- data/js/{comm/sha → core/rsence_ns}/js.inc +0 -0
- data/js/core/rsence_ns/rsence_ns.js +15 -0
- data/js/{controls/datetime → datetime}/calendar/calendar.js +1 -0
- data/js/{comm/values/value → datetime/calendar}/js.inc +0 -0
- data/js/{controls/datetime → datetime}/calendar/themes/default/calendar.css +0 -0
- data/js/{controls/datetime → datetime}/calendar/themes/default/calendar.html +0 -0
- data/js/{controls/datetime → datetime}/calendar/themes/default/calendar_arrows-ie6.gif +0 -0
- data/js/{controls/datetime → datetime}/calendar/themes/default/calendar_arrows.png +0 -0
- data/js/{controls/datetime → datetime}/datetimevalue/datetimevalue.js +1 -0
- data/js/{comm/values/valuematrix → datetime/datetimevalue}/js.inc +0 -0
- data/js/{controls/datetime/calendar → datetime/timesheet}/js.inc +0 -0
- data/js/{controls/datetime → datetime}/timesheet/themes/default/timesheet.css +0 -0
- data/js/{controls/datetime → datetime}/timesheet/themes/default/timesheet.html +0 -0
- data/js/{controls/datetime → datetime}/timesheet/timesheet.js +1 -0
- data/js/{controls/datetime/datetimevalue → datetime/timesheet_item}/js.inc +0 -0
- data/js/{controls/datetime → datetime}/timesheet_item/themes/default/timesheet_item.css +0 -0
- data/js/{controls/datetime → datetime}/timesheet_item/themes/default/timesheet_item.html +0 -0
- data/js/{controls/datetime → datetime}/timesheet_item/timesheet_item.js +1 -0
- data/js/{controls/datetime/timesheet → datetime/timesheet_item_edit}/js.inc +0 -0
- data/js/{controls/datetime → datetime}/timesheet_item_edit/timesheet_item_edit.js +1 -1
- data/js/foundation/application/application.js +1 -2
- data/js/foundation/control/control.js +1 -4
- data/js/foundation/control/controldefaults/controldefaults.js +1 -4
- data/js/foundation/control/dummyvalue/dummyvalue.js +1 -0
- data/js/foundation/control/dyncontrol/dyncontrol.js +1 -2
- data/js/foundation/control/eventresponder/eventresponder.js +11 -3
- data/js/{controls/datetime/timesheet_item → foundation/control/valuematrix}/js.inc +0 -0
- data/js/{comm/values → foundation/control}/valuematrix/valuematrix.js +2 -5
- data/js/foundation/control/valueresponder/valueresponder.js +3 -1
- data/js/foundation/eventmanager/eventmanager.js +884 -0
- data/js/{controls/datetime/timesheet_item_edit → foundation/eventmanager}/js.inc +0 -0
- data/js/foundation/geom/point/point.js +2 -2
- data/js/foundation/geom/rect/rect.js +1 -0
- data/js/foundation/json_renderer/json_renderer.js +2 -0
- data/js/foundation/system/system.js +2 -1
- data/js/foundation/thememanager/thememanager.js +29 -23
- data/js/{controls/lists/checkboxlist → foundation/value}/js.inc +0 -0
- data/js/{comm/values → foundation}/value/value.js +1 -0
- data/js/foundation/view/markupview/markupview.js +2 -1
- data/js/foundation/view/morphanimation/morphanimation.js +1 -0
- data/js/foundation/view/view.js +6 -12
- data/js/foundation/view/viewdefaults/viewdefaults.js +1 -0
- data/js/{controls/lists → lists}/checkboxlist/checkboxlist.js +1 -0
- data/js/{controls/lists/listitems → lists/checkboxlist}/js.inc +0 -0
- data/js/{controls/lists/radiobuttonlist → lists/listitems}/js.inc +0 -0
- data/js/{controls/lists → lists}/listitems/listitems.js +22 -3
- data/js/lists/radiobuttonlist/js.inc +0 -0
- data/js/{controls/lists → lists}/radiobuttonlist/radiobuttonlist.js +2 -12
- data/js/util/reloadapp/js.inc +0 -0
- data/js/{comm → util}/reloadapp/reloadapp.js +10 -8
- data/js/{comm → util}/reloadapp/themes/default/reloadapp_warning-ie6.gif +0 -0
- data/js/{comm → util}/reloadapp/themes/default/reloadapp_warning.png +0 -0
- data/js/util/sha/js.inc +0 -0
- data/js/{comm → util}/sha/sha.js +27 -33
- data/js/views/centerview/centerview.js +33 -3
- data/js/views/inlineview/inlineview.js +1 -0
- data/js/views/scrollview/scrollview.js +1 -0
- data/lib/conf/argv.rb +34 -22
- data/lib/conf/default.rb +165 -173
- data/lib/daemon/daemon.rb +9 -9
- data/lib/daemon/sigcomm.rb +4 -4
- data/lib/http/broker.rb +30 -27
- data/lib/http/rackup.rb +2 -3
- data/lib/http/request.rb +1 -2
- data/lib/http/response.rb +10 -10
- data/lib/plugins/dependencies.rb +2 -1
- data/lib/plugins/gui_plugin.rb +77 -50
- data/lib/plugins/guiparser.rb +26 -22
- data/lib/plugins/plugin.rb +207 -427
- data/lib/plugins/plugin_base.rb +162 -0
- data/lib/plugins/plugin_plugins.rb +21 -15
- data/lib/plugins/plugin_sqlite_db.rb +45 -20
- data/lib/plugins/pluginmanager.rb +10 -5
- data/lib/plugins/plugins.rb +65 -31
- data/lib/plugins/servlet.rb +74 -26
- data/lib/rsence.rb +32 -0
- data/lib/session/msg.rb +131 -96
- data/lib/session/sessionmanager.rb +5 -4
- data/lib/session/sessionstorage.rb +4 -3
- data/lib/transporter/transporter.rb +30 -21
- data/lib/util/gzstring.rb +4 -2
- data/lib/util/ruby19_fixes.rb +18 -0
- data/lib/values/hvalue.rb +139 -88
- data/lib/values/valuemanager.rb +60 -46
- data/plugins/client_pkg/client_pkg.rb +6 -5
- data/plugins/client_pkg/lib/client_pkg_build.rb +5 -5
- data/plugins/client_pkg/lib/client_pkg_serve.rb +8 -0
- data/plugins/index_html/index_html.rb +3 -1
- data/plugins/index_html/tmpl/index.html +2 -3
- data/plugins/main/js/main.js +84 -0
- data/plugins/main/main.rb +54 -27
- data/plugins/ticket/lib/common.rb +4 -2
- data/plugins/ticket/lib/favicon.rb +3 -2
- data/plugins/ticket/lib/file.rb +2 -2
- data/plugins/ticket/lib/img.rb +2 -2
- data/plugins/ticket/lib/objblob.rb +2 -2
- data/plugins/ticket/lib/rsrc.rb +2 -2
- data/plugins/ticket/lib/upload.rb +9 -8
- data/plugins/ticket/ticket.rb +141 -8
- data/setup/welcome/welcome.rb +1 -0
- metadata +76 -72
- data/lib/plugins/plugin_util.rb +0 -107
- data/plugins/index_html/tmpl/startup_index.html +0 -29
- data/plugins/main/js/riassence_ns.js +0 -87
- data/setup/legacy/info.yaml +0 -18
- data/setup/legacy/legacy.rb +0 -17
- data/setup/welcome/gui/welcome.yaml +0 -68
- data/setup/welcome/text/welcome.html +0 -8
data/lib/plugins/guiparser.rb
CHANGED
@@ -6,27 +6,31 @@
|
|
6
6
|
# with this software package. If not, contact licensing@riassence.com
|
7
7
|
##
|
8
8
|
|
9
|
-
|
9
|
+
|
10
|
+
module RSence
|
11
|
+
|
12
|
+
|
10
13
|
module Plugins
|
11
14
|
|
15
|
+
|
12
16
|
# This class automatically loads a YAML file from "gui" subdirectory of a plugin.
|
13
|
-
#
|
14
|
-
# this work automatically.
|
15
|
-
#
|
16
|
-
# Initialize like this from inside a plugin method. This will load the "gui/my_gui.yaml" file.
|
17
|
-
#
|
18
|
-
#
|
17
|
+
#
|
18
|
+
# Extend your plugin from the {GUIPlugin__ GUIPlugin} class instead of the Plugin class to make this work automatically.
|
19
|
+
#
|
20
|
+
# @example Initialize like this from inside a plugin method. This will load the "gui/my_gui.yaml" file.
|
21
|
+
# gui = GUIParser.new( self, 'my_gui' )
|
22
|
+
#
|
23
|
+
# @example To make the client render the contents of the yaml do this:
|
19
24
|
# ses = get_ses( msg )
|
20
25
|
# params = { :values => @gui.values( ses ) }
|
21
|
-
#
|
26
|
+
# gui.init( msg, params )
|
22
27
|
class GUIParser
|
23
|
-
|
24
|
-
include ::RSence
|
25
|
-
|
28
|
+
|
29
|
+
# include ::RSence
|
30
|
+
|
26
31
|
# Use this method to send the client all commands required to construct the GUI Tree using JSONRenderer.
|
27
|
-
#
|
28
|
-
#
|
29
|
-
# +params+:: An hash containing all parameters referred from the YAML file.
|
32
|
+
# @param [Message] msg The +Message+ instance +msg+ used all over the place.
|
33
|
+
# @param [Hash] params Containing all parameters referred from the YAML file, see: {GUIPlugin__#gui_params GUIPlugin#gui_params}
|
30
34
|
def init( msg, params )
|
31
35
|
gui_data = YAML.load( @yaml_src )
|
32
36
|
parse_gui( gui_data, params )
|
@@ -44,24 +48,24 @@ module ::RSence
|
|
44
48
|
json_data = JSON.dump( gui_data )
|
45
49
|
msg.reply( "JSONRenderer.nu(#{json_data});", true )
|
46
50
|
end
|
47
|
-
|
51
|
+
|
48
52
|
# Use this method to extract all the value id's of the +ses+ hash.
|
49
53
|
def values( ses )
|
50
54
|
ids = {}
|
51
55
|
ses.each do | key, value |
|
52
56
|
if value.class == HValue
|
53
|
-
ids[ key ] = value.
|
57
|
+
ids[ key ] = value.value_id
|
54
58
|
end
|
55
59
|
end
|
56
60
|
return ids
|
57
61
|
end
|
58
|
-
|
62
|
+
|
59
63
|
private
|
60
|
-
|
64
|
+
|
61
65
|
def json_fun( value )
|
62
66
|
JSON.parse( "[#{value}]" ).first
|
63
67
|
end
|
64
|
-
|
68
|
+
|
65
69
|
# Parses the gui data using params. Called from +init+.
|
66
70
|
def parse_gui( gui_data, params )
|
67
71
|
data_class = gui_data.class
|
@@ -86,7 +90,7 @@ module ::RSence
|
|
86
90
|
end
|
87
91
|
return gui_data
|
88
92
|
end
|
89
|
-
|
93
|
+
|
90
94
|
# Searches the params hash for parameters whenever encountered a Symbol in the YAML.
|
91
95
|
def get_params( params_path, params )
|
92
96
|
item = params_path.shift
|
@@ -104,7 +108,7 @@ module ::RSence
|
|
104
108
|
end
|
105
109
|
return ''
|
106
110
|
end
|
107
|
-
|
111
|
+
|
108
112
|
# Loads the YAML file.
|
109
113
|
# = Parameters
|
110
114
|
# +parent+:: The Plugin instance called from, use +self+ when constructing in a Plugin method.
|
@@ -113,7 +117,7 @@ module ::RSence
|
|
113
117
|
@parent = parent
|
114
118
|
@yaml_src = yaml_src
|
115
119
|
end
|
116
|
-
|
120
|
+
|
117
121
|
end
|
118
122
|
end
|
119
123
|
end
|
data/lib/plugins/plugin.rb
CHANGED
@@ -6,314 +6,92 @@
|
|
6
6
|
# with this software package. If not, contact licensing@riassence.com
|
7
7
|
##
|
8
8
|
|
9
|
-
|
9
|
+
|
10
|
+
module RSence
|
10
11
|
module Plugins
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
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
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
## The +#idle+ method is called each time a client performs a data
|
80
|
-
## synchronization or "idle poll" request.
|
81
|
-
##
|
82
|
-
## The +#init_ses+ method is called once in the same request a new session
|
83
|
-
## is created. A new session is created, when a user enters accesses the
|
84
|
-
## server the first time, or the first time after the previous session is
|
85
|
-
## expired.
|
86
|
-
##
|
87
|
-
## The +#init_ui+ method is called by the "main" plugin after the client has
|
88
|
-
## booted successfully. The +GUIPlugin+ class extends this method to
|
89
|
-
## automatically load and initialize the user interface from a data structure.
|
90
|
-
##
|
91
|
-
## The +#restore_ses+ method is called once in the same request an old
|
92
|
-
## session is restored. A session is restored, when the user returns to
|
93
|
-
## the page or reloads the page before the session is expired.
|
94
|
-
##
|
95
|
-
## === When the server is configured to restore previous sessions (default):
|
96
|
-
## If the user accesses the same page using the same browser (in different
|
97
|
-
## tabs or windows), only the most recently restored one is valid, while
|
98
|
-
## the previous ones are immediately invalidated.
|
99
|
-
## If your application is intended to support several sessions per browser,
|
100
|
-
## enable session cloning in the configuration file.
|
101
|
-
##
|
102
|
-
## === When the server is configured to restore and clone previous sessions:
|
103
|
-
## When sessions are cloned, the previous session is not invalidated and
|
104
|
-
## exists until timing out as a result of the web browser window being closed
|
105
|
-
## or client computer losing network connectivity for a certain (configurable)
|
106
|
-
## time frame.
|
107
|
-
##
|
108
|
-
## The +#cloned_target+ method is like +#restore_ses+, but called when
|
109
|
-
## the session is a clone of a previous session.
|
110
|
-
##
|
111
|
-
## The +#cloned_source+ method is called on the next request of the previous
|
112
|
-
## session after it has been cloned.
|
113
|
-
##
|
114
|
-
## == Server event methods
|
115
|
-
## Extend the +#init+ method to invoke constructor functionality that
|
116
|
-
## depends on the plugin to be constructed and registered as a part of
|
117
|
-
## the system.
|
118
|
-
##
|
119
|
-
## Extend the +#open+, +#flush+ and +#close+ methods to open, flush and close
|
120
|
-
## streams or other similar functionality.
|
121
|
-
##
|
122
|
-
## == Data handling
|
123
|
-
## The data exchange system exists to support bi-directional
|
124
|
-
## data synchronization between the browser and the plugin. The values
|
125
|
-
## are stored in the session as +HValue+ instances.
|
126
|
-
##
|
127
|
-
## Values support Hashes, Arrays, Strings, Numbers, Booleans and
|
128
|
-
## combinations of them. The data is automatically converted between
|
129
|
-
## ruby objects (server) and json objects (client).
|
130
|
-
##
|
131
|
-
## Each instance may be bound to plugin methods that are used as
|
132
|
-
## value change notification responders.
|
133
|
-
##
|
134
|
-
## When a method is bound to the value, the method is called as an
|
135
|
-
## event notification whenever the client has changed the value and
|
136
|
-
## synchronizes it to the server. The responders act as validators
|
137
|
-
## by default.
|
138
|
-
##
|
139
|
-
## Values are also bound in the client to classes implementing the
|
140
|
-
## HValueResponder interface, like any derivate of HControl. See the
|
141
|
-
## client documentation for instructions about using them.
|
142
|
-
##
|
143
|
-
## To define a value responder method, it needs to respond to exactly
|
144
|
-
## two parameters: the +Message+ instance +msg+ and the HValue object
|
145
|
-
## (in that order). The method's return value must be either +true+
|
146
|
-
## or +false+. When the method returns +false+, the change is discarded
|
147
|
-
## and the previously server-set value is sent back to the client.
|
148
|
-
##
|
149
|
-
## A minimal value responder method is defined like this:
|
150
|
-
##
|
151
|
-
## def my_value_responder( msg, my_value )
|
152
|
-
## return true
|
153
|
-
## end
|
154
|
-
##
|
155
|
-
## To access the content of the value, use the +HValue#data+ attribute.
|
156
|
-
##
|
157
|
-
## def int_between_100_and_200( msg, value )
|
158
|
-
## data = value.data.to_i
|
159
|
-
## return ( data >= 100 and data <= 200 )
|
160
|
-
## end
|
161
|
-
##
|
162
|
-
## To change the content of the value, use the +HValue#set+ method.
|
163
|
-
##
|
164
|
-
## def int_between_100_and_200( msg, value )
|
165
|
-
## data = value.data.to_i
|
166
|
-
## value.set( msg, 100 ) if data < 100
|
167
|
-
## value.set( msg, 200 ) if data > 200
|
168
|
-
## return true
|
169
|
-
## end
|
170
|
-
##
|
171
|
-
## == Defining values
|
172
|
-
## The simplest and recommended way of defining the values is to define
|
173
|
-
## the value configuration file +values.yaml+. Its configuration is then
|
174
|
-
## applied to sessions automatically.
|
175
|
-
##
|
176
|
-
##
|
177
|
-
## === Syntax reference of the contents of a +values.yaml+ file:
|
178
|
-
##
|
179
|
-
## # The name of the value (:value_name).
|
180
|
-
## # A hash key in the yaml syntax
|
181
|
-
## :value_name:
|
182
|
-
##
|
183
|
-
## # All of these keys are optional!
|
184
|
-
##
|
185
|
-
## # Default value, a string "Foo" here.
|
186
|
-
## # Defaults to 0
|
187
|
-
## :value: Foo
|
188
|
-
##
|
189
|
-
## # A plugin method to call to define the default value
|
190
|
-
## # instead of the one defined in :value
|
191
|
-
## :value_call:
|
192
|
-
## :plugin: plugin_name # defaults to the plugin where defined
|
193
|
-
##
|
194
|
-
## # Mandatory; name of the method to call
|
195
|
-
## :method: method_name
|
196
|
-
##
|
197
|
-
## # Optional, list of parameter values for the :method
|
198
|
-
## :args:
|
199
|
-
## # three parameters: 1, 'foo', 3
|
200
|
-
## - 1
|
201
|
-
## - foo
|
202
|
-
## - 3
|
203
|
-
##
|
204
|
-
## # When false, doesn't pass the msg as the first parameter.
|
205
|
-
## # Defaults to true
|
206
|
-
## :uses_msg: true
|
207
|
-
##
|
208
|
-
## # Restore the default, when the session is restored; defaults to true
|
209
|
-
## :restore_default: false
|
210
|
-
##
|
211
|
-
## # List of value responder methods to bind.
|
212
|
-
## :responders:
|
213
|
-
## -
|
214
|
-
## # name of plugin to call, defaults to the plugin where defined:
|
215
|
-
## :plugin: plugin_name
|
216
|
-
##
|
217
|
-
## # mandatory, name of the method to call
|
218
|
-
## :method: method_name
|
219
|
-
##
|
220
|
-
## # Another responder, this one using the same plugin where defined:
|
221
|
-
## - :method: another_method
|
222
|
-
##
|
223
|
-
## # Another value, this one just defining the defaults
|
224
|
-
## # by supplying an empty Hash:
|
225
|
-
## # (value: 0, default restored, no responders or calls)
|
226
|
-
## :value_with_defaults: {}
|
227
|
-
##
|
228
|
-
## # This value defines a Number (123) and doesn't restore
|
229
|
-
## # the default, when restoring the session.
|
230
|
-
## :one_two_three:
|
231
|
-
## :value: 123
|
232
|
-
## :restore_default: false
|
233
|
-
##
|
234
|
-
## # This value gets a random string and specifies a responder,
|
235
|
-
## # that ensures it's unique, if changed in the client.
|
236
|
-
## :random_unique_string:
|
237
|
-
## :value_call:
|
238
|
-
## :method: get_unique_random_string
|
239
|
-
## :uses_msg: false
|
240
|
-
## :responders:
|
241
|
-
## - :method: ensure_unique_random_string
|
242
|
-
##
|
243
|
-
## = Examples
|
244
|
-
## More examples are available in the repository;
|
245
|
-
## http://svn.rsence.org/contrib/plugins
|
246
|
-
## ..as well as the standard "main" plugin in the "plugins" directory.
|
247
|
-
##
|
248
|
-
##
|
249
|
-
## == A minimal Plugin bundle
|
250
|
-
## The minimal active plugin bundle (named "name_of_plugin")
|
251
|
-
## is defined like this:
|
252
|
-
##
|
253
|
-
## [dir] name_of_plugin
|
254
|
-
## |
|
255
|
-
## +---[file] name_of_plugin.rb
|
256
|
-
##
|
257
|
-
## This sample Plugin doesn't do anything except construct itself and
|
258
|
-
## respond as 'name_of_plugin'.
|
259
|
-
##
|
260
|
-
## Plugin.new.register('name_of_plugin')
|
261
|
-
##
|
262
|
-
## However, this is not very useful in itself, so you'll need to extend
|
263
|
-
## its functionality to do anything useful.
|
264
|
-
##
|
265
|
-
## == A simple Plugin extension
|
266
|
-
## This plugin logs session events to the logs/session_log file.
|
267
|
-
##
|
268
|
-
## [dir] ses_logger
|
269
|
-
## |
|
270
|
-
## +---[file] ses_logger.rb
|
271
|
-
## |
|
272
|
-
## +---[dir] logs
|
273
|
-
## |
|
274
|
-
## +---[file] session_log
|
275
|
-
##
|
276
|
-
## == Contents of "ses_logger.rb"
|
277
|
-
##
|
278
|
-
## class SessionLogger < Plugin
|
279
|
-
## def init
|
280
|
-
## super
|
281
|
-
## @logfile = false
|
282
|
-
## end
|
283
|
-
## def open
|
284
|
-
## log_path = bundle_path( 'session_log', 'logs' )
|
285
|
-
## @logfile = File.open( log_path, 'a' )
|
286
|
-
## end
|
287
|
-
## def close
|
288
|
-
## @logfile.close if @logfile
|
289
|
-
## @logfile = false
|
290
|
-
## end
|
291
|
-
## def flush
|
292
|
-
## @logfile.flush if @logfile
|
293
|
-
## end
|
294
|
-
## def init_ses( msg )
|
295
|
-
## super
|
296
|
-
## @logfile.write( "#{Time.new} -- Session id #{msg.ses_id} was created.\n" )
|
297
|
-
## end
|
298
|
-
## def restore_ses( msg )
|
299
|
-
## super
|
300
|
-
## @logfile.write( "#{Time.new} -- Session id #{msg.ses_id} was restored.\n" )
|
301
|
-
## end
|
302
|
-
## def idle( msg )
|
303
|
-
## @logfile.write( "#{Time.new} -- Client of session id #{msg.ses_id} connected.\n" )
|
304
|
-
## end
|
305
|
-
## end
|
306
|
-
## SessionLogger.new.register( 'ses_logger' )
|
307
|
-
##
|
308
|
-
class PluginTemplate
|
309
|
-
include PluginUtil
|
13
|
+
# The Plugin__ is actually available as +Plugin+ from plugin bundles using the {RSence::Plugins::Plugin} class mimic method.
|
14
|
+
#
|
15
|
+
# The Plugin class is the base class for extending server logic. A single Plugin instance serves the requests of all sessions, which makes them very cpu and memory efficient compared to systems, where the server classes are constructed and destructed for each request.
|
16
|
+
#
|
17
|
+
# Plugins are designed to be contained in a plugin directory bundle and to be loaded by the main {PluginManager}, which is also responsible for delegating the events and other calls throughout the system.
|
18
|
+
#
|
19
|
+
#
|
20
|
+
# == Anatomy of a plugin bundle
|
21
|
+
#
|
22
|
+
# First read about the {file:PluginBundles Plugin Bundles}.
|
23
|
+
#
|
24
|
+
# The plugin bundle contains all data needed to run the plugin. Design your plugin without any hard-coded paths, remember that it's intended to be installed by moving or copying the whole plugin into one of the "plugins" directories. Use {#bundle_path} to construct paths.
|
25
|
+
#
|
26
|
+
# The {PluginManager} looks for these bundles and evaluates them into an anonymous +Module+ namespace. The contents of the ruby source file is then responsible for including its libraries, constructing an instance of itself and registering itself as a part of the system.
|
27
|
+
#
|
28
|
+
# Use the {GUIPlugin__ GUIPlugin} class for plugins that handle user interfaces. Use the {Plugin__ Plugin} class for plugin bundles that provide supplemental functionality, value responders and other utilities that supplement the user interface.
|
29
|
+
#
|
30
|
+
# = Extension hooks for server events
|
31
|
+
# These methods are provided as the basic server event hooks:
|
32
|
+
# * {#init +#init+} -- Use instead of +initialize+
|
33
|
+
# * {#open +#open+} -- Extend to open objects
|
34
|
+
# * {#flush +#flush+} -- Extend to write the state and to flush buffers
|
35
|
+
# * {#close +#close+} -- Extend to close objects
|
36
|
+
#
|
37
|
+
# = Extension hooks for session events
|
38
|
+
# * {#idle +#idle+} -- Extend to implement logic for each client data synchronization and "idle poll" request.
|
39
|
+
# * {#init_ses +#init_ses+} -- Extend to implement logic when a new session is created. A new session is created, when a user enters accesses the server the first time, or the first time after the previous session expired.
|
40
|
+
# * {#restore_ses +#restore_ses+} -- Extend to implement logic when an old session is restored. A session is restored, when the user returns to the page or reloads the page before the session is expired.
|
41
|
+
#
|
42
|
+
# == Extension hooks for session events, If the server is configured to restore and clone previous sessions (default):
|
43
|
+
# When sessions are cloned, the previous session is not invalidated and exists until timing out as a result of the web browser window being closed or client computer losing network connectivity for a certain (configurable) time frame.
|
44
|
+
# * {#cloned_target +#cloned_target+} -- Extend to implement logic in the request when session is a clone of the original session.
|
45
|
+
# * {#cloned_source +#cloned_source+} -- Extend to implement logic in the next request of the original session after it has been cloned.
|
46
|
+
#
|
47
|
+
# == If the server is configured to not clone sessions:
|
48
|
+
# When the user accesses the same page using the same browser (in different tabs or windows), only the most recently restored one is valid, while the previous ones are immediately invalidated. This is a more secure mode of operation, but has several drawback to usability, so it's not enabled by default.
|
49
|
+
#
|
50
|
+
# = Utility methods
|
51
|
+
# These are general utility methods not intended to be extended.
|
52
|
+
# * {#get_ses +#get_ses+} Returns the bundle-specific session Hash.
|
53
|
+
# * {#file_read +#file_read+} Use to read files
|
54
|
+
# * {#yaml_read +#yaml_read+} Use to read yaml data
|
55
|
+
# * {#file_write +#file_write+} Use to write files
|
56
|
+
# * {#bundle_path +#bundle_path+} Use for plugin bundle -specific paths
|
57
|
+
# * {#httime +#httime+} Use for HTTP date/time
|
58
|
+
#
|
59
|
+
# = Client-support
|
60
|
+
# These methods are intended for server-client interaction. Namely, commanding the client.
|
61
|
+
# * {#read_js +#read_js+} Returns a javascript source file.
|
62
|
+
# * {#read_js_once +#read_js_once+} Returns a javascript source file once per session.
|
63
|
+
# * {#values_js +#values_js+} Returns a javascript source snippet containing references to values.
|
64
|
+
# * {#include_js +#include_js+} Tells the client to load a library package.
|
65
|
+
#
|
66
|
+
# = See also
|
67
|
+
# * {file:PluginBundles Plugin Bundles} -- General information about the plugin bundle system
|
68
|
+
# * {file:Values Values} -- General information about the value exchange system
|
69
|
+
# * {file:PluginBundleInfo Plugin Bundle +info.yaml+ files} -- General information about the meta-information files.
|
70
|
+
# * {PluginBase PluginBase} -- The PluginBase module
|
71
|
+
# * {Servlet__ Servlet} -- The Servlet base class
|
72
|
+
# * {GUIPlugin__ GUIPlugin} -- The GUIPlugin base class
|
73
|
+
class Plugin__
|
74
|
+
|
75
|
+
|
76
|
+
include PluginBase
|
77
|
+
|
78
|
+
# @private Class type identifier for the PluginManager.
|
79
|
+
# @return [:Plugin]
|
310
80
|
def self.bundle_type; :Plugin; end
|
311
81
|
|
312
|
-
#
|
313
|
-
attr_reader :name
|
82
|
+
# @return [Symbol] The name of the plugin bundle
|
83
|
+
attr_reader :name
|
84
|
+
|
85
|
+
# @return [String] The absolute path of the plugin bundle.
|
86
|
+
attr_reader :path
|
87
|
+
|
88
|
+
# @return [Hash] The {file:PluginBundleInfo meta-information} of the plugin bundle.
|
89
|
+
attr_reader :info
|
90
|
+
|
91
|
+
# @private State of the plugin.
|
92
|
+
attr_reader :inited
|
314
93
|
|
315
|
-
# The constructor should not
|
316
|
-
# to extend the +#init+ method, because it's called after the plugin is set up.
|
94
|
+
# @private The constructor should not be accessed from anywhere else than the PluginManager, which does it automatically.
|
317
95
|
def initialize( bundle_name, bundle_info, bundle_path, plugin_manager )
|
318
96
|
@inited = false
|
319
97
|
@info = bundle_info
|
@@ -324,58 +102,69 @@ module ::RSence
|
|
324
102
|
end
|
325
103
|
|
326
104
|
# Extend this method to do any initial tasks before other methods are called.
|
327
|
-
#
|
105
|
+
#
|
106
|
+
# By default {#init_values} is called to load the {file:Values +values.yaml+} configuration file.
|
107
|
+
#
|
108
|
+
# @return [nil]
|
109
|
+
#
|
110
|
+
# @see PluginBase#init
|
328
111
|
def init
|
329
112
|
@values = init_values
|
330
113
|
end
|
331
114
|
|
332
115
|
# Extend this method to do any tasks every time the client makes a request.
|
116
|
+
#
|
117
|
+
# @param [Message] msg The message is supplied by the system.
|
118
|
+
#
|
119
|
+
# @return [nil]
|
333
120
|
def idle( msg )
|
334
121
|
end
|
335
122
|
|
336
123
|
# Extend this method to invoke actions, when a new session is created.
|
337
|
-
#
|
338
|
-
# +values.yaml+ configuration file.
|
124
|
+
#
|
125
|
+
# By default {#init_ses_values} is called to initialize values defined in the {file:Values +values.yaml+} configuration file.
|
126
|
+
#
|
127
|
+
# @param [Message] msg The message is supplied by the system.
|
128
|
+
#
|
129
|
+
# @return [nil]
|
339
130
|
def init_ses( msg )
|
340
131
|
init_ses_values( msg )
|
341
132
|
end
|
342
133
|
|
343
134
|
# Extend this method to invoke actions, when a previous session is restored.
|
344
|
-
#
|
345
|
-
# defined in the +values.yaml+ configuration file.
|
135
|
+
#
|
136
|
+
# By default +#restore_ses_values+ is called to perform actions on values as defined in the {file:Values +values.yaml+} configuration file.
|
137
|
+
#
|
138
|
+
# @param [Message] msg The message is supplied by the system.
|
139
|
+
#
|
140
|
+
# @return [nil]
|
346
141
|
def restore_ses( msg )
|
347
142
|
restore_ses_values( msg )
|
348
143
|
end
|
349
144
|
|
350
|
-
# Extend this method to invoke actions, when the session
|
351
|
-
# is a clone of another session. It's called once, just
|
352
|
-
# before +#restore_ses+ is called.
|
145
|
+
# Extend this method to invoke actions, when the session is a clone of another session. It's called once, just before {#restore_ses} is called.
|
353
146
|
#
|
354
|
-
# A session is cloned, when a user opens a another browser
|
355
|
-
# window or tab, while the previous session is still active.
|
147
|
+
# A session is cloned, when a user opens a another browser window or tab, while the previous session is still active.
|
356
148
|
#
|
357
|
-
# The
|
358
|
-
# was used as the source of the clone.
|
149
|
+
# @param [Message] msg The message is supplied by the system.
|
150
|
+
# @param [Hash] source_session The actual previous session object, which was used as the source of the clone.
|
151
|
+
#
|
152
|
+
# @return [nil]
|
359
153
|
def cloned_target( msg, source_session )
|
360
154
|
end
|
361
155
|
|
362
|
-
# Extend this method to invoke actions, when the session
|
363
|
-
#
|
364
|
-
#
|
365
|
-
# the cloning happened.
|
156
|
+
# Extend this method to invoke actions, when the session has been cloned to another session. It's called once, just before {#restore_ses} is called on the first request after the cloning happened.
|
157
|
+
#
|
158
|
+
# A session is cloned, when a user opens a another browser window or tab, while the previous session is still active.
|
366
159
|
#
|
367
|
-
#
|
368
|
-
#
|
160
|
+
# @param [Message] msg The message is supplied by the system.
|
161
|
+
# @param [Hash] target_session The actual cloned session object, which is a copy of the current session.
|
369
162
|
#
|
370
|
-
#
|
371
|
-
# is a copy of the current session.
|
163
|
+
# @return [nil]
|
372
164
|
def cloned_source( msg, target_sessions )
|
373
165
|
end
|
374
166
|
|
375
|
-
# This method must be called to register the plugin instance
|
376
|
-
# into the system. Otherwise, it's subject to destruction
|
377
|
-
# and garbage collection. Use the +name+ parameter to
|
378
|
-
# give the (unique) name of your plugin.
|
167
|
+
# @private This method must be called to register the plugin instance into the system. Otherwise, it's subject to destruction and garbage collection. Use the +name+ parameter to give the (unique) name of your plugin.
|
379
168
|
def register( name=false )
|
380
169
|
if @inited
|
381
170
|
@plugins.register_alias( @name, name )
|
@@ -390,28 +179,13 @@ module ::RSence
|
|
390
179
|
end
|
391
180
|
end
|
392
181
|
|
393
|
-
|
394
|
-
|
395
|
-
# This method looks looks for a file called "values.yaml"
|
396
|
-
# in the plugin's bundle directory
|
397
|
-
#.
|
398
|
-
# If this file is found, it loads it for initial value definitions.
|
399
|
-
#
|
400
|
-
# These definitions are accessible as the +@values+ attribute.
|
401
|
-
def init_values
|
402
|
-
values_path = bundle_path( 'values.yaml' )
|
403
|
-
return yaml_read( values_path )
|
404
|
-
end
|
405
|
-
|
406
|
-
# Returns all the names your plugin respond to.
|
407
|
-
# def name
|
408
|
-
# return @names.first
|
409
|
-
# end
|
410
|
-
|
411
|
-
|
412
|
-
# Returns or creates a new session hash for the plugin.
|
182
|
+
# This method returns (or creates and returns) the entry in the session based on the name your plugin is registered as. It's advised to use this call instead of manually managing {Message#session msg#session} in most cases.
|
413
183
|
#
|
414
184
|
# Uses the first name registered for the plugin and converts it to a symbol.
|
185
|
+
#
|
186
|
+
# @param [Message] msg The message is supplied by the system.
|
187
|
+
#
|
188
|
+
# @return [Hash] Plugin-specific session hash
|
415
189
|
def get_ses( msg )
|
416
190
|
name_sym = name.to_sym
|
417
191
|
unless msg.session.has_key?( name_sym )
|
@@ -420,21 +194,23 @@ module ::RSence
|
|
420
194
|
return msg.session[ name_sym ]
|
421
195
|
end
|
422
196
|
|
423
|
-
# Returns the source code of the javascript file +
|
424
|
-
#
|
197
|
+
# Returns the source code of the javascript file +js_name+ in the 'js' subdirectory of the plugin bundle. Use it to send raw javascript command code to the client. Use {#read_js_once} for libraries.
|
198
|
+
#
|
199
|
+
# @param [String] js_name Javascript source file name without the '.js' suffix.
|
200
|
+
#
|
201
|
+
# @return [String] The source of the file.
|
202
|
+
# @return [false] Returns false, when file was not found.
|
425
203
|
def read_js( js_name )
|
426
204
|
file_read( bundle_path( js_name, 'js', '.js' ) )
|
427
205
|
end
|
428
|
-
|
429
|
-
#
|
430
|
-
alias require_js read_js
|
431
|
-
|
432
|
-
# Like +#read_js+, but reads the file only once per session.
|
206
|
+
|
207
|
+
# Like {#read_js}, but reads the file only once per session. Use for inclusion of custom library code.
|
433
208
|
#
|
434
|
-
#
|
435
|
-
#
|
209
|
+
# @param [Message] msg The message is supplied by the system.
|
210
|
+
# @param [String] js_name Javascript source file name without the '.js' suffix.
|
436
211
|
#
|
437
|
-
#
|
212
|
+
# @return [String] The source of the file on the first call in a session, or an empty string on the subsequent calls.
|
213
|
+
# @return [false] Returns false, when file was not found.
|
438
214
|
def read_js_once( msg, js_name )
|
439
215
|
ses = msg.session
|
440
216
|
if not ses.has_key?(:deps)
|
@@ -448,13 +224,72 @@ module ::RSence
|
|
448
224
|
return ''
|
449
225
|
end
|
450
226
|
end
|
451
|
-
|
452
|
-
#
|
453
|
-
|
454
|
-
|
455
|
-
#
|
456
|
-
#
|
457
|
-
#
|
227
|
+
|
228
|
+
# Extracts +HValue+ references as javascript from the session Hash.
|
229
|
+
#
|
230
|
+
# @param [Message] msg The message is supplied by the system.
|
231
|
+
# @param [Hash] ses Used for supplying a Hash with the {HValue} instances. It's optional and defaults to the current plugin node in the active session.
|
232
|
+
#
|
233
|
+
# @return [String] A string representing a javascript object similar to the ruby Hash +ses+.
|
234
|
+
#
|
235
|
+
# @example
|
236
|
+
# values_js( msg, get_ses(msg) )
|
237
|
+
def values_js( msg, ses=false )
|
238
|
+
# backwards-compatible with pre-1.3 behavior
|
239
|
+
ses = msg if msg.class == Hash
|
240
|
+
# gets the session automatically, if false
|
241
|
+
ses = get_ses( msg ) unless ses
|
242
|
+
js_references = []
|
243
|
+
ses.each_key do |key_name|
|
244
|
+
if ses[key_name].class == HValue
|
245
|
+
js_references.push( "#{key_name.to_s}:HVM.values['#{ses[key_name].val_id}']" )
|
246
|
+
end
|
247
|
+
end
|
248
|
+
return "{#{js_references.join(',')}}"
|
249
|
+
end
|
250
|
+
|
251
|
+
|
252
|
+
# Tells the js client framework to load a list of pre-packaged client libraries.
|
253
|
+
#
|
254
|
+
# It keeps track of what's loaded, so nothing library loaded twice.
|
255
|
+
#
|
256
|
+
# @param [Message] msg The message is supplied by the system.
|
257
|
+
# @param [Array] dependencies A list of package names.
|
258
|
+
#
|
259
|
+
# @return [nil]
|
260
|
+
#
|
261
|
+
# @example
|
262
|
+
# include_js( msg, [ 'default_theme', 'controls' ] )
|
263
|
+
#
|
264
|
+
def include_js( msg, dependencies=[] )
|
265
|
+
ses = msg.session
|
266
|
+
# check, if the session has a dependency array
|
267
|
+
if not ses.has_key?( :deps )
|
268
|
+
# make an array of dependencies for this session, if not already done
|
269
|
+
ses[:deps] = []
|
270
|
+
end
|
271
|
+
dependencies = [dependencies] if dependencies.class == String
|
272
|
+
# Check the required dependencies until everything is loaded.
|
273
|
+
dependencies.each do |dependency|
|
274
|
+
unless ses[:deps].include?( dependency )
|
275
|
+
ses[:deps].push( dependency )
|
276
|
+
msg.reply(%{jsLoader.load("#{dependency}");})
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
|
282
|
+
# @private This method looks looks for a file called "values.yaml" in the plugin's bundle directory.
|
283
|
+
# If this file is found, it loads it for initial value definitions.
|
284
|
+
# These definitions are accessible as the +@values+ attribute.
|
285
|
+
def init_values
|
286
|
+
values_path = bundle_path( 'values.yaml' )
|
287
|
+
return yaml_read( values_path )
|
288
|
+
end
|
289
|
+
|
290
|
+
# @private Creates a new instance of HValue, assigns it as +value_name+ into the
|
291
|
+
# session and uses the +value_properties+ Hash to define the default
|
292
|
+
# value and value responders.
|
458
293
|
#
|
459
294
|
# This method is invoked automatically, when handling the properties
|
460
295
|
# of the +values.yaml+ configuration file of a new session.
|
@@ -512,18 +347,18 @@ module ::RSence
|
|
512
347
|
end
|
513
348
|
end
|
514
349
|
end
|
515
|
-
|
516
|
-
# Initializes session values, if the contents of the +values.yaml+
|
517
|
-
#
|
350
|
+
|
351
|
+
# @private Initializes session values, if the contents of the +values.yaml+
|
352
|
+
# file is defined in the bundle directory and loaded in +#init_values+.
|
518
353
|
def init_ses_values( msg )
|
519
354
|
return unless @values
|
520
355
|
@values.each do | value_name, value_properties |
|
521
356
|
init_ses_value( msg, value_name, value_properties )
|
522
357
|
end
|
523
358
|
end
|
524
|
-
|
525
|
-
# Returns a value based on the :method and :plugin members of the
|
526
|
-
#
|
359
|
+
|
360
|
+
# @private Returns a value based on the :method and :plugin members of the
|
361
|
+
# +value_call+ hash.
|
527
362
|
#
|
528
363
|
# The call is made via msg.run if the method is not defined in
|
529
364
|
# the local plugin bundle.
|
@@ -573,8 +408,8 @@ module ::RSence
|
|
573
408
|
end
|
574
409
|
end
|
575
410
|
end
|
576
|
-
|
577
|
-
# Restores session values to default, unless specified otherwise.
|
411
|
+
|
412
|
+
# @private Restores session values to default, unless specified otherwise.
|
578
413
|
#
|
579
414
|
# Called from +#restore_ses+
|
580
415
|
def restore_ses_values( msg )
|
@@ -597,61 +432,6 @@ module ::RSence
|
|
597
432
|
end
|
598
433
|
end
|
599
434
|
end
|
600
|
-
|
601
|
-
# Extracts +HValue+ references as javascript from the session Hash.
|
602
|
-
# The +ses+ parameter is used for supplying a hash with the +HValue+
|
603
|
-
# instances. It's optional and defaults to the current plugin node in
|
604
|
-
# the active session.
|
605
|
-
#
|
606
|
-
# The return value is a string representing a js object similar to
|
607
|
-
# the ruby Hash +ses+.
|
608
|
-
#
|
609
|
-
# Sample usage:
|
610
|
-
#
|
611
|
-
# values_js( msg, msg.session[:main] )
|
612
|
-
#
|
613
|
-
def values_js( msg, ses=false )
|
614
|
-
# backwards-compatible with pre-1.3 behaviour
|
615
|
-
ses = msg if msg.class == Hash
|
616
|
-
# gets the session automatically, if false
|
617
|
-
ses = get_ses( msg ) unless ses
|
618
|
-
js_references = []
|
619
|
-
ses.each_key do |key_name|
|
620
|
-
if ses[key_name].class == HValue
|
621
|
-
js_references.push( "#{key_name.to_s}:HVM.values['#{ses[key_name].val_id}']" )
|
622
|
-
end
|
623
|
-
end
|
624
|
-
return "{#{js_references.join(',')}}"
|
625
|
-
end
|
626
|
-
|
627
|
-
# Deprecated name of +#values_js+
|
628
|
-
alias extract_hvalues_from_hash values_js
|
629
|
-
|
630
|
-
# Tells the js client framework to load a list of dependency packages.
|
631
|
-
# It keeps track of what's loaded, so nothing library loaded twice.
|
632
|
-
#
|
633
|
-
# The +dependencies+ parameter is an Array of dependencies.
|
634
|
-
#
|
635
|
-
# Sample usage:
|
636
|
-
#
|
637
|
-
# include_js( msg, [ 'default_theme', 'controls', 'lists', 'datetime' ] )
|
638
|
-
#
|
639
|
-
def include_js( msg, dependencies=[] )
|
640
|
-
ses = msg.session
|
641
|
-
# check, if the session has a dependency array
|
642
|
-
if not ses.has_key?( :deps )
|
643
|
-
# make an array of dependencies for this session, if not already done
|
644
|
-
ses[:deps] = []
|
645
|
-
end
|
646
|
-
dependencies = [dependencies] if dependencies.class == String
|
647
|
-
# Check the required dependencies until everything is loaded.
|
648
|
-
dependencies.each do |dependency|
|
649
|
-
unless ses[:deps].include?( dependency )
|
650
|
-
ses[:deps].push( dependency )
|
651
|
-
msg.reply(%{jsLoader.load("#{dependency}");})
|
652
|
-
end
|
653
|
-
end
|
654
|
-
end
|
655
435
|
end
|
656
436
|
end
|
657
437
|
end
|