rsence 2.0.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (311) hide show
  1. data/INSTALL.rdoc +295 -0
  2. data/LICENSE +622 -0
  3. data/README.rdoc +24 -0
  4. data/VERSION +1 -0
  5. data/bin/build_client.rb +254 -0
  6. data/bin/help +6 -0
  7. data/bin/launch.rb +120 -0
  8. data/bin/rdoc.sh +2 -0
  9. data/bin/restart +6 -0
  10. data/bin/rsence +120 -0
  11. data/bin/run +6 -0
  12. data/bin/run.rb +6 -0
  13. data/bin/save +6 -0
  14. data/bin/start +6 -0
  15. data/bin/status +6 -0
  16. data/bin/stop +6 -0
  17. data/conf/config.ru +5 -0
  18. data/conf/default_conf.yaml +337 -0
  19. data/conf/default_strings.yaml +77 -0
  20. data/conf/local_conf.yaml +14 -0
  21. data/conf/unicorn.conf +78 -0
  22. data/js/comm/comm/autosync/autosync.js +18 -0
  23. data/js/comm/comm/autosync/js.inc +0 -0
  24. data/js/comm/comm/comm.js +195 -0
  25. data/js/comm/comm/js.inc +0 -0
  26. data/js/comm/comm/queue/js.inc +0 -0
  27. data/js/comm/comm/queue/queue.js +183 -0
  28. data/js/comm/comm/session/js.inc +0 -0
  29. data/js/comm/comm/session/session.js +51 -0
  30. data/js/comm/comm/sessionwatcher/js.inc +0 -0
  31. data/js/comm/comm/sessionwatcher/sessionwatcher.js +43 -0
  32. data/js/comm/comm/transporter/js.inc +0 -0
  33. data/js/comm/comm/transporter/transporter.js +257 -0
  34. data/js/comm/comm/urlresponder/js.inc +0 -0
  35. data/js/comm/comm/urlresponder/urlresponder.js +148 -0
  36. data/js/comm/comm/values/js.inc +0 -0
  37. data/js/comm/comm/values/values.js +432 -0
  38. data/js/comm/jsloader/js.inc +0 -0
  39. data/js/comm/jsloader/jsloader.js +114 -0
  40. data/js/comm/reloadapp/js.inc +0 -0
  41. data/js/comm/reloadapp/reloadapp.js +150 -0
  42. data/js/comm/reloadapp/themes/default/reloadapp_warning-ie6.gif +0 -0
  43. data/js/comm/reloadapp/themes/default/reloadapp_warning.png +0 -0
  44. data/js/comm/sha/js.inc +0 -0
  45. data/js/comm/sha/sha.js +432 -0
  46. data/js/comm/values/value/js.inc +0 -0
  47. data/js/comm/values/value/value.js +182 -0
  48. data/js/comm/values/valuematrix/js.inc +0 -0
  49. data/js/comm/values/valuematrix/valuematrix.js +138 -0
  50. data/js/controls/button/button.js +57 -0
  51. data/js/controls/button/js.inc +0 -0
  52. data/js/controls/button/themes/bright/button.css +89 -0
  53. data/js/controls/button/themes/bright/button.html +7 -0
  54. data/js/controls/button/themes/bright/button_parts1-ie6.gif +0 -0
  55. data/js/controls/button/themes/bright/button_parts1.png +0 -0
  56. data/js/controls/button/themes/default/button.css +89 -0
  57. data/js/controls/button/themes/default/button.html +7 -0
  58. data/js/controls/button/themes/default/button_parts1-ie6.gif +0 -0
  59. data/js/controls/button/themes/default/button_parts1.png +0 -0
  60. data/js/controls/checkbox/checkbox.js +47 -0
  61. data/js/controls/checkbox/js.inc +0 -0
  62. data/js/controls/checkbox/themes/default/checkbox.css +69 -0
  63. data/js/controls/checkbox/themes/default/checkbox.html +5 -0
  64. data/js/controls/checkbox/themes/default/checkbox_parts1-ie6.gif +0 -0
  65. data/js/controls/checkbox/themes/default/checkbox_parts1.png +0 -0
  66. data/js/controls/datetime/calendar/calendar.js +197 -0
  67. data/js/controls/datetime/calendar/js.inc +0 -0
  68. data/js/controls/datetime/calendar/themes/default/calendar.css +108 -0
  69. data/js/controls/datetime/calendar/themes/default/calendar.html +9 -0
  70. data/js/controls/datetime/calendar/themes/default/calendar_arrows-ie6.gif +0 -0
  71. data/js/controls/datetime/calendar/themes/default/calendar_arrows.png +0 -0
  72. data/js/controls/datetime/datetimevalue/datetimevalue.js +246 -0
  73. data/js/controls/datetime/datetimevalue/js.inc +0 -0
  74. data/js/controls/datetime/timesheet/js.inc +0 -0
  75. data/js/controls/datetime/timesheet/themes/default/timesheet.css +30 -0
  76. data/js/controls/datetime/timesheet/themes/default/timesheet.html +2 -0
  77. data/js/controls/datetime/timesheet/timesheet.js +182 -0
  78. data/js/controls/datetime/timesheet_item/js.inc +0 -0
  79. data/js/controls/datetime/timesheet_item/themes/default/timesheet_item.css +42 -0
  80. data/js/controls/datetime/timesheet_item/themes/default/timesheet_item.html +8 -0
  81. data/js/controls/datetime/timesheet_item/timesheet_item.js +247 -0
  82. data/js/controls/datetime/timesheet_item_edit/js.inc +0 -0
  83. data/js/controls/datetime/timesheet_item_edit/timesheet_item_edit.js +274 -0
  84. data/js/controls/dialogs/alert_sheet/alert_sheet.js +62 -0
  85. data/js/controls/dialogs/alert_sheet/js.inc +0 -0
  86. data/js/controls/dialogs/confirm_sheet/confirm_sheet.js +36 -0
  87. data/js/controls/dialogs/confirm_sheet/js.inc +0 -0
  88. data/js/controls/dialogs/sheet/js.inc +0 -0
  89. data/js/controls/dialogs/sheet/sheet.js +83 -0
  90. data/js/controls/dialogs/sheet/themes/default/sheet.css +64 -0
  91. data/js/controls/dialogs/sheet/themes/default/sheet.html +14 -0
  92. data/js/controls/dialogs/sheet/themes/default/sheet_bg-ie6.gif +0 -0
  93. data/js/controls/dialogs/sheet/themes/default/sheet_bg.png +0 -0
  94. data/js/controls/dialogs/sheet/themes/default/sheet_dim-ie6.gif +0 -0
  95. data/js/controls/dialogs/sheet/themes/default/sheet_dim.png +0 -0
  96. data/js/controls/dialogs/sheet/themes/default/sheet_parts1-ie6.gif +0 -0
  97. data/js/controls/dialogs/sheet/themes/default/sheet_parts1.png +0 -0
  98. data/js/controls/dialogs/sheet/themes/default/sheet_parts2-ie6.gif +0 -0
  99. data/js/controls/dialogs/sheet/themes/default/sheet_parts2.png +0 -0
  100. data/js/controls/dialogs/sheet/themes/default/sheet_warning-ie6.gif +0 -0
  101. data/js/controls/dialogs/sheet/themes/default/sheet_warning.png +0 -0
  102. data/js/controls/imageview/imageview.js +108 -0
  103. data/js/controls/imageview/js.inc +0 -0
  104. data/js/controls/imageview/themes/default/blank.gif +0 -0
  105. data/js/controls/lists/checkboxlist/checkboxlist.js +170 -0
  106. data/js/controls/lists/checkboxlist/js.inc +0 -0
  107. data/js/controls/lists/listitems/js.inc +0 -0
  108. data/js/controls/lists/listitems/listitems.js +65 -0
  109. data/js/controls/lists/radiobuttonlist/js.inc +0 -0
  110. data/js/controls/lists/radiobuttonlist/radiobuttonlist.js +126 -0
  111. data/js/controls/passwordcontrol/js.inc +0 -0
  112. data/js/controls/passwordcontrol/passwordcontrol.js +22 -0
  113. data/js/controls/passwordcontrol/themes/default/passwordcontrol.css +0 -0
  114. data/js/controls/passwordcontrol/themes/default/passwordcontrol.html +18 -0
  115. data/js/controls/progress/progressbar/js.inc +0 -0
  116. data/js/controls/progress/progressbar/progressbar.js +36 -0
  117. data/js/controls/progress/progressbar/themes/default/progressbar.css +16 -0
  118. data/js/controls/progress/progressbar/themes/default/progressbar.html +2 -0
  119. data/js/controls/progress/progressindicator/js.inc +0 -0
  120. data/js/controls/progress/progressindicator/progressindicator.js +43 -0
  121. data/js/controls/radiobutton/js.inc +0 -0
  122. data/js/controls/radiobutton/radiobutton.js +41 -0
  123. data/js/controls/radiobutton/themes/default/radiobutton.css +69 -0
  124. data/js/controls/radiobutton/themes/default/radiobutton.html +5 -0
  125. data/js/controls/radiobutton/themes/default/radiobutton_parts1-ie6.gif +0 -0
  126. data/js/controls/radiobutton/themes/default/radiobutton_parts1.png +0 -0
  127. data/js/controls/sliders/slider/js.inc +0 -0
  128. data/js/controls/sliders/slider/slider.js +356 -0
  129. data/js/controls/sliders/slider/themes/default/hslider_tracks-ie6.gif +0 -0
  130. data/js/controls/sliders/slider/themes/default/hslider_tracks.png +0 -0
  131. data/js/controls/sliders/slider/themes/default/slider.css +108 -0
  132. data/js/controls/sliders/slider/themes/default/slider.html +5 -0
  133. data/js/controls/sliders/slider/themes/default/slider_thumbs-ie6.gif +0 -0
  134. data/js/controls/sliders/slider/themes/default/slider_thumbs.png +0 -0
  135. data/js/controls/sliders/vslider/js.inc +0 -0
  136. data/js/controls/sliders/vslider/themes/default/vslider.css +52 -0
  137. data/js/controls/sliders/vslider/themes/default/vslider.html +5 -0
  138. data/js/controls/sliders/vslider/themes/default/vslider_tracks-ie6.gif +0 -0
  139. data/js/controls/sliders/vslider/themes/default/vslider_tracks.png +0 -0
  140. data/js/controls/sliders/vslider/vslider.js +40 -0
  141. data/js/controls/stepper/js.inc +0 -0
  142. data/js/controls/stepper/stepper.js +212 -0
  143. data/js/controls/stepper/themes/default/stepper-ie6.gif +0 -0
  144. data/js/controls/stepper/themes/default/stepper.css +14 -0
  145. data/js/controls/stepper/themes/default/stepper.html +2 -0
  146. data/js/controls/stepper/themes/default/stepper.png +0 -0
  147. data/js/controls/stringview/js.inc +0 -0
  148. data/js/controls/stringview/stringview.js +49 -0
  149. data/js/controls/stringview/themes/default/stringview.css +8 -0
  150. data/js/controls/stringview/themes/default/stringview.html +1 -0
  151. data/js/controls/tab/js.inc +0 -0
  152. data/js/controls/tab/tab.js +276 -0
  153. data/js/controls/tab/themes/bright/tab.css +76 -0
  154. data/js/controls/tab/themes/bright/tab.html +6 -0
  155. data/js/controls/tab/themes/bright/tab_bg_color-ie6.gif +0 -0
  156. data/js/controls/tab/themes/bright/tab_bg_color.png +0 -0
  157. data/js/controls/tab/themes/bright/tab_border_pattern-ie6.gif +0 -0
  158. data/js/controls/tab/themes/bright/tab_border_pattern.png +0 -0
  159. data/js/controls/tab/themes/bright/tab_parts1-ie6.gif +0 -0
  160. data/js/controls/tab/themes/bright/tab_parts1.png +0 -0
  161. data/js/controls/tab/themes/default/tab.css +77 -0
  162. data/js/controls/tab/themes/default/tab.html +6 -0
  163. data/js/controls/tab/themes/default/tab_bg_color-ie6.gif +0 -0
  164. data/js/controls/tab/themes/default/tab_bg_color.png +0 -0
  165. data/js/controls/tab/themes/default/tab_border_pattern-ie6.gif +0 -0
  166. data/js/controls/tab/themes/default/tab_border_pattern.png +0 -0
  167. data/js/controls/tab/themes/default/tab_parts1-ie6.gif +0 -0
  168. data/js/controls/tab/themes/default/tab_parts1.png +0 -0
  169. data/js/controls/textarea/js.inc +0 -0
  170. data/js/controls/textarea/textarea.js +23 -0
  171. data/js/controls/textarea/themes/default/textarea.css +21 -0
  172. data/js/controls/textarea/themes/default/textarea.html +18 -0
  173. data/js/controls/textcontrol/js.inc +0 -0
  174. data/js/controls/textcontrol/textcontrol.js +372 -0
  175. data/js/controls/textcontrol/themes/default/textcontrol.css +107 -0
  176. data/js/controls/textcontrol/themes/default/textcontrol.html +18 -0
  177. data/js/controls/textcontrol/themes/default/textcontrol_parts1-ie6.gif +0 -0
  178. data/js/controls/textcontrol/themes/default/textcontrol_parts1.png +0 -0
  179. data/js/controls/textcontrol/themes/default/textcontrol_parts2-ie6.gif +0 -0
  180. data/js/controls/textcontrol/themes/default/textcontrol_parts2.png +0 -0
  181. data/js/controls/textcontrol/themes/default/textcontrol_parts3-ie6.gif +0 -0
  182. data/js/controls/textcontrol/themes/default/textcontrol_parts3.png +0 -0
  183. data/js/controls/uploader/js.inc +0 -0
  184. data/js/controls/uploader/themes/default/upload_progress.gif +0 -0
  185. data/js/controls/uploader/themes/default/uploader.css +108 -0
  186. data/js/controls/uploader/themes/default/uploader.html +27 -0
  187. data/js/controls/uploader/uploader.js +153 -0
  188. data/js/controls/validatorview/js.inc +0 -0
  189. data/js/controls/validatorview/themes/default/validator-ie6.gif +0 -0
  190. data/js/controls/validatorview/themes/default/validator.png +0 -0
  191. data/js/controls/validatorview/themes/default/validatorview.css +0 -0
  192. data/js/controls/validatorview/themes/default/validatorview.html +0 -0
  193. data/js/controls/validatorview/validatorview.js +55 -0
  194. data/js/controls/window/js.inc +0 -0
  195. data/js/controls/window/themes/default/window.css +219 -0
  196. data/js/controls/window/themes/default/window.html +17 -0
  197. data/js/controls/window/themes/default/window_bg_active-ie6.gif +0 -0
  198. data/js/controls/window/themes/default/window_bg_active.png +0 -0
  199. data/js/controls/window/themes/default/window_bg_inactive-ie6.gif +0 -0
  200. data/js/controls/window/themes/default/window_bg_inactive.png +0 -0
  201. data/js/controls/window/themes/default/window_buttons-ie6.gif +0 -0
  202. data/js/controls/window/themes/default/window_buttons.png +0 -0
  203. data/js/controls/window/themes/default/window_parts1-ie6.gif +0 -0
  204. data/js/controls/window/themes/default/window_parts1.png +0 -0
  205. data/js/controls/window/themes/default/window_parts2-ie6.gif +0 -0
  206. data/js/controls/window/themes/default/window_parts2.png +0 -0
  207. data/js/controls/window/window.js +284 -0
  208. data/js/core/class/class.js +317 -0
  209. data/js/core/class/js.inc +0 -0
  210. data/js/core/elem/elem.js +1376 -0
  211. data/js/core/elem/js.inc +0 -0
  212. data/js/core/event/event.js +1021 -0
  213. data/js/core/event/js.inc +0 -0
  214. data/js/core/iefix/ie_css_element.htc +5 -0
  215. data/js/core/iefix/ie_css_style.htc +5 -0
  216. data/js/core/iefix/iefix.js +359 -0
  217. data/js/core/iefix/js.inc +0 -0
  218. data/js/debugg/debugg.js +43 -0
  219. data/js/debugg/js.inc +0 -0
  220. data/js/foundation/application/application.js +209 -0
  221. data/js/foundation/application/js.inc +0 -0
  222. data/js/foundation/control/control.js +342 -0
  223. data/js/foundation/control/controldefaults/controldefaults.js +59 -0
  224. data/js/foundation/control/controldefaults/js.inc +0 -0
  225. data/js/foundation/control/dummyvalue/dummyvalue.js +50 -0
  226. data/js/foundation/control/dummyvalue/js.inc +0 -0
  227. data/js/foundation/control/dyncontrol/dyncontrol.js +494 -0
  228. data/js/foundation/control/dyncontrol/js.inc +0 -0
  229. data/js/foundation/control/dyncontrol/themes/default/dyncontrol.css +0 -0
  230. data/js/foundation/control/dyncontrol/themes/default/dyncontrol.html +0 -0
  231. data/js/foundation/control/eventresponder/eventresponder.js +713 -0
  232. data/js/foundation/control/eventresponder/js.inc +0 -0
  233. data/js/foundation/control/js.inc +0 -0
  234. data/js/foundation/control/valueresponder/js.inc +0 -0
  235. data/js/foundation/control/valueresponder/valueresponder.js +77 -0
  236. data/js/foundation/geom/point/js.inc +0 -0
  237. data/js/foundation/geom/point/point.js +202 -0
  238. data/js/foundation/geom/rect/js.inc +0 -0
  239. data/js/foundation/geom/rect/rect.js +610 -0
  240. data/js/foundation/json_renderer/js.inc +0 -0
  241. data/js/foundation/json_renderer/json_renderer.js +231 -0
  242. data/js/foundation/system/js.inc +0 -0
  243. data/js/foundation/system/system.js +369 -0
  244. data/js/foundation/thememanager/js.inc +0 -0
  245. data/js/foundation/thememanager/thememanager.js +387 -0
  246. data/js/foundation/view/js.inc +0 -0
  247. data/js/foundation/view/markupview/js.inc +0 -0
  248. data/js/foundation/view/markupview/markupview.js +113 -0
  249. data/js/foundation/view/morphanimation/js.inc +0 -0
  250. data/js/foundation/view/morphanimation/morphanimation.js +236 -0
  251. data/js/foundation/view/view.js +1804 -0
  252. data/js/foundation/view/viewdefaults/js.inc +0 -0
  253. data/js/foundation/view/viewdefaults/viewdefaults.js +25 -0
  254. data/js/views/centerview/centerview.js +45 -0
  255. data/js/views/centerview/js.inc +0 -0
  256. data/js/views/inlineview/inlineview.js +14 -0
  257. data/js/views/inlineview/js.inc +0 -0
  258. data/js/views/scrollview/js.inc +0 -0
  259. data/js/views/scrollview/scrollview.js +39 -0
  260. data/lib/conf/default.rb +220 -0
  261. data/lib/conf/wizard.rb +303 -0
  262. data/lib/daemon/daemon.rb +293 -0
  263. data/lib/http/broker.rb +102 -0
  264. data/lib/http/rackup.rb +88 -0
  265. data/lib/http/request.rb +69 -0
  266. data/lib/http/response.rb +63 -0
  267. data/lib/plugins/gui_plugin.rb +129 -0
  268. data/lib/plugins/guiparser.rb +114 -0
  269. data/lib/plugins/plugin.rb +652 -0
  270. data/lib/plugins/plugin_plugins.rb +47 -0
  271. data/lib/plugins/plugin_sqlite_db.rb +72 -0
  272. data/lib/plugins/plugin_util.rb +96 -0
  273. data/lib/plugins/pluginmanager.rb +517 -0
  274. data/lib/plugins/servlet.rb +69 -0
  275. data/lib/session/msg.rb +291 -0
  276. data/lib/session/sessionmanager.rb +491 -0
  277. data/lib/session/sessionstorage.rb +314 -0
  278. data/lib/transporter/transporter.rb +254 -0
  279. data/lib/util/gzstring.rb +5 -0
  280. data/lib/values/hvalue.rb +323 -0
  281. data/lib/values/valuemanager.rb +152 -0
  282. data/plugins/client_pkg/client_pkg.rb +186 -0
  283. data/plugins/client_pkg/info.yaml +25 -0
  284. data/plugins/client_pkg/lib/client_pkg_build.rb +569 -0
  285. data/plugins/client_pkg/lib/client_pkg_cache.rb +50 -0
  286. data/plugins/client_pkg/lib/client_pkg_serve.rb +210 -0
  287. data/plugins/client_pkg/log/build_log +0 -0
  288. data/plugins/index_html/img/loading.gif +0 -0
  289. data/plugins/index_html/img/riassence.gif +0 -0
  290. data/plugins/index_html/index_html.rb +150 -0
  291. data/plugins/index_html/tmpl/index.html +22 -0
  292. data/plugins/index_html/tmpl/startup_index.html +29 -0
  293. data/plugins/legacy/disabled +0 -0
  294. data/plugins/legacy/disabled- +0 -0
  295. data/plugins/legacy/info.yaml +22 -0
  296. data/plugins/legacy/legacy.rb +15 -0
  297. data/plugins/main/js/riassence_ns.js +87 -0
  298. data/plugins/main/main.rb +234 -0
  299. data/plugins/main/values.yaml +8 -0
  300. data/plugins/ticketservices/lib/common.rb +300 -0
  301. data/plugins/ticketservices/lib/favicon.rb +38 -0
  302. data/plugins/ticketservices/lib/file.rb +58 -0
  303. data/plugins/ticketservices/lib/img.rb +50 -0
  304. data/plugins/ticketservices/lib/objblob.rb +66 -0
  305. data/plugins/ticketservices/lib/rsrc.rb +34 -0
  306. data/plugins/ticketservices/lib/upload.rb +206 -0
  307. data/plugins/ticketservices/ticketservices.rb +268 -0
  308. data/var/db/.git_include +0 -0
  309. data/var/log/.git_include +0 -0
  310. data/var/run/.git_include +0 -0
  311. metadata +390 -0
