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
@@ -1,6 +1,6 @@
1
1
  // ========================================================================
2
2
  // SproutCore
3
- // copyright 2006-2007 Sprout Systems, Inc.
3
+ // copyright 2006-2008 Sprout Systems, Inc.
4
4
  // ========================================================================
5
5
 
6
6
  require('views/view') ;
@@ -1,34 +1,74 @@
1
1
  // ==========================================================================
2
- // Sproutcore.ScrollView
2
+ // SC.ScrollView
3
3
  // ==========================================================================
4
4
 
5
+ require('mixins/scrollable') ;
5
6
  require('views/container') ;
6
7
 
7
- /** @class
8
+ /**
9
+ @class
8
10
 
9
- The scroll view is used throughout SproutCore anytime you need to display
10
- content that can be scrolled. Although you can make any div scrollable in
11
- HTML using CSS, SC.ScrollView provides a number of additional advantages
12
- including support for incremental rendering, auto-scrolling during a
13
- drag operations and support for custom scroll bars.
14
-
15
- Scroll views are generally included automatically if you use the built-in
16
- view helpers in SproutCore. Depending on the views you are writing, you may
17
- want to use scroll views yourself as well. The following sections describe
18
- how you can use the scroll view to support incremental rendering and auto-
19
- scrolling dragging.
20
-
21
- h3. Using Scroll Views for Incremental Rendering
11
+ Scroll Views are used throughout SproutCore to provide scrollable areas.
12
+ Although you can use overflow: auto to provide scrollbar anywhere, using
13
+ a ScrollView is preferrable because it will also notify child views anytime
14
+ the view is scrolled.
22
15
 
23
- Coming Soon...
24
-
25
16
  @extends SC.View
26
17
  @author Charles Jolley
27
18
  @version 1.0
28
19
  */
