sproutcore 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (270) hide show
  1. data/History.txt +4 -0
  2. data/License.txt +20 -0
  3. data/Manifest.txt +269 -0
  4. data/README.txt +67 -0
  5. data/Rakefile +4 -0
  6. data/app_generators/sproutcore/USAGE +5 -0
  7. data/app_generators/sproutcore/sproutcore_generator.rb +66 -0
  8. data/app_generators/sproutcore/templates/README +77 -0
  9. data/app_generators/sproutcore/templates/environment.yml +4 -0
  10. data/bin/sc-build +145 -0
  11. data/bin/sc-gen +24 -0
  12. data/bin/sc-server +63 -0
  13. data/bin/sproutcore +21 -0
  14. data/clients/sc_docs/controllers/docs.js +118 -0
  15. data/clients/sc_docs/core.js +19 -0
  16. data/clients/sc_docs/english.lproj/body.css +159 -0
  17. data/clients/sc_docs/english.lproj/body.rhtml +33 -0
  18. data/clients/sc_docs/english.lproj/controls.css +0 -0
  19. data/clients/sc_docs/english.lproj/icons/small/next.png +0 -0
  20. data/clients/sc_docs/english.lproj/icons/small/reset.png +0 -0
  21. data/clients/sc_docs/english.lproj/images/gradients.png +0 -0
  22. data/clients/sc_docs/english.lproj/images/indicator.gif +0 -0
  23. data/clients/sc_docs/english.lproj/images/toolbar.png +0 -0
  24. data/clients/sc_docs/english.lproj/no_docs.rhtml +7 -0
  25. data/clients/sc_docs/english.lproj/strings.js +14 -0
  26. data/clients/sc_docs/english.lproj/warning.rhtml +6 -0
  27. data/clients/sc_docs/fixtures/doc.js +11 -0
  28. data/clients/sc_docs/main.js +21 -0
  29. data/clients/sc_docs/models/doc.js +9 -0
  30. data/clients/sc_docs/tests/controllers/docs.rhtml +21 -0
  31. data/clients/sc_docs/tests/models/doc.rhtml +21 -0
  32. data/clients/sc_docs/tests/views/doc_frame.rhtml +21 -0
  33. data/clients/sc_docs/tests/views/doc_label_view.rhtml +21 -0
  34. data/clients/sc_docs/views/doc_frame.js +33 -0
  35. data/clients/sc_docs/views/doc_label.js +20 -0
  36. data/clients/sc_test_runner/controllers/runner.js +175 -0
  37. data/clients/sc_test_runner/core.js +19 -0
  38. data/clients/sc_test_runner/english.lproj/body.css +151 -0
  39. data/clients/sc_test_runner/english.lproj/body.rhtml +35 -0
  40. data/clients/sc_test_runner/english.lproj/controls.css +0 -0
  41. data/clients/sc_test_runner/english.lproj/icons/small/next.png +0 -0
  42. data/clients/sc_test_runner/english.lproj/icons/small/reset.png +0 -0
  43. data/clients/sc_test_runner/english.lproj/images/gradients.png +0 -0
  44. data/clients/sc_test_runner/english.lproj/images/indicator.gif +0 -0
  45. data/clients/sc_test_runner/english.lproj/images/toolbar.png +0 -0
  46. data/clients/sc_test_runner/english.lproj/no_tests.rhtml +6 -0
  47. data/clients/sc_test_runner/english.lproj/strings.js +14 -0
  48. data/clients/sc_test_runner/english.lproj/warning.rhtml +6 -0
  49. data/clients/sc_test_runner/fixtures/test.js +12 -0
  50. data/clients/sc_test_runner/main.js +26 -0
  51. data/clients/sc_test_runner/models/test.js +11 -0
  52. data/clients/sc_test_runner/views/runner_frame.js +72 -0
  53. data/clients/sc_test_runner/views/test_label.js +20 -0
  54. data/config/hoe.rb +70 -0
  55. data/config/requirements.rb +17 -0
  56. data/environment.yml +9 -0
  57. data/frameworks/prototype/prototype.js +4186 -0
  58. data/frameworks/sproutcore/Core.js +378 -0
  59. data/frameworks/sproutcore/README +3 -0
  60. data/frameworks/sproutcore/controllers/array.js +236 -0
  61. data/frameworks/sproutcore/controllers/collection.js +305 -0
  62. data/frameworks/sproutcore/controllers/controller.js +323 -0
  63. data/frameworks/sproutcore/controllers/object.js +372 -0
  64. data/frameworks/sproutcore/drag/drag.js +549 -0
  65. data/frameworks/sproutcore/drag/drag_data_source.js +32 -0
  66. data/frameworks/sproutcore/drag/drag_source.js +64 -0
  67. data/frameworks/sproutcore/drag/drop_target.js +153 -0
  68. data/frameworks/sproutcore/english.lproj/blank.gif +0 -0
  69. data/frameworks/sproutcore/english.lproj/buttons.css +589 -0
  70. data/frameworks/sproutcore/english.lproj/buttons.png +0 -0
  71. data/frameworks/sproutcore/english.lproj/inline_text_editor.css +21 -0
  72. data/frameworks/sproutcore/english.lproj/menu.css +121 -0
  73. data/frameworks/sproutcore/english.lproj/panels/background-fat.jpg +0 -0
  74. data/frameworks/sproutcore/english.lproj/panels/background-thin.jpg +0 -0
  75. data/frameworks/sproutcore/english.lproj/panels/bottom-edge.png +0 -0
  76. data/frameworks/sproutcore/english.lproj/panels/bottom-left-corner.png +0 -0
  77. data/frameworks/sproutcore/english.lproj/panels/bottom-right-corner.png +0 -0
  78. data/frameworks/sproutcore/english.lproj/panels/left-edge.png +0 -0
  79. data/frameworks/sproutcore/english.lproj/panels/overlay.png +0 -0
  80. data/frameworks/sproutcore/english.lproj/panels/right-edge.png +0 -0
  81. data/frameworks/sproutcore/english.lproj/panels/top-edge.png +0 -0
  82. data/frameworks/sproutcore/english.lproj/panels/top-left-corner.png +0 -0
  83. data/frameworks/sproutcore/english.lproj/panels/top-right-corner.png +0 -0
  84. data/frameworks/sproutcore/english.lproj/panes.css +155 -0
  85. data/frameworks/sproutcore/english.lproj/picker.css +22 -0
  86. data/frameworks/sproutcore/english.lproj/strings.js +15 -0
  87. data/frameworks/sproutcore/english.lproj/tab.css +23 -0
  88. data/frameworks/sproutcore/english.lproj/tests.css +67 -0
  89. data/frameworks/sproutcore/english.lproj/theme.css +77 -0
  90. data/frameworks/sproutcore/foundation/animator.js +670 -0
  91. data/frameworks/sproutcore/foundation/application.js +199 -0
  92. data/frameworks/sproutcore/foundation/array.js +348 -0
  93. data/frameworks/sproutcore/foundation/benchmark.js +211 -0
  94. data/frameworks/sproutcore/foundation/binding.js +384 -0
  95. data/frameworks/sproutcore/foundation/date.js +357 -0
  96. data/frameworks/sproutcore/foundation/error.js +39 -0
  97. data/frameworks/sproutcore/foundation/input_manager.js +153 -0
  98. data/frameworks/sproutcore/foundation/json.js +296 -0
  99. data/frameworks/sproutcore/foundation/mock.js +42 -0
  100. data/frameworks/sproutcore/foundation/node_descriptor.js +56 -0
  101. data/frameworks/sproutcore/foundation/object.js +777 -0
  102. data/frameworks/sproutcore/foundation/observable.js +451 -0
  103. data/frameworks/sproutcore/foundation/page.js +63 -0
  104. data/frameworks/sproutcore/foundation/path_module.js +413 -0
  105. data/frameworks/sproutcore/foundation/responder.js +310 -0
  106. data/frameworks/sproutcore/foundation/routes.js +371 -0
  107. data/frameworks/sproutcore/foundation/run_loop.js +21 -0
  108. data/frameworks/sproutcore/foundation/server.js +491 -0
  109. data/frameworks/sproutcore/foundation/set.js +96 -0
  110. data/frameworks/sproutcore/foundation/string.js +149 -0
  111. data/frameworks/sproutcore/foundation/undo_manager.js +186 -0
  112. data/frameworks/sproutcore/foundation/unittest.js +622 -0
  113. data/frameworks/sproutcore/foundation/utils.js +61 -0
  114. data/frameworks/sproutcore/globals/panels.js +182 -0
  115. data/frameworks/sproutcore/globals/popups.js +60 -0
  116. data/frameworks/sproutcore/globals/window.js +381 -0
  117. data/frameworks/sproutcore/lib/index.rhtml +66 -0
  118. data/frameworks/sproutcore/models/collection.js +395 -0
  119. data/frameworks/sproutcore/models/record.js +622 -0
  120. data/frameworks/sproutcore/models/store.js +295 -0
  121. data/frameworks/sproutcore/panes/dialog.js +16 -0
  122. data/frameworks/sproutcore/panes/manager.js +164 -0
  123. data/frameworks/sproutcore/panes/menu.js +45 -0
  124. data/frameworks/sproutcore/panes/overlay.js +231 -0
  125. data/frameworks/sproutcore/panes/pane.js +90 -0
  126. data/frameworks/sproutcore/panes/panel.js +19 -0
  127. data/frameworks/sproutcore/panes/picker.js +45 -0
  128. data/frameworks/sproutcore/tests/controllers/array.rhtml +86 -0
  129. data/frameworks/sproutcore/tests/controllers/controller.rhtml +273 -0
  130. data/frameworks/sproutcore/tests/controllers/object.rhtml +327 -0
  131. data/frameworks/sproutcore/tests/foundation/application.rhtml +125 -0
  132. data/frameworks/sproutcore/tests/foundation/array.rhtml +221 -0
  133. data/frameworks/sproutcore/tests/foundation/object.rhtml +69 -0
  134. data/frameworks/sproutcore/tests/globals/window.rhtml +45 -0
  135. data/frameworks/sproutcore/tests/panes/pane.rhtml +88 -0
  136. data/frameworks/sproutcore/tests/views/collection.rhtml +137 -0
  137. data/frameworks/sproutcore/tests/views/popup_button.rhtml +115 -0
  138. data/frameworks/sproutcore/tests/views/text_field.rhtml +37 -0
  139. data/frameworks/sproutcore/validators/credit_card.js +92 -0
  140. data/frameworks/sproutcore/validators/date.js +36 -0
  141. data/frameworks/sproutcore/validators/email.js +29 -0
  142. data/frameworks/sproutcore/validators/not_empty.js +24 -0
  143. data/frameworks/sproutcore/validators/number.js +55 -0
  144. data/frameworks/sproutcore/validators/password.js +78 -0
  145. data/frameworks/sproutcore/validators/validator.js +304 -0
  146. data/frameworks/sproutcore/views/button.js +425 -0
  147. data/frameworks/sproutcore/views/checkbox_field.js +30 -0
  148. data/frameworks/sproutcore/views/collection.js +1521 -0
  149. data/frameworks/sproutcore/views/container.js +62 -0
  150. data/frameworks/sproutcore/views/error_explanation.js +45 -0
  151. data/frameworks/sproutcore/views/field.js +214 -0
  152. data/frameworks/sproutcore/views/filter_button.js +29 -0
  153. data/frameworks/sproutcore/views/form.js +591 -0
  154. data/frameworks/sproutcore/views/image.js +141 -0
  155. data/frameworks/sproutcore/views/inline_text_editor.js +96 -0
  156. data/frameworks/sproutcore/views/label.js +176 -0
  157. data/frameworks/sproutcore/views/menu_item.js +90 -0
  158. data/frameworks/sproutcore/views/pagination.js +54 -0
  159. data/frameworks/sproutcore/views/popup_button.js +86 -0
  160. data/frameworks/sproutcore/views/popup_menu.js +137 -0
  161. data/frameworks/sproutcore/views/progress.js +100 -0
  162. data/frameworks/sproutcore/views/radio_field.js +107 -0
  163. data/frameworks/sproutcore/views/radio_group.js +48 -0
  164. data/frameworks/sproutcore/views/segmented.js +80 -0
  165. data/frameworks/sproutcore/views/select_field.js +272 -0
  166. data/frameworks/sproutcore/views/spinner.js +11 -0
  167. data/frameworks/sproutcore/views/tab.js +126 -0
  168. data/frameworks/sproutcore/views/text_field.js +179 -0
  169. data/frameworks/sproutcore/views/textarea_field.js +14 -0
  170. data/frameworks/sproutcore/views/toolbar.js +29 -0
  171. data/frameworks/sproutcore/views/view.js +1389 -0
  172. data/frameworks/sproutcore/views/workspace.js +170 -0
  173. data/generators/client/README +3 -0
  174. data/generators/client/USAGE +12 -0
  175. data/generators/client/client_generator.rb +53 -0
  176. data/generators/client/templates/core.js +19 -0
  177. data/generators/client/templates/english.lproj/body.css +0 -0
  178. data/generators/client/templates/english.lproj/body.rhtml +3 -0
  179. data/generators/client/templates/english.lproj/controls.css +0 -0
  180. data/generators/client/templates/english.lproj/strings.js +14 -0
  181. data/generators/client/templates/main.js +37 -0
  182. data/generators/controller/USAGE +16 -0
  183. data/generators/controller/controller_generator.rb +51 -0
  184. data/generators/controller/templates/controller.js +21 -0
  185. data/generators/controller/templates/test.rhtml +21 -0
  186. data/generators/framework/README +7 -0
  187. data/generators/framework/USAGE +12 -0
  188. data/generators/framework/framework_generator.rb +53 -0
  189. data/generators/framework/templates/core.js +20 -0
  190. data/generators/framework/templates/english.lproj/body.css +0 -0
  191. data/generators/framework/templates/english.lproj/body.rhtml +3 -0
  192. data/generators/framework/templates/english.lproj/controls.css +0 -0
  193. data/generators/framework/templates/english.lproj/strings.js +14 -0
  194. data/generators/language/USAGE +16 -0
  195. data/generators/language/language_generator.rb +47 -0
  196. data/generators/language/templates/strings.js +10 -0
  197. data/generators/model/USAGE +24 -0
  198. data/generators/model/model_generator.rb +55 -0
  199. data/generators/model/templates/fixture.js +11 -0
  200. data/generators/model/templates/model.js +20 -0
  201. data/generators/model/templates/test.rhtml +21 -0
  202. data/generators/test/USAGE +16 -0
  203. data/generators/test/templates/test.rhtml +21 -0
  204. data/generators/test/test_generator.rb +47 -0
  205. data/generators/view/USAGE +16 -0
  206. data/generators/view/templates/test.rhtml +21 -0
  207. data/generators/view/templates/view.js +20 -0
  208. data/generators/view/view_generator.rb +51 -0
  209. data/jsdoc/README.txt +119 -0
  210. data/jsdoc/app/DocFile.js +137 -0
  211. data/jsdoc/app/DocTag.js +110 -0
  212. data/jsdoc/app/Doclet.js +63 -0
  213. data/jsdoc/app/Dumper.js +143 -0
  214. data/jsdoc/app/JsDoc.js +103 -0
  215. data/jsdoc/app/JsHilite.js +45 -0
  216. data/jsdoc/app/JsIO.js +163 -0
  217. data/jsdoc/app/JsParse.js +385 -0
  218. data/jsdoc/app/JsPlate.js +130 -0
  219. data/jsdoc/app/JsTestrun.js +129 -0
  220. data/jsdoc/app/JsToke.js +564 -0
  221. data/jsdoc/app/Symbol.js +298 -0
  222. data/jsdoc/app/Transformer.js +14 -0
  223. data/jsdoc/app/Util.js +97 -0
  224. data/jsdoc/app/js.jar +0 -0
  225. data/jsdoc/app/run.js +144 -0
  226. data/jsdoc/plugins/min.js +316 -0
  227. data/jsdoc/plugins/strip.js +20 -0
  228. data/jsdoc/templates/sproutcore/class.tmpl +438 -0
  229. data/jsdoc/templates/sproutcore/default.css +241 -0
  230. data/jsdoc/templates/sproutcore/index.html +13 -0
  231. data/jsdoc/templates/sproutcore/index.tmpl +21 -0
  232. data/jsdoc/templates/sproutcore/prototype.js +4186 -0
  233. data/jsdoc/templates/sproutcore/publish.js +236 -0
  234. data/jsdoc/templates/sproutcore/splash.html +7 -0
  235. data/lib/sproutcore/build_tools/html_builder.rb +88 -0
  236. data/lib/sproutcore/build_tools/resource_builder.rb +194 -0
  237. data/lib/sproutcore/build_tools.rb +44 -0
  238. data/lib/sproutcore/bundle.rb +517 -0
  239. data/lib/sproutcore/bundle_manifest.rb +397 -0
  240. data/lib/sproutcore/generator_helper.rb +170 -0
  241. data/lib/sproutcore/helpers/capture_helper.rb +42 -0
  242. data/lib/sproutcore/helpers/static_helper.rb +80 -0
  243. data/lib/sproutcore/helpers/tag_helper.rb +110 -0
  244. data/lib/sproutcore/helpers/text_helper.rb +336 -0
  245. data/lib/sproutcore/helpers.rb +3 -0
  246. data/lib/sproutcore/jsdoc.rb +40 -0
  247. data/lib/sproutcore/jsmin.rb +247 -0
  248. data/lib/sproutcore/library.rb +258 -0
  249. data/lib/sproutcore/merb/bundle_controller.rb +179 -0
  250. data/lib/sproutcore/merb/router.rb +43 -0
  251. data/lib/sproutcore/merb.rb +27 -0
  252. data/lib/sproutcore/version.rb +9 -0
  253. data/lib/sproutcore/view_helpers/button_views.rb +302 -0
  254. data/lib/sproutcore/view_helpers/core_views.rb +284 -0
  255. data/lib/sproutcore/view_helpers/form_views.rb +258 -0
  256. data/lib/sproutcore/view_helpers/menu_views.rb +94 -0
  257. data/lib/sproutcore/view_helpers.rb +628 -0
  258. data/lib/sproutcore.rb +30 -0
  259. data/script/destroy +14 -0
  260. data/script/generate +14 -0
  261. data/script/txt2html +74 -0
  262. data/setup.rb +1585 -0
  263. data/spec/spec.opts +1 -0
  264. data/spec/spec_helper.rb +7 -0
  265. data/spec/sproutcore_spec.rb +11 -0
  266. data/tasks/deployment.rake +34 -0
  267. data/tasks/environment.rake +7 -0
  268. data/tasks/rspec.rake +21 -0
  269. data/tasks/website.rake +17 -0
  270. metadata +365 -0
