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,777 @@
1
+ // ========================================================================
2
+ // SproutCore
3
+ // copyright 2006-2007 Sprout Systems, Inc.
4
+ // ========================================================================
5
+
6
+ require('Core') ;
7
+ require('foundation/benchmark') ;
8
+ require('foundation/observable') ;
9
+
10
+ SC.BENCHMARK_OBJECTS = NO;
11
+
12
+ /**
13
+ @class Root Object for SproutCore framework.
14
+
15
+ This is the root object of the SproutCore framework. All other objects
16
+ inherit from you. SC.Object among other things implements support for
17
+ class inheritance, observers, and bindings. You should use SC.Object to
18
+ create your own subclasses as well.
19
+
20
+ Please see online documentation for more information about this.
21
+
22
+ I should be able to put a long list of things here I suppose.
23
+
24
+ Do bullet
25
+ points
26
+ work?
27
+
28
+ @extends SC.Observable
29
+ */
30
+ SC.Object = function(noinit) {
31
+ if (noinit == SC.Object._noinit_) return ;
32
+ var ret = SC.Object._init.apply(this,$A(arguments)) ;
33
+ return ret ;
34
+ };
35
+
36
+ Object.extend(SC.Object, {
37
+
38
+ _noinit_: '__noinit__',
39
+
40
+ // Use this to add class methods to an object.
41
+ mixin: function() {
42
+ var ext = $A(arguments) ;
43
+ for(var loc=0;loc<ext.length;loc++) {
44
+ Object.extend(this,ext[loc]);
45
+ }
46
+ return this ;
47
+ },
48
+
49
+ // this will created a new version of the passed object, updating the
50
+ // prototype to use the new code.
51
+ extend: function() {
52
+
53
+ if (SC.BENCHMARK_OBJECTS) SC.Benchmark.start('SC.Object.extend') ;
54
+
55
+ // build function. copy class methods on to it.
56
+ var ret = function(noinit) {
57
+ if (noinit && (typeof(noinit) == 'string') && (noinit == SC.Object._noinit_)) return ;
58
+ var ret = SC.Object._init.apply(this,$A(arguments));
59
+ return ret ;
60
+ };
61
+ for(var prop in this) { ret[prop] = this[prop]; }
62
+
63
+ // extend the prototype with passed arguments.
64
+ var base = new this(SC.Object._noinit_) ;
65
+
66
+ // var base = SC.Object._extend({},this.prototype) ;
67
+ var extensions = $A(arguments) ;
68
+ for(var loc=0;loc<extensions.length;loc++) {
69
+ base = SC.Object._extend(base, extensions[loc]);
70
+ }
71
+ ret.prototype = base ;
72
+
73
+ // return new extension
74
+ ret._guid = SC._nextGUID++ ; // each time we extend, get a new guid.
75
+ ret._type = this ;
76
+
77
+ if (SC.BENCHMARK_OBJECTS) SC.Benchmark.end('SC.Object.extend') ;
78
+
79
+ return ret ;
80
+ },
81
+
82
+ // create a new instance of the object.
83
+ create: function() {
84
+ var ret = new this($A(arguments),this) ;
85
+ return ret ;
86
+ },
87
+
88
+ // takes an array of configs and returns instances of each object.
89
+ createArray: function(array) {
90
+ var obj = this ;
91
+ return array.map(function(props) { return obj.create(props); }) ;
92
+ },
93
+
94
+ // configure this object as an outlet
95
+ outlet: function() {
96
+ var obj = this ;
97
+ return function() {
98
+ var ret = obj.create() ; ret.owner = this ; return ret ;
99
+ } ;
100
+ },
101
+
102
+ isClass: true,
103
+
104
+ // ..........................................
105
+ // PROPERTY SUPPORT METHODS
106
+ //
107
+ // get the tuple for a property path (the object and key).
108
+ tupleForPropertyPath: function(path,root) {
109
+ if (path.constructor == Array) return path ;
110
+
111
+ // * = the rest is a chained property.
112
+ var parts = path.split('*') ; var key = null ;
113
+ if (parts && parts.length > 1) {
114
+ key = parts.pop(); path = parts.join('*') ;
115
+ }
116
+
117
+ // get object path. property is last part if * was nt found.
118
+ parts = path.split('.') ;
119
+ if (!key) key = parts.pop() ;
120
+
121
+ // convert path to object.
122
+ var obj = this.objectForPropertyPath(parts,root) ;
123
+ return (obj && key) ? [obj,key] : null ;
124
+ },
125
+
126
+ objectForPropertyPath: function(path,root) {
127
+ var parts = (typeof(path) == "string") ? path.split('.') : path ;
128
+ if (!root) root = window ;
129
+ var key = parts.shift() ;
130
+ while(key && root) {
131
+ root = (root.get) ? root.get(key) : root[key];
132
+ key = parts.shift();
133
+ }
134
+ return (parts.length > 0) ? undefined : root ;
135
+ },
136
+
137
+
138
+ // ..........................................
139
+ // INTERNAL SUPPORT METHODS
140
+ //
141
+ _init: function(extensions,type) {
142
+
143
+ var ret = this ;
144
+ for(var loc=0;loc<extensions.length;loc++) {
145
+ ret = SC.Object._extend(ret,extensions[loc]) ;
146
+ }
147
+ ret._guid = SC._nextGUID++ ;
148
+ ret._type = type ;
149
+ ret.init() ;
150
+
151
+ return ret ;
152
+ },
153
+
154
+ // This will extend the base object with the properties passed in the second
155
+ // var, maintaining super's for the functions and concatinating cprops.
156
+ _extend: function(base,ext) { return this._extendAllProps(false, base, ext); },
157
+
158
+ _extendAllProps: function(allProperties, base,ext) {
159
+ var cprops = base._cprops ; var f = Prototype.emptyFunction ;
160
+
161
+ // first, save any concat props.
162
+ var concats = {} ;
163
+ if (cprops) for(var cloc=0;cloc<cprops.length;cloc++) {
164
+ var p = cprops[cloc]; var p1 = base[p]; var p2 = ext[p] ;
165
+ p1 = (p1 && p2) ? p1.concat(p2) : (p1 || p2) ;
166
+ concats[p] = p1 ;
167
+ }
168
+
169
+ // deal with observers, bindings, and properties only if they are not
170
+ // defined already in the ext. If they are defined in ext, they will be
171
+ // concated using the above code.
172
+ var bindings = (ext._bindings) ? null : (base._bindings || []).slice() ;
173
+ var observers = (ext._observers) ? null : (base._observers || []).slice();
174
+ var properties = (ext._properties) ? null : (base._properties || []).slice() ;
175
+
176
+ // now copy properties, add superclass to func.
177
+ for(var key in ext) {
178
+ // avoid copying builtin methods
179
+ if (!allProperties && !ext.hasOwnProperty(key)) continue ;
180
+
181
+ // add super to funcs. Be sure not to set the base of a func to itself
182
+ // to avoid infinite loops.
183
+ var value = (concats.hasOwnProperty(key) ? concats[key] : null) || ext[key] ;
184
+ if (value && (value instanceof Function) && (!value.base)) {
185
+ if (value != base[key]) value.base = base[key] || f;
186
+ }
187
+
188
+ // Possibly add to a bindings.
189
+ var keyLen = key.length ;
190
+ if (bindings && (key.slice(keyLen-7,keyLen) == "Binding")) {
191
+ bindings.push(key) ;
192
+
193
+ // Also add observers and properties for functions...
194
+ } else if (value && (value instanceof Function)) {
195
+ if (observers && value.propertyPaths) {
196
+ observers.push(key) ;
197
+ } else if (properties && value.dependentKeys) {
198
+ properties.push(key) ;
199
+ }
200
+ }
201
+
202
+ // copy property
203
+ base[key] = value ;
204
+ }
205
+
206
+ // copy bindings, observers, and properties if defined.
207
+ if (bindings) base._bindings = bindings;
208
+ if (observers) base._observers = observers ;
209
+ if (properties) base._properties = properties ;
210
+
211
+ //console.log('bindings: %@ -- observers: %@ -- properties: %@'.format(base._bindings,base._observers,base._properties)) ;
212
+
213
+ return base ;
214
+ },
215
+
216
+ toString: function() { return 'Object('+ SC.getGUID(this) +')'; },
217
+
218
+ // Returns true if the receiver is a subclass of the named class. If the
219
+ // receiver is the class passed, this will return false. See kindOf().
220
+ subclassOf: function(scClass) {
221
+ if (this == scClass) return false ;
222
+ var t = this._type ;
223
+ while(t) {
224
+ if (t == scClass) return true ;
225
+ t = t._type ;
226
+ }
227
+ return false ;
228
+ },
229
+
230
+ // Returns true if the receiver is the passed class or is any subclass.
231
+ kindOf: function(scClass) {
232
+ if (this == scClass) return true ;
233
+ return this.subclassOf(scClass);
234
+ }
235
+
236
+ }) ;
237
+
238
+ SC.idt = { count: 0, t: 0.0, keys: 0, observers: 0, bindings: 0, pv: 0, observers_t: 0, bindings_t: 0, pv_t: 0, conf_t: 0, b1_t: 0, b2_t: 0, b3_t: 0, e_count: 0, e_t: 0, v_count: 0, v_t: 0, vc_t: 0 ,active: false } ;
239
+
240
+ SC.report = function() {
241
+ var c = SC.idt.count ;
242
+ var e = SC.idt.e_count ;
243
+ var v = SC.idt.v_count ;
244
+ var ret = [] ;
245
+ ret.push('CREATED: ' + c + ' (avg time: '+(Math.floor(SC.idt.t * 100 / c) / 100)+' msec)') ;
246
+ ret.push('EXTENDED: ' + e + ' (avg time: '+(Math.floor(SC.idt.e_t * 100 / e) / 100)+' msec)') ;
247
+ ret.push('AVG KEYS: ' + (Math.floor(SC.idt.keys * 100 / c) / 100)) ;
248
+ ret.push('AVG OBSERVERS: ' + (Math.floor(SC.idt.observers * 100 / c) / 100) + ' ('+ (Math.floor(SC.idt.observers_t * 100 / c) / 100) + ' msec)') ;
249
+ ret.push('AVG BINDINGS: ' + (Math.floor(SC.idt.bindings * 100 / c) / 100) + ' ('+ (Math.floor(SC.idt.bindings_t * 100 / c) / 100) + ' msec)') ;
250
+ ret.push('AVG PV: ' + (Math.floor(SC.idt.pv * 100 / c) / 100) + ' ('+ (Math.floor(SC.idt.pv_t * 100 / c) / 100) + ' msec)') ;
251
+ ret.push('AVG CONFIGURE OUTLETS: ' + (Math.floor(SC.idt.conf_t * 100 / c) / 100) + ' msec') ;
252
+ ret.push('AVG B1: ' + (Math.floor(SC.idt.b1_t * 100 / c) / 100) + ' msec') ;
253
+ ret.push('EXT: ' + SC.idt.ext_c + ' (avg time: ' + (Math.floor(SC.idt.ext_t * 100 / SC.idt.ext_c) / 100) + ' msec)') ;
254
+ ret.push('VIEWS: ' + v + ' (avg time: ' + (Math.floor(SC.idt.v_t * 100 / v) / 100) + ' msec)') ;
255
+ ret.push('VIEW CREATE: ' + (Math.floor(SC.idt.vc_t * 100 / v) / 100) + ' msec)') ;
256
+ console.log(ret.join("\n")) ;
257
+ return ret.join("\n") ;
258
+ } ;
259
+
260
+ // ..........................................
261
+ // DEFAULT OBJECT INSTANCE
262
+ //
263
+ SC.Object.prototype = {
264
+
265
+ isObject: true,
266
+
267
+ respondsTo: function( name )
268
+ {
269
+ return !!(name && this[name] && ($type(this[name]) == T_FUNCTION));
270
+ },
271
+
272
+ tryToPerform: function( name, args )
273
+ {
274
+ if ( !name ) return false;
275
+
276
+ var args = $A(arguments);
277
+ var name = args.shift();
278
+ if (this.respondsTo(name))
279
+ {
280
+ return this[name].apply(this,args);
281
+ }
282
+ return false;
283
+ },
284
+
285
+ /**
286
+ this function is called automatically when a new object instance is
287
+ created. You can use this to configure your child elements if you want.
288
+ Be sure to invoke the base method.
289
+ */
290
+ init: function() {
291
+
292
+ // This keySource is used to fix a bug in FF that will not iterate through
293
+ // keys you add to an HTMLElement. The key values are still accessible,
294
+ // they just aren't visible to the for...in loop. viewType is the hash
295
+ // of values that was applied to the HTMLElement, so its a 1:1 substitute.
296
+ var keySource = this.viewType || this ;
297
+ var loc ; var keys ; var key ; var value ;
298
+
299
+ var r = SC.idt.active ; var idtStart ; var idtSt ;
300
+ if (r) {
301
+ SC.idt.count++;
302
+ idtStart = new Date().getTime() ;
303
+ } ;
304
+
305
+ // Add Observers
306
+ if (keys = keySource._observers) for(loc=0;loc<keys.length;loc++) {
307
+ key = keys[loc] ; value = this[key] ;
308
+
309
+ if (r) {
310
+ SC.idt.keys++ ;
311
+ SC.idt.observers++ ;
312
+ idtSt = new Date().getTime() ;
313
+ }
314
+
315
+ var propertyPaths = null ;
316
+ if ((value instanceof Function) && value.propertyPaths) {
317
+ propertyPaths = value.propertyPaths ;
318
+ value = value.bind(this) ;
319
+ } else if (typeof(value) == "string") {
320
+ propertyPaths = [value] ;
321
+ value = this.propertyObserver.bind(this,key.slice(0,-8)) ;
322
+ }
323
+
324
+ // a property path string was found. Convert this to an object/path
325
+ // and observe.
326
+ if (propertyPaths) for(var ploc=0;ploc<propertyPaths.length;ploc++) {
327
+ var propertyPath = propertyPaths[ploc] ;
328
+ var object = null;
329
+
330
+ // most common case. refers to local property.
331
+ if (propertyPath.indexOf('.') == -1) {
332
+ this.addObserver(propertyPath, value) ;
333
+
334
+ // deal with more exotic cases
335
+ } else switch(propertyPath.slice(0,1)) {
336
+ // start with a . or * means this is a chained local path.
337
+ case '*':
338
+ case '.':
339
+ propertyPath = propertyPath.slice(1,propertyPath.length) ;
340
+ this.addObserver(propertyPath, value) ;
341
+ break ;
342
+
343
+ // this is an absolute path. so hook 'er up.
344
+ default:
345
+ SC.Observers.addObserver(propertyPath, value) ;
346
+ }
347
+ }
348
+
349
+ if (r) SC.idt.observers_t += (new Date().getTime()) - idtSt ;
350
+ }
351
+
352
+ // Add Bindings
353
+ this.bindings = [] ;
354
+ if (keys = keySource._bindings) for(loc=0;loc<keys.length;loc++) {
355
+ key = keys[loc] ; value = this[key] ;
356
+
357
+ if (r) {
358
+ SC.idt.keys++ ;
359
+ SC.idt.bindings++ ;
360
+ idtSt = new Date().getTime() ;
361
+ }
362
+
363
+ // get propertyKey
364
+ var propertyKey = key.slice(0,-7) ; // contentBinding => content
365
+ this[key] = this.bind(propertyKey, value) ;
366
+ if (r) SC.idt.bindings_t += (new Date().getTime()) - idtSt ;
367
+ }
368
+
369
+ // Add Properties
370
+ if (keys = keySource._properties) for(loc=0;loc<keys.length;loc++) {
371
+ key = keys[loc] ; value = this[key] ;
372
+ if (value && value.dependentKeys && (value.dependentKeys.length > 0)) {
373
+ args = value.dependentKeys.slice() ;
374
+ args.unshift(key) ;
375
+ this.registerDependentKey.apply(this,args) ;
376
+ }
377
+ }
378
+
379
+ if (r) { SC.idt.t += ((new Date().getTime()) - idtStart); }
380
+ },
381
+
382
+ /**
383
+ EXPERIMENTAL: You can use this to call super in any method. This
384
+ currently does not work in some versions of Safari.
385
+ */
386
+ $super: function(args) {
387
+ var caller = SC.Object.prototype.$super.caller;
388
+ if (!caller) throw "$super cannot determine the caller method" ;
389
+ if (caller.base) caller.base.apply(this, arguments) ;
390
+ },
391
+
392
+ /**
393
+ Use this to add class methods to an object.
394
+ */
395
+ mixin: function() { return SC.Object.mixin.apply(this,arguments) ; },
396
+
397
+ /**
398
+ Returns all the keys defined on this object, excluding any defined in
399
+ parent classes unless you pass all.
400
+
401
+ @param {Boolean} all OPTIONAL: if YES return all keys, NO return only keys belonging to object itself. Defaults to NO.
402
+ */
403
+ keys: function(all) {
404
+ var ret = []; for(var key in this) {
405
+ if (all || ret.hasOwnProperty(key)) ret.push(key);
406
+ }; return ret ;
407
+ },
408
+
409
+ /**
410
+ returns true if the receiver is an instance of the named class. See also
411
+ kindOf().
412
+ */
413
+ instanceOf: function(scClass) {
414
+ return this._type == scClass ;
415
+ },
416
+
417
+ /**
418
+ Returns true if the receiver is an instance of the named class or any
419
+ subclass of the named class. See also instanceOf().
420
+ */
421
+ kindOf: function(scClass) {
422
+ var t = this._type ;
423
+ while(t) {
424
+ if (t == scClass) return true ;
425
+ t = t._type ;
426
+ }
427
+ return false ;
428
+ },
429
+
430
+ /** @private */
431
+ _enumerator: function() {
432
+
433
+ // build in enumerator.
434
+ if (this.objectAtIndex) {
435
+ ret = {
436
+ nextObject: function() {
437
+ var loc = this.loc ;
438
+ return (loc>=0) ? this.obj.objectAtIndex(--loc) : null ;
439
+ },
440
+ loc: this.get('length') || 0,
441
+ obj: this
442
+ } ;
443
+
444
+ // or just return one that does nothing.
445
+ } else {
446
+ ret = { nextObject: function() { return null; } } ;
447
+ }
448
+
449
+ return ret ;
450
+ },
451
+
452
+ // ..........................................
453
+ // OUTLETS
454
+ //
455
+
456
+ /**
457
+ A view may contain outlets. Outlets are a way to find and connect to
458
+ elements within the view.
459
+ */
460
+ awake: function(key) {
461
+ // if a key is passed, convert that from an outlet and awake it. otherwise
462
+ // awake self.
463
+ if (key !== undefined) {
464
+ var obj = this.outlet(key) ;
465
+ if (obj) obj.awake() ;
466
+ return ;
467
+ }
468
+
469
+ if (this._awake) return ;
470
+ this._awake = true ;
471
+
472
+ // it would be cool to do this in a recursive way, but sadly we cannot
473
+ // without a stack overflow problem. Just loop through outlets and collect
474
+ // items to awake.
475
+ this.bindings.invoke('relay') ;
476
+
477
+ if (this.outlets && this.outlets.length) {
478
+ var stack = [] ;
479
+ var working = [this, this.outlets.slice()] ;
480
+ while(working) {
481
+ // find the next item to work on.
482
+ var next = working[1].pop() ;
483
+ var obj = working[0] ;
484
+
485
+ // an item was found in the array. Process it.
486
+ if (next) {
487
+ next = obj[next] ;
488
+ if (next) {
489
+ // awake these bindings.
490
+ if (next.bindings) next.bindings.invoke('relay') ;
491
+
492
+ // next has outlets itself. Start a new context and process them.
493
+ if (next.outlets && next.outlets.length > 0) {
494
+ stack.push(working) ;
495
+ working = [next,next.outlets.slice()] ;
496
+ }
497
+ }
498
+
499
+ // no more items found in the current array. pop the stack.
500
+ } else working = stack.pop() ;
501
+ }
502
+ }
503
+
504
+ },
505
+
506
+ /**
507
+ name your outlets here or name the outlets "somethingOutlet". See
508
+ also outletFor in views.
509
+ */
510
+ outlets: [],
511
+
512
+ /**
513
+ This method works just like get() except if the value of the property
514
+ is an outlet-packaged View, the view will be created first. You can use
515
+ this to create lazy outlets. (DOC-INCOMPLETE)
516
+
517
+ @param {String} key The key to read as an outlet.
518
+ */
519
+ outlet: function(key) {
520
+ var value = this[key] ; // get the current value.
521
+
522
+ // if its an outlet, then configure it first.
523
+ if (value && (value instanceof Function) && value.isOutlet == true) {
524
+ if (!this._originalOutlets) this._originalOutlets = {} ;
525
+ this._originalOutlets[key] = value ;
526
+
527
+ value = value.call(this) ;
528
+ this.set(key, value) ;
529
+ } else if (typeof(value) == "string") {
530
+ if (!this._originalOutlets) this._originalOutlets = {} ;
531
+ this._originalOutlets[key] = value ;
532
+
533
+ value = (this.$$sel) ? this.$$sel(value) : $$sel(value) ;
534
+ if (value) value = (value.length > 0) ? ((value.length == 1) ? value[0] : value) : null ;
535
+ this.set(key, value) ;
536
+ }
537
+
538
+ return value ;
539
+ },
540
+
541
+ /**
542
+ DEPRECATED: Will be removed in SproutCore 1.0.
543
+ */
544
+ invokeLater: function(period) {
545
+ var args = $A(arguments) ; args.unshift(this) ;
546
+ return SC.runLoop.schedule.apply(SC.runLoop,args) ;
547
+ },
548
+
549
+ _cprops: ['_cprops','outlets','_bindings','_observers','_properties']
550
+
551
+ } ;
552
+
553
+ Object.extend(SC.Object.prototype, SC.Observable) ;
554
+
555
+
556
+ function logChange(target,key,value) {
557
+ console.log("CHANGE: " + target + "["+key+"]=" + value) ;
558
+ }
559
+
560
+ // ........................................................................
561
+ // FUNCTION ENHANCEMENTS
562
+ //
563
+ // Enhance function.
564
+ Object.extend(Function.prototype,{
565
+
566
+ // Declare a function as a property. This makes it something that can be
567
+ // accessed via get/set.
568
+ property: function() {
569
+ this.dependentKeys = $A(arguments) ;
570
+ this.isProperty = true; return this;
571
+ },
572
+
573
+ // Declare that a function should observe an object at the named path. Note
574
+ // that the path is used only to construct the observation one time.
575
+ observes: function(propertyPaths) {
576
+ this.propertyPaths = $A(arguments);
577
+ return this;
578
+ },
579
+
580
+ typeConverter: function() {
581
+ this.isTypeConverter = true; return this ;
582
+ }
583
+
584
+ }) ;
585
+
586
+ // ........................................................................
587
+ // OBSERVER QUEUE
588
+ //
589
+ // This queue is used to hold observers when the object you tried to observe
590
+ // does not exist yet. This queue is flushed just before any property
591
+ // notification is sent.
592
+ SC.Observers = {
593
+ queue: {},
594
+
595
+ addObserver: function(propertyPath, func) {
596
+ // try to get the tuple for this.
597
+ if (typeof(propertyPath) == "string") {
598
+ var tuple = SC.Object.tupleForPropertyPath(propertyPath) ;
599
+ } else {
600
+ var tuple = propertyPath;
601
+ }
602
+
603
+ if (tuple) {
604
+ tuple[0].addObserver(tuple[1],func) ;
605
+ } else {
606
+ var ary = this.queue[propertyPath] || [] ;
607
+ ary.push(func) ;
608
+ this.queue[propertyPath] = ary ;
609
+ }
610
+ },
611
+
612
+ removeObserver: function(propertyPath, func) {
613
+ var tuple = SC.Object.tupleForPropertyPath(propertyPath) ;
614
+ if (tuple) {
615
+ tuple[0].removeObserver(tuple[1],func) ;
616
+ }
617
+
618
+ var ary = this.queue[propertyPath] ;
619
+ if (ary) {
620
+ ary = ary.without(func) ;
621
+ this.queue[propertyPath] = ary ;
622
+ }
623
+ },
624
+
625
+ flush: function() {
626
+ var newQueue = {} ;
627
+ for(var path in this.queue) {
628
+ var funcs = this.queue[path] ;
629
+ var tuple = SC.Object.tupleForPropertyPath(path) ;
630
+ if (tuple) {
631
+ var loc = funcs.length ;
632
+ while(--loc >= 0) {
633
+ var func = funcs[loc] ;
634
+ tuple[0].addObserver(tuple[1],func) ;
635
+ }
636
+ } else newQueue[path] = funcs ;
637
+ }
638
+
639
+ // set queue to remaining items
640
+ this.queue = newQueue ;
641
+ }
642
+ } ;
643
+
644
+ // ........................................................................
645
+ // NOTIFCATION QUEUE
646
+ //
647
+ // Property notifications are placed into this queue first and then processed
648
+ // to keep the stack size down.
649
+ SC.NotificationQueue = {
650
+ queue: [],
651
+ maxFlush: 5000, // max time you can spend flushing before we reschedule.
652
+ _flushing: false,
653
+ add: function(target, func, args) { this.queue.push([target, func, args]);},
654
+ flush: function() {
655
+ if (this._flushing) return ;
656
+ this._flushing = true ;
657
+
658
+ var start = new Date().getTime() ;
659
+ var now = start ;
660
+ var n = null ;
661
+ while(((now - start) < this.maxFlush) && (n = this.queue.pop())) {
662
+ try {
663
+ var t = n[0] || n[1] ;
664
+ n[1].apply(t,n[2]) ;
665
+ }
666
+ catch(e) {
667
+ console.log("Exception while notify("+n[1]+"): " + e) ;
668
+ } // catch
669
+ now = Date.now() ;
670
+ }
671
+ this._flushing = false ;
672
+
673
+ if (this.queue.length > 0) {
674
+ setTimeout(this._reflush,1);
675
+ }
676
+ },
677
+
678
+ _reflush: function() { SC.NotificationQueue.flush(); }
679
+ } ;
680
+
681
+ // ........................................................................
682
+ // CHAIN OBSERVER
683
+ //
684
+
685
+ // ChainObservers are used to automatically monitor a property several
686
+ // layers deep.
687
+ // org.plan.name = SC._ChainObserver.create({
688
+ // target: this, property: 'org',
689
+ // next: SC._ChainObserver.create({
690
+ // property: 'plan',
691
+ // next: SC._ChainObserver.create({
692
+ // property: 'name', func: myFunc
693
+ // })
694
+ // })
695
+ // })
696
+ //
697
+ SC._ChainObserver = SC.Object.extend({
698
+
699
+ isChainObserver: true,
700
+
701
+ // the object this link in the chain is observing.
702
+ target: null,
703
+
704
+ // the property on the object this link is observing
705
+ property: null,
706
+
707
+ // if not null, the next link in the chain. The target property
708
+ // of this next link will be set to the value of this link.
709
+ next: null,
710
+
711
+ // if not null, the function to be called when the property value changes.
712
+ func: null,
713
+
714
+ propertyObserver: function(observing,target,key,value) {
715
+ if ((key == 'target') && (value != this._target)) {
716
+ var func = this.boundObserver() ;
717
+ if (this._target && this._target.removeObserver) {
718
+ this._target.removeObserver(this.property,func);
719
+ }
720
+ this._target = value ;
721
+ if (this._target && this._target.addObserver) {
722
+ this._target.addObserver(this.property,func) ;
723
+ }
724
+
725
+ // the target property has probably changed since the target has
726
+ // changed. notify myself of this.
727
+ if (!(observing == 'init')) this.targetPropertyObserver() ;
728
+ }
729
+ },
730
+
731
+ boundObserver: function() {
732
+ if (!this._boundObserver) {
733
+ this._boundObserver = this.targetPropertyObserver.bind(this) ;
734
+ }
735
+ return this._boundObserver ;
736
+ },
737
+
738
+ // invoked when the target property changes. act based
739
+ targetPropertyObserver: function() {
740
+
741
+ // get the new target property value. if the target or property is
742
+ // not valid, just use null.
743
+ var value = (this.target && this.target.get && this.property) ? this.target.get(this.property) : null ;
744
+
745
+ if (value !== this._lastTargetProperty) {
746
+ this._lastTargetProperty = value ;
747
+ // if we have another item in the chain, just forward the change.
748
+ if (this.next) {
749
+ this.next.set('target',value) ;
750
+
751
+ // otherwise, invoke the function.
752
+ } else if (this.func) this.func(this.target,this.property,value) ;
753
+ }
754
+
755
+ },
756
+
757
+ // hookup observer.
758
+ init: function() {
759
+ arguments.callee.base.call(this) ;
760
+ this.propertyObserver('init',this,'target',this.get('target')) ;
761
+ }
762
+
763
+ }) ;
764
+
765
+ // Class Methods.
766
+ SC._ChainObserver.mixin({
767
+ createChain: function(target,keys,func) {
768
+ var property = keys.shift() ;
769
+ var nextTarget = (target && property && target.get) ? target.get(property) : null ;
770
+ var next = (keys && keys.length>0) ? this.createChain(nextTarget,keys,func) : null ;
771
+
772
+ return this.create({
773
+ target: target, property: property,
774
+ next: next, func: ((next) ? null : func)
775
+ }) ;
776
+ }
777
+ }) ;