29
- SC.ScrollView = SC.View.extend(
30
- /** @scope SC.ScrollView.prototype */ {
20
+ SC.ScrollView = SC.ContainerView.extend(SC.Scrollable, {
21
+
22
+ emptyElement: '<div class="sc-scroll-view"></div>',
23
+
24
+ /**
25
+ Determines if the view should be scrollable vertically.
26
+
27
+ If this property is set to NO then the vertical scrollbar will always
28
+ be hidden.
29
+
30
+ @field
31
+ */
32
+ canScrollVertical: YES,
31
33
 
32
- emptyElement: '<div class="sc-scroll-view"></div>'
34
+ /**
35
+ Determines if the view should be scrollable horizontally.
36
+
37
+ If this property is set to NO then the horizontal scrollbale will always
38
+ be hidden.
33
39
 
40
+ @field
41
+ */
42
+ canScrollHorizontal: NO,
43
+
44
+ _canScrollVerticalObserver: function() {
45
+ this.setClassName('sc-scroll-vertical', this.get('canScrollVertical'));
46
+ }.observes('canScrollVertical'),
47
+
48
+ _canScrollHorizontalObserver: function() {
49
+ this.setClassName('sc-scroll-horizontal', this.get('canScrollHorizontal'));
50
+ }.observes('canScrollHorizontal'),
51
+
52
+ init: function() {
53
+ arguments.callee.base.apply(this, arguments) ;
54
+ this._canScrollVerticalObserver() ;
55
+ this._canScrollHorizontalObserver() ;
56
+ },
57
+
58
+ // auto fit child view based on which scrollviews are visible
59
+ resizeChildrenWithOldSize: function(oldSize) {
60
+ var v = this.get('firstChild') ;
61
+ if (v) {
62
+ var f = v.get('frame');
63
+ var orig = Object.clone(f) ;
64
+ var innerFrame = this.get('innerFrame') ;
65
+ f.x = f.y = 0 ;
66
+ if (!this.get('canScrollHorizontal')) f.width = innerFrame.width ;
67
+ if (!this.get('canScrollVertical')) f.height = innerFrame.height ;
68
+ if (!SC.rectsEqual(f, orig)) v.set('frame', f) ;
69
+ }
70
+ }
71
+
34
72
  }) ;
73
+
74
+
@@ -1,6 +1,6 @@
1
1
  // ========================================================================
2
2
  // SproutCore
3
- // copyright 2006-2007 Sprout Systems, Inc.
3
+ // copyright 2006-2008 Sprout Systems, Inc.
4
4
  // ========================================================================
5
5
 
6
6
  require('views/view') ;
@@ -0,0 +1,132 @@
1
+ // ==========================================================================
2
+ // SC.SliderView
3
+ // ==========================================================================
4
+
5
+ require('views/view');
6
+ require('mixins/control');
7
+
8
+ /** @class
9
+
10
+ A SliderView shows a horizontal slider control that you can use to set
11
+ variable values.
12
+
13
+ You can use a slider view much like you would any other control. Simply
14
+ set the value or content/contentValueKey to whatever value you want to
15
+ display. You can also set the maximumValue and minValue properties to determine
16
+ the mapping of the control to its children.
17
+
18
+ @extends SC.View
19
+ @extends SC.Control
20
+
21
+ @author Charles Jolley
22
+ @version 1.0
23
+ */
24
+ SC.SliderView = SC.View.extend(SC.Control,
25
+ /** @scope SC.SliderView.prototype */ {
26
+
27
+ emptyElement: '<span class="sc-slider-view"><span class="inner"><img src="%@" class="sc-handle" /></span></span>'.fmt(static_url('blank')),
28
+
29
+ /** @private */
30
+ outlets: ['handleElement'],
31
+
32
+ /**
33
+ The DOM element that displays the handle.
34
+ */
35
+ handleElement: '.sc-handle?',
36
+
37
+ /**
38
+ The minimum value of the slider.
39
+ */
40
+ minimum: 0,
41
+
42
+ /**
43
+ The maximum value of the slider.
44
+ */
45
+ maximum: 1.0,
46
+
47
+ /**
48
+ Optionally set to the minimum step size allowed.
49
+
50
+ All values will be rounded to this step size when displayed.
51
+ */
52
+ step: 0.1,
53
+
54
+ /**
55
+ The value of the slider. Set this property or the content property.
56
+ */
57
+ value: 0.50,
58
+
59
+ /** @private */
60
+ valueBindingDefault: SC.Binding.SingleNotEmpty,
61
+
62
+ _valueDidChangeObserver: function() {
63
+ if (!this.didChangeFor('value', 'value', 'minimum', 'maximum')) return;
64
+
65
+
66
+ var min = this.get('minimum') ;
67
+ var max = this.get('maximum') ;
68
+ var value = this.get('value') ;
69
+
70
+ // constrain value. If value did not match, set it back.
71
+ var constrained = Math.min(Math.max(value, min), max) ;
72
+
73
+ var step = this.get('step') ;
74
+ if (step && step !== 0) {
75
+ constrained = Math.round(constrained / step) * step ;
76
+ }
77
+
78
+ if (Math.abs(value - constrained) > 0.01) this.set('value', constrained) ;
79
+ value = constrained ;
80
+
81
+ // determine the percent across
82
+ value = (value - min) / (max - min) ;
83
+
84
+
85
+ // convert to a value within the width of the receiver's innerFrame.
86
+ var f = this.get('innerFrame') ;
87
+ value = Math.round((f.width-18) * value) ;
88
+
89
+ // set handle. This assumes the handle is centered over its origin.
90
+ // adjust by 48px since this lives inside the inner div. Also the
91
+ // divider is shown shifted by 8 so account for that also.
92
+ value -= (39) ;
93
+ Element.setStyle(this.handleElement, { left: '%@px'.fmt(value) }) ;
94
+
95
+ }.observes('value', 'minimum', 'maximum'),
96
+
97
+ mouseDown: function(evt) {
98
+
99
+ if (!this.get('isEnabled')) return true ; // nothing to do
100
+
101
+ // add active class
102
+ this.addClassName('active') ;
103
+
104
+ // find new location -- adjust from left edge of display.
105
+ var loc = this.convertFrameFromView(Event.pointerLocation(evt), null).x ;
106
+ var f = this.get('innerFrame') ;
107
+ loc -= (f.x + 9) ;
108
+
109
+ // find percent across
110
+ var value = loc / (f.width - 18) ;
111
+
112
+ // convert to value and constrain
113
+ var min = this.get('minimum') ;
114
+ var max = this.get('maximum') ;
115
+ value = (value * (max - min)) + min ;
116
+ value = Math.min(Math.max(value, min), max) ;
117
+
118
+ this.setIfChanged('value', value) ;
119
+
120
+ return true;
121
+ },
122
+
123
+ // mouseDragged uses same technique as mouseDown.
124
+ mouseDragged: function(evt) { return this.mouseDown(evt); },
125
+
126
+ // remove active class
127
+ mouseUp: function(evt) {
128
+ this.removeClassName('active') ;
129
+ }
130
+
131
+
132
+ }) ;
@@ -0,0 +1,130 @@
1
+ // ==========================================================================
2
+ // SC.ListItemView
3
+ // ==========================================================================
4
+
5
+ require('views/view') ;
6
+ require('mixins/delegate_support');
7
+ require('mixins/control') ;
8
+ require('views/button/disclosure');
9
+
10
+ /** @class
11
+
12
+ Displays a group view in a source list. Handles displaying a disclosure
13
+ triangle which can be used to show/hide children.
14
+
15
+ @extends SC.View
16
+ @extends SC.DelegateSupport
17
+ @author Charles Jolley
18
+ @version 0.1
19
+ */
20
+
21
+ SC.SourceListGroupView = SC.View.extend(SC.Control, SC.DelegateSupport, {
22
+
23
+ emptyElement: ['<div class="sc-source-list-group">',
24
+ '<a href="javascript:;" class="sc-source-list-label sc-disclosure-view sc-button-view button disclosure no-disclosure">',
25
+ '<img src="%@" class="button" />'.fmt(static_url('blank')),
26
+ '<span class="label"></span></a>',
27
+ '</div>'].join(''),
28
+
29
+ /**
30
+ The group value to display for this group.
31
+ */
32
+ content: null,
33
+
34
+ /**
35
+ The current group visibility. Used by the source list to determine
36
+ the layout size of the group.
37
+ */
38
+ isGroupVisible: YES,
39
+
40
+ /**
41
+ YES if group is showing its titlebar.
42
+
43
+ Group views will typically hide their header if the content is set to
44
+ null. You can also override this method to always hide the header if
45
+ you want and the SourceListView will not leave room for it.
46
+ */
47
+ hasGroupTitle: YES,
48
+
49
+ groupTitleKey: null,
50
+
51
+ groupVisibleKey: null,
52
+
53
+ contentPropertyDidChange: function(target, key) {
54
+ var content = this.get('content') ;
55
+ var labelView = this.outlet('labelView') ;
56
+
57
+ // hide labelView if content is null.
58
+ if (content == null) {
59
+ labelView.setIfChanged('isVisible', NO) ;
60
+ this.setIfChanged('hasGroupTitle', NO) ;
61
+ return ;
62
+ } else {
63
+ labelView.setIfChanged('isVisible', YES) ;
64
+ this.setIfChanged('hasGroupTitle', YES) ;
65
+ }
66
+
67
+ // set the title if that changed.
68
+ var groupTitleKey = this.getDelegateProperty(this.displayDelegate, 'groupTitleKey') ;
69
+ if ((key == '*') || (groupTitleKey && (key == groupTitleKey))) {
70
+ var title = (content && content.get && groupTitleKey) ? content.get(groupTitleKey) : content;
71
+ if (title != this._title) {
72
+ this._title = title ;
73
+ if (title) title = title.capitalize() ;
74
+ labelView.set('title', title) ;
75
+ }
76
+ }
77
+
78
+ // set the group visibility if changed
79
+ var groupVisibleKey = this.getDelegateProperty(this.displayDelegate, 'groupVisibleKey') ;
80
+ if ((key == '*') || (groupVisibleKey && (key == groupVisibileKey))) {
81
+
82
+ if (groupVisibleKey) {
83
+
84
+ labelView.removeClassName('no-disclosure') ;
85
+
86
+ var isVisible = (content && content.get) ? !!content.get(groupVisibleKey) : YES ;
87
+ if (isVisible != this.get('isGroupVisible')) {
88
+ this.set('isGroupVisible', isVisible) ;
89
+ labelView.set('value', isVisible) ;
90
+ }
91
+
92
+ } else labelView.addClassName('no-disclosure') ;
93
+ }
94
+ },
95
+
96
+ // called when the user clicks on the disclosure triangle
97
+ disclosureValueDidChange: function(newValue) {
98
+ if (newValue == this.get('isGroupVisible')) return; // nothing to do
99
+
100
+ // update group if necessary
101
+ var group = this.get('content') ;
102
+ var groupVisibleKey = this.getDelegateProperty(this.displayDelegate, 'groupVisibleKey') ;
103
+ if (group && group.set && groupVisibleKey) {
104
+ group.set(groupVisibleKey, newValue) ;
105
+ }
106
+
107
+ // update my own value and then update my collection view.
108
+ this.set('isGroupVisible', newValue) ;
109
+ if (this.owner && this.owner.updateChildren) this.owner.updateChildren(true) ;
110
+
111
+ },
112
+
113
+ /** @private */
114
+ labelView: SC.DisclosureView.extend({
115
+
116
+ /**
117
+ Always default to open disclosures.
118
+ */
119
+ value: YES,
120
+
121
+ // if the disclosure value changes, call the owner's method. Note
122
+ // normally you would do this with a binding, but since this is a semi-
123
+ // private class anyway, there is no reason to go to all that trouble.
124
+ _valueObserver: function() {
125
+ if (this.owner) this.owner.disclosureValueDidChange(this.get('value'));
126
+ }.observes('value')
127
+
128
+ }).outletFor('.sc-source-list-label:1:1')
129
+
130
+ }) ;
@@ -1,6 +1,6 @@
1
1
  // ========================================================================
2
2
  // SproutCore
3
- // copyright 2006-2007 Sprout Systems, Inc.
3
+ // copyright 2006-2008 Sprout Systems, Inc.
4
4
  // ========================================================================
5
5
 
6
6
  require('views/view') ;
@@ -0,0 +1,292 @@
1
+ // ========================================================================
2
+ // SproutCore
3
+ // copyright 2006-2008 Sprout Systems, Inc.
4
+ // ========================================================================
5
+
6
+ require('views/view') ;
7
+ require('mixins/delegate_support');
8
+
9
+ SC.HORIZONTAL = 'horizontal' ;
10
+ SC.VERTICAL = 'vertical' ;
11
+
12
+ /**
13
+ @class
14
+
15
+ A split view is used to show views that the user can resize or collapse.
16
+ To use the split view, you need to add the child views you want layed out
17
+ separated by divider views (instances of SC.SplitDividerView).
18
+
19
+ When the user clicks and drags on a divider view, it will automatically
20
+ resize the views immediately before and after the view. You can constrain
21
+ the resizing allowed by the split view either by setting a minThickness and
22
+ maxThickness property on the views themselves or by implementing methods
23
+ on a delegate object.
24
+
25
+ In addition to resizing views, users can also collapse views by double
26
+ clicking on a divider view. When a view is collapsed, it's isVisible
27
+ property is set to NO and its space it removed from the view. Double
28
+ clicking on a divider again will restore a collapse view. A user can also
29
+ start to drag the divider to show the collapsed view.
30
+
31
+ You can programmatically control collapsing behavior by setting the
32
+ canCollapseViews property on the SplitView, a canCollapse property on each
33
+ child view, or by implementing the appropriate delegate method.
34
+
35
+ Finally, SplitViews can layout their child views either horizontally or
36
+ vertically. To choose the direction of layout set the layoutDirection
37
+ property on the view. This property should be set when the view is created.
38
+ Changing it dynamically will have an unknown effect.
39
+
40
+ @extends SC.View
41
+ @extends SC.DelegateSupport
42
+
43
+ @author Charles Jolley
44
+ */
45
+ SC.SplitView = SC.View.extend(SC.DelegateSupport,
46
+ /** @scope SC.SplitView.prototype */ {
47
+
48
+ emptyElement: '<div class="sc-split-view"></div>',
49
+
50
+ /**
51
+ delegate for controlling split view behavior.
52
+ */
53
+ delegate: null,
54
+
55
+ /**
56
+ Direction of layout. Must be SC.HORIZONTAL || SC.VERTICAL.
57
+ */
58
+ layoutDirection: SC.HORIZONTAL,
59
+
60
+ /**
61
+ Set to NO to disable collapsing for all views.
62
+ */
63
+ canCollapseViews: YES,
64
+
65
+ /**
66
+ Used by split divider to decide if the view can be collapsed.
67
+ */
68
+ canCollapseView: function(view) {
69
+ if (!this.get('canCollapseViews')) return NO ;
70
+ if (view.get('canCollapse') === NO) return NO ;
71
+ return this.invokeDelegateMethod(this.delegate, 'splitViewCanCollapse', this, view) ;
72
+ },
73
+
74
+ /**
75
+ One view in your array must have a flexible width to allow proper
76
+ resizing. You can set this view manually with this outlet or you can
77
+ just let the split view choose the center-most view.
78
+
79
+ Views to the left/top of this view will be anchored to the left/top of
80
+ the parent view. Views to the right/bottom of this view will be anchored
81
+ to the right/bottom.
82
+ */
83
+ flexibleView: null,
84
+
85
+ /**
86
+ Sets the thickness of the named view and then lays out the rest of the
87
+ views.
88
+
89
+ @param {SC.View} view the view to adjust. Must not be a divider.
90
+ @param {Number} offset the new desired offset
91
+ @returns the actual allowed offset
92
+ */
93
+ setThicknessForView: function(view, thickness) {
94
+ if (view.get('parentNode') != this) {
95
+ throw "view must belong to reciever (view: %@)".fmt(view);
96
+ }
97
+
98
+ var direction = this.get('layoutDirection') ;
99
+
100
+ // constrain to thickness set on view.
101
+ var max = view.get('maxThickness') ;
102
+ var min = view.get('minThickness') ;
103
+ if (max != null) thickness = Math.min(max, thickness) ;
104
+ if (min != null) thickness = Math.max(min, thickness) ;
105
+
106
+ // constrain to thickness determined by delegate.
107
+ thickness = this.invokeDelegateMethod(this.delegate, 'splitViewConstrainThickness', this, view, thickness) ;
108
+
109
+ // thickness cannot be greater than the total of all the other views (
110
+ // except for the flexibleView) added together.
111
+ var total = this.get('innerFrame') ;
112
+ available = (direction == SC.HORIZONTAL) ? total.width : total.height ;
113
+ var views = this.get('childNodes') ;
114
+ var idx = view.length ;
115
+ var flexibleView = this.get('flexibleView') ;
116
+ while(--idx >= 0) {
117
+ var currentView = views[idx] ;
118
+ if ((currentView != view) && (currentView != flexibleView)) {
119
+ available -= this.thicknessForView(currentView) ;
120
+ }
121
+ }
122
+ thickness = Math.min(thickness, available) ;
123
+
124
+ // cannot be less than 0
125
+ thickness = Math.max(0, thickness) ;
126
+
127
+ // now apply constrained value
128
+ if (thickness != this.thicknessForView(view)) {
129
+
130
+ // un-collapse if needed.
131
+ view.set('isCollapsed', (thickness <= 0)) ;
132
+
133
+ // set new frame
134
+ var f = (direction === SC.HORIZONTAL) ? { width: thickness } : { height: thickness } ;
135
+ view.set('frame', f) ;
136
+
137
+ // and layout
138
+ this.layout() ;
139
+ }
140
+
141
+ },
142
+
143
+ /**
144
+ Returns the thickness for a given view.
145
+
146
+ @param {SC.View} view the view to get.
147
+ @returns the view with the width.
148
+ */
149
+ thicknessForView: function(view) {
150
+ var direction = this.get('layoutDirection') ;
151
+ var ret = view.get('frame') ;
152
+ return (direction === SC.HORIZONTAL) ? ret.width : ret.height ;
153
+ },
154
+
155
+ /**
156
+ Finds the flexible view.
157
+
158
+ This will use the flexibleView property if you set it or use the center
159
+ most view that is not a divider.
160
+ */
161
+ computeFlexibleView: function() {
162
+ var flexibleView = this.get('flexibleView') ;
163
+ if (!flexibleView) {
164
+ var views = this.get('childNodes') ;
165
+ flexibleView = views[Math.ceil(views.length/2)] ;
166
+ }
167
+
168
+ // If the flexible view is a divider, find the first non-g.
169
+ while(flexibleView && (flexibleView instanceof SC.SplitDividerView)) {
170
+ flexibleView = flexibleView.get('nextSibling') ;
171
+ }
172
+
173
+ return flexibleView;
174
+ },
175
+
176
+ /**
177
+ Layout the views.
178
+
179
+ This method needs to be called anytime you change the view thicknesses
180
+ to make sure they are arranged properly. This will setup the views so
181
+ that they can resize appropriately.
182
+ */
183
+ layout: function() {
184
+
185
+ var views = this.get('childNodes') ;
186
+
187
+ // find the flexible view, if it is not set.
188
+ var flexibleView = this.computeFlexibleView();
189
+
190
+ // everything before the flexible view is anchored to the left/top
191
+ var direction = this.get('layoutDirection') ;
192
+ var view = views[0];
193
+ var offset = 0 ;
194
+ while(view && (view !== flexibleView)) {
195
+ var isCollapsed = view.get('isCollapsed') || NO ;
196
+ view.setIfChanged('isVisible', !isCollapsed) ;
197
+ if (!isCollapsed) {
198
+ view.viewFrameWillChange() ;
199
+ if (direction == SC.HORIZONTAL) {
200
+ view.setIfChanged('styleLeft', offset) ;
201
+ view.setIfChanged('styleRight', null) ;
202
+ } else {
203
+ view.setIfChanged('styleTop', offset) ;
204
+ view.setIfChanged('styleBottom', null) ;
205
+ }
206
+ view.viewFrameDidChange() ;
207
+
208
+ offset += this.thicknessForView(view) ;
209
+ }
210
+ view = view.get('nextSibling') ;
211
+ }
212
+
213
+ var flexHead = offset ;
214
+
215
+ // everything after the flexible view is anchored to the right/bottom.
216
+ var view = views.last() ;
217
+ var offset = 0;
218
+ while(view && (view !== flexibleView)) {
219
+ var isCollapsed = view.get('isCollapsed') || NO ;
220
+ view.setIfChanged('isVisible', !isCollapsed) ;
221
+ if (!isCollapsed) {
222
+ view.viewFrameWillChange() ;
223
+ if (direction == SC.HORIZONTAL) {
224
+ view.setIfChanged('styleLeft', null) ;
225
+ view.setIfChanged('styleRight', offset) ;
226
+ } else {
227
+ view.setIfChanged('styleTop', null) ;
228
+ view.setIfChanged('styleBottom', offset) ;
229
+ }
230
+ view.viewFrameDidChange() ;
231
+
232
+ offset += this.thicknessForView(view) ;
233
+ }
234
+ view = view.get('previousSibling') ;
235
+ }
236
+
237
+ var flexTail = offset ;
238
+
239
+ if (flexibleView) {
240
+ view = flexibleView ;
241
+ view.viewFrameWillChange() ;
242
+ if (direction == SC.HORIZONTAL) {
243
+ view.setIfChanged('styleLeft', flexHead) ;
244
+ view.setIfChanged('styleRight', flexTail) ;
245
+ view.setIfChanged('styleWidth', null) ;
246
+ } else {
247
+ view.setIfChanged('styleTop', flexHead) ;
248
+ view.setIfChanged('styleBottom', flexTail) ;
249
+ view.setIfChanged('styleHeight', null) ;
250
+ }
251
+ view.viewFrameDidChange() ;
252
+ }
253
+
254
+ },
255
+
256
+ /**
257
+ (DELEGATE) Control whether a view can be collapsed.
258
+
259
+ The default implemention returns YES.
260
+
261
+ @param {SC.SplitView} splitView the split view
262
+ @param {SC.View} view the view we want to collapse.
263
+ @returns {Boolean} YES to allow collapse.
264
+ */
265
+ splitViewCanCollapse: function(splitView, view) { return YES; },
266
+
267
+ /**
268
+ (DELEGATE) Constrain a views allowed thickness.
269
+
270
+ The default implementation allows any thickness. The view will
271
+ automatically constrain the view to not allow views to overflow the
272
+ visible area.
273
+
274
+ @param {SC.SplitView} splitView the split view
275
+ @param {SC.View} view the view in question
276
+ @param {Number} proposedThickness the proposed thickness.
277
+ @returns the allowed thickness
278
+ */
279
+ splitViewConstrainThickness: function(splitView, view, proposedThickness) {
280
+ return proposedThickness;
281
+ },
282
+
283
+ /** @private */
284
+ init: function() {
285
+ arguments.callee.base.apply(this, arguments) ;
286
+ this.addClassName(this.get('layoutDirection')) ;
287
+ }
288
+
289
+
290
+ }) ;
291
+
292
+