sproutcore 0.9.1 → 0.9.2

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 (208) hide show
  1. data/History.txt +233 -0
  2. data/Manifest.txt +67 -34
  3. data/bin/sc-build +12 -1
  4. data/bin/sc-gen +1 -1
  5. data/bin/sproutcore +14 -0
  6. data/clients/sc_docs/controllers/docs.js +38 -8
  7. data/clients/sc_docs/english.lproj/body.css +80 -127
  8. data/clients/sc_docs/english.lproj/body.rhtml +43 -23
  9. data/clients/sc_docs/english.lproj/no_docs.rhtml +2 -1
  10. data/clients/sc_docs/english.lproj/tabs.rhtml +16 -0
  11. data/clients/sc_docs/main.js +14 -9
  12. data/clients/sc_docs/models/doc.js +1 -1
  13. data/clients/sc_docs/tests/controllers/docs.rhtml +1 -2
  14. data/clients/sc_docs/tests/models/doc.rhtml +1 -2
  15. data/clients/sc_docs/tests/views/doc_frame.rhtml +1 -2
  16. data/clients/sc_docs/tests/views/doc_label_view.rhtml +1 -2
  17. data/clients/sc_docs/views/doc_frame.js +1 -1
  18. data/clients/sc_test_runner/controllers/runner.js +31 -8
  19. data/clients/sc_test_runner/english.lproj/body.css +62 -122
  20. data/clients/sc_test_runner/english.lproj/body.rhtml +62 -26
  21. data/clients/sc_test_runner/main.js +1 -6
  22. data/clients/sc_test_runner/models/test.js +14 -1
  23. data/clients/sc_test_runner/views/runner_frame.js +4 -2
  24. data/clients/view_builder/builders/builder.js +339 -0
  25. data/clients/view_builder/builders/button.js +81 -0
  26. data/clients/view_builder/controllers/document.js +21 -0
  27. data/clients/view_builder/core.js +19 -0
  28. data/clients/view_builder/english.lproj/body.css +77 -0
  29. data/clients/view_builder/english.lproj/body.rhtml +41 -0
  30. data/clients/{sc_docs → view_builder}/english.lproj/controls.css +0 -0
  31. data/clients/view_builder/english.lproj/strings.js +14 -0
  32. data/clients/view_builder/main.js +38 -0
  33. data/clients/view_builder/tests/controllers/document.rhtml +20 -0
  34. data/clients/view_builder/tests/views/builder.rhtml +20 -0
  35. data/clients/view_builder/views/builder.js +23 -0
  36. data/frameworks/prototype/prototype.js +1 -1
  37. data/frameworks/sproutcore/Core.js +32 -7
  38. data/frameworks/sproutcore/README +1 -1
  39. data/frameworks/sproutcore/animation/animation.js +411 -0
  40. data/frameworks/sproutcore/controllers/array.js +17 -9
  41. data/frameworks/sproutcore/controllers/collection.js +9 -110
  42. data/frameworks/sproutcore/controllers/controller.js +1 -1
  43. data/frameworks/sproutcore/controllers/object.js +2 -1
  44. data/frameworks/sproutcore/drag/drag.js +267 -56
  45. data/frameworks/sproutcore/drag/drag_data_source.js +24 -16
  46. data/frameworks/sproutcore/drag/drag_source.js +53 -42
  47. data/frameworks/sproutcore/drag/drop_target.js +2 -2
  48. data/frameworks/sproutcore/english.lproj/buttons.css +337 -236
  49. data/frameworks/sproutcore/english.lproj/core.css +115 -0
  50. data/frameworks/sproutcore/english.lproj/icons.css +227 -0
  51. data/{clients/sc_docs → frameworks/sproutcore}/english.lproj/images/indicator.gif +0 -0
  52. data/frameworks/sproutcore/english.lproj/images/sc-theme-sprite.png +0 -0
  53. data/frameworks/sproutcore/english.lproj/images/sc-theme-ysprite.png +0 -0
  54. data/frameworks/sproutcore/english.lproj/images/shared-icons.png +0 -0
  55. data/frameworks/sproutcore/english.lproj/menu.css +1 -1
  56. data/frameworks/sproutcore/english.lproj/strings.js +1 -1
  57. data/frameworks/sproutcore/english.lproj/theme.css +405 -31
  58. data/frameworks/sproutcore/foundation/application.js +15 -11
  59. data/frameworks/sproutcore/foundation/benchmark.js +1 -1
  60. data/frameworks/sproutcore/foundation/binding.js +2 -2
  61. data/frameworks/sproutcore/foundation/date.js +1 -1
  62. data/frameworks/sproutcore/foundation/error.js +1 -1
  63. data/frameworks/sproutcore/foundation/input_manager.js +32 -21
  64. data/frameworks/sproutcore/foundation/mock.js +1 -1
  65. data/frameworks/sproutcore/foundation/node_descriptor.js +9 -6
  66. data/frameworks/sproutcore/foundation/object.js +249 -177
  67. data/frameworks/sproutcore/foundation/page.js +5 -2
  68. data/frameworks/sproutcore/foundation/path_module.js +11 -10
  69. data/frameworks/sproutcore/foundation/responder.js +5 -2
  70. data/frameworks/sproutcore/foundation/routes.js +17 -13
  71. data/frameworks/sproutcore/foundation/run_loop.js +249 -11
  72. data/frameworks/sproutcore/foundation/server.js +1 -1
  73. data/frameworks/sproutcore/foundation/set.js +3 -3
  74. data/frameworks/sproutcore/foundation/string.js +5 -3
  75. data/frameworks/sproutcore/foundation/timer.js +371 -0
  76. data/frameworks/sproutcore/foundation/undo_manager.js +1 -1
  77. data/frameworks/sproutcore/foundation/unittest.js +3 -3
  78. data/frameworks/sproutcore/foundation/utils.js +161 -2
  79. data/frameworks/sproutcore/globals/panels.js +1 -1
  80. data/frameworks/sproutcore/globals/popups.js +4 -3
  81. data/frameworks/sproutcore/globals/window.js +44 -4
  82. data/frameworks/sproutcore/lib/button_views.rb +328 -0
  83. data/frameworks/sproutcore/lib/collection_view.rb +80 -0
  84. data/frameworks/sproutcore/lib/core_views.rb +281 -0
  85. data/frameworks/sproutcore/lib/form_views.rb +253 -0
  86. data/frameworks/sproutcore/lib/index.rhtml +2 -0
  87. data/frameworks/sproutcore/lib/menu_views.rb +88 -0
  88. data/frameworks/sproutcore/{foundation → mixins}/array.js +60 -29
  89. data/frameworks/sproutcore/mixins/control.js +265 -0
  90. data/frameworks/sproutcore/mixins/delegate_support.js +66 -0
  91. data/frameworks/sproutcore/{foundation → mixins}/observable.js +176 -6
  92. data/frameworks/sproutcore/mixins/scrollable.js +245 -0
  93. data/frameworks/sproutcore/mixins/selection_support.js +148 -0
  94. data/frameworks/sproutcore/mixins/validatable.js +152 -0
  95. data/frameworks/sproutcore/models/collection.js +5 -5
  96. data/frameworks/sproutcore/models/record.js +1 -1
  97. data/frameworks/sproutcore/models/store.js +1 -1
  98. data/frameworks/sproutcore/panes/dialog.js +1 -1
  99. data/frameworks/sproutcore/panes/manager.js +1 -1
  100. data/frameworks/sproutcore/panes/menu.js +1 -1
  101. data/frameworks/sproutcore/panes/overlay.js +2 -2
  102. data/frameworks/sproutcore/panes/panel.js +1 -1
  103. data/frameworks/sproutcore/panes/picker.js +1 -1
  104. data/frameworks/sproutcore/tests/controllers/array.rhtml +44 -4
  105. data/frameworks/sproutcore/tests/foundation/timer/invalidate.rhtml +33 -0
  106. data/frameworks/sproutcore/tests/foundation/timer/invokeLater.rhtml +145 -0
  107. data/frameworks/sproutcore/tests/foundation/timer/isPaused.rhtml +70 -0
  108. data/frameworks/sproutcore/tests/foundation/timer/schedule.rhtml +145 -0
  109. data/frameworks/sproutcore/tests/views/{scroll.rhtml → checkbox.rhtml} +3 -3
  110. data/frameworks/sproutcore/tests/views/{collection.rhtml → collection/base.rhtml} +33 -32
  111. data/frameworks/sproutcore/tests/views/collection/incremental_rendering.rhtml +260 -0
  112. data/frameworks/sproutcore/tests/views/image_cell.rhtml +19 -0
  113. data/frameworks/sproutcore/tests/views/label_item.rhtml +2 -4
  114. data/frameworks/sproutcore/tests/views/list.rhtml +2 -3
  115. data/frameworks/sproutcore/tests/views/list_item.rhtml +20 -0
  116. data/frameworks/sproutcore/tests/views/slider.rhtml +20 -0
  117. data/frameworks/sproutcore/tests/views/text_cell.rhtml +19 -0
  118. data/frameworks/sproutcore/tests/views/view/clippingFrame.rhtml +395 -0
  119. data/frameworks/sproutcore/tests/views/view/frame.rhtml +353 -0
  120. data/frameworks/sproutcore/tests/views/view/innerFrame.rhtml +347 -0
  121. data/frameworks/sproutcore/tests/views/view/isVisibleInWindow.rhtml +148 -0
  122. data/frameworks/sproutcore/tests/views/view/scrollFrame.rhtml +468 -0
  123. data/frameworks/sproutcore/validators/credit_card.js +33 -13
  124. data/frameworks/sproutcore/validators/date.js +26 -6
  125. data/frameworks/sproutcore/validators/email.js +21 -3
  126. data/frameworks/sproutcore/validators/not_empty.js +11 -1
  127. data/frameworks/sproutcore/validators/number.js +18 -4
  128. data/frameworks/sproutcore/validators/password.js +12 -1
  129. data/frameworks/sproutcore/validators/validator.js +204 -194
  130. data/frameworks/sproutcore/views/{button.js → button/button.js} +96 -94
  131. data/frameworks/sproutcore/views/button/checkbox.js +29 -0
  132. data/frameworks/sproutcore/views/button/disclosure.js +42 -0
  133. data/frameworks/sproutcore/views/button/radio.js +29 -0
  134. data/frameworks/sproutcore/views/{collection.js → collection/collection.js} +1373 -1024
  135. data/frameworks/sproutcore/views/collection/grid.js +124 -46
  136. data/frameworks/sproutcore/views/collection/image_cell.js +17 -46
  137. data/frameworks/sproutcore/views/collection/list.js +45 -35
  138. data/frameworks/sproutcore/views/collection/source_list.js +386 -0
  139. data/frameworks/sproutcore/views/collection/table.js +118 -0
  140. data/frameworks/sproutcore/views/container.js +7 -2
  141. data/frameworks/sproutcore/views/error_explanation.js +23 -10
  142. data/frameworks/sproutcore/views/{checkbox_field.js → field/checkbox_field.js} +16 -6
  143. data/frameworks/sproutcore/views/field/field.js +219 -0
  144. data/frameworks/sproutcore/views/{radio_field.js → field/radio_field.js} +27 -12
  145. data/frameworks/sproutcore/views/{select_field.js → field/select_field.js} +116 -90
  146. data/frameworks/sproutcore/views/{text_field.js → field/text_field.js} +57 -8
  147. data/frameworks/sproutcore/views/{textarea_field.js → field/textarea_field.js} +13 -3
  148. data/frameworks/sproutcore/views/filter_button.js +2 -2
  149. data/frameworks/sproutcore/views/form.js +3 -3
  150. data/frameworks/sproutcore/views/image.js +128 -21
  151. data/frameworks/sproutcore/views/inline_text_editor.js +1 -1
  152. data/frameworks/sproutcore/views/label.js +149 -92
  153. data/frameworks/sproutcore/views/list_item.js +225 -0
  154. data/frameworks/sproutcore/views/menu_item.js +10 -4
  155. data/frameworks/sproutcore/views/pagination.js +11 -4
  156. data/frameworks/sproutcore/views/popup_button.js +25 -21
  157. data/frameworks/sproutcore/views/popup_menu.js +10 -4
  158. data/frameworks/sproutcore/views/progress.js +29 -16
  159. data/frameworks/sproutcore/views/radio_group.js +1 -1
  160. data/frameworks/sproutcore/views/scroll.js +60 -20
  161. data/frameworks/sproutcore/views/segmented.js +1 -1
  162. data/frameworks/sproutcore/views/slider.js +132 -0
  163. data/frameworks/sproutcore/views/source_list_group.js +130 -0
  164. data/frameworks/sproutcore/views/spinner.js +1 -1
  165. data/frameworks/sproutcore/views/split.js +292 -0
  166. data/frameworks/sproutcore/views/split_divider.js +109 -0
  167. data/frameworks/sproutcore/views/tab.js +1 -1
  168. data/frameworks/sproutcore/views/toolbar.js +1 -1
  169. data/frameworks/sproutcore/views/view.js +1272 -591
  170. data/generators/client/templates/english.lproj/body.css +1 -1
  171. data/generators/controller/controller_generator.rb +1 -1
  172. data/generators/controller/templates/test.rhtml +2 -1
  173. data/generators/model/templates/test.rhtml +1 -1
  174. data/generators/test/templates/test.rhtml +1 -1
  175. data/generators/view/templates/test.rhtml +1 -1
  176. data/jsdoc/templates/sproutcore/class.tmpl +241 -338
  177. data/jsdoc/templates/sproutcore/default.css +105 -155
  178. data/jsdoc/templates/sproutcore/index.tmpl +43 -8
  179. data/jsdoc/templates/sproutcore/publish.js +9 -4
  180. data/lib/sproutcore/build_tools/html_builder.rb +29 -13
  181. data/lib/sproutcore/build_tools/resource_builder.rb +1 -1
  182. data/lib/sproutcore/bundle.rb +86 -25
  183. data/lib/sproutcore/jsdoc.rb +2 -0
  184. data/lib/sproutcore/version.rb +1 -1
  185. data/lib/sproutcore/view_helpers.rb +36 -3
  186. data/tasks/deployment.rake +1 -1
  187. metadata +69 -36
  188. data/clients/sc_docs/english.lproj/icons/small/next.png +0 -0
  189. data/clients/sc_docs/english.lproj/icons/small/reset.png +0 -0
  190. data/clients/sc_docs/english.lproj/images/gradients.png +0 -0
  191. data/clients/sc_docs/english.lproj/images/toolbar.png +0 -0
  192. data/clients/sc_docs/english.lproj/warning.rhtml +0 -6
  193. data/clients/sc_test_runner/english.lproj/warning.rhtml +0 -6
  194. data/frameworks/sproutcore/english.lproj/buttons.png +0 -0
  195. data/frameworks/sproutcore/english.lproj/collections.css +0 -82
  196. data/frameworks/sproutcore/english.lproj/images/buttons-sprite.png +0 -0
  197. data/frameworks/sproutcore/views/collection/collection_item.js +0 -36
  198. data/frameworks/sproutcore/views/collection/text_cell.js +0 -128
  199. data/frameworks/sproutcore/views/field.js +0 -214
  200. data/frameworks/sproutcore/views/workspace.js +0 -170
  201. data/generators/client/templates/english.lproj/controls.css +0 -0
  202. data/generators/framework/templates/english.lproj/body.css +0 -0
  203. data/generators/framework/templates/english.lproj/body.rhtml +0 -3
  204. data/generators/framework/templates/english.lproj/controls.css +0 -0
  205. data/lib/sproutcore/view_helpers/button_views.rb +0 -302
  206. data/lib/sproutcore/view_helpers/core_views.rb +0 -292
  207. data/lib/sproutcore/view_helpers/form_views.rb +0 -258
  208. data/lib/sproutcore/view_helpers/menu_views.rb +0 -94