@@ -0,0 +1,69 @@
1
+ #--
2
+ ## Riassence Framework
3
+ # Copyright 2008 Riassence Inc.
4
+ # http://riassence.com/
5
+ #
6
+ # You should have received a copy of the GNU General Public License along
7
+ # with this software package. If not, contact licensing@riassence.com
8
+ ##
9
+ #++
10
+
11
+
12
+ require 'rubygems'
13
+ require 'rack'
14
+
15
+ module RSence
16
+
17
+ class Request < Rack::Request
18
+ attr_reader :header, :path, :query
19
+ def initialize(env)
20
+ @header = {
21
+
22
+ }
23
+ super
24
+ env2header()
25
+ @path = path_info()
26
+ @query = params()
27
+ end
28
+ def unparsed_uri
29
+ return @header['request-uri']
30
+ end
31
+ def env2header
32
+ [ ['SERVER_NAME', 'server-name'],
33
+ ['HTTP_USER_AGENT', 'user-agent'],
34
+ ['HTTP_ACCEPT_ENCODING', 'accept-encoding'],
35
+ ['PATH_INFO', 'path-info'],
36
+ ['HTTP_HOST', 'host'],
37
+ ['HTTP_ACCEPT_LANGUAGE', 'accept-language'],
38
+ ['SERVER_PROTOCOL', 'server-protocol'],
39
+ ['REQUEST_PATH', 'request-path'],
40
+ ['HTTP_KEEP_ALIVE', 'keep-alive'],
41
+ ['SERVER_SOFTWARE', 'server-software'],
42
+ ['REMOTE_ADDR', 'remote-addr'],
43
+ ['HTTP_REFERER', 'referer'],
44
+ ['HTTP_VERSION', 'version'],
45
+ ['HTTP_ACCEPT_CHARSET', 'accept-charset'],
46
+ ['REQUEST_URI', 'request-uri'],
47
+ ['SERVER_PORT', 'server-port'],
48
+ ['QUERY_STRING', 'query-string'],
49
+ ['HTTP_ACCEPT', 'accept'],
50
+ ['REQUEST_METHOD', 'request-method'],
51
+ ['HTTP_CONNECTION', 'connection'],
52
+ ['HTTP_SOAPACTION', 'soapaction'],
53
+ ['HTTP_FORWARDED_HOST', 'forwarded-host']
54
+ ].each do |env_key,header_key|
55
+ if @env.has_key?(env_key)
56
+ @header[header_key] = @env[env_key]
57
+ end
58
+ if env_key.start_with?( 'HTTP_' )
59
+ x_env_key = "HTTP_X#{env_key[4..-1]}"
60
+ if @env.has_key?( x_env_key )
61
+ @header["x-#{header_key}"] = @env[ x_env_key ]
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+
68
+
69
+ end
@@ -0,0 +1,63 @@
1
+ #--
2
+ ## Riassence Framework
3
+ # Copyright 2008 Riassence Inc.
4
+ # http://riassence.com/
5
+ #
6
+ # You should have received a copy of the GNU General Public License along
7
+ # with this software package. If not, contact licensing@riassence.com
8
+ ##
9
+ #++
10
+
11
+
12
+ module RSence
13
+
14
+ class ResponseBody < Array
15
+ def +(body_data)
16
+ self.push(body_data)
17
+ end
18
+ end
19
+
20
+ ## Minimally WEBrick -compatible Response object.
21
+ ## Implements only the methods used by the framework.
22
+ class Response
23
+ def initialize
24
+ @body = ResponseBody.new(1)
25
+ @body[0] = ''
26
+ @status = 200
27
+ @header = {
28
+ 'Content-Type' => 'text/plain',
29
+ 'Server' => 'Riassence Framework'
30
+ }
31
+ end
32
+ def body=(body_data)
33
+ @body = ResponseBody.new(1)
34
+ @body[0] = body_data
35
+ end
36
+ def body
37
+ @body.join
38
+ end
39
+ def content_type=(new_content_type)
40
+ @header['Content-Type'] = new_content_type
41
+ end
42
+ def content_type
43
+ @header['Content-Type']
44
+ end
45
+ def camelize( header_key )
46
+ header_key.capitalize.gsub(/\-([a-z])/) { '-'+$1.upcase }
47
+ end
48
+ def []=(header_key,header_val)
49
+ @header[camelize( header_key )] = header_val.to_s
50
+ end
51
+ def status=(new_val)
52
+ @status = new_val.to_i
53
+ end
54
+ def status
55
+ @status
56
+ end
57
+ def header
58
+ @header
59
+ end
60
+ end
61
+
62
+ end
63
+
@@ -0,0 +1,129 @@
1
+ ## Riassence Framework
2
+ # Copyright 2009 Riassence Inc.
3
+ # http://riassence.com/
4
+ #
5
+ # You should have received a copy of the GNU General Public License along
6
+ # with this software package. If not, contact licensing@riassence.com
7
+ ##
8
+
9
+ ## The GUIPlugin extends Plugin by automatically initializing an GUIParser
10
+ ## instance as @gui
11
+ ## It makes the include_js method public to enable automatic dependency
12
+ ## loading based on the dependencies item in the YAML gui declaration.
13
+ ## It also makes the @path public.
14
+ ## It inits the gui automatically.
15
+ ## Extend the gui_params method to define your own params for the gui data.
16
+ ##
17
+ ## HValues can be defined inside values.yaml at the root directory of
18
+ ## plugin. The HValues may be linked directly with methods on the values.yaml
19
+ ## as well.
20
+ ##
21
+ ## == Values.yaml
22
+ ## :valuename: # name of the HValue
23
+ ## :value: 2.56 # defined value
24
+ ## :responders: # methods responding to the value on ruby code upon change
25
+ ## - :method: validate_convert_factor
26
+ ##
27
+ ##
28
+ ##
29
+ class GUIPlugin < Plugin
30
+
31
+ @@default_yaml_src = %{
32
+ type: GUITree
33
+ version: 0.5
34
+
35
+ class: HApplication
36
+ options:
37
+ label: "Dummy Application"
38
+ }
39
+
40
+ # Automatically initializes an GUIParser instance as @gui
41
+ def init
42
+ super
43
+ yaml_src = file_read( "gui/#{@name}.yaml" )
44
+ yaml_src = file_read( "gui/main.yaml" ) unless yaml_src
45
+ yaml_src = @@default_yaml_src unless yaml_src
46
+ @gui = GUIParser.new( self, yaml_src )
47
+ @client_pkgs = false
48
+ end
49
+
50
+ # Extend this method to return custom params to GUIParser#init.
51
+ # Called from init_ui.
52
+ # By default assigns the session values as :values to use for
53
+ # valueObjId: ":values.my_value_name" in the YAML GUI file.
54
+ def gui_params( msg )
55
+ return {
56
+ :values => @gui.values( get_ses( msg ) )
57
+ }
58
+ end
59
+
60
+ def install_client_pkgs
61
+ if @client_pkgs
62
+ warn "install_client_pkgs: called with @client_pkgs defined; returning"
63
+ return
64
+ end
65
+ @client_pkgs = yaml_read( 'client_pkgs.yaml' )
66
+ if @client_pkgs
67
+ if @client_pkgs.has_key?(:src_dirs)
68
+ @client_pkgs[:src_dirs].each do |src_dir|
69
+ src_dir = bundle_path( src_dir[2..-1] ) if src_dir.start_with?('./')
70
+ @plugins.client_pkg.add_src_dir( src_dir )
71
+ end
72
+ end
73
+ @plugins.client_pkg.add_packages( @client_pkgs[:packages ] ) if @client_pkgs.has_key?(:packages )
74
+ @plugins.client_pkg.add_themes( @client_pkgs[:theme_names ] ) if @client_pkgs.has_key?(:theme_names )
75
+ @plugins.client_pkg.add_gfx_formats( @client_pkgs[:gfx_formats ] ) if @client_pkgs.has_key?(:gfx_formats )
76
+ @plugins.client_pkg.add_reserved_names( @client_pkgs[:reserved_names] ) if @client_pkgs.has_key?(:reserved_names)
77
+ @plugins.client_pkg.rebuild_client
78
+ end
79
+ end
80
+
81
+ def uninstall_client_pkgs
82
+ if not @client_pkgs
83
+ warn "uninstall_client_pkgs: called without @client_pkgs defined"
84
+ else
85
+ if @client_pkgs.has_key?(:src_dirs)
86
+ @client_pkgs[:src_dirs].each do |src_dir|
87
+ src_dir = bundle_path( src_dir[2..-1] ) if src_dir.start_with?('./')
88
+ @plugins.client_pkg.del_src_dir( src_dir )
89
+ end
90
+ end
91
+ @plugins.client_pkg.del_reserved_names( @client_pkgs[:reserved_names] ) if @client_pkgs.has_key?(:reserved_names)
92
+ @plugins.client_pkg.del_gfx_formats( @client_pkgs[:gfx_formats ] ) if @client_pkgs.has_key?(:gfx_formats )
93
+ @plugins.client_pkg.del_themes( @client_pkgs[:theme_names ] ) if @client_pkgs.has_key?(:theme_names )
94
+ @plugins.client_pkg.del_packages( @client_pkgs[:packages].keys ) if @client_pkgs.has_key?(:packages )
95
+ @plugins.client_pkg.rebuild_client
96
+ end
97
+ @client_pkgs = false
98
+ end
99
+
100
+ def open
101
+ super
102
+ install_client_pkgs if File.exist? bundle_path( 'client_pkgs.yaml' )
103
+ end
104
+
105
+ def close
106
+ super
107
+ uninstall_client_pkgs if @client_pkgs
108
+ end
109
+
110
+ # Sends gui specification to the main plugin
111
+ def spec_ui( msg )
112
+ # TODO
113
+ end
114
+
115
+ # Automatically inits the UI using GUIParser#init.
116
+ # Passes on the return value of gui_params.
117
+ def init_ui( msg ); @gui.init( msg, gui_params( msg ) ); end
118
+
119
+ # Automatically kills the UI using GUIParser#kill
120
+ def kill_ui( msg ); @gui.kill( msg ); end
121
+
122
+ # Makes include_js public to enable calls to it from GUIParser
123
+ public :include_js, :read_js_once
124
+
125
+ attr_reader :plugins
126
+
127
+ end
128
+
129
+
@@ -0,0 +1,114 @@
1
+ ## Riassence Framework
2
+ # Copyright 2009 Riassence Inc.
3
+ # http://riassence.com/
4
+ #
5
+ # You should have received a copy of the GNU General Public License along
6
+ # with this software package. If not, contact licensing@riassence.com
7
+ ##
8
+
9
+ # This class automatically loads a YAML file from "gui" subdirectory of a plugin.
10
+ # Extend your plugin from the GUIPlugin class instead of the Plugin class to make
11
+ # this work automatically.
12
+ # = Usage:
13
+ # Initialize like this from inside a plugin method. This will load the "gui/my_gui.yaml" file.
14
+ # @gui = GUIParser.new( self, 'my_gui' )
15
+ # To make the client render the contents of the yaml do this:
16
+ # ses = get_ses( msg )
17
+ # params = { :values => @gui.values( ses ) }
18
+ # @gui.init( msg, params )
19
+ class GUIParser
20
+
21
+ include ::RSence
22
+
23
+ # Use this method to send the client all commands required to construct the GUI Tree using JSONRenderer.
24
+ # = Parameters
25
+ # +msg+:: The +Message+ instance +msg+ used all over the place.
26
+ # +params+:: An hash containing all parameters referred from the YAML file.
27
+ def init( msg, params )
28
+ gui_data = YAML.load( @yaml_src )
29
+ parse_gui( gui_data, params )
30
+ if gui_data.has_key?('dependencies')
31
+ @parent.include_js( msg, gui_data['dependencies'] )
32
+ gui_data.delete('dependencies')
33
+ end
34
+ if gui_data.has_key?('include')
35
+ gui_data['include'].each do | js_file |
36
+ js_src = @parent.read_js_once( msg, js_file )
37
+ msg.reply( js_src )
38
+ end
39
+ end
40
+ gui_name = @parent.name
41
+ msg.reply( "JSONRenderer.nu(#{gui_data.to_json});", true )
42
+ end
43
+
44
+ # Use this method to extract all the value id's of the +ses+ hash.
45
+ def values( ses )
46
+ ids = {}
47
+ ses.each do | key, value |
48
+ if value.class == HValue
49
+ ids[ key ] = value.val_id
50
+ end
51
+ end
52
+ return ids
53
+ end
54
+
55
+ private
56
+
57
+ def json_fun( value )
58
+ JSON.parse( "[#{value}]" ).first
59
+ end
60
+
61
+ # Parses the gui data using params. Called from +init+.
62
+ def parse_gui( gui_data, params )
63
+ data_class = gui_data.class
64
+ if data_class == Array
65
+ gui_data.each_with_index do | item, i |
66
+ gui_data[i] = parse_gui( item, params )
67
+ end
68
+ elsif data_class == Hash
69
+ gui_data.each do | key, value |
70
+ gui_data[key] = parse_gui( value, params )
71
+ end
72
+ elsif data_class == Symbol
73
+ sym_str = gui_data.to_s
74
+ if sym_str.include? '.'
75
+ sym_arr = sym_str.split('.')
76
+ else
77
+ sym_arr = [ sym_str ]
78
+ end
79
+ return get_params( sym_arr, params )
80
+ elsif data_class == String and gui_data.strip.start_with?('function(')
81
+ return @parent.plugins[:client_pkg].squeeze( "a="+json_fun( gui_data.to_json ) )[2..-1]
82
+ end
83
+ return gui_data
84
+ end
85
+
86
+ # Searches the params hash for parameters whenever encountered a Symbol in the YAML.
87
+ def get_params( params_path, params )
88
+ item = params_path.shift
89
+ if params.class == Hash
90
+ has_str = params.has_key?( item )
91
+ has_sym = params.has_key?( item.to_sym )
92
+ item = item.to_sym if has_sym
93
+ if has_str or has_sym
94
+ if params_path.size == 0
95
+ return params[item]
96
+ else
97
+ return get_params( params_path, params[ item ] )
98
+ end
99
+ end
100
+ end
101
+ return ''
102
+ end
103
+
104
+ # Loads the YAML file.
105
+ # = Parameters
106
+ # +parent+:: The Plugin instance called from, use +self+ when constructing in a Plugin method.
107
+ # +yaml_src+:: The YAML source template for the GUI
108
+ def initialize( parent, yaml_src )
109
+ @parent = parent
110
+ @yaml_src = yaml_src
111
+ end
112
+
113
+ end
114
+
@@ -0,0 +1,652 @@
1
+ ## Riassence Framework
2
+ # Copyright 2006 Riassence Inc.
3
+ # http://riassence.com/
4
+ #
5
+ # You should have received a copy of the GNU General Public License along
6
+ # with this software package. If not, contact licensing@riassence.com
7
+ ##
8
+
9
+ ## = Abstract
10
+ ## The Plugin class is the base class for extending server logic.
11
+ ## A single Plugin instance serves the requests of all sessions,
12
+ ## which makes them very cpu and memory efficient compared to systems,
13
+ ## where the server classes are constructed and destructed for each
14
+ ## request.
15
+ ##
16
+ ## Plugins are designed to be contained in a plugin directory bundle and
17
+ ## to be loaded by the +PluginManager+, which is also responsible for
18
+ ## delegating the events and other calls throughout the system.
19
+ ##
20
+ ## == Anatomy of a plugin bundle
21
+ ## The plugin bundle contains all data needed to run the plugin. Design
22
+ ## your plugin without any hard-coded paths, remember that it's intended
23
+ ## to be deployed by "dropping" the whole plugin into one of the server's
24
+ ## plugins directories.
25
+ ##
26
+ ## The +PluginManager+ looks for such bundles and evaluates them into an
27
+ ## anonymous +Module+ namespace. The content of the ruby source file
28
+ ## is then responsible for including its libraries, constructing an
29
+ ## instance of itself and registering itself as a part of the system.
30
+ ##
31
+ ## It's advised to use the +GUIPlugin+ class for plugins that handle
32
+ ## user interfaces. Usage of the +Plugin+ bundle is advised to use
33
+ ## for plugins that provide extra functionality, value responders
34
+ ## and other utilities that supplement the user interface.
35
+ ##
36
+ ## You must call the +#register+ method after the class is constructed.
37
+ ## Otherwise, the class is not connected to the system and just discarded
38
+ ## and then garbage collected.
39
+ ##
40
+ ## == Messages
41
+ ## As a side effect of having single instances of plugins serve the requests
42
+ ## of all sessions, the request/response/session messaging is implemented
43
+ ## as messaging objects. These objects contain or delegate all the necessary
44
+ ## hooks required by the complete request/response cycle.
45
+ ##
46
+ ## The naming convention of the +Message+ instance is +msg+ and it's
47
+ ## given as the first parameter of methods needing it.
48
+ ##
49
+ ## Use +msg.ses_id+ to identify the session's serial number and +msg.user_id+
50
+ ## to identify the user's identity.
51
+ ##
52
+ ## Use the +msg.session+ +Hash+ to store any persistent data
53
+ ## associated with the user's session, preferably using the name of the
54
+ ## plugin or its registered name as the primary key entry in the Hash.
55
+ ## The session data is persistent; it's stored in the session database
56
+ ## by +SessionStorage+ automatically.
57
+ ##
58
+ ## The +msg+ instance also provides access to the +Request+ and +Response+
59
+ ## objects as +msg.request+ and +msg.response+, respectively.
60
+ ##
61
+ ## Use the +msg.run+ method to call other plugins.
62
+ ##
63
+ ## To append js source code to be evaluated in the client, use the +msg.reply+
64
+ ## call. The +msg.console+ call appends messages to the browser's js console.
65
+ ##
66
+ ##
67
+ ## == Session -related event methods
68
+ ## The +#get_ses+ method returns (or creates and returns) the entry in
69
+ ## the session based on the name your plugin is registered as. It's advised
70
+ ## to use this call instead of manually managing +msg.session+ in most cases.
71
+ ##
72
+ ## The +#idle+ method is called each time a client performs a data
73
+ ## synchronization or "idle poll" request.
74
+ ##
75
+ ## The +#init_ses+ method is called once in the same request a new session
76
+ ## is created. A new session is created, when a user enters accesses the
77
+ ## server the first time, or the first time after the previous session is
78
+ ## expired.
79
+ ##
80
+ ## The +#init_ui+ method is called by the "main" plugin after the client has
81
+ ## booted successfully. The +GUIPlugin+ class extends this method to
82
+ ## automatically load and initialize the user interface from a data structure.
83
+ ##
84
+ ## The +#restore_ses+ method is called once in the same request an old
85
+ ## session is restored. A session is restored, when the user returns to
86
+ ## the page or reloads the page before the session is expired.
87
+ ##
88
+ ## === When the server is configured to restore previous sessions (default):
89
+ ## If the user accesses the same page using the same browser (in different
90
+ ## tabs or windows), only the most recently restored one is valid, while
91
+ ## the previous ones are immediately invalidated.
92
+ ## If your application is intended to support several sessions per browser,
93
+ ## enable session cloning in the configuration file.
94
+ ##
95
+ ## === When the server is configured to restore and clone previous sessions:
96
+ ## When sessions are cloned, the previous session is not invalidated and
97
+ ## exists until timing out as a result of the web browser window being closed
98
+ ## or client computer losing network connectivity for a certain (configurable)
99
+ ## time frame.
100
+ ##
101
+ ## The +#cloned_target+ method is like +#restore_ses+, but called when
102
+ ## the session is a clone of a previous session.
103
+ ##
104
+ ## The +#cloned_source+ method is called on the next request of the previous
105
+ ## session after it has been cloned.
106
+ ##
107
+ ## == Server event methods
108
+ ## Extend the +#init+ method to invoke constructor functionality that
109
+ ## depends on the plugin to be constructed and registered as a part of
110
+ ## the system.
111
+ ##
112
+ ## Extend the +#open+, +#flush+ and +#close+ methods to open, flush and close
113
+ ## streams or other similar functionality.
114
+ ##
115
+ ## == Data handling
116
+ ## The data exchange system exists to support bi-directional
117
+ ## data synchronization between the browser and the plugin. The values
118
+ ## are stored in the session as +HValue+ instances.
119
+ ##
120
+ ## Values support Hashes, Arrays, Strings, Numbers, Booleans and
121
+ ## combinations of them. The data is automatically converted between
122
+ ## ruby objects (server) and json objects (client).
123
+ ##
124
+ ## Each instance may be bound to plugin methods that are used as
125
+ ## value change notification responders.
126
+ ##
127
+ ## When a method is bound to the value, the method is called as an
128
+ ## event notification whenever the client has changed the value and
129
+ ## synchronizes it to the server. The responders act as validators
130
+ ## by default.
131
+ ##
132
+ ## Values are also bound in the client to classes implementing the
133
+ ## HValueResponder interface, like any derivate of HControl. See the
134
+ ## client documentation for instructions about using them.
135
+ ##
136
+ ## To define a value responder method, it needs to respond to exactly
137
+ ## two parameters: the +Message+ instance +msg+ and the HValue object
138
+ ## (in that order). The method's return value must be either +true+
139
+ ## or +false+. When the method returns +false+, the change is discarded
140
+ ## and the previously server-set value is sent back to the client.
141
+ ##
142
+ ## A minimal value responder method is defined like this:
143
+ ##
144
+ ## def my_value_responder( msg, my_value )
145
+ ## return true
146
+ ## end
147
+ ##
148
+ ## To access the content of the value, use the +HValue#data+ attribute.
149
+ ##
150
+ ## def int_between_100_and_200( msg, value )
151
+ ## data = value.data.to_i
152
+ ## return ( data >= 100 and data <= 200 )
153
+ ## end
154
+ ##
155
+ ## To change the content of the value, use the +HValue#set+ method.
156
+ ##
157
+ ## def int_between_100_and_200( msg, value )
158
+ ## data = value.data.to_i
159
+ ## value.set( msg, 100 ) if data < 100
160
+ ## value.set( msg, 200 ) if data > 200
161
+ ## return true
162
+ ## end
163
+ ##
164
+ ## == Defining values
165
+ ## The simplest and recommended way of defining the values is to define
166
+ ## the value configuration file +values.yaml+. Its configuration is then
167
+ ## applied to sessions automatically.
168
+ ##
169
+ ##
170
+ ## === Syntax reference of the contents of a +values.yaml+ file:
171
+ ##
172
+ ## # The name of the value (:value_name).
173
+ ## # A hash key in the yaml syntax
174
+ ## :value_name:
175
+ ##
176
+ ## # All of these keys are optional!
177
+ ##
178
+ ## # Default value, a string "Foo" here.
179
+ ## # Defaults to 0
180
+ ## :value: Foo
181
+ ##
182
+ ## # A plugin method to call to define the default value
183
+ ## # instead of the one defined in :value
184
+ ## :value_call:
185
+ ## :plugin: plugin_name # defaults to the plugin where defined
186
+ ##
187
+ ## # Mandatory; name of the method to call
188
+ ## :method: method_name
189
+ ##
190
+ ## # Optional, list of parameter values for the :method
191
+ ## :args:
192
+ ## # three parameters: 1, 'foo', 3
193
+ ## - 1
194
+ ## - foo
195
+ ## - 3
196
+ ##
197
+ ## # When false, doesn't pass the msg as the first parameter.
198
+ ## # Defaults to true
199
+ ## :uses_msg: true
200
+ ##
201
+ ## # Restore the default, when the session is restored; defaults to false
202
+ ## :restore_default: false
203
+ ##
204
+ ## # List of value responder methods to bind.
205
+ ## :responders:
206
+ ## -
207
+ ## # name of plugin to call, defaults to the plugin where defined:
208
+ ## :plugin: plugin_name
209
+ ##
210
+ ## # mandatory, name of the method to call
211
+ ## :method: method_name
212
+ ##
213
+ ## # Another responder, this one using the same plugin where defined:
214
+ ## - :method: another_method
215
+ ##
216
+ ## # Another value, this one just defining the defaults
217
+ ## # by supplying an empty Hash:
218
+ ## # (value: 0, default restored, no responders or calls)
219
+ ## :value_with_defaults: {}
220
+ ##
221
+ ## # This value defines a Number (123) and doesn't restore
222
+ ## # the default, when restoring the session.
223
+ ## :one_two_three:
224
+ ## :value: 123
225
+ ## :restore_default: false
226
+ ##
227
+ ## # This value gets a random string and specifies a responder,
228
+ ## # that ensures it's unique, if changed in the client.
229
+ ## :random_unique_string:
230
+ ## :value_call:
231
+ ## :method: get_unique_random_string
232
+ ## :uses_msg: false
233
+ ## :responders:
234
+ ## - :method: ensure_unique_random_string
235
+ ##
236
+ ## = Examples
237
+ ## More examples are available in the repository;
238
+ ## http://svn.rsence.org/contrib/plugins
239
+ ## ..as well as the standard "main" plugin in the "plugins" directory.
240
+ ##
241
+ ##
242
+ ## == A minimal Plugin bundle
243
+ ## The minimal active plugin bundle (named "name_of_plugin")
244
+ ## is defined like this:
245
+ ##
246
+ ## [dir] name_of_plugin
247
+ ## |
248
+ ## +---[file] name_of_plugin.rb
249
+ ##
250
+ ## This sample Plugin doesn't do anything except construct itself and
251
+ ## respond as 'name_of_plugin'.
252
+ ##
253
+ ## Plugin.new.register('name_of_plugin')
254
+ ##
255
+ ## However, this is not very useful in itself, so you'll need to extend
256
+ ## its functionality to do anything useful.
257
+ ##
258
+ ## == A simple Plugin extension
259
+ ## This plugin logs session events to the logs/session_log file.
260
+ ##
261
+ ## [dir] ses_logger
262
+ ## |
263
+ ## +---[file] ses_logger.rb
264
+ ## |
265
+ ## +---[dir] logs
266
+ ## |
267
+ ## +---[file] session_log
268
+ ##
269
+ ## == Contents of "ses_logger.rb"
270
+ ##
271
+ ## class SessionLogger < Plugin
272
+ ## def init
273
+ ## super
274
+ ## @logfile = false
275
+ ## end
276
+ ## def open
277
+ ## log_path = compose_plugin_path( 'session_log', 'logs' )
278
+ ## @logfile = File.open( log_path, 'a' )
279
+ ## end
280
+ ## def close
281
+ ## @logfile.close if @logfile
282
+ ## @logfile = false
283
+ ## end
284
+ ## def flush
285
+ ## @logfile.flush if @logfile
286
+ ## end
287
+ ## def init_ses( msg )
288
+ ## super
289
+ ## @logfile.write( "#{Time.new} -- Session id #{msg.ses_id} was created.\n" )
290
+ ## end
291
+ ## def restore_ses( msg )
292
+ ## super
293
+ ## @logfile.write( "#{Time.new} -- Session id #{msg.ses_id} was restored.\n" )
294
+ ## end
295
+ ## def idle( msg )
296
+ ## @logfile.write( "#{Time.new} -- Client of session id #{msg.ses_id} connected.\n" )
297
+ ## end
298
+ ## end
299
+ ## SessionLogger.new.register( 'ses_logger' )
300
+ ##
301
+ class Plugin
302
+
303
+ include PluginUtil
304
+
305
+ # The +names+ is a list of (usually just one) names the plugin is registered under.
306
+ attr_reader :name, :path, :info, :inited
307
+
308
+ # The constructor should not take any parameters. In most cases, it's better
309
+ # to extend the +#init+ method, because it's called after the plugin is set up.
310
+ def initialize
311
+ @inited = false
312
+ @info = @@bundle_info
313
+ @name = @@bundle_name
314
+ @path = @@bundle_path
315
+ @plugins = @@plugin_manager
316
+ register unless @info[:inits_self]
317
+ end
318
+
319
+ # Extend this method to do any initial tasks before other methods are called.
320
+ # By default init_values is called to load the +values.yaml+ configuration file.
321
+ def init
322
+ @values = init_values
323
+ end
324
+
325
+ # Extend this method to do any tasks every time the client makes a request.
326
+ def idle( msg )
327
+ end
328
+
329
+ # Extend this method to invoke actions, when a new session is created.
330
+ # By default +#init_ses_values+ is called to initialize values defined in the
331
+ # +values.yaml+ configuration file.
332
+ def init_ses( msg )
333
+ init_ses_values( msg )
334
+ end
335
+
336
+ # Extend this method to invoke actions, when a previous session is restored.
337
+ # By default +#restore_ses_values+ is called to perform actions on values as
338
+ # defined in the +values.yaml+ configuration file.
339
+ def restore_ses( msg )
340
+ restore_ses_values( msg )
341
+ end
342
+
343
+ # Extend this method to invoke actions, when the session
344
+ # is a clone of another session. It's called once, just
345
+ # before +#restore_ses+ is called.
346
+ #
347
+ # A session is cloned, when a user opens a another browser
348
+ # window or tab, while the previous session is still active.
349
+ #
350
+ # The +source_ses+ is the actual previous session object, which
351
+ # was used as the source of the clone.
352
+ def cloned_target( msg, source_session )
353
+ end
354
+
355
+ # Extend this method to invoke actions, when the session
356
+ # has been cloned to another session. It's called once, just
357
+ # before +#restore_ses+ is called on the first request after
358
+ # the cloning happened.
359
+ #
360
+ # A session is cloned, when a user opens a another browser
361
+ # window or tab, while the previous session is still active.
362
+ #
363
+ # The +target_ses+ is the actual cloned session object, which
364
+ # is a copy of the current session.
365
+ def cloned_source( msg, target_sessions )
366
+ end
367
+
368
+ # This method must be called to register the plugin instance
369
+ # into the system. Otherwise, it's subject to destruction
370
+ # and garbage collection. Use the +name+ parameter to
371
+ # give the (unique) name of your plugin.
372
+ def register( name=false )
373
+ if @inited
374
+ @plugins.register_alias( @name, name )
375
+ else
376
+ if name
377
+ name = name.to_s
378
+ else
379
+ name = @name
380
+ end
381
+ @plugins.register_bundle( self, name )
382
+ @inited = true
383
+ end
384
+ end
385
+
386
+ private
387
+
388
+ # This method looks looks for a file called "values.yaml"
389
+ # in the plugin's bundle directory
390
+ #.
391
+ # If this file is found, it loads it for initial value definitions.
392
+ #
393
+ # These definitions are accessible as the +@values+ attribute.
394
+ def init_values
395
+ values_path = compose_plugin_path( 'values.yaml' )
396
+ return yaml_read( values_path )
397
+ end
398
+
399
+ # Returns all the names your plugin respond to.
400
+ # def name
401
+ # return @names.first
402
+ # end
403
+
404
+
405
+ # Returns or creates a new session hash for the plugin.
406
+ #
407
+ # Uses the first name registered for the plugin and converts it to a symbol.
408
+ def get_ses( msg )
409
+ name_sym = name.to_sym
410
+ unless msg.session.has_key?( name_sym )
411
+ msg.session[ name_sym ] = {}
412
+ end
413
+ return msg.session[ name_sym ]
414
+ end
415
+
416
+ # Returns the source code of the javascript file +name+ in the 'js'
417
+ # subdirectory of the plugin bundle.
418
+ def read_js( js_name )
419
+ file_read( compose_plugin_path( js_name, 'js', '.js' ) )
420
+ end
421
+
422
+ # Deprecated name of +#read_js+
423
+ alias require_js read_js
424
+
425
+ # Like +#read_js+, but reads the file only once per session.
426
+ #
427
+ # Returns the contents of the file on the first call,
428
+ # an empty string on the subsequent calls.
429
+ #
430
+ # Returns false otherwise.
431
+ def read_js_once( msg, js_name )
432
+ ses = msg.session
433
+ if not ses.has_key?(:deps)
434
+ ses[:deps] = []
435
+ end
436
+ path = compose_plugin_path( js_name, 'js', '.js' )
437
+ unless ses[:deps].include?( path )
438
+ ses[:deps].push( path )
439
+ return file_read( path )
440
+ else
441
+ return ''
442
+ end
443
+ end
444
+
445
+ # Deprecated name of +#read_js_once+
446
+ alias require_js_once read_js_once
447
+
448
+ # Creates a new instance of HValue, assigns it as +value_name+ into the
449
+ # session and uses the +value_properties+ Hash to define the default
450
+ # value and value responders.
451
+ #
452
+ # This method is invoked automatically, when handling the properties
453
+ # of the +values.yaml+ configuration file of a new session.
454
+ #
455
+ # It's invoked by +#init_ses+ via +#init_ses_values+.
456
+ #
457
+ # Structure of +value_properties+, all top-level items are optional:
458
+ #
459
+ # {
460
+ # # Default value; defaults to 0
461
+ # :value => 'foo',
462
+ #
463
+ # # A plugin method to call to define the default value instead of the one defined in :value
464
+ # :value_call => {
465
+ # :plugin => 'plugin_name', # defaults to the plugin where defined
466
+ # :method => 'method_name', # mandatory; name of the method to call
467
+ # :args => [ 1, 'foo', 3 ], # optional, list of parameter values for the :method
468
+ # :uses_msg => true # defaults to true; when false, doesn't pass the msg as the first parameter
469
+ # },
470
+ #
471
+ # # Restore the default, when the session is restored; defaults to false
472
+ # :restore_default => false,
473
+ #
474
+ # # List of value responder methods to bind.
475
+ # :responders => [
476
+ # {
477
+ # :plugin => 'plugin_name', # defaults to the plugin where defined
478
+ # :method => 'method_name' # mandatory, name of the method to call
479
+ # },
480
+ # # You can supply as many responders as you like:
481
+ # { :plugin => 'another_plugin', :method => 'another_method' }
482
+ # ]
483
+ # }
484
+ #
485
+ def init_ses_value( msg, value_name, value_properties )
486
+ ses = get_ses( msg )
487
+ if value_properties.has_key?(:value_call)
488
+ default_value = init_value_call( msg, value_properties[:value_call] )
489
+ elsif value_properties.has_key?(:value)
490
+ default_value = value_properties[:value]
491
+ else
492
+ default_value = 0
493
+ end
494
+ ses[value_name] = HValue.new( msg, default_value )
495
+ if value_properties.has_key?(:responders)
496
+ value_properties[:responders].each do |responder|
497
+ if responder.has_key?(:plugin)
498
+ responder_plugin = responder[:plugin]
499
+ else
500
+ responder_plugin = @name
501
+ end
502
+ if responder.has_key?(:method)
503
+ ses[value_name].bind( responder_plugin, responder[:method] )
504
+ end
505
+ end
506
+ end
507
+ end
508
+
509
+ # Initializes session values, if the contents of the +values.yaml+
510
+ # file is defined in the bundle directory and loaded in +#init_values+.
511
+ def init_ses_values( msg )
512
+ return unless @values
513
+ @values.each do | value_name, value_properties |
514
+ init_ses_value( msg, value_name, value_properties )
515
+ end
516
+ end
517
+
518
+ # Returns a value based on the :method and :plugin members of the
519
+ # +value_call+ hash.
520
+ #
521
+ # The call is made via msg.run if the method is not defined in
522
+ # the local plugin bundle.
523
+ #
524
+ # This method is called from +#init_ses_value+.
525
+ #
526
+ # Structure of the +value_call+ Hash:
527
+ # { :plugin => 'plugin_name', # defaults to the plugin where defined
528
+ # :method => 'method_name', # mandatory; name of the method to call
529
+ # :args => [ 1, 'foo', 3 ], # optional, list of parameter values for the :method
530
+ # :uses_msg => true # defaults to true; when false, doesn't pass the msg as the first parameter
531
+ # }
532
+ def init_value_call( msg, value_call )
533
+ value_call_method = value_call[:method]
534
+ if value_call.has_key?(:plugin)
535
+ value_call_plugin = value_call[:plugin]
536
+ else
537
+ value_call_plugin = false
538
+ end
539
+ if value_call.has_key?(:args)
540
+ if value_call.has_key?(:uses_msg) and value_call[:uses_msg] != false
541
+ if value_call_plugin
542
+ return msg.run( value_call_plugin, value_call_method, msg, *value_call[:args] )
543
+ else
544
+ return self.method( value_call_method ).call( msg, *value_call[:args] )
545
+ end
546
+ else
547
+ if value_call_plugin
548
+ return msg.run( value_call_plugin, value_call_method, *value_call[:args] )
549
+ else
550
+ return self.method( value_call_method ).call( *value_call[:args] )
551
+ end
552
+ end
553
+ else
554
+ if value_call.has_key?(:uses_msg) and value_call[:uses_msg] != false
555
+ if value_call_plugin
556
+ return msg.run( value_call_plugin, value_call_method, msg )
557
+ else
558
+ return self.method( value_call_method ).call( msg )
559
+ end
560
+ else
561
+ if value_call_plugin
562
+ return msg.run( value_call_plugin, value_call_method )
563
+ else
564
+ return self.method( value_call_method ).call( )
565
+ end
566
+ end
567
+ end
568
+ end
569
+
570
+ # Restores session values to default, unless specified otherwise.
571
+ #
572
+ # Called from +#restore_ses+
573
+ def restore_ses_values( msg )
574
+ return unless @values
575
+ ses = get_ses( msg )
576
+ @values.each do | value_name, value_properties |
577
+ if ses.has_key?( value_name ) and ses[ value_name ].class == HValue
578
+ unless value_properties[:restore_default] == false
579
+ if value_properties.has_key?(:value_call)
580
+ default_value = init_value_call( msg, value_properties[:value_call] )
581
+ elsif value_properties.has_key?(:value)
582
+ default_value = value_properties[:value]
583
+ else
584
+ default_value = 0
585
+ end
586
+ ses[value_name].set( msg, default_value )
587
+ end
588
+ else
589
+ init_ses_value( msg, value_name, value_properties )
590
+ end
591
+ end
592
+ end
593
+
594
+ # Extracts +HValue+ references as javascript from the session Hash.
595
+ # The +ses+ parameter is used for supplying a hash with the +HValue+
596
+ # instances. It's optional and defaults to the current plugin node in
597
+ # the active session.
598
+ #
599
+ # The return value is a string representing a js object similar to
600
+ # the ruby Hash +ses+.
601
+ #
602
+ # Sample usage:
603
+ #
604
+ # values_js( msg, msg.session[:main] )
605
+ #
606
+ def values_js( msg, ses=false )
607
+ # backwards-compatible with pre-1.3 behaviour
608
+ ses = msg if msg.class == Hash
609
+ # gets the session automatically, if false
610
+ ses = get_ses( msg ) unless ses
611
+ js_references = []
612
+ ses.each_key do |key_name|
613
+ if ses[key_name].class == HValue
614
+ js_references.push( "#{key_name.to_s}:HVM.values['#{ses[key_name].val_id}']" )
615
+ end
616
+ end
617
+ return "{#{js_references.join(',')}}"
618
+ end
619
+
620
+ # Deprecated name of +#values_js+
621
+ alias extract_hvalues_from_hash values_js
622
+
623
+ # Tells the js client framework to load a list of dependency packages.
624
+ # It keeps track of what's loaded, so nothing library loaded twice.
625
+ #
626
+ # The +dependencies+ parameter is an Array of dependencies.
627
+ #
628
+ # Sample usage:
629
+ #
630
+ # include_js( msg, [ 'default_theme', 'controls', 'lists', 'datetime' ] )
631
+ #
632
+ def include_js( msg, dependencies=[] )
633
+ ses = msg.session
634
+ # check, if the session has a dependency array
635
+ if not ses.has_key?( :deps )
636
+ # make an array of dependencies for this session, if not already done
637
+ ses[:deps] = []
638
+ end
639
+ dependencies = [dependencies] if dependencies.class == String
640
+ # Check the required dependencies until everything is loaded.
641
+ dependencies.each do |dependency|
642
+ unless ses[:deps].include?( dependency )
643
+ ses[:deps].push( dependency )
644
+ msg.reply(%{jsLoader.load("#{dependency}");})
645
+ end
646
+ end
647
+ end
648
+
649
+
650
+ end
651
+
652
+