sproutcore 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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
+