@@ -22,6 +22,7 @@
22
22
  # :requires option in routes.rb.
23
23
  -%>
24
24
  <%= stylesheets_for_client %>
25
+ <%= @content_for_page_styles %>
25
26
  </head>
26
27
  <body class="<%= @theme || 'sc-theme' %>">
27
28
  <% #
@@ -50,6 +51,7 @@
50
51
  -%>
51
52
  <!-- Include Site Javascript -->
52
53
  <%= javascripts_for_client %>
54
+ <%= @content_for_page_javascript %>
53
55
 
54
56
  <% #
55
57
  # The following lines to the closing body tag must be included at the
@@ -0,0 +1,88 @@
1
+ ############################################################
2
+ # MENU VIEW HELPERS
3
+ #
4
+ # The view helpers defined in this file help you create popup menus. You can
5
+ # define a menu in your RHTML helper to be used somewhere else with code like
6
+ # this:
7
+ #
8
+
9
+ # This is the quick way to define a menu item. Use this approach if you just
10
+ # want to create a menu with item names and perform an action:
11
+ #
12
+ # <% menu_view :action_menu, :validate=>'My.controller.validate' do |m| %>
13
+ # <%= m.item :item_1, 'Item 1', :action => 'doSomething' %>
14
+ # <%= m.separator_item %>
15
+ # <%= m.item :item_2, 'Item 2', :action => 'doAnother Thing' %>
16
+ # <% end %>
17
+ #
18
+ require_helpers 'core_views'
19
+ require_helpers 'button_views'
20
+
21
+ # This will create a popup menu. You should define internal outlets
22
+ # for the menu items. More options to follow.
23
+ view_helper :popup_menu_view do
24
+ var :tag, 'ul'
25
+ view 'SC.PopupMenuView'
26
+ end
27
+
28
+ # Creates a menu item view. Normally you don't want to create these
29
+ # directly. Instead use the menu_view helpers.
30
+ #
31
+ # OPTIONS:
32
+ # :action =>
33
+ # The action to invoke when the menu item is selected.
34
+ #
35
+ # :label =>
36
+ # The label for the menu item.
37
+ #
38
+ # :icon =>
39
+ # The icon for the menu item. No icon will show if this is not set.
40
+ #
41
+ # :shortcut =>
42
+ # The shortcut key for this menu item. Shortcuts are only active when
43
+ # the anchorview the popup menu is attached to is part of the in-focus
44
+ # pane. Shortcuts should be named in the standard input manager
45
+ # syntax like this: alt_ctrl_shift_k (for Alt-Ctrl-Shift-K)
46
+ #
47
+ # Note that on the web, Cmd (on the Mac) and Ctrl are equivalent.
48
+ # Always use ctrl when defining shortcuts.
49
+ #
50
+ # :enabled (bindable) =>
51
+ # Determines if the menu item will be enabled or not. This is generally
52
+ # handled by your validate method or through bindings.
53
+ #
54
+ # :selected (bindable) =>
55
+ # Determines if the menu item is selected or not. May also be a mixed
56
+ # state. This is generally handled by your validate method or through
57
+ # bindings.
58
+ #
59
+ # :alt =>
60
+ # name another item in this menu that is the alternate form of the
61
+ # receiver. If the alt item is enabled, this one will be hidden and
62
+ # visa versa.
63
+ #
64
+ view_helper :menu_item_view, :extends => :button_view do
65
+
66
+ # JavaScript
67
+ view 'SC.MenuItemView'
68
+
69
+ # HTML
70
+ var :tag, 'li'
71
+ var(:shortcut) { |sc| sc.split('_').map { |x| x.capitalize } * '-' }
72
+ css_class_names << 'menu-item'
73
+
74
+ @my_href = @href || 'javascript:;'
75
+ @href = nil
76
+ @inner_html = [
77
+ %(<a href="#{@my_href}">),
78
+ '<span class="sel">&#x2713;</span>',
79
+ '<span class="mixed">-</span>',
80
+ '<span class="inner">',
81
+ @image,
82
+ %(<span class="label">#{@label}</span>),
83
+ '</span>',
84
+ %(<span class="shortcut">#{@shortcut}</span>),
85
+ '</a>'
86
+ ] * ''
87
+
88
+ end
@@ -1,9 +1,9 @@
1
1
  // ==========================================================================
2
2
  // SproutCore -- JavaScript Application Framework
3
- // copyright 2006-2007, Sprout Systems, Inc. and contributors.
3
+ // copyright 2006-2008, Sprout Systems, Inc. and contributors.
4
4
  // ==========================================================================
5
5
 
6
- require('foundation/observable');
6
+ require('mixins/observable');
7
7
 
8
8
  // Make Arrays observable
9
9
  Object.extend(Array.prototype, SC.Observable) ;
@@ -11,7 +11,7 @@ Object.extend(Array.prototype, SC.Observable) ;
11
11
  SC.OUT_OF_RANGE_EXCEPTION = "Index out of range" ;
12
12
 
13
13
  /**
14
- @namespace SC.Array
14
+ @namespace
15
15
 
16
16
  This module implements Observer-friendly Array-like behavior. This mixin is
17
17
  picked up by the Array class as well as other controllers, etc. that want to
@@ -125,8 +125,9 @@ SC.Array = {
125
125
  */
126
126
  removeAt: function(idx) {
127
127
  if ((idx < 0) || (idx >= this.get('length'))) throw SC.OUT_OF_RANGE_EXCEPTION;
128
+ var ret = this.objectAt(idx) ;
128
129
  this.replace(idx,1,[]);
129
- return this ;
130
+ return ret ;
130
131
  },
131
132
 
132
133
  /**
@@ -198,8 +199,35 @@ SC.Array = {
198
199
  if (ary.objectAt(loc) != this.objectAt(loc)) return false ;
199
200
  }
200
201
  return true ;
202
+ },
203
+
204
+ /**
205
+ Invoke the passed method and arguments on the member elements as long as
206
+ the value returned is the first argument.
207
+
208
+ @param {Object} retValue the expected return value
209
+ @param {String} methodName the method to call
210
+ @returns {Object} the return value of the last time the method was
211
+ invoked.
212
+ */
213
+ invokeWhile: function(retValue, methodName) {
214
+ var ret ;
215
+ var args = $A(arguments) ;
216
+ retValue = args.shift() ;
217
+ methodName = args.shift() ;
218
+
219
+ try {
220
+ this._each(function(item) {
221
+ var func = (item) ? item[methodName] : null ;
222
+ ret = func.apply(item, args) ;
223
+ if (ret != retValue) throw $break ;
224
+ });
225
+ } catch (e) {
226
+ if (e != $break) throw e ;
227
+ }
228
+ return ret ;
201
229
  }
202
-
230
+
203
231
  } ;
204
232
 
205
233
  // All arrays have the SC.Array mixin. Do this before we add the
@@ -279,21 +307,15 @@ Object.extend(Array.prototype, {
279
307
  return ret ;
280
308
  },
281
309
 
282
- map: function(iterator) {
283
- var ret = [] ;
284
- try {
285
- for(var index=0;index<this.length;index++) {
286
- var item = this[index] ;
287
- ret.push((iterator || Prototype.K).call(item,item,index)) ;
288
- } ;
289
- } catch (e) {
290
- if (e != $break) throw e ;
291
- }
292
- return ret ;
293
- },
294
-
295
- // This will invoke the passed method and arguments on the member elements
296
- // as long as the value returned is the first argument.
310
+ /*
311
+ Invoke the passed method and arguments on the member elements as long as
312
+ the value returned is the first argument.
313
+
314
+ @param {Object} retValue the expected return value
315
+ @param {String} methodName the method to call
316
+ @returns {Object} the return value of the last time the method was
317
+ invoked.
318
+ */
297
319
  invokeWhile: function(retValue, methodName) {
298
320
  var ret ;
299
321
  var args = $A(arguments) ;
@@ -313,6 +335,20 @@ Object.extend(Array.prototype, {
313
335
  return ret ;
314
336
  },
315
337
 
338
+ map: function(iterator) {
339
+ var ret = [] ;
340
+ try {
341
+ for(var index=0;index<this.length;index++) {
342
+ var item = this[index] ;
343
+ ret.push((iterator || Prototype.K).call(item,item,index)) ;
344
+ } ;
345
+ } catch (e) {
346
+ if (e != $break) throw e ;
347
+ }
348
+ return ret ;
349
+ },
350
+
351
+
316
352
  // If you ask for an unknown property, then try to collect the value
317
353
  // from member items.
318
354
  unknownProperty: function(key, value) {
@@ -328,17 +364,12 @@ Array.prototype.collect = Array.prototype.map ;
328
364
  // Returns the passed item as an array. If the item is already an array,
329
365
  // it is returned as is. If it is not an array, it is placed into one. If
330
366
  // it is null, an empty array is returned.
331
- Array.asArray = function (array)
332
- {
333
- if(array && !(array instanceof Array))
334
- {
367
+ Array.asArray = function (array) {
368
+ if(array &&
369
+ ((array.length === undefined) || ($type(array) == T_FUNCTION))) {
335
370
  return [array];
336
371
  }
337
- if(array)
338
- {
339
- return array;
340
- }
341
- return [];
372
+ return (array) ? array : [] ;
342
373
  };
343
374
 
344
375
  // Alias for asArray
@@ -0,0 +1,265 @@
1
+ // ========================================================================
2
+ // SproutCore
3
+ // copyright 2006-2008 Sprout Systems, Inc.
4
+ // ========================================================================
5
+
6
+ /**
7
+ Indicates a value has a mixed state of both on and off.
8
+ */
9
+ SC.MIXED_STATE = '__MIXED__' ;
10
+
11
+ /**
12
+ @namespace
13
+
14
+ A Control is a view that also implements some basic state functionality.
15
+ Apply this mixin to any view that you want to have standard control
16
+ functionality including showing a selected state, enabled state, focus
17
+ state, etc.
18
+
19
+ h2. About Values and Content
20
+
21
+ Controls typically are used to represent a single value, such as a number,
22
+ boolean or string. The value a control is managing is typically stored in
23
+ a "value" property. You will typically use the value property when working
24
+ with controls such as buttons and text fields in a form.
25
+
26
+ An alternative way of working with a control is to use it to manage some
27
+ specific aspect of a content object. For example, you might use a label
28
+ view control to display the "name" property of a Contact record. This
29
+ approach is often necessary when using the control as part of a collection
30
+ view.
31
+
32
+ You can use the content-approach to work with a control by setting the
33
+ "content" and "contentValueKey" properties of the control. The
34
+ "content" property is the content object you want to manage, while the
35
+ "contentValueKey" is the name of the property on the content object
36
+ you want the control to display.
37
+
38
+ The default implementation of the Control mixin will essentially map the
39
+ contentValueKey of a content object to the value property of the
40
+ control. Thus if you are writing a custom control yourself, you can simply
41
+ work with the value property and the content object support will come for
42
+ free. Just write an observer for the value property and update your
43
+ view accordingly.
44
+
45
+ If you are working with a control that needs to display multiple aspects
46
+ of a single content object (for example showing an icon and label), then
47
+ you can override the contentValueDidChange() method instead of observing
48
+ the value property. This method will be called anytime _any_ property
49
+ on the content object changes. You should use this method to check the
50
+ properties you care about on the content object and update your view if
51
+ anything you care about has changed.
52
+
53
+ h2. Delegate Support
54
+
55
+ Controls can optionally get the contentDisplayProperty from a
56
+ displayDelegate, if it is set. The displayDelegate is often used to
57
+ delegate common display-related configurations such as which content value
58
+ to show. Anytime your control is shown as part of a collection view, the
59
+ collection view will be automatically set as its displayDelegate.
60
+
61
+ */
62
+ SC.Control = {
63
+
64
+ initMixin: function() {
65
+ this._contentObserver(); // setup content observing if needed.
66
+ this.isSelectedObserver() ;
67
+ this.isEnabledObserver() ;
68
+ this.isFocusedObserver();
69
+ },
70
+
71
+ /**
72
+ Set to true when the item is selected.
73
+
74
+ This property is observable and bindable.
75
+ */
76
+ isSelected: false,
77
+ isSelectedBindingDefault: SC.Binding.OneWayBool,
78
+
79
+ /**
80
+ Set to true when the item is enabled.
81
+
82
+ This property is observable and bindable.
83
+ */
84
+ isEnabled: true,
85
+ isEnabledBindingDefault: SC.Binding.OneWayBool,
86
+
87
+ /**
88
+ The value represented by this control.
89
+
90
+ Most controls represent a value of some type, such as a number, string
91
+ or image URL. This property should hold that value. It is bindable
92
+ and observable. Changing this value will immediately change the
93
+ appearance of the control. Likewise, editing the control
94
+ will immediately change this value.
95
+
96
+ If instead of setting a single value on a control, you would like to
97
+ set a content object and have the control display a single property
98
+ of that control, then you should use the content property instead.
99
+ */
100
+ value: null,
101
+
102
+ /**
103
+ The content object represented by this control.
104
+
105
+ Often you need to use a control to display some single aspect of an
106
+ object, especially if you are using the control as an item view in a
107
+ collection view.
108
+
109
+ In those cases, you can set the content and contentValueKey for the
110
+ control. This will cause the control to observe the content object for
111
+ changes to the value property and then set the value of that property
112
+ on the "value" property of this object.
113
+
114
+ Note that unless you are using this control as part of a form or
115
+ collection view, then it would be better to instead bind the value of
116
+ the control directly to a controller property.
117
+ */
118
+ content: null,
119
+
120
+ /**
121
+ The property on the content object that would want to represent the
122
+ value of this control. This property should only be set before the
123
+ content object is first set. If you have a displayDelegate, then
124
+ you can also use the contentValueKey of the displayDelegate.
125
+ */
126
+ contentValueKey: null,
127
+
128
+ /**
129
+ Invoked whenever any property on the content object changes.
130
+
131
+ The default implementation will update the value property of the view
132
+ if the contentValueKey property has changed. You can override this
133
+ method to implement whatever additional changes you would like.
134
+
135
+ The key will typically contain the name of the property that changed or
136
+ '*' if the content object itself has changed. You should generally do
137
+ a total reset of '*' is changed.
138
+
139
+ @param {Object} target the content object
140
+ @param {String} key the property that changes
141
+ */
142
+ contentPropertyDidChange: function(target, key) {
143
+ if (!!this._contentValueKey && ((key == this._contentValueKey) || (key == '*'))) {
144
+ var content = this.get('content') ;
145
+ var value = (content) ? content.get(this._contentValueKey) : null;
146
+ if (value != this._contentValue) {
147
+ this._contentValue = value ;
148
+ this.set('value', value) ;
149
+ }
150
+ }
151
+ },
152
+
153
+ /**
154
+ Relays changes to the value back to the content object if you are using
155
+ a content object.
156
+
157
+ This observer is triggered whenever the value changes. It will only do
158
+ something if it finds you are using the content property and
159
+ contentValueKey and the new value does not match the old value of the
160
+ content object.
161
+
162
+ If you are using contentValueKey in some other way than typically
163
+ implemented by this mixin, then you may want to override this method as
164
+ well.
165
+ */
166
+ updateContentWithValueObserver: function() {
167
+ if (!this._contentValueKey) return; // do nothing if disabled
168
+
169
+ // get value. return if value matches current content value.
170
+ // this avoids infinite loops where setting the value from the content
171
+ // in turns sets the content and so on.
172
+ var value = this.get('value') ;
173
+ if (value == this._contentValue) return ;
174
+
175
+ var content = this.get('content') ;
176
+ if (!content) return; // do nothing if no content.
177
+
178
+ // passed all of our checks, update the content (and the _contentValue
179
+ // to avoid infinite loops)
180
+ this._contentValue = value ;
181
+ content.set(this._contentValueKey, value) ;
182
+
183
+ }.observes('value'),
184
+
185
+ /**
186
+ Default observer for selected state changes
187
+
188
+ The default will simply add either a "mixed" or "sel" class name to the
189
+ root element of your view based on the state. You can override this with
190
+ your own behavior if you prefer.
191
+ */
192
+ isSelectedObserver: function() {
193
+ var sel = this.get('isSelected') ;
194
+ this.setClassName('mixed', sel == SC.MIXED_STATE) ;
195
+ this.setClassName('sel', sel && (sel != SC.MIXED_STATE)) ;
196
+ }.observes('isSelected'),
197
+
198
+ /**
199
+ Default observer for the isEnabled state.
200
+
201
+ The default will simply add or remove a "disabled" class name to the root
202
+ element of your view based on the state. You can override this with your
203
+ own behavior if you prefer.
204
+ */
205
+ isEnabledObserver: function() {
206
+ var disabled = !this.get('isEnabled') ;
207
+ this.setClassName('disabled', disabled);
208
+
209
+ // set disabled attr as well if relevant
210
+ if (this.rootElement && (this.rootElement.disabled !== undefined) && (this.rootElement.disabled != disabled)) {
211
+ this.rootElement.disabled = disabled ;
212
+ }
213
+ }.observes('isEnabled'),
214
+
215
+ /**
216
+ Default observer for the isFirstResponder state.
217
+
218
+ The default will add or remove a "focus" class name ot the root element
219
+ of your view based on the state. You can override this with your own
220
+ behavior if you prefer.
221
+ */
222
+ isFocusedObserver: function() {
223
+ this.setClassName('focus', !!this.get('isFirstResponder')) ;
224
+ }.observes('isFirstResponder'),
225
+
226
+ // This should be null so that if content is also null, the
227
+ // _contentObserver won't do anything on init.
228
+ _content: null,
229
+
230
+ /** @private
231
+ Observes when a content object has changed and handles notifying
232
+ changes to the value of the content object.
233
+ */
234
+ _contentObserver: function() {
235
+ var content = this.get('content') ;
236
+ if (this._content == content) return; // nothing changed
237
+
238
+ // create bound observer function
239
+ if (!this._boundContentPropertyDidChangeObserver) {
240
+ this._boundContentPropertyDidChangeObserver = this.contentPropertyDidChange.bind(this) ;
241
+ }
242
+ var f = this._boundContentPropertyDidChangeObserver ;
243
+
244
+ // remove an observer from the old content if necessary
245
+ if (this._content && this._content.removeObserver) {
246
+ this._content.removeObserver('*', f) ;
247
+ }
248
+
249
+ // cache for future use
250
+ var del = this.displayDelegate ;
251
+ this._contentValueKey = this.getDelegateProperty(del, 'contentValueKey');
252
+
253
+
254
+ // add observer to new content if necessary.
255
+ this._content = content ;
256
+ if (this._content && this._content.addObserver) {
257
+ this._content.addObserver('*', f) ;
258
+ }
259
+
260
+ // notify that value did change.
261
+ this.contentPropertyDidChange(this._content, '*') ;
262
+
263
+ }.observes('content')
264
+
265
+ };