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,517 @@
1
+ require 'sproutcore/build_tools'
2
+
3
+ module SproutCore
4
+
5
+ # A bundle can map a directory of source files to an output format optimized
6
+ # for delivery on the web. It can also return the URLs to use for a particular client.
7
+ # A Bundle cannot actually build resources for you, but it works in concert with the
8
+ # ResourceBuilder to help you with that.
9
+ #
10
+ # When you create a bundle, you must pass the name of the client and the library the bundle
11
+ # belongs to. The library is used to generate default paths for most resources and to find
12
+ # other bundles.
13
+ #
14
+ # You must provide the following properties to every build:
15
+ #
16
+ # bundle_name:: A name used to identify the client for required URLs, etc.
17
+ # library:: The root URL of the library holding the client
18
+ #
19
+ # The following properties are also required, but have defaults you can rely use:
20
+ #
21
+ # bundle_type:: :framework|:client (default :client)
22
+ # required_bundles:: Names of required frameworks. (default: none)
23
+ # stylesheet_libs:: URLs to requires CSS not managed by the build system. (default: none)
24
+ # javascript_libs:: URLS to requires JavaScript notn managed by the build system (def:non)
25
+ #
26
+ # The following properties are required for the build process but can be generated
27
+ # automatically using other properties you specify:
28
+ #
29
+ # source_root:: The directory containing the source files
30
+ # default: :library_root/pluralize(:build_type)/:bundle_name
31
+ #
32
+ # build_root:: The directory that should contain the built files.
33
+ # default: :public_root/:url_prefix/:bundle_name
34
+ #
35
+ # url_root:: The url that can be used to reach the built resources
36
+ # default: /:url_prefix/:bundle_name
37
+ #
38
+ # index_root:: The root url that can be used to reach retrieve the index.html.
39
+ # default: /:index_prefix/:bundle_name
40
+ #
41
+ # If you do not want to specify all of these options, you can provide the following defaults
42
+ # and the rest will be inferred:
43
+ #
44
+ # library_root:: The root URL for the library. This is computed from the library if
45
+ # you pass one.
46
+ #
47
+ # public_root:: The root directory accessible to the web browser.
48
+ # default: :library_root/public
49
+ #
50
+ # url_prefix:: The prefix to put in front of all resource requests.
51
+ # default: static
52
+ #
53
+ # index_prefix:: The prefix to put in front of all index.html request.
54
+ # default: ''
55
+ #
56
+ # preferred_language:: The default language to use for this bundle. Defaults to :en
57
+ #
58
+ # build_mode:: Determines whether the JS & CSS resources should be combined or
59
+ # linked directly
60
+ #
61
+ # layout: Path to the layout resource. This should be of the form
62
+ # bundle_name:relative_path/to/client. Default: sproutcore:lib/index.html
63
+ #
64
+ class Bundle
65
+
66
+ LONG_LANGUAGE_MAP = { :english => :en, :french => :fr, :german => :de, :japanese => :jp, :spanish => :es, :italian => :it }
67
+ SHORT_LANGUAGE_MAP = { :en => :english, :fr => :french, :de => :german, :jp => :japanese, :es => :spanish, :it => :italian }
68
+
69
+ # The default build mode for bundles. This should be set once before you start using
70
+ # bundles. You can override this when you create a specific bundle, but that should not
71
+ # be the typical behavior
72
+ def self.build_mode; @build_mode || :development; end
73
+
74
+ def self.build_mode=(new_mode); @build_mode = new_mode; end
75
+
76
+
77
+ attr_reader :bundle_name, :bundle_type, :required_bundles, :preferred_language
78
+ attr_reader :javascript_libs, :stylesheet_libs
79
+ attr_reader :library, :public_root, :url_prefix, :index_prefix
80
+ attr_reader :source_root, :build_root, :url_root, :index_root
81
+ attr_reader :build_mode, :layout
82
+
83
+ def library_root
84
+ @library_root ||= library.nil? ? nil : library.root_path
85
+ end
86
+
87
+ # ==== Returns
88
+ # All bundles required directly or indirectly by this bundles. These are returned in
89
+ # their proper load order.
90
+ #
91
+ def all_required_bundles(seen=nil)
92
+ seen ||= Set.new
93
+ seen << self
94
+
95
+ ret = []
96
+ # before you load me, load my bundles
97
+ required_bundles.each do |name|
98
+ b = library.bundle_for(name)
99
+ next if seen.include?(b)
100
+ raise "Cannot locate required bundle '#{name}' for #{bundle_name}" if b.nil?
101
+ ret += b.all_required_bundles(seen)
102
+ end
103
+ ret << self
104
+ return ret
105
+ end
106
+
107
+ # ==== Returns
108
+ # The computed path to the layout rhtml.
109
+ def layout_path
110
+ return @layout_path unless @layout_path.nil?
111
+ bundle_name, entry_name = layout.split(':')
112
+ entry_name, bundle_name = bundle_name, entry_name if entry_name.nil?
113
+
114
+ # Get the bundle. If bundle_name is nil, self
115
+ layout_bundle = bundle_name.nil? ? self : library.bundle_for(bundle_name.to_sym)
116
+ return nil if layout_bundle.nil?
117
+
118
+ # Now look for an entry with that name. This will use the primary language
119
+ # since we do not support localized layouts.
120
+ entry = layout_bundle.entry_for(entry_name, :hidden => :include)
121
+
122
+ # If the entry was not found, then we don't have a layout. Oh no!
123
+ if entry.nil?
124
+ raise "Could not find layout named #{entry_name} in bundle #{layout_bundle.bundle_name}!"
125
+ end
126
+
127
+ # The return value if the source_path of the entry.
128
+ @layout_path = entry.source_path
129
+ end
130
+
131
+ # Returns the root URL to the current library.
132
+ def initialize(bundle_name, opts ={})
133
+
134
+ # You must provide the following properties to every build:
135
+ # bundle_name:: A name used to identify the client for required URLs, etc.
136
+ @bundle_name = bundle_name.to_sym
137
+
138
+ # The following are not required by the build system, but they can be used to
139
+ # automatically construct the key paths listed below. Often times defaults will
140
+ # do the right thing
141
+ #
142
+ # library:: The root URL of the library holding the client
143
+ @library = opts[:library]
144
+ @library_root = opts[:library_root]
145
+ raise "Bundles must belong to a library or have a library_root" if library_root.nil?
146
+
147
+ # The following properties are also required, but have defaults you can rely use:
148
+ # bundle_type:: :framework|:client (default :client)
149
+ @bundle_type = (opts[:bundle_type] || opts[:type] || :client).to_sym
150
+
151
+ # dependencies:: Names of required frameworks. (default: :sproutapp)
152
+ @required_bundles = opts[:required_bundles] || opts[:required] || []
153
+
154
+ # preferred_language:: The default language to use for this bundle.
155
+ @preferred_language = (opts[:preferred_language] || opts[:language] || :en).to_sym
156
+
157
+ # javacript_libs:: External required libraries.
158
+ @javascript_libs = opts[:javascript_libs] || opts[:js_libs] || []
159
+
160
+ # stylesheet_libs:: External required stylesheet library
161
+ @stylesheet_libs = opts[:stylesheet_libs] || opts[:css_libs] || []
162
+
163
+ # public_root:: The root directory accessible to the web browser.
164
+ @public_root = normalize_path(opts[:public_root] || 'public')
165
+ #
166
+ # url_prefix:: The prefix to put in front of all resource requests.
167
+ @url_prefix = opts[:url_prefix] || opts[:resources_at] || opts[:at] || 'static'
168
+ #
169
+ # index_prefix:: The prefix to put in front of all index.html request.
170
+ @index_prefix = opts[:index_prefix] || opts[:index_at] || ''
171
+
172
+ # The following properties are required for the build process but can be generated
173
+ # automatically using other properties you specify:
174
+ # source_root:: The directory containing the source files
175
+ @source_root = normalize_path(opts[:source_root] || File.join(bundle_type.to_s.pluralize, bundle_name.to_s))
176
+
177
+ # build_root:: The directory that should contain the built files.
178
+ @build_root = normalize_path(opts[:build_root] || File.join(public_root, url_prefix.to_s, bundle_name.to_s))
179
+
180
+ # url_root:: The url that can be used to reach the built resources
181
+ @url_root = opts[:url_root] || ['', (url_prefix.nil? || url_prefix.size==0) ? nil : url_prefix, bundle_name.to_s].compact.join('/')
182
+
183
+ # index_root:: The root url that can be used to reach retrieve the index.html.
184
+ @index_root = opts[:index_root] || ['',(index_prefix.nil? || index_prefix.size==0) ? nil : index_prefix, bundle_name.to_s].compact.join('/')
185
+
186
+ # build_mode:: The build mode to use when combining resources.
187
+ @build_mode = opts[:build_mode] || SproutCore::Bundle.build_mode
188
+
189
+ # layout: Path to the layout resource. This should be of the form
190
+ @layout = opts[:layout] || 'sproutcore:lib/index.rhtml'
191
+
192
+ reload!
193
+ end
194
+
195
+ ######################################################
196
+ ## RETRIEVING RESOURCES
197
+ ##
198
+
199
+ # ==== Returns
200
+ # The array of stylesheet entries sorted in load order.
201
+ def sorted_stylesheet_entries(opts = {})
202
+ opts[:language] ||= preferred_language
203
+ entries = entries_for(:stylesheet, opts)
204
+ BuildTools::ResourceBuilder.sort_entries_by_load_order(entries, opts[:language], self)
205
+ end
206
+
207
+ # ==== Returns
208
+ # The array of javascript entries sorted in load order.
209
+ def sorted_javascript_entries(opts = {})
210
+ opts[:language] ||= preferred_language
211
+ entries = entries_for(:javascript, opts)
212
+ BuildTools::JavaScriptResourceBuilder.sort_entries_by_load_order(entries, opts[:language], self)
213
+ end
214
+
215
+ # This method returns the manifest entries for resources of the specified type.
216
+ #
217
+ # ==== Params
218
+ # type:: must be one of :javascript, :stylesheet, :resource, :html, :fixture, :test
219
+ #
220
+ # ==== Options
221
+ # language:: The language to use. Defaults to preferred language.
222
+ # hidden:: Can be :none|:include|:only
223
+ #
224
+ def entries_for(resource_type, opts={})
225
+ with_hidden = opts[:hidden] || :none
226
+ manifest = manifest_for(opts[:language] || preferred_language)
227
+ ret = manifest.entries_for(resource_type)
228
+
229
+ case with_hidden
230
+ when :none
231
+ ret = ret.reject { |x| x.hidden }
232
+ when :only
233
+ ret = ret.reject { |x| !x.hidden }
234
+ end
235
+ return ret
236
+ end
237
+
238
+ # This method returns the manifest entry for a resource with the specified name.
239
+ #
240
+ # ==== Params
241
+ # name: The name of the entry.
242
+ #
243
+ # ==== Options
244
+ # language:: The language to use. Defaults to preferred language
245
+ # hidden:: Can be :none|:include|:only
246
+ #
247
+ def entry_for(resource_name, opts={})
248
+ with_hidden = opts[:hidden] || :none
249
+ manifest = manifest_for(opts[:language] || preferred_language)
250
+ ret = manifest.entry_for(resource_name)
251
+
252
+ case with_hidden
253
+ when :none
254
+ ret = nil if ret && ret.hidden?
255
+ when :only
256
+ ret = nil unless ret && ret.hidden?
257
+ end
258
+ return ret
259
+ end
260
+
261
+ # Returns the entry for the specified URL. This will extract the language from the URL.
262
+ #
263
+ # ==== Params
264
+ # url<String>:: The url
265
+ #
266
+ # ==== Options
267
+ # hidden:: Use :include,:none,:only to control hidden options
268
+ # language:: Explicitly include the language. Leave this out to autodetect from URL.
269
+ #
270
+ def entry_for_url(url, opts={})
271
+ # get the language
272
+ opts[:language] ||= url.match(/^#{url_root}\/([^\/]+)\//).to_a[1] || preferred_language
273
+ entries(opts).each do |entry|
274
+ return entry if entry.url == url
275
+ end
276
+ return nil # not found!
277
+ end
278
+
279
+ # Helper method. This will normalize a URL into one that can map directly to an
280
+ # entry in the bundle. If the URL is of a format that cannot be converted, returns nil.
281
+ #
282
+ # ==== Params
283
+ # url<String>:: The URL
284
+ #
285
+ def normalize_url(url)
286
+
287
+ # Get the default index.
288
+ if (url == index_root)
289
+ url = [index_root, preferred_language.to_s, 'index.html'].join('/')
290
+
291
+ # Requests to url_root/lang should have index.html appended to them
292
+ elsif /^#{index_root}\/[^\/\.]+$/ =~ url
293
+ url << '/index.html'
294
+ end
295
+
296
+ return url
297
+ end
298
+
299
+ # Returns all of the entries for the manifest.
300
+ #
301
+ # ==== Options
302
+ # language:: The language to use. Defaults to preferred language
303
+ # hidden:: Can be :none|:include|:only
304
+ #
305
+ def entries(opts ={})
306
+ with_hidden = opts[:hidden] || :none
307
+ manifest = manifest_for(opts[:language] || preferred_language)
308
+ ret = manifest.entries
309
+
310
+ case with_hidden
311
+ when :none
312
+ ret = ret.reject { |x| x.hidden }
313
+ when :only
314
+ ret = ret.reject { |x| !x.hidden }
315
+ end
316
+ return ret
317
+ end
318
+
319
+ # Does a deep search of the entries, looking for a resource that is a close
320
+ # match of the specified resource. This does not need to match the filename
321
+ # exactly and it can omit the extension
322
+ def find_resource_entry(filename, opts={})
323
+ extname = File.extname(filename)
324
+ rootname = filename.gsub(/#{extname}$/,'')
325
+ entry_extname = entry_rootname = nil
326
+
327
+ ret = entries_for(:resource, opts.merge(:hidden => :none)).reject do |entry|
328
+ entry_extname = File.extname(entry.filename)
329
+ entry_rootname = entry.filename.gsub(/#{entry_extname}$/,'')
330
+
331
+ ext_match = (extname.nil? || extname.size == 0) || (entry_extname == extname)
332
+ !(ext_match && (/#{rootname}$/ =~ entry_rootname))
333
+ end
334
+
335
+ ret.first
336
+ end
337
+
338
+ # Builds the passed array of entries. If the entry is already built, then this
339
+ # method does nothing unless force => true
340
+ #
341
+ # The exact action taken by this method varies by resource type. Some resources
342
+ # will simply be copied. Others will actually be compiled.
343
+ #
344
+ # ==== Params
345
+ #
346
+ # entries:: The entries to build
347
+ #
348
+ # ==== Options
349
+ #
350
+ # force:: If true then the entry will be built again, even if it already exists.
351
+ # hidden:: Set to :none, :include, or :only
352
+ #
353
+ def build_entries(entries, opts={})
354
+
355
+ with_hidden = opts[:hidden] || :none
356
+
357
+ # First, start an "already seen" set.
358
+ created_seen = @seen.nil?
359
+ @seen ||= Set.new
360
+
361
+ # Now, process the entries, adding them to the seen set.
362
+ entries.each do |entry|
363
+
364
+ # skip if hidden, already seen, or already built (unless forced)
365
+ if entry.hidden? && with_hidden == :none
366
+ SC.logger.debug("~ Skipping Entry: #{entry.filename} because it is hidden") and next
367
+ end
368
+
369
+ if !entry.hidden? && with_hidden == :only
370
+ SC.logger.debug("~ Skipping Entry: #{entry.filename} because it is not hidden") and next
371
+ end
372
+
373
+ # Nothing interesting to log here.
374
+ next if @seen.include?(entry)
375
+ @seen << entry
376
+
377
+ # Do not build if file exists and source paths are not newer.
378
+ if !opts[:force] && File.exists?(entry.build_path)
379
+ source_mtime = entry.source_path_mtime
380
+ if source_mtime && (File.mtime(entry.build_path) >= source_mtime)
381
+ SC.logger.debug("~ Skipping Entry: #{entry.filename} because it has not changed") and next
382
+ end
383
+ end
384
+
385
+
386
+ # OK, looks like this is ready to be built.
387
+ if entry.use_symlink?
388
+ SC.logger.debug("~ Creating Symlink: #{entry.filename}")
389
+ BuildTools.build_symlink(entry, self)
390
+ else
391
+ SC.logger.debug("~ Building #{entry.type.to_s.capitalize}: #{entry.filename}")
392
+ BuildTools.send("build_#{entry.type}".to_sym, entry, self)
393
+ end
394
+ end
395
+
396
+ # Clean up the seen set when we exit.
397
+ @seen = nil if created_seen
398
+ end
399
+
400
+ # Easy singular form of build_entries(). Take same parameters except for a single entry
401
+ # instead of an array.
402
+ def build_entry(entry, opts={})
403
+ build_entries([entry], opts)
404
+ end
405
+
406
+ # Invoked by build tools when they build a dependent entry. This will add the entry
407
+ # to the list of seen entries during a build so that it will not be rebuilt.
408
+ def did_build_entry(entry)
409
+ @seen << entry unless @seen.nil?
410
+ end
411
+
412
+ # This will perform a complete build for the named language
413
+ def build_language(language)
414
+ SC.logger.info("~ Language: #{language}")
415
+ build_entries(entries(:language => language))
416
+ SC.logger.debug("~ Done.\n")
417
+ end
418
+
419
+ # This will perform a complete build for all languages that have a matching lproj.
420
+ # You can also pass in an array of languages you would like to build
421
+ def build(*languages)
422
+
423
+ # Get the installed languages (and the preferred language, just in case)
424
+ languages = languages.flatten
425
+ languages = installed_languages if languages.nil? || languages.size == 0
426
+ languages.uniq!
427
+
428
+ SC.logger.debug("~ Build Mode: #{build_mode}")
429
+ SC.logger.debug("~ Source Root: #{source_root}")
430
+ SC.logger.debug("~ Build Root: #{build_root}")
431
+
432
+ languages.uniq.each { |lang| build_language(lang) }
433
+
434
+ # After build is complete, try to copy the index.html file of the preferred language
435
+ # to the build_root
436
+ index_entry = entry_for('index.html', :language => preferred_language)
437
+ if index_entry && File.exists?(index_entry.build_path)
438
+ FileUtils.mkdir_p(build_root)
439
+ FileUtils.cp_r(index_entry.build_path, File.join(build_root,'index.html'))
440
+ end
441
+ end
442
+
443
+ ######################################################
444
+ ## MANIFESTS
445
+ ##
446
+
447
+ # Invoke this method whenever you think the bundle's contents on disk might have changed
448
+ # this will throw away any cached information in bundle. This is generally a cheap
449
+ # operation so it is OK to call it often, though it will be less performant overall.
450
+ def reload!
451
+ @manifests = {}
452
+ end
453
+
454
+ # Returns the bundle manifest for the specified language. The manifest will be created
455
+ # if it does not yet exist.
456
+ def manifest_for(language)
457
+ @manifests[language.to_sym] ||= BundleManifest.new(self, language.to_sym)
458
+ end
459
+
460
+ # ==== Returns
461
+ # Languages installed in the source directory
462
+ #
463
+ def installed_languages
464
+ ret = Dir.glob(File.join(source_root,'*.lproj')).map do |x|
465
+ x.match(/([^\/]+)\.lproj$/).to_a[1]
466
+ end
467
+ ret << preferred_language
468
+ ret.compact.map { |x| LONG_LANGUAGE_MAP[x.to_sym] || x.to_sym }.uniq
469
+ end
470
+
471
+ # Finds the actual lproj directory (in the source) for the language code. If the named
472
+ # language does not exist, returns the lproj for the preferred language.
473
+ def lproj_for(language)
474
+
475
+ # try language as passed in.
476
+ ret = "#{language}.lproj"
477
+ return ret if File.exists?(File.join(source_root,ret))
478
+
479
+ # failed, try to map to long language
480
+ if long_language = SHORT_LANGUAGE_MAP[language.to_sym]
481
+ ret = "#{long_language}.lproj"
482
+ return ret if File.exists?(File.join(source_root,ret))
483
+ end
484
+
485
+ # failed, try to map to short language
486
+ if short_language = LONG_LANGUAGE_MAP[language.to_sym]
487
+ ret = "#{short_language}.lproj"
488
+ return ret if File.exists?(File.join(source_root,ret))
489
+ end
490
+
491
+ # failed, return using preferred_language unless this is the preferred language
492
+ ret = (language != preferred_language) ? lproj_for(preferred_language) : nil
493
+ return ret unless ret.nil?
494
+
495
+ # Super-ultra massive fail. Possible that no localized resources exist at all.
496
+ # Return english.lproj and hope for the best
497
+ return 'english.lproj'
498
+ end
499
+
500
+ # Used by the bundle manifest. Only true if bundle_type is client
501
+ def can_have_html?
502
+ return bundle_type == :client
503
+ end
504
+
505
+ protected
506
+
507
+ # Converts the named path to a fully qualified path name using the library root, if it
508
+ # does not begin with a slash
509
+ def normalize_path(path)
510
+ (path[0] == '/'[0]) ? path : File.join(library_root, path)
511
+ end
512
+
513
+ end
514
+
515
+ end
516
+
517
+