@@ -0,0 +1,628 @@
1
+
2
+ module SproutCore
3
+
4
+ # The PageHelper is a singleton object that can render the Page javascript
5
+ # object.
6
+ module PageHelper
7
+
8
+ @@render_contexts = []
9
+ @@outlets = {}
10
+ @@outlet_names = []
11
+ @@styles = []
12
+ @@defines = {}
13
+
14
+ # This is the current helper state used when rendering the HTML. When
15
+ # a view helper is rendered, it may add itself as an outlet to the current
16
+ # helper state instead of to the page helper.
17
+ def self.current_render_context
18
+ @@render_contexts.last
19
+ end
20
+
21
+ def self.push_render_context(state)
22
+ @@render_contexts.push(state)
23
+ end
24
+
25
+ def self.pop_render_context
26
+ @@render_contexts.pop
27
+ end
28
+
29
+ # reset the page helper.
30
+ def self.reset!
31
+ @@render_contexts = []
32
+ @@outlets = {}
33
+ @@outlet_names = []
34
+ @@styles = []
35
+ @@defines = {}
36
+ end
37
+
38
+ def self.set_define(key, opts = {})
39
+ @@defines[key] = opts
40
+ end
41
+
42
+ def self.set_outlet(key,opts = {})
43
+ @@outlet_names << key
44
+ @@outlets[key] = opts
45
+ end
46
+
47
+ def self.add_styles(styles)
48
+ @@styles << styles
49
+ end
50
+
51
+ # renders the page object for the current page. If you include a prefix
52
+ # that will be used to create a separate page object. Otherwise, the
53
+ # object will live in the SC namespace.
54
+ #
55
+ # returns the text to insert into the HTML.
56
+ def self.render_js(prefix = 'SC')
57
+
58
+ outlets = []
59
+ @@outlet_names.each do | key |
60
+ opts = @@outlets[key]
61
+ outlet_path = opts[:outlet_path] || "##{opts[:id] || key}"
62
+ outlets << %{ #{key}: #{opts[:class] || 'SC.View'}.extend({\n #{ opts[:properties].gsub("\n","\n ") }\n }).outletFor("#{outlet_path}") }
63
+ end
64
+
65
+ # defines let you define classes to include in your UI.
66
+ ret = @@defines.map do | key, opts |
67
+ %{#{key} = #{opts[:class] || 'SC.View'}.extend({\n #{ opts[:properties] }\n});}
68
+ end
69
+ ret << %{#{prefix}.page = SC.Page.create({\n#{ outlets * ",\n\n" }\n}); }
70
+ return ret * "\n"
71
+
72
+ end
73
+
74
+ def self.render_css
75
+ if @@styles.size > 0
76
+ %(<style type="application/css">\n#{ @@styles * "\n" }\n</style>)
77
+ else
78
+ ''
79
+ end
80
+ end
81
+
82
+ end
83
+
84
+ module ViewHelperSupport
85
+
86
+ @@helpers = {}
87
+ def self.find_helper(helper_name)
88
+ @@helpers[helper_name.to_sym] || @@helpers[:view]
89
+ end
90
+
91
+ def self.set_helper(helper_name,obj)
92
+ @@helpers[helper_name.to_sym] = obj
93
+ end
94
+
95
+ class RenderContext
96
+
97
+ # options passed in from the view helper
98
+ attr_reader :item_id
99
+ attr_accessor :outlet
100
+ attr_accessor :define
101
+ attr_accessor :current_helper
102
+ attr_accessor :client_builder
103
+
104
+ def initialize(item_id, opts={}, client_builder = nil)
105
+ @_options = opts.dup
106
+ @bindings = (@_options[:bind] || {}).dup
107
+ @outlets = {}
108
+ @prototypes = {}
109
+ @item_id = item_id
110
+ @outlet = opts[:outlet]
111
+ @define = opts[:define]
112
+ @client_builder = client_builder
113
+ @outlet_names = []
114
+
115
+ @attributes = (@_options[:attributes] || {}).dup
116
+
117
+ @_properties = {}
118
+ if @_options[:properties]
119
+ @_options[:properties].each do | key, value |
120
+ @_properties[key.to_s.camelize(:lower)] = prepare_for_javascript(value)
121
+ end
122
+ end
123
+ end
124
+
125
+ def options
126
+ @_options
127
+ end
128
+
129
+ def set_outlet(key,opts = {})
130
+ @outlet_names << key
131
+ @outlets[key] = opts
132
+ end
133
+
134
+ def prepare_bindings
135
+ @bindings.each do | k,v |
136
+ key = k.to_s.camelize(:lower) + 'Binding'
137
+ @_properties[key] = v.include?('(') ? v : prepare_for_javascript(v)
138
+ end
139
+ end
140
+
141
+ def prepare_outlets
142
+ return if @outlets.size == 0
143
+ outlets = []
144
+ @outlet_names.each do | key |
145
+ opts = @outlets[key]
146
+ outlet_key = key.to_s.camelize(:lower)
147
+ outlets << outlet_key unless opts[:lazy]
148
+
149
+ outlet_path = opts[:outlet_path] || ".#{opts[:id] || key }?"
150
+ str = %{#{opts[:class] || 'SC.View'}.extend({\n#{ opts[:properties] }\n}).outletFor("#{outlet_path}")}
151
+ @_properties[outlet_key] = str
152
+ end
153
+
154
+ @_properties['outlets'] = outlets
155
+ end
156
+
157
+ def parent_helper(opts = {})
158
+ if @current_helper && @current_helper.parent_helper
159
+ @_options.merge! opts
160
+ @current_helper.parent_helper.prepare_context(self)
161
+ end
162
+ end
163
+
164
+ ### RENDER METHODS
165
+ def render_content
166
+ @attributes[:id] = @item_id if @item_id && !(@outlet || @define)
167
+
168
+ old_client_builder = self.client_builder
169
+ self.client_builder = @content_render_client_builder unless @content_render_client_builder.nil?
170
+ ret = _do_render(@content_render)
171
+ self.client_builder = old_client_builder
172
+ return ret
173
+ end
174
+
175
+ def render_view
176
+ prepare_bindings
177
+ prepare_outlets
178
+ _do_render(@view_render)
179
+ end
180
+
181
+ def view_class
182
+ @view_class
183
+ end
184
+
185
+ def render_styles
186
+ _do_render(@styles_render)
187
+ end
188
+
189
+ ### BASIC CONFIG METHODS
190
+ # These are called in the helper's prepare_context method.
191
+
192
+ # This method must be called to configure the view.
193
+ def view(view_class,text = nil, &block)
194
+ @view_class = view_class
195
+ @view_render = text || block if (text || block)
196
+ end
197
+
198
+ # this method must be called to configure the HTML.
199
+ # also captures the client builder in use at the time it is called.
200
+ def content(text = nil, &block)
201
+ @content_render_client_builder = self.client_builder
202
+ @content_render = text || block if (text || block)
203
+ end
204
+
205
+ # this method may be called to add CSS styles
206
+ def styles(text = nil, &block)
207
+ @styles_render = text || block if (text || block)
208
+ end
209
+
210
+ def static_url(resource_name, opts = {})
211
+ opts[:language] ||= @language
212
+ entry = @client_builder.find_resource_entry(resource_name, opts)
213
+ entry.nil? ? '' : entry.url
214
+ end
215
+
216
+ def blank_url
217
+ static_url('blank.gif')
218
+ end
219
+
220
+ ### HTML HELPER METHODS
221
+
222
+ # This will extract the specified value and put it into an ivar you can
223
+ # access later during rendering. For example:
224
+ #
225
+ # var :label, 'Default label'
226
+ #
227
+ # will now be accessible in your code via @label
228
+ #
229
+ # Parameters:
230
+ # option_key: (req) the option to map.
231
+ # default_value: (opt) if passed, this will be used as the default value
232
+ # if the option is not passed in.
233
+ #
234
+ # :key => (opt) the name of the resulting ivar. defaults to the option
235
+ # key.
236
+ #
237
+ # :optional => (opt) if true, then the attribute will not be included if
238
+ # it is not explicitly passed in the options. if no default value is
239
+ # specified, then this will default to true, otherwise defaults to
240
+ # false.
241
+ #
242
+ # :constant => (opt) if true, then any passed in options will be ignored
243
+ # for this key and the default you specify will be used instead.
244
+ # Defaults to false
245
+ #
246
+ # you may also pass a block that will be used to compute the value at
247
+ # render time. Expect a single parameter which is the initial value.
248
+ #
249
+ def var(option_key, default_value=:__UNDEFINED__, opts={}, &block)
250
+ ret = _pair(option_key, default_value, opts, &block)
251
+ return if ret[2] # ignore
252
+ instance_variable_set("@#{ret[0]}".to_sym, ret[1])
253
+ ret[1]
254
+ end
255
+
256
+ # returns the standard attributes for the HTML. This will automatically
257
+ # include the item id. You can also declare added attributes using the
258
+ # attribute param.
259
+ def attributes
260
+ final_class_names = css_class_names
261
+ final_styles = css_styles
262
+
263
+ ret = @attributes.map do |key,value|
264
+
265
+ # if the css class or css style is declared, replace the current
266
+ # set coming from the view_helper
267
+ if key.to_sym == :class && value
268
+ final_class_names = value
269
+ nil
270
+ elsif key.to_sym == :style && value
271
+ final_styles = value
272
+ nil
273
+ else
274
+ value ? %(#{key}="#{value}") : nil
275
+ end
276
+ end
277
+
278
+ # add in class names
279
+ final_class_names = [final_class_names].flatten
280
+ final_class_names << @item_id
281
+ final_class_names.compact!
282
+ unless final_class_names.empty?
283
+ ret << %(class="#{final_class_names.uniq * ' '}")
284
+ end
285
+
286
+ # add in styles
287
+ unless final_styles.nil?
288
+ final_styles = [final_styles].flatten
289
+ final_styles.compact!
290
+ ret << %(style="#{final_styles.uniq * ' '}") unless final_styles.empty?
291
+ end
292
+
293
+ ret.compact * ' '
294
+ end
295
+
296
+ # Your view helper can add text to by appended to the styles attribute
297
+ # by adding to this array.
298
+ def css_styles
299
+ @css_styles ||= []
300
+ end
301
+
302
+ def css_styles=(new_ary)
303
+ @css_styles = new_ary
304
+ end
305
+
306
+ # Your view helper can add css classes to be appended to the classes
307
+ # attribute by adding to this array.
308
+ def css_class_names
309
+ @css_class_names ||= []
310
+ end
311
+
312
+ def css_class_names=(new_ary)
313
+ @css_class_names = new_ary
314
+ end
315
+
316
+ # This does the standard open tag with the default tag and attributes. Usually
317
+ # you can use this.
318
+ def open_tag
319
+ %{<#{@tag} #{attributes}>}
320
+ end
321
+ alias_method :ot, :open_tag
322
+
323
+ def close_tag
324
+ %{</#{@tag}>}
325
+ end
326
+ alias_method :ct, :close_tag
327
+
328
+ # Call this method in your view helper definition to map an option to
329
+ # an attribute. This attribute can then be rendered with attributes.
330
+ # This method takes the same options as var
331
+ def attribute(option_key, default_value=:__UNDEFINED__, opts={}, &block)
332
+ ret = _pair(option_key, default_value, opts, &block)
333
+ return if ret[2] # ignore
334
+ @attributes[ret[0]] = ret[1]
335
+ end
336
+
337
+ # returns all the JS properties specified by the property method.
338
+ def properties
339
+ keys = @_properties.keys
340
+ ret = []
341
+
342
+ # example element, if there is one
343
+ if @define
344
+ @_properties['emptyElement'] = %($sel("#resources? .#{@item_id}:1:1"))
345
+ ret << _partial_properties(['emptyElement'])
346
+ end
347
+
348
+ # outlets first
349
+ if keys.include?('outlets')
350
+ outlets = @_properties['outlets']
351
+ @_properties['outlets'] = '["' + (outlets * '","') + '"]'
352
+ ret << _partial_properties(['outlets'])
353
+ ret << _partial_properties(outlets,",\n\n")
354
+ keys.reject! { |k| outlets.include?(k) || (k == 'outlets') }
355
+ end
356
+
357
+ bindings = keys.reject { |k| !k.match(/Binding$/) }
358
+ if bindings.size > 0
359
+ ret << _partial_properties(bindings)
360
+ keys.reject! { |k| bindings.include?(k) }
361
+ end
362
+
363
+ if keys.size > 0
364
+ ret << _partial_properties(keys)
365
+ end
366
+
367
+ ret = ret * ",\n\n"
368
+ ' ' + ret.gsub("\n","\n ")
369
+ end
370
+
371
+ def _partial_properties(keys,join = ",\n")
372
+ ret = keys.map do |key|
373
+ value = @_properties[key]
374
+ next if value.nil?
375
+ %(#{key}: #{value})
376
+ end
377
+ ret * join
378
+ end
379
+
380
+ # Call this method to make a binding available or to set a default
381
+ # binding. You can use this for properties you want to allow a
382
+ # binding for but don't want to take as a fully property.
383
+ def bind(option_key, default_value=:__UNDEFINED__, opts={})
384
+ key, v, ignore = _pair(option_key, default_value, opts, false)
385
+
386
+ # always look for the option key in the bindings passed by the user.
387
+ # if present, this should override whatever we set
388
+ if found = @bindings[option_key.to_sym] || @bindings[option_key.to_s]
389
+ v = found
390
+ ignore = false
391
+ @bindings.delete option_key.to_sym
392
+ @bindings.delete option_key.to_s
393
+ end
394
+
395
+ # finally, set the binding value.
396
+ unless ignore
397
+ v = v.include?('(') ? v : prepare_for_javascript(v)
398
+ @_properties["#{key.camelize(:lower)}Binding"] = v
399
+ end
400
+
401
+ end
402
+
403
+ # Call this method in your view helper to specify a property you want
404
+ # added to the javascript declaration. This methos take the same
405
+ # options as var. Note that normally the type of value returned here
406
+ # will be marshalled into the proper type for JavaScript. If you
407
+ # provide a block to compute the property, however, the value will be
408
+ # inserted directly.
409
+ def property(option_key, default_value=:__UNDEFINED__, opts={}, &block)
410
+ ret = _pair(option_key, default_value, opts, &block)
411
+ key = ret[0].camelize(:lower)
412
+
413
+ unless ret[2] # ignore
414
+ value = ret[1]
415
+ value = prepare_for_javascript(value) unless block_given?
416
+ @_properties[key] = value
417
+ end
418
+
419
+ # also look for a matching binding and set it needed.
420
+ if v = @bindings[option_key.to_sym] || @bindings[option_key.to_s]
421
+ v = v.include?('(') ? v : prepare_for_javascript(v)
422
+ @_properties["#{key}Binding"] = v
423
+ @bindings.delete option_key.to_sym
424
+ @bindings.delete option_key.to_s
425
+ end
426
+
427
+ end
428
+
429
+ def prepare_for_javascript(value)
430
+ return 'null' if value.nil?
431
+ case value
432
+ when String:
433
+ %("#{ value.gsub('"','\"').gsub("\n",'\n') }")
434
+ when Symbol:
435
+ %("#{ value.to_s.gsub('"','\"').gsub("\n",'\n') }")
436
+ when Array:
437
+ "[#{value.map { |v| prepare_for_javascript(v) } * ','}]"
438
+ when Hash:
439
+ items = value.map do |k,v|
440
+ [prepare_for_javascript(k),prepare_for_javascript(v)] * ': '
441
+ end
442
+ "{ #{items * ', '} }"
443
+ when FalseClass:
444
+ "false"
445
+ when TrueClass:
446
+ "true"
447
+ else
448
+ value.to_s
449
+ end
450
+ end
451
+
452
+ ### INTERNAL SUPPORT
453
+ private
454
+
455
+ def _do_render(render_item)
456
+ if render_item.nil?
457
+ ''
458
+ elsif render_item.instance_of?(Proc)
459
+ render_item.call
460
+ else
461
+ render_item
462
+ end
463
+ end
464
+
465
+ def _pair(option_key, default_value, opts, look_for_key = true)
466
+ if default_value.instance_of?(Hash)
467
+ opts = default_value
468
+ default_value = :__UNDEFINED__
469
+ end
470
+
471
+ # get the attribute value. possibly return if no value and optional.
472
+ optional = opts.has_key?(:optional) ? opts[:optional] : (default_value == :__UNDEFINED__)
473
+ if opts[:constant] == true
474
+ value = default_value
475
+ elsif look_for_key && options.has_key?(option_key.to_sym)
476
+ value = options[option_key.to_sym]
477
+ elsif look_for_key && options.has_key?(option_key.to_s)
478
+ value = options[option_key.to_s]
479
+ else
480
+ value = default_value
481
+ end
482
+
483
+
484
+ if (optional==true) && value == :__UNDEFINED__
485
+ ignore = true
486
+ value = nil
487
+ else
488
+ ignore = false
489
+ value = nil if value == :__UNDEFINED__
490
+ value = yield(value) if block_given?
491
+ end
492
+
493
+ attr_key = (opts[:key] || option_key).to_s
494
+ [attr_key, value, ignore]
495
+ end
496
+
497
+ end
498
+
499
+ class HelperState
500
+ attr_reader :name
501
+ attr_reader :parent_helper
502
+ attr_reader :prepare_block
503
+
504
+ def initialize(helper_name, opts={}, &block)
505
+ @name = helper_name
506
+ @prepare_block = block
507
+ @parent_helper = SproutCore::ViewHelperSupport.find_helper(opts[:wraps] || opts[:extends] || :view)
508
+ @extends = opts[:wraps].nil?
509
+ end
510
+
511
+ def prepare_context(render_context)
512
+ # automatically call parent helper if extends was used.
513
+ if parent_helper && @extends
514
+ parent_helper.prepare_context(render_context)
515
+ else
516
+ render_context.current_helper = self
517
+ end
518
+
519
+ render_context.instance_eval &prepare_block
520
+ render_context.current_helper = nil
521
+ end
522
+
523
+ end
524
+
525
+ @@tick = 0
526
+ def self._gen_id(type="id")
527
+ @@tick += 1
528
+ return "#{type}_#{(Time.now.to_i + @@tick)}"
529
+ end
530
+
531
+ extend SproutCore::Helpers::CaptureHelper
532
+ extend SproutCore::Helpers::TextHelper
533
+
534
+ # :outlet => define if you want this to be used as an outlet.
535
+ # :prototype => define if you want this to be used as a prototype.
536
+ def self.render_view(view_helper_id, item_id, opts={}, client_builder=nil, &block)
537
+
538
+ # item_id is optional. If it is not a symbol or string, then generate
539
+ # an item_id
540
+ if item_id.instance_of?(Hash)
541
+ opts = item_id; item_id = nil
542
+ end
543
+ item_id = _gen_id if item_id.nil?
544
+
545
+ # create the new render context and set it.
546
+ client_builder = opts[:client] if opts[:client]
547
+ rc = RenderContext.new(item_id, opts, client_builder)
548
+ hs = find_helper(view_helper_id)
549
+
550
+ # render the inner_html using the block, if one is given.
551
+ SproutCore::PageHelper.push_render_context(rc)
552
+ rc.options[:inner_html] = capture(&block) if block_given?
553
+
554
+ # now, use the helper state to prepare the render context. This will
555
+ # extract the properties from the options and setup the render procs.
556
+ hs.prepare_context(rc) unless hs.nil?
557
+
558
+ # how have the render context render the HTML content. This may also
559
+ # make changes to the other items to render.
560
+ ret = rc.render_content
561
+
562
+ SproutCore::PageHelper.pop_render_context
563
+
564
+ # get the JS. Save as an outlet or in the page.
565
+ cur_rc = SproutCore::PageHelper.current_render_context
566
+ view_class = opts[:view] || rc.view_class
567
+ unless view_class.nil?
568
+ view_settings = { :id => item_id, :class => view_class, :properties => rc.render_view, :lazy => opts[:lazy], :outlet_path => opts[:outlet_path] }
569
+
570
+ # if an outlet item is passed, then register this as an outlet.
571
+ outlet = opts[:outlet] || rc.outlet
572
+ define = opts[:define]
573
+ if outlet && cur_rc
574
+ outlet = item_id if outlet == true
575
+ cur_rc.set_outlet(outlet, view_settings)
576
+
577
+ elsif define
578
+ define = define.to_s.camelize.gsub('::','.')
579
+ SproutCore::PageHelper.set_define(define, view_settings)
580
+
581
+ # otherwise, add it to the page-wide setting.
582
+ else
583
+ prop = item_id.to_s.camelize(:lower)
584
+ SproutCore::PageHelper.set_outlet(prop, view_settings)
585
+ end
586
+ end
587
+
588
+ # get the styles, if any
589
+ styles = rc.render_styles
590
+ SproutCore::PageHelper.add_styles(styles) if styles && styles.size > 0
591
+
592
+ # done. return the generated HTML
593
+ concat(ret,block) if block_given?
594
+ return ret
595
+ end
596
+
597
+ end
598
+
599
+ module ViewHelpers
600
+
601
+ def self.view_helper(helper_name,opts={},&prepare_block)
602
+ hs = SproutCore::ViewHelperSupport::HelperState.new(helper_name,opts,&prepare_block)
603
+ SproutCore::ViewHelperSupport.set_helper(helper_name, hs)
604
+
605
+ ## install the helper method
606
+ SproutCore::ViewHelpers.class_eval %{
607
+ def #{helper_name}(item_id=nil, opts={}, &block)
608
+ SproutCore::ViewHelperSupport.render_view(:#{helper_name}, item_id, opts, bundle, &block)
609
+ end }
610
+
611
+ SproutCore::ViewHelpers.class_eval %{
612
+ def self.#{helper_name}(item_id=nil, opts={}, &block)
613
+ SproutCore::ViewHelperSupport.render_view(:#{helper_name}, item_id, opts, bundle, &block)
614
+ end }
615
+
616
+ end
617
+
618
+ def render_page_views
619
+ ret = %(<script type="text/javascript">\n#{SproutCore::PageHelper.render_js}\n</script>)
620
+ SproutCore::PageHelper.reset!
621
+ return ret
622
+ end
623
+
624
+ end
625
+
626
+ end
627
+
628
+ Dir.glob(File.join(File.dirname(__FILE__),'view_helpers','**','*.rb')).each { |x| require x }
data/lib/sproutcore.rb ADDED
@@ -0,0 +1,30 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require 'rubygems'
4
+ require 'activesupport'
5
+
6
+ module SproutCore
7
+
8
+ # Returns a library for the current working directory. This is useful when
9
+ # working on the command line
10
+ def self.library
11
+ Library.library_for(Dir.pwd)
12
+ end
13
+
14
+ def self.library_for(path, opts={})
15
+ Library.library_for(path, opts)
16
+ end
17
+
18
+ def self.logger; @logger ||= Logger.new(STDOUT); end
19
+ def self.logger=(new_logger); @logger = new_logger; end
20
+
21
+ end
22
+
23
+ # Force load the code files. Others may be loaded only as required
24
+ %w(library bundle bundle_manifest jsdoc jsmin version).each do |fname|
25
+ require "sproutcore/#{fname}"
26
+ end
27
+
28
+ SC= SproutCore
29
+
30
+
data/script/destroy ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
data/script/generate ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)