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,211 @@
1
+ // ========================================================================
2
+ // SproutCore
3
+ // copyright 2006-2007 Sprout Systems, Inc.
4
+ // ========================================================================
5
+
6
+ require('Core') ;
7
+ require('foundation/date');
8
+ require('foundation/string') ;
9
+
10
+ /** @namespace SC.Benchmark
11
+
12
+ This bit of meta-programming magic can install a benchmark handler on any
13
+ object method. When a benchmark is installed, the time required to execute
14
+ the method will be printed to the console log everytime the method is
15
+ called.
16
+
17
+ This class can be used to implement benchmarking. To use this object, just
18
+ call start() with a key name and end() with a keyname. The benchmark will
19
+ be logged. If you set verbose = true, then benchmark will log everytime it
20
+ saves a bench. Otherwise, it just keeps stats. You can get the stats by
21
+ calling report().
22
+
23
+ Benchmark does not require anything other than the date.js class. It also
24
+ does not rely on SC.Object so that you can benchmark code in that area as
25
+ well.
26
+
27
+ */
28
+ SC.Benchmark = {
29
+
30
+ /**
31
+ If true, then benchmarks will be logged to the console as they are
32
+ recorded.
33
+
34
+ @type bool
35
+ */
36
+ verbose: NO,
37
+
38
+ /**
39
+ If false, benchmarking will be disabled. You might want to disable this
40
+ during production to maximize performance.
41
+
42
+ @type bool
43
+ */
44
+ enabled: YES,
45
+
46
+ /**
47
+ This hash stores collected stats. It contains key value pairs. The value
48
+ will be a hash with the following properties:
49
+
50
+ * * *runs*: the number of times this stat has run
51
+ * * *amt*: the total time consumed by this (divide by runs to get avg)
52
+ * * *name*: an optional longer name you assigned to the stat key. Set this using name().
53
+ * * *_starts*: this array is used internally.
54
+ */
55
+ stats: {},
56
+
57
+ /**
58
+ Call this method at the start of whatever you want to collect.
59
+ if topLevelOnly is passed, then recursive calls to the start will be
60
+ ignored and only the top level call will be benchmarked.
61
+ */
62
+ start: function(key, topLevelOnly) {
63
+ if (!this.enabled) return ;
64
+ var stat = this._statFor(key) ;
65
+
66
+ if (topLevelOnly && stat._starts.length > 0) {
67
+ stat._starts.push('ignore') ;
68
+ } else {
69
+ stat._starts.push(Date.now()) ;
70
+ }
71
+ },
72
+
73
+ /**
74
+ Call this method at the end of whatever you want to collect. This will
75
+ save the collected benchmark.
76
+ */
77
+ end: function(key) {
78
+ if (!this.enabled) return ;
79
+ var stat = this._statFor(key) ;
80
+ var start = stat._starts.pop() ;
81
+ if (!start) {
82
+ console.log('WARNING: SC.Benchmark "%@" ended without a matching start. No information was saved.'.fmt(key));
83
+ return ;
84
+ }
85
+
86
+ // top level only.
87
+ if (start == 'ignore') return ;
88
+
89
+ stat.amt += Date.now() - start ;
90
+ stat.runs++ ;
91
+
92
+ if (this.verbose) this.log(key) ;
93
+ },
94
+
95
+ /**
96
+ This is a simple way to benchmark a function. The function will be
97
+ run with the name you provide the number of times you indicate. Only the
98
+ function is a required param.
99
+ */
100
+ bench: function(func, key, reps) {
101
+ if (!key) key = "bench%@".fmt(this._benchCount++) ;
102
+ if (!reps) reps = 1 ;
103
+ var ret ;
104
+
105
+ while(--reps >= 0) {
106
+ SC.Benchmark.start(key) ;
107
+ ret = func();
108
+ SC.Benchmark.end(key) ;
109
+ }
110
+
111
+ return ret ;
112
+ },
113
+
114
+ /**
115
+ This bit of metaprogramming magic install a wrapper around a method and
116
+ benchmark it whenever it is run.
117
+ */
118
+ install: function(object,method, topLevelOnly) {
119
+
120
+ // vae the original method.
121
+ var __func = object['b__' + method] = object[method] ;
122
+
123
+ // replace with this helper.
124
+ object[method] = function() {
125
+ var key = '%@(%@)'.fmt(method, $A(arguments).join(', ')) ;
126
+ SC.Benchmark.start(key, topLevelOnly) ;
127
+ var ret = __func.apply(this, arguments) ;
128
+ SC.Benchmark.end(key) ;
129
+ return ret ;
130
+ } ;
131
+ },
132
+
133
+ /**
134
+ Restore the original method, deactivating the benchmark.
135
+
136
+ @param {object} object the object to change
137
+ @param {string} method the method name as a string.
138
+
139
+ */
140
+ restore: function(object,method) {
141
+ object[method] = object['b__' + method] ;
142
+ },
143
+
144
+ /**
145
+ This method will return a string containing a report of the stats
146
+ collected so far. If you pass a key, only the stats for that key will
147
+ be returned. Otherwise, all keys will be used.
148
+ */
149
+ report: function(key) {
150
+ if (key) return this._genReport(key) ;
151
+ var ret = [] ;
152
+ for(var key in this.stats) {
153
+ if (!this.stats.hasOwnProperty(key)) continue ;
154
+ ret.push(this._genReport(key)) ;
155
+ }
156
+ return ret.join("\n") ;
157
+ },
158
+
159
+ /**
160
+ This method is just like report() except that it will log the results to
161
+ the console.
162
+ */
163
+ log: function(key) {
164
+ console.log(this.report(key)) ;
165
+ },
166
+
167
+ /**
168
+ This will activate profiling if you have Firebug installed. Otherwise
169
+ does nothing.
170
+ */
171
+ startProfile: function(key) {
172
+ if (!this.enabled) return ;
173
+ if (console && console.profile) console.profile(key) ;
174
+ },
175
+
176
+ endProfile: function(key) {
177
+ if (!this.enabled) return ;
178
+ if (console && console.profileEnd) console.profileEnd(key) ;
179
+ },
180
+
181
+ // PRIVATE METHODS
182
+
183
+ _genReport: function(key) {
184
+ var stat = this._statFor(key) ;
185
+ var avg = (stat.runs > 0) ? (Math.floor(stat.amt * 1000 / stat.runs) / 1000) : 0 ;
186
+
187
+ return 'BENCH %@ msec: %@ (%@x)'.fmt(avg, (stat.name || key), stat.runs) ;
188
+ },
189
+
190
+ // @private
191
+ // returns a stats hash for the named key. If the hash does not exist yet,
192
+ // creates it.
193
+ _statFor: function(key) {
194
+ var ret = this.stats[key] ;
195
+ if (!ret) ret = this.stats[key] = {
196
+ runs: 0, amt: 0, name: key, _starts: []
197
+ };
198
+ return ret ;
199
+ },
200
+
201
+ reset: function() { this.stats = {} ; },
202
+
203
+ // This is private, but it is used in some places, so we are keeping this for
204
+ // compatibility.
205
+ _bench: function(func, name) {
206
+ SC.Benchmark.bench(func, name, 1) ;
207
+ },
208
+
209
+ _benchCount: 1
210
+
211
+ } ;
@@ -0,0 +1,384 @@
1
+ // ========================================================================
2
+ // SproutCore
3
+ // copyright 2006-2007 Sprout Systems, Inc.
4
+ // ========================================================================
5
+
6
+ require('foundation/object') ;
7
+
8
+ // A relay simply allows you to connect the properties of two objects.
9
+ // Whenever the value of one property changes, the value of the other
10
+ // property will change also. This allows you to design your system more
11
+ // modular.
12
+ //
13
+ // You can also configure a relay to be one way so only the from -> to path
14
+ // changes are permitted. We will also allow transforms and placeholder values
15
+ // eventually.
16
+
17
+ SC.Binding = SC.Object.extend({
18
+
19
+ // ......................................
20
+ // PROPERTIES
21
+ // Configure these on setup. They should be either tuples or property
22
+ // paths. The relay will try to observe both of them.
23
+ from: '', to: '',
24
+
25
+ // set to true if you don't want changes to -> from to relay.
26
+ oneWay: false,
27
+
28
+ // set this to some value if you want a placeholder when the source
29
+ // value is an empty array or null (if you don't also set a nullPlaceholder)
30
+ emptyPlaceholder: null,
31
+
32
+ // set this to some value if you want a placeholder value when the source
33
+ // value is null. If you don't set this but you do set an emptyPlaceholder
34
+ // then the emptyPlaceholder will be used instead.
35
+ nullPlaceholder: null,
36
+
37
+ // set this to some value if you want a placeholder when the value is
38
+ // an array with multiple values. If you set this, arrays with single
39
+ // values will be converted to indivdual objects. If this is set ot null,
40
+ // multiple values will be allowed to pass untouched.
41
+ multiplePlaceholder: null,
42
+
43
+ // set this to a function if you want a transform performed on an input
44
+ // value. This transform is performed both ways and before placeholder
45
+ // values are applied.
46
+ transform: null,
47
+
48
+ // ......................................
49
+ // METHODS
50
+
51
+ // This will connect the relay so that properties can be forwarded. If
52
+ // the items are already connected, this has no effect.
53
+ connect: function() {
54
+ if (this._connected) return ;
55
+ var funcs = this._boundObservers() ;
56
+
57
+ SC.Observers.addObserver(this.get('from'),funcs.from) ;
58
+ SC.Observers.addObserver(this.get('to'),funcs.to) ;
59
+ this._connected = true ;
60
+ return this ;
61
+ },
62
+
63
+ // this will disconnect the relay from its observing. Call this if you
64
+ // want to destroy the relay. This returns null so you can use it in
65
+ // assignment.
66
+ disconnect: function() {
67
+ if (!this._connected) return ;
68
+ var funcs = this._boundObservers() ;
69
+ SC.Observers.removeObserver(this.get('from'),funcs.from) ;
70
+ SC.Observers.removeObserver(this.get('to'),funcs.to) ;
71
+ this._connected = false ;
72
+ return this ;
73
+ },
74
+
75
+ // simulate a from -> to relay.
76
+ relay: function() {
77
+ var tuple = SC.Object.tupleForPropertyPath(this.get('from')) ;
78
+ if (tuple) tuple = this._walkTuple(tuple) ;
79
+ if (tuple) this._fromObserver(tuple[0],tuple[1],tuple[0].get(tuple[1]));
80
+ },
81
+
82
+ // ......................................
83
+ // INTERNAL METHODS
84
+
85
+ init: function() {
86
+ arguments.callee.base.call(this) ;
87
+ this.connect() ;
88
+ },
89
+
90
+ _boundObservers: function() {
91
+ var ret = this._boundObserverFuncs ;
92
+ if (!ret) {
93
+ this._boundObserverFuncs = ret = {
94
+ from: this._fromObserver.bind(this),
95
+ to: this._toObserver.bind(this)
96
+ } ;
97
+ }
98
+ return ret ;
99
+ },
100
+
101
+ _fromObserver: function(target,key,value, propertyRevision) {
102
+ // to avoid echos, check against last toProperty revision.
103
+ if (propertyRevision <= this._lastFromPropertyRevision) return ;
104
+ this._lastFromPropertyRevision = propertyRevision ;
105
+
106
+ // no need to forward values if they haven't actually changed.
107
+ if (!this._didChange(this._lastFromValue,value)) return ;
108
+ this._lastFromValue = value ;
109
+
110
+ // try to get the to object.
111
+ var tuple = SC.Object.tupleForPropertyPath(this.get('to')) ;
112
+ if (tuple) tuple = this._walkTuple(tuple) ;
113
+ if (tuple) {
114
+
115
+ // transform the value
116
+ var transformFunc = this.transform ;
117
+ if (transformFunc) value = transformFunc('to', key, value) ;
118
+ this._lastToValue = value ;
119
+
120
+ // apply placeholder settings.
121
+ var pholder ;
122
+
123
+ // handle empty placeholder.
124
+ if (value && (value == []) && (pholder = this.get('emptyPlaceholder'))) {
125
+ value = pholder ;
126
+
127
+ // handle multiple value placeholder
128
+ } else if (value && (value instanceof Array) && (pholder = this.get('multiplePlaceholder'))) {
129
+ value = (value.length == 1) ? value[0] : pholder ;
130
+ }
131
+
132
+ // now handle null placeholder. This is used if one of these other
133
+ // transforms results in a null value.
134
+ if ((value == null) && (pholder = this.get('nullPlaceholder') || this.get('emptyPlaceholder'))) {
135
+ value = pholder ;
136
+ }
137
+
138
+ tuple[0].set(tuple[1],value) ;
139
+ this._lastToPropertyRevision = tuple[0].propertyRevision ;
140
+
141
+ }
142
+ },
143
+
144
+ _toObserver: function(target,key,value, propertyRevision) {
145
+ // try to get the to object.
146
+ if (this.get('oneWay')) return ; // block.
147
+
148
+ // to avoid echos, check against last toProperty revision.
149
+ if (propertyRevision <= this._lastToPropertyRevision) return ;
150
+ this._lastToPropertyRevision = propertyRevision ;
151
+
152
+ // no need to forward values if they haven't actually changed.
153
+ if (!this._didChange(this._lastToValue,value)) return ;
154
+ this._lastToValue = value ;
155
+
156
+ var tuple = SC.Object.tupleForPropertyPath(this.get('from')) ;
157
+ if (tuple) tuple = this._walkTuple(tuple) ;
158
+ if (tuple) {
159
+ // transform the value
160
+ var transformFunc = this.get('transform') ;
161
+ if (transformFunc) value = transformFunc('from', key, value) ;
162
+ this._lastFromValue = value ;
163
+
164
+ // send along to the 'from' source.
165
+ var result = tuple[0].set(tuple[1],value) ;
166
+ if (result) this._lastFromPropertyRevision = result.propertyRevision ;
167
+
168
+ // now that it has been set, the FROM object might not allow some
169
+ // changes. If that is the case, then we need to set this back on the
170
+ // sender.
171
+ if (result != value) {
172
+ target.set(key,result) ;
173
+ this._lastToPropertyRevision = target.propertyRevision ;
174
+ }
175
+
176
+ }
177
+ },
178
+
179
+ _didChange: function(lastValue, newValue) {
180
+ if (newValue && lastValue) {
181
+ if (typeof(newValue) == typeof(lastValue)) {
182
+ if (lastValue == newValue) return false ;
183
+ }
184
+ } else if (((newValue === null) && (lastValue === null)) || ((newValue === undefined) && (lastValue === undefined))) return false ;
185
+ return true ;
186
+ },
187
+
188
+ _lastToPropertyRevision: 0,
189
+ _lastFromPropertyRevision: 0,
190
+
191
+ _walkTuple: function(tuple) {
192
+ var parts = tuple[1].split('.') ;
193
+ if (parts.length > 1) {
194
+ tuple = tuple.slice() ; // duplicate to avoid an error.
195
+ var obj = tuple[0] ;
196
+ tuple[1] = parts.pop() ;
197
+ for(var loc=0;(obj && (loc<parts.length));loc++) {
198
+ obj = obj.get(parts[loc]) ;
199
+ }
200
+ tuple[0] = obj ;
201
+ }
202
+ return (tuple[0] && tuple[1]) ? tuple : null ;
203
+ }
204
+
205
+ }) ;
206
+
207
+ SC.Binding.mixin({
208
+ // Constant values for placeholders
209
+ MULTIPLE_PLACEHOLDER: '@@MULT@@',
210
+ NULL_PLACEHOLDER: '@@NULL@@',
211
+ EMPTY_PLACEHOLDER: '@@EMPTY@@'
212
+ }) ;
213
+
214
+ // This is the basic method you can use to create a builder function for
215
+ // different types of relays. The first param is either a string or a set
216
+ // of properties. The second param is a set of properties. Both are opt.
217
+ SC.Binding.From = function(from,opts) {
218
+ if (!opts) opts = {} ;
219
+ if ((typeof(from) == "string") || (from instanceof Array)) {
220
+ opts.from = from ;
221
+ } else Object.extend(opts,from) ;
222
+ var ret = SC.Binding.extend(opts) ;
223
+ return ret ;
224
+ } ;
225
+
226
+ SC.Binding.build = function(tr) {
227
+ return function(from) {
228
+ return SC.Binding.From(from,{ transform: tr }) ;
229
+ } ;
230
+ } ;
231
+
232
+ SC.Binding.NoChange = SC.Binding.From;
233
+
234
+ // This binding will return errors as null.
235
+ SC.Binding.NoError = SC.Binding.build(function(dir, key, value) {
236
+ return ($type(value) == T_ERROR) ? null : value ;
237
+ }) ;
238
+
239
+ SC.Binding.NoError.ext = function(bindFunc) {
240
+ return function(d,k,v) {
241
+ return ($type(value) == T_ERROR) ? null : bindFunc(d,k,v) ;
242
+ } ;
243
+ } ;
244
+
245
+ // This binding only allows single, null, or error values. If an array is
246
+ // passed, it will be mapped like so:
247
+ //
248
+ // [] => null
249
+ // [x] => x
250
+ // [x,x,x] => MULTIPLE_PLACEHOLDER
251
+ //
252
+ SC.Binding.Single = SC.Binding.build(function(d,k,v) {
253
+ if ($type(v) == T_ARRAY) {
254
+ switch(v.length) {
255
+ case 0:
256
+ v = null ;
257
+ break ;
258
+ case 1:
259
+ v = v[0] ;
260
+ break ;
261
+ default:
262
+ v = SC.Binding.MULTIPLE_PLACEHOLDER ;
263
+ }
264
+ }
265
+ return v;
266
+ });
267
+
268
+ // This binding works just like Single except if you pass a multiple value
269
+ // it will be converted to NULL.
270
+ SC.Binding.SingleNull = SC.Binding.build(function(d,k,v) {
271
+ if ($type(v) == T_ARRAY) {
272
+ switch(v.length) {
273
+ case 0:
274
+ v = null ;
275
+ break ;
276
+ case 1:
277
+ v = v[0] ;
278
+ break ;
279
+ default:
280
+ v = null ;
281
+ }
282
+ }
283
+ return v;
284
+ });
285
+
286
+ // NoError versions.
287
+ SC.Binding.SingleNoError = SC.Binding.NoError.ext(SC.Binding.Single);
288
+ SC.Binding.SingleNullNoError = SC.Binding.NoError.ext(SC.Binding.SingleNull);
289
+
290
+ // This requires the value to be a multiple. null => [], x => [x]
291
+ SC.Binding.Multiple = SC.Binding.build(function(d,k,v) {
292
+ var t = $type(v) ;
293
+ if (t != T_ARRAY) {
294
+ if (t == null) {
295
+ v = [] ;
296
+ } else if (t != T_ERROR) {
297
+ v = [v] ;
298
+ }
299
+ }
300
+ return v ;
301
+ }) ;
302
+
303
+ SC.Binding.MultipleNoError = SC.Binding.NoError.ext(SC.Binding.Multiple);
304
+
305
+ // Converts value to a bool. true if: not null, not empty array, not 0, '',
306
+ // etc.
307
+ SC.Binding.Bool = SC.Binding.build(function(d,k,v) {
308
+ return ($type(v) == T_ARRAY) ? (t.length > 0) : !!v ;
309
+ }) ;
310
+
311
+ // Converts value to a bool, but its only true if not null
312
+ SC.Binding.NotNull = SC.Binding.build(function(d,k,v) {
313
+ return (v != null) ;
314
+ }) ;
315
+
316
+ // Converts inverse of bool.
317
+ SC.Binding.Not = SC.Binding.build(function(d,k,v) {
318
+ return !(($type(v) == T_ARRAY) ? (t.length > 0) : !!v) ;
319
+ }) ;
320
+
321
+ // Converts value to a bool, but its only true if not null
322
+ SC.Binding.IsNull = SC.Binding.build(function(d,k,v) {
323
+ return (v == null) ;
324
+ }) ;
325
+
326
+ // No Error versions.
327
+ SC.Binding.BoolNoError = SC.Binding.NoError.ext(SC.Binding.Bool) ;
328
+ SC.Binding.NotNullNoError = SC.Binding.NoError.ext(SC.Binding.NotNull) ;
329
+ SC.Binding.NotNoError = SC.Binding.NoError.ext(SC.Binding.Not) ;
330
+ SC.Binding.IsNullNoError = SC.Binding.NoError.ext(SC.Binding.IsNull) ;
331
+
332
+ // .........................................................
333
+ // DEPRECATED
334
+
335
+ // This relay forces all values to be multiple values
336
+ SC.Binding.Multiple = function(from) {
337
+ return SC.Binding.From(from,{
338
+ transform: function(dir,key,value) {
339
+ return (value) ? (SC.isArray(value) ? value : [value]) : value;
340
+ }
341
+ }) ;
342
+ } ;
343
+
344
+ // This relay forces all values to be multiple values, null values are not
345
+ // allowed.
346
+ SC.Binding.MultipleNotEmpty = function(from) {
347
+ return SC.Binding.From(from,{
348
+ transform: function(dir,key,value) {
349
+ return (value) ? (SC.isArray(value) ? value : [value]) : [];
350
+ }
351
+ }) ;
352
+ } ;
353
+
354
+ // This relay allows single values and no null/empty values.
355
+ SC.Binding.SingleNotEmpty = function(from) {
356
+ return SC.Binding.From(from,{
357
+ multiplePlaceholder: SC.Binding.MULTIPLE_PLACEHOLDER,
358
+ emptyPlaceholder: SC.Binding.EMPTY_PLACEHOLDER,
359
+ nullPlaceholder: SC.Binding.NULL_PLACEHOLDER
360
+ }) ;
361
+ } ;
362
+
363
+ // This relay allows any values, but only one way flow.
364
+ SC.Binding.OneWay = function(from) {
365
+ return SC.Binding.From(from, { oneWay: true }) ;
366
+ } ;
367
+
368
+ // This relay forces the value to be true or false. Empty and null values
369
+ // represent false.
370
+ SC.Binding.Flag = function(from) {
371
+ return SC.Binding.From(from, {
372
+ transform: function(dir,key,value) {
373
+ return (value && (value instanceof Array)) ? (value.length == 0) : !!value ;
374
+ }
375
+ }) ;
376
+ } ;
377
+
378
+ SC.Binding.OneWayFlag = function(from) {
379
+ var ret = SC.Binding.Flag(from) ;
380
+ ret.oneWay = true ;
381
+ return ret ;
382
+ } ;
383
+
384
+