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,451 @@
1
+ // ========================================================================
2
+ // SproutCore
3
+ // copyright 2006-2007 Sprout Systems, Inc.
4
+ // ========================================================================
5
+
6
+ /**
7
+ @namespace Implements Key-Value Observing
8
+
9
+ Key-Value Observing is one of the fundamental ways that models, controllers
10
+ and views communicate with each other in a SproutCore application. Any
11
+ object that has this module applied to it can be used in KVO-operations.
12
+
13
+ This module is applied automatically to all objects that inherit from
14
+ SC.Object, which includes most objects bundled with the SproutCore
15
+ framework. You will not generally apply this module to classes yourself,
16
+ but you will use the features provided by this module frequently, so it is
17
+ important to understand how to use it.
18
+
19
+ h2. About Key Value Observing
20
+
21
+ Key-Value-Observing (KVO) simply allows one object to observe changes to a
22
+ property on another object. This can replace much of the "glue code" that
23
+ you often have to write to make parts of your application work together.
24
+
25
+ Using KVO is easy. All you have to do is use the KVO methods to get and set
26
+ properties. Instead of writing:
27
+
28
+ {{{
29
+ var aName = contact.firstName ;
30
+ contact.firstName = 'Charles' ;
31
+ }}}
32
+
33
+ you use:
34
+
35
+ {{{
36
+ var aName = contact.get('firstName') ;
37
+ contact.set('firstName', 'Charles') ;
38
+ }}}
39
+
40
+ get() and set() work just like the normal "dot operators" provided by
41
+ JavaScript but they provide you with much more power, including not only
42
+ observing but computed properties as well.
43
+
44
+ INCOMPLETE
45
+
46
+ */
47
+ SC.Observable = {
48
+
49
+ /**
50
+ Manually add a new binding to an object. This is the same as doing
51
+ the more familiar propertyBinding: 'property.path' approach.
52
+ */
53
+ bind: function(toKey, fromPropertyPath) {
54
+
55
+ var r = SC.idt.active ;
56
+
57
+ var binding ;
58
+ var props = { to: [this, toKey] } ;
59
+
60
+ // for strings try to do default relay
61
+ var pathType = $type(fromPropertyPath) ;
62
+ if (pathType == T_STRING || pathType == T_ARRAY) {
63
+ binding = this[toKey + 'BindingDefault'] || SC.Binding.From;
64
+ binding = binding(fromPropertyPath) ;
65
+ } else binding = fromPropertyPath ;
66
+
67
+ // check the 'from' value of the relay. if it starts w/
68
+ // '.' || '*' then convert to a local tuple.
69
+ var relayFrom = binding.prototype.from ;
70
+ if ($type(relayFrom) == T_STRING) switch(relayFrom.slice(0,1)) {
71
+ case '*':
72
+ case '.':
73
+ relayFrom = [this,relayFrom.slice(1,relayFrom.length)];
74
+ }
75
+
76
+ if(r) bt = new Date().getTime();
77
+
78
+ binding = binding.create(props, { from: relayFrom }) ;
79
+ this.bindings.push(binding) ;
80
+
81
+ if (r) SC.idt.b1_t += (new Date().getTime()) - bt ;
82
+
83
+ return binding ;
84
+ },
85
+
86
+ /**
87
+ didChangeFor makes it easy for you to verify that you haven't seen any
88
+ changed values. You need to use this if your method observes multiple
89
+ properties. To use this, call it like this:
90
+
91
+ if (this.didChangeFor('render','height','width')) {
92
+ // DO SOMETHING HERE IF CHANGED.
93
+ }
94
+ */
95
+ didChangeFor: function(context) {
96
+ var keys = $A(arguments) ;
97
+ context = keys.shift() ;
98
+
99
+ var ret = false ;
100
+ if (!this._didChangeCache) this._didChangeCache = {} ;
101
+ if (!this._didChangeRevisionCache) this._didChangeRevisionCache = {};
102
+
103
+ var seen = this._didChangeCache[context] || {} ;
104
+ var seenRevisions = this._didChangeRevisionCache[context] || {} ;
105
+ var loc = keys.length ;
106
+ var rev = this._kvo().revision ;
107
+
108
+ while(--loc >= 0) {
109
+ var key = keys[loc] ;
110
+ if (seenRevisions[key] != rev) {
111
+ var val = this.get(key) ;
112
+ if (seen[key] !== val) ret = true ;
113
+ seen[key] = val ;
114
+ }
115
+ seenRevisions[key] = rev ;
116
+ }
117
+
118
+ this._didChangeCache[context] = seen ;
119
+ this._didChangeRevisionCache[context] = seenRevisions ;
120
+ return ret ;
121
+ },
122
+
123
+ // ..........................................
124
+ // PROPERTIES
125
+ //
126
+ // Use these methods to get/set properties. This will handle observing
127
+ // notifications as well as allowing you to define functions that can be
128
+ // used as properties.
129
+
130
+ /**
131
+ Use this to get a property value instead of obj.key.
132
+ */
133
+ get: function(key) {
134
+ var ret = this[key] ;
135
+ if (ret === undefined) {
136
+ return this.unknownProperty(key) ;
137
+ } else if (ret && (ret instanceof Function) && ret.isProperty) {
138
+ return ret.call(this,key) ;
139
+ } else return ret ;
140
+ },
141
+
142
+ /**
143
+ use this to set a property value instead of obj.key = value.
144
+ */
145
+ set: function(key, value) {
146
+ var func = this[key] ;
147
+ var ret = value ;
148
+
149
+ this.propertyWillChange(key) ;
150
+
151
+ // set the value.
152
+ if (func && (func instanceof Function) && (func.isProperty)) {
153
+ ret = func.call(this,key,value) ;
154
+ } else if (func === undefined) {
155
+ ret = this.unknownProperty(key,value) ;
156
+ } else ret = this[key] = value ;
157
+
158
+ // post out notifications.
159
+ this.propertyDidChange(key, ret) ;
160
+ return ret ;
161
+ },
162
+
163
+ /**
164
+ use this to automatically navigate a property path.
165
+ */
166
+ getPath: function(path) {
167
+ var tuple = SC.Object.tupleForPropertyPath(path, this) ;
168
+ if (tuple[0] == null) return null ;
169
+ return tuple[0].get(tuple[1]) ;
170
+ },
171
+
172
+ setPath: function(path, value) {
173
+ var tuple = SC.Object.tupleForPropertyPath(path, this) ;
174
+ if (tuple[0] == null) return null ;
175
+ return tuple[0].set(tuple[1], value) ;
176
+ },
177
+
178
+ /**
179
+ Increments the value of a property.
180
+ */
181
+ incrementProperty: function(key) {
182
+ return this.set(key,(this.get(key) || 0)+1);
183
+ },
184
+
185
+ /**
186
+ decrements a property
187
+ */
188
+ decrementProperty: function(key) {
189
+ return this.set(key,(this.get(key) || 0) - 1 ) ;
190
+ },
191
+
192
+ /**
193
+ inverts a property. Property should be a bool.
194
+ */
195
+ toggleProperty: function(key,value,alt) {
196
+ if (value === undefined) value = true ;
197
+ if (alt == undefined) alt = false ;
198
+ value = (this.get(key) == value) ? alt : value ;
199
+ this.set(key,value);
200
+ },
201
+
202
+ /**
203
+ This is a generic property handler. If you define it, it will be called
204
+ when the named property is not yet set in the object. The default does
205
+ nothing.
206
+ */
207
+ unknownProperty: function(key,value) {
208
+ if (!(value === undefined)) { this[key] = value; }
209
+ return value ;
210
+ },
211
+
212
+ /**
213
+ Override to receive generic observation notices.
214
+ */
215
+ propertyObserver: function(observer,target,key,value) {},
216
+
217
+ /**
218
+ You can wrap property changes with these methods to cause notifications
219
+ to be delivered only after groups are closed.
220
+ */
221
+ beginPropertyChanges: function() {
222
+ this._kvo().changes++ ;
223
+ },
224
+
225
+ endPropertyChanges: function() {
226
+ var kvo = this._kvo() ; kvo.changes--;
227
+ if (kvo.changes <= 0) this._notifyPropertyObservers() ;
228
+ },
229
+
230
+ /**
231
+ If you are not going to use get/set, you can notify observers this way.
232
+ */
233
+ propertyWillChange: function(key) {
234
+ this._kvo().changes++ ;
235
+ },
236
+
237
+ propertyDidChange: function(key,value) {
238
+ this._kvo().changed[key] = value ;
239
+ var kvo = this._kvo() ; kvo.changes--; kvo.revision++ ;
240
+ if (kvo.changes <= 0) this._notifyPropertyObservers() ;
241
+ },
242
+
243
+ /**
244
+ This may be a simpler way to notify of changes if you are making a major
245
+ update or don't know exactly which properties have changed. This ignores
246
+ property gorups.
247
+ */
248
+ allPropertiesDidChange: function() {
249
+ this._notifyPropertyObservers(true) ;
250
+ },
251
+
252
+ /**
253
+ Add an observer
254
+ */
255
+ addObserver: function(key,func) {
256
+ var kvo = this._kvo() ;
257
+
258
+ // if the key contains a '.', then create a chained observer.
259
+ key = key.toString() ;
260
+ var parts = key.split('.') ;
261
+ if (parts.length > 1) {
262
+ var co = SC._ChainObserver.createChain(this,parts,func) ;
263
+ co.masterFunc = func ;
264
+ var chainObservers = kvo.chainObservers[key] || [] ;
265
+ chainObservers.push(co) ;
266
+ kvo.chainObservers[key] = chainObservers ;
267
+
268
+ // otherwise, bind as a normal property
269
+ } else {
270
+ var observers = kvo.observers[key] = (kvo.observers[key] || []) ;
271
+ var found = false; var loc = observers.length;
272
+ while(!found && --loc >= 0) found = (observers[loc] == func) ;
273
+ if (!found) observers.push(func) ;
274
+ }
275
+
276
+ },
277
+
278
+ addProbe: function(key) { this.addObserver(key,logChange); },
279
+ removeProbe: function(key) { this.removeObserver(key,logChange); },
280
+
281
+ /**
282
+ This method will listen for the observed value to change one time and
283
+ then will remove itself. You can also set an optional timeout that
284
+ will cause the function to be triggered (and the observer removed) after
285
+ a set amount of time even if the value never changes. The function
286
+ can expect an extra parameter, 'didTimeout', set to true.
287
+
288
+ The returned value is the function actually set as the observer. You
289
+ can manually remove this observer by calling the cancel() method on it.
290
+ */
291
+ observeOnce: function(key, func, timeout) {
292
+ var timeoutObject = null ;
293
+ var target = this ;
294
+ var handler = function(theTarget,theKey,theValue,didTimeout) {
295
+ func(theTarget,theKey,theValue,didTimeout) ;
296
+ target.removeObserver(key,handler) ;
297
+ if (timeoutObject) { clearTimeout(timeoutObject); }
298
+ } ;
299
+
300
+ target.addObserver(key,handler) ;
301
+ if (timeout) timeoutObject = setTimeout(function() {
302
+ handler(target,key,target.get(key),true) ;
303
+ }, timeout) ;
304
+
305
+ handler.cancel = function() { target.removeObserver(key,handler); } ;
306
+ return handler ;
307
+ },
308
+
309
+ removeObserver: function(key,func) {
310
+ var kvo = this._kvo() ;
311
+
312
+ // if the key contains a '.', this is a chained observer.
313
+ key = key.toString() ;
314
+ var parts = key.split('.') ;
315
+ if (parts.length > 1) {
316
+ var chainObservers = kvo.chainObserver[key] || [] ;
317
+ var newObservers = [] ;
318
+ chainObservers.each(function(co) {
319
+ if (co.masterFunc != func) newObservers.push(co) ;
320
+ }) ;
321
+ kvo.chainObservers[key] = newObservers ;
322
+
323
+ // otherwise, just like a normal observer.
324
+ } else {
325
+ var observers = kvo.observers[key] || [] ;
326
+ observers = observers.without(func) ;
327
+ kvo.observers[key] = observers ;
328
+ }
329
+ },
330
+
331
+ /**
332
+ Use this to indicate that one key changes if other keys it depends on
333
+ change.
334
+ */
335
+ registerDependentKey: function(key) {
336
+ var keys = $A(arguments) ;
337
+ var dependent = keys.shift() ;
338
+ var kvo = this._kvo() ;
339
+ for(var loc=0;loc<keys.length;loc++) {
340
+ var key = keys[loc];
341
+ if (key instanceof Array) {
342
+ key.push(dependent) ;
343
+ this.registerDependentKey.apply(this,key) ;
344
+ } else {
345
+ var dependents = kvo.dependents[key] || [] ;
346
+ dependents.push(dependent) ;
347
+ kvo.dependents[key] = dependents ;
348
+ }
349
+ }
350
+ },
351
+
352
+ // INTERNAL PROPERTY SUPPORT
353
+
354
+ // returns the kvo object.
355
+ _kvo: function() {
356
+ if (!this._kvod) this._kvod = {
357
+ changes: 0, changed: {}, observers: {}, dependents: {},
358
+ chainObservers: {}, revision: 0
359
+ } ;
360
+ return this._kvod ;
361
+ },
362
+
363
+ propertyRevision: 1,
364
+
365
+ // this is invoked when the properties changed.
366
+ _notifyPropertyObservers: function(allObservers) {
367
+ // locals
368
+ var key ; var observers ; var keys = [] ;
369
+ var loc; var oloc ; var value ;
370
+ var kvo = this._kvo() ;
371
+
372
+ SC.Observers.flush() ; // hookup as many observers as possible.
373
+
374
+ // increment revision
375
+ this.propertyRevision++;
376
+
377
+ // find the keys to notify on.
378
+ var keySource = (allObservers) ? kvo.observers : kvo.changed ;
379
+ var allKeys = {} ;
380
+
381
+ // This private function is used to recursively discover all
382
+ // dependent keys.
383
+ var _addDependentKeys = function(key) {
384
+ if (allKeys[key] !== undefined) return ;
385
+ allKeys[key] = key ;
386
+
387
+ if (allObservers) return ;
388
+ var dependents = kvo.dependents[key] ;
389
+ if (dependents && dependents.length > 0) {
390
+ var loc = dependents.length ;
391
+ while(--loc >= 0) {
392
+ var depKey = dependents[loc] ;
393
+ _addDependentKeys(depKey) ;
394
+ }
395
+ }
396
+ } ;
397
+
398
+ // loop throught keys to notify. find all dependent keys as well.
399
+ // note that this loops recursively.
400
+ for(key in keySource) {
401
+ if (!keySource.hasOwnProperty(key)) continue ;
402
+ _addDependentKeys(key) ;
403
+ }
404
+
405
+ // Convert the found keys into an array
406
+ for(key in allKeys) {
407
+ if (!allKeys.hasOwnProperty(key)) continue ;
408
+ keys.push(key) ;
409
+ }
410
+ var starObservers = kvo.observers['*'] ;
411
+
412
+ // clear out changed to avoid recursion.
413
+ var changed = kvo.changed ; kvo.changed = {} ;
414
+
415
+ // notify all observers.
416
+ var target = this ;
417
+ loc = keys.length ;
418
+
419
+ var notifiedKeys = {} ; // avoid duplicates.
420
+ while(--loc >= 0) {
421
+ key = keys[loc] ; observers = kvo.observers[key] ;
422
+ if (!notifiedKeys[key]) {
423
+ notifiedKeys[key] = key ;
424
+ value = (allObservers || (!changed[key])) ? this.get(key) : changed[key];
425
+
426
+ if (starObservers) {
427
+ observers = (observers) ? observers.concat(starObservers) : starObservers ;
428
+ }
429
+
430
+ if (observers) {
431
+ oloc = observers.length ;
432
+ var args = [target, key, value, this.propertyRevision] ;
433
+ while(--oloc >= 0) {
434
+ var observer = observers[oloc] ;
435
+ SC.NotificationQueue.add(null, observer, args) ;
436
+ } // while(oloc)
437
+ } // if (observers)
438
+
439
+ // notify self.
440
+ if (this.propertyObserver != SC.Object.prototype.propertyObserver) {
441
+ SC.NotificationQueue.add(this, this.propertyObserver,
442
+ [null, target, key, value, this.propertyRevision]) ;
443
+ }
444
+ }
445
+
446
+ } // while(--loc)
447
+
448
+ SC.NotificationQueue.flush() ;
449
+ }
450
+
451
+ } ;
@@ -0,0 +1,63 @@
1
+ // ========================================================================
2
+ // SproutCore
3
+ // copyright 2006-2007 Sprout Systems, Inc.
4
+ // ========================================================================
5
+
6
+ require('foundation/path_module') ;
7
+
8
+ /**
9
+ @class SC.Page
10
+
11
+ The Page object is used to store a set of views that can be lazily
12
+ configured on page load. Page assumes that all of its properties are
13
+ basically outlets and will try to configure them as such.
14
+
15
+ @extends SC.Object
16
+ */
17
+ SC.Page = SC.Object.extend(
18
+ /** @scope SC.Page.prototype */
19
+ {
20
+
21
+ get: function(key) {
22
+ var value = this[key] ;
23
+ if (value && (value instanceof Function) && (value.isOutlet)) {
24
+ var ret = this.outlet(key) ;
25
+ if (SC.window && !ret.parentNode) {
26
+ SC.window._insertBefore(ret, null, false) ;
27
+ SC.window._rebuildChildNodes();
28
+ }
29
+ ret.awake() ;
30
+ return ret ;
31
+ } else return arguments.callee.base.apply(this,arguments) ;
32
+ },
33
+
34
+ // in addition to activating bindings, calling awake on the page object
35
+ // will cause any outlet properties to be loaded.
36
+ awake: function() {
37
+ arguments.callee.base.call(this) ;
38
+ for(var key in this) {
39
+ if (this.hasOwnProperty(key) && this[key] && this[key].isOutlet) {
40
+ this.get(key) ; // convert to outlet.
41
+ }
42
+ }
43
+ },
44
+
45
+ init: function() {
46
+ arguments.callee.base.apply(this,arguments) ;
47
+ var el = this.rootElement = $('resources') ;
48
+ SC.callOnLoad(function() {
49
+ if (el && el.parentNode) el.parentNode.removeChild(el) ;
50
+ }) ;
51
+ },
52
+
53
+ // returns the property, but only if it is already configured.
54
+ getIfConfigured: function(key) {
55
+ var value = this[key] ;
56
+ if (value && (value instanceof Function) && (value.isOutlet)) {
57
+ return null ;
58
+ } else return value ;
59
+ }
60
+
61
+ }) ;
62
+
63
+ Object.extend(SC.Page.prototype, SC.PathModule) ;