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,21 +1,34 @@
1
1
  // ========================================================================
2
2
  // SproutCore
3
- // copyright 2006-2007 Sprout Systems, Inc.
3
+ // copyright 2006-2008 Sprout Systems, Inc.
4
4
  // ========================================================================
5
5
 
6
- require('views/field') ;
6
+ require('views/field/field') ;
7
7
 
8
- // A text field is an input element with type "text". This view adds support
9
- // for hinted values, etc.
10
- SC.TextFieldView = SC.FieldView.extend({
8
+ /**
9
+ @class
10
+
11
+ A text field is an input element with type "text". This view adds support
12
+ for hinted values, etc.
13
+
14
+ @extends SC.FieldView
15
+ @author Charles Jolley
16
+ */
17
+ SC.TextFieldView = SC.FieldView.extend(
18
+ /** @scope SC.TextFieldView.prototype */ {
11
19
 
12
20
  emptyElement: '<input type="text" value="" />',
13
21
 
14
22
  // PROPERTIES
15
- // set this property to the hinted value.
23
+
24
+ /**
25
+ The hint to display while the field is not active. Can be a loc key.
26
+ */
16
27
  hint: null,
17
28
 
18
- // automatically set by text field if the hint is current showing.
29
+ /**
30
+ automatically set to YES if the hint is currently showing.
31
+ */
19
32
  isHintShowing: false,
20
33
 
21
34
 
@@ -59,7 +72,10 @@ SC.TextFieldView = SC.FieldView.extend({
59
72
  this.resignFirstResponder() ;
60
73
  }
61
74
  },
62
-
75
+
76
+ /**
77
+ tied to the isEnabled state
78
+ */
63
79
  acceptsFirstResponder: function() {
64
80
  return this.get('isEnabled');
65
81
  }.property('isEnabled'),
@@ -70,6 +86,7 @@ SC.TextFieldView = SC.FieldView.extend({
70
86
 
71
87
  // when we become first responder, focus the text field if needed and
72
88
  // hide the hint text.
89
+ /** @private */
73
90
  didBecomeFirstResponder: function() {
74
91
 
75
92
  // focus the text field.
@@ -87,6 +104,7 @@ SC.TextFieldView = SC.FieldView.extend({
87
104
 
88
105
  // when we lose first responder, blur the text field if needed and show
89
106
  // the hint text if needed.
107
+ /** @private */
90
108
  willLoseFirstResponder: function() {
91
109
 
92
110
  if (this._isFocused) {
@@ -116,16 +134,19 @@ SC.TextFieldView = SC.FieldView.extend({
116
134
  },
117
135
 
118
136
  // field value updates...
137
+ /** @private */
119
138
  getFieldValue: function() {
120
139
  return this._value ;
121
140
  },
122
141
 
142
+ /** @private */
123
143
  setFieldValue: function(value) {
124
144
  if (this._value == value) return ;
125
145
  this._value = value ;
126
146
  this._updateFieldHint() ;
127
147
  },
128
148
 
149
+ /** @private */
129
150
  mouseDown: function(e)
130
151
  {
131
152
  e._stopWhenHandled = false;
@@ -133,6 +154,7 @@ SC.TextFieldView = SC.FieldView.extend({
133
154
  },
134
155
 
135
156
  // trap key-press events and notify as needed.
157
+ /** @private */
136
158
  keyDown: function(evt) {
137
159
  if (this._value != this.rootElement.value) {
138
160
  this._value = this.rootElement.value ;
@@ -143,6 +165,7 @@ SC.TextFieldView = SC.FieldView.extend({
143
165
  //return false;
144
166
  },
145
167
 
168
+ /** @private */
146
169
  keyUp: function() {
147
170
  if (this._value != this.rootElement.value) {
148
171
  this._value = this.rootElement.value ;
@@ -162,18 +185,44 @@ SC.TextFieldView = SC.FieldView.extend({
162
185
  // THESE ARE DUMMY IMPLEMENTATIONS OF THE REPONDER METHODS FOR KEYBOARD
163
186
  // ACTIONS HANDLED BY THE BROWSER. This avoids having the responder
164
187
  // bubble up these items.
188
+
189
+ /** @private */
165
190
  deleteBackward: function(evt) { evt._stopWhenHandled = false; return true; },
191
+
192
+ /** @private */
166
193
  deleteForward: function(evt) { evt._stopWhenHandled = false; return true; },
194
+
195
+ /** @private */
167
196
  moveLeft: function(evt) { evt._stopWhenHandled = false; return true; },
197
+
198
+ /** @private */
168
199
  moveRight: function(evt) { evt._stopWhenHandled = false; return true; },
200
+
201
+ /** @private */
169
202
  moveUp: function(evt) { evt._stopWhenHandled = false; return true; },
203
+
204
+ /** @private */
170
205
  moveDown: function(evt) { evt._stopWhenHandled = false; return true; },
206
+
207
+ /** @private */
171
208
  moveLeftAndModifySelection: function(evt) { evt._stopWhenHandled = false; return true; },
209
+
210
+ /** @private */
172
211
  moveRightAndModifySelection: function(evt) { evt._stopWhenHandled = false; return true; },
212
+
213
+ /** @private */
173
214
  moveUpAndModifySelection: function(evt) { evt._stopWhenHandled = false; return true; },
215
+
216
+ /** @private */
174
217
  moveDownAndModifySelection: function(evt) { evt._stopWhenHandled = false; return true; },
218
+
219
+ /** @private */
175
220
  moveToBeginningOfDocument: function(evt) { evt._stopWhenHandled = false; return true; },
221
+
222
+ /** @private */
176
223
  moveToEndOfDocument: function(evt) { evt._stopWhenHandled = false; return true; },
224
+
225
+ /** @private */
177
226
  selectAll: function(evt) { evt._stopWhenHandled = false; return true; }
178
227
 
179
228
  }) ;
@@ -1,11 +1,21 @@
1
1
  // ========================================================================
2
2
  // SproutCore
3
- // copyright 2006-2007 Sprout Systems, Inc.
3
+ // copyright 2006-2008 Sprout Systems, Inc.
4
4
  // ========================================================================
5
5
 
6
- require('views/text_field') ;
6
+ require('views/field/text_field') ;
7
7
 
8
- SC.TextareaFieldView = SC.TextFieldView.extend({
8
+ /**
9
+ @class
10
+
11
+ Manages a text area field.
12
+
13
+ @extends SC.TextFieldView
14
+ @author Skip Baney
15
+ @version 1.0
16
+ */
17
+ SC.TextareaFieldView = SC.TextFieldView.extend(
18
+ /** @scope SC.TextareaFieldView.prototype */ {
9
19
 
10
20
  emptyElement: '<textarea></textarea>',
11
21
 
@@ -1,9 +1,9 @@
1
1
  // ========================================================================
2
2
  // SproutCore
3
- // copyright 2006-2007 Sprout Systems, Inc.
3
+ // copyright 2006-2008 Sprout Systems, Inc.
4
4
  // ========================================================================
5
5
 
6
- require('views/button') ;
6
+ require('views/button/button') ;
7
7
 
8
8
  // A filter button sets a filter property to whatever you specifiy. It
9
9
  // also binds to the same property and updates its isSelected state based
@@ -1,11 +1,11 @@
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') ;
7
- require('views/button') ;
8
- require('views/text_field') ;
7
+ require('views/button/button') ;
8
+ require('views/field/text_field') ;
9
9
 
10
10
  // FormView provides a simple way for you to "stage" input by capturing
11
11
  // data from your views into the form before it is set on your actual
@@ -1,38 +1,134 @@
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') ;
7
+ require('mixins/control') ;
7
8
 
8
9
  lc_cnt = 0 ;
9
10
 
10
- SC.ImageView = SC.View.extend({
11
- emptyElement: '<img src="%@" />'.fmt(static_url('blank')),
11
+ SC.IMAGE_STATE_NONE = 'none';
12
+ SC.IMAGE_STATE_LOADING = 'loading';
13
+ SC.IMAGE_STATE_LOADED = 'loaded';
14
+ SC.IMAGE_STATE_FAILED = 'failed';
15
+
16
+ /**
17
+ URL to a transparent GIF. Used for spriting.
18
+ */
19
+ SC.BLANK_IMAGE_URL = static_url('blank.gif');
20
+
21
+ /**
22
+ @class
23
+
24
+ Displays an image in the browser.
25
+
26
+ The ImageView can be used to efficiently display images in the browser.
27
+ It includes a built in support for a number of features that can improve
28
+ your page load time if you use a lot of images including a image loading
29
+ queue and automatic support for CSS spriting.
30
+
31
+ @extends SC.View
32
+ @extends SC.Control
33
+ @author Charles Jolley
34
+ */
35
+ SC.ImageView = SC.View.extend(SC.Control,
36
+ /** @scope SC.ImageView.prototype */ {
12
37
 
13
- status: 'unknown',
38
+ /** Image views contain an img tag. */
39
+ emptyElement: '<img src="%@" class="sc-image-view" />'.fmt(SC.BLANK_IMAGE_URL),
14
40
 
15
- content: null, // becomes the url.
16
- contentBindingDefault: SC.Binding.Single,
41
+ /**
42
+ Current load status of the image.
43
+
44
+ This status changes as an image is loaded from the server. If spriting
45
+ is used, this will always be loaded. Must be one of the following
46
+ constants: SC.IMAGE_STATE_NONE, SC.IMAGE_STATE_LOADING,
47
+ SC.IMAGE_STATE_LOADED, SC.IMAGE_STATE_FAILED
48
+ */
49
+ status: SC.IMAGE_STATE_NONE,
17
50
 
18
- // override with your own function to transform content into a URL.
51
+ /**
52
+ A url or CSS class name.
53
+
54
+ This is the image you want the view to display. It should be either a
55
+ url or css class name. You can also set the content and
56
+ contentValueKey properties to have this value extracted
57
+ automatically.
58
+
59
+ If you want to use CSS spriting, set this value to a CSS class name. If
60
+ you need to use multiple class names to set your icon, separate them by
61
+ spaces.
62
+ */
63
+ value: null,
64
+ _value: null,
65
+
66
+ /**
67
+ Invoked whenever the content or value changes. (To be removed in
68
+ SproutCore 1.0)
69
+
70
+ This method is no longer necessary since we have the standard SC.Control
71
+ behavior.
72
+
73
+ @deprecated
74
+ @param {Object} content The content object.
75
+ @returns {String} the URL or CSS class name
76
+ */
19
77
  transform: function(content) { return content; },
20
78
 
21
- contentObserver: function() {
22
- var prop = this.get('content') || '' ;
23
- var url = this.transform(prop) ;
79
+ valueObserver: function() {
80
+
81
+ // get the new URL.
82
+ var value = this.get('value') ;
83
+
84
+ // invoke the old transform method if it is defined
85
+ if (this.transform !== SC.ImageView.prototype.transform) {
86
+ var content = this.get('content') || '' ;
87
+ value = this.transform(content) ;
88
+ }
89
+
90
+ // if the value has not changed, do nothing.
91
+ if (value == this._value) return ;
24
92
 
25
- if (url && url.length > 0) {
93
+ // if the old value was a class name, then we need to remove it.
94
+ if (this._value && this._value.length>0 && !SC.ImageView.valueIsUrl(this._value)) {
95
+ var classNames = this._value.split(' ') ;
96
+ var idx = classNames.length ;
97
+ while(--idx >= 0) {
98
+ this.removeClassName(classNames[idx]);
99
+ }
100
+ this.removeClassName('sc-sprite') ;
101
+ }
102
+ this._value = value ;
103
+
104
+ // if the new value is empty, just clear the img.
105
+ if (!value || value.length == 0) {
106
+ this.rootElement.src = SC.BLANK_IMAGE_URL;
107
+ this.set('status', SC.IMAGE_STATE_NONE) ;
108
+
109
+ // if a new value was set that is a URL, load the image URL.
110
+ } else if (SC.ImageView.valueIsUrl(value)) {
26
111
  this.beginPropertyChanges() ;
27
- this.set('status','loading') ;
28
- SC.imageCache.loadImage(url, this, this._onLoadComplete) ;
112
+ this.set('status', SC.IMAGE_STATE_LOADING) ;
113
+ SC.imageCache.loadImage(value, this, this._onLoadComplete) ;
29
114
  this.endPropertyChanges() ;
115
+
116
+ // if the new is a CSS class name, set an empty image and add class name
30
117
  } else {
31
- this.rootElement.src = '' ;
32
- this.set('status','unknown') ;
118
+ var classNames = value.split(' ');
119
+ var idx = classNames.length ;
120
+ while(--idx >= 0) this.addClassName(classNames[idx]) ;
121
+ this.addClassName('sc-sprite') ;
122
+ this.rootElement.src = SC.BLANK_IMAGE_URL ;
123
+ this.set('status', SC.IMAGE_STATE_LOADED) ;
33
124
  }
34
- }.observes('content') ,
125
+ }.observes('value'),
35
126
 
127
+
128
+ /**
129
+ Invoked once an image loads. If an image has already been loaded,
130
+ this method will be invoked immediately.
131
+ */
36
132
  _onLoadComplete: function(url, status, img) {
37
133
  this.beginPropertyChanges() ;
38
134
  this.set('imageWidth', parseInt(img.width,0)) ;
@@ -40,7 +136,7 @@ SC.ImageView = SC.View.extend({
40
136
  this.set('status',status) ;
41
137
  this.endPropertyChanges() ;
42
138
 
43
- if (status == 'loaded') {
139
+ if (status == SC.IMAGE_STATE_LOADED) {
44
140
  if (this.imageDidLoad) this.imageDidLoad(url) ;
45
141
  this.rootElement.src = url ;
46
142
  } else {
@@ -50,6 +146,7 @@ SC.ImageView = SC.View.extend({
50
146
 
51
147
  init: function() {
52
148
  arguments.callee.base.apply(this,arguments) ;
149
+ this.valueObserver() ;
53
150
  if (this.rootElement.src) {
54
151
  this.set('imageWidth',parseInt(this.rootElement.width,0)) ;
55
152
  this.set('imageHeight',parseInt(this.rootElement.height,0)) ;
@@ -58,9 +155,19 @@ SC.ImageView = SC.View.extend({
58
155
 
59
156
  }) ;
60
157
 
61
- // The image cache will create Image objects to preload a set of
62
- // images. This will control the number of images being loaded to maximize
63
- // browser throughput.
158
+ /**
159
+ Returns YES if the passed value looks like an URL and not a CSS class
160
+ name.
161
+ */
162
+ SC.ImageView.valueIsUrl = function(value) {
163
+ return (value.indexOf('/') >= 0) || (value.indexOf('.') >= 0) ;
164
+ } ;
165
+
166
+ /**
167
+ The image cache will create Image objects to preload a set of
168
+ images. This will control the number of images being loaded to maximize
169
+ browser throughput.
170
+ */
64
171
  SC.imageCache = SC.Object.create({
65
172
 
66
173
  // this restricts the maximum number of images that can load in.
@@ -83,7 +190,7 @@ SC.imageCache = SC.Object.create({
83
190
  if (dta.img == null) {
84
191
  this._queue.push(dta) ;
85
192
  if (!this._imgTimeout) {
86
- this._imgTimeout = setTimeout(this.loadNextImage.bind(this),100) ;
193
+ this._imgTimeout = this.invokeLater(this.loadNextImage, 100) ;
87
194
  }
88
195
  }
89
196
 
@@ -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
  SC.inlineTextEditor = SC.View.extend({
@@ -1,22 +1,113 @@
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') ;
7
+ require('mixins/control') ;
8
+ require('mixins/delegate_support');
7
9
 
8
- SC.LabelView = SC.View.extend({
10
+ /**
11
+ @class
12
+
13
+ Displays a static string of text.
14
+
15
+ You use a label view anytime you need to display a static string of text
16
+ or to display text that may need to be edited using only an inline control.
17
+
18
+ @extends SC.View
19
+ @extends SC.Control
20
+ @extends SC.DelegateSupport
21
+ @author Charles Jolley
22
+ @version 1.0
23
+ */
24
+ SC.LabelView = SC.View.extend(SC.DelegateSupport, SC.Control,
25
+ /** @scope SC.LabelView.prototype */ {
26
+
27
+ emptyElement: '<span class="sc-label-view"></span>',
9
28
 
10
29
  /**
11
- * Can the label be edited using the inline editor?
12
- * @type Boolean
13
- **/
14
- isEditable: false,
30
+ If true, value will be escaped to avoid scripting attacks.
31
+
32
+ This is a default value that can be overridden by the
33
+ settings on the owner view.
34
+ */
35
+ escapeHtml: true,
36
+
37
+ /**
38
+ If true, then the value will be localized.
39
+
40
+ This is a default default that can be overidden by the
41
+ settings in the owner view.
42
+ */
43
+ localize: false,
44
+
15
45
  /**
16
- * Is the editor open?
17
- * @type Boolean
18
- **/
19
- isEditing: false,
46
+ Set this to a validator or to a function and the value
47
+ will be passed through it before being set.
48
+
49
+ This is a default default that can be overidden by the
50
+ settings in the owner view.
51
+ */
52
+ formatter: null,
53
+
54
+ /**
55
+ The value of the label.
56
+
57
+ You may also set the value using a content object and a contentValueKey.
58
+
59
+ @field {String}
60
+ */
61
+ value: '',
62
+
63
+ /**
64
+ [RO] The value that will actually be displayed.
65
+
66
+ This property is dynamically computed by applying localization,
67
+ string conversion and other normalization utilities.
68
+
69
+ @field
70
+ */
71
+ displayValue: function() {
72
+ var value = this.get('value') ;
73
+
74
+ // 1. apply the formatter
75
+ var formatter = this.getDelegateProperty(this.displayDelegate, 'formatter') ;
76
+ if (formatter) {
77
+ var formattedValue = ($type(formatter) == T_FUNCTION) ? formatter(value, this) : formatter.fieldValueForObject(value, this) ;
78
+ if (formattedValue != null) value = formattedValue ;
79
+ }
80
+
81
+ // 2. If the returned value is an array, convert items to strings and
82
+ // join with commas.
83
+ if ($type(value) == T_ARRAY) {
84
+ var ary = [];
85
+ for(var idx=0;idx<value.get('length');idx++) {
86
+ var x = value.objectAt(idx) ;
87
+ if (x != null && x.toString) x = x.toString() ;
88
+ ary.push(x) ;
89
+ }
90
+ value = ary.join(',') ;
91
+ }
92
+
93
+ // 3. If value is not a string, convert to string. (handles 0)
94
+ if (value != null && value.toString) value = value.toString() ;
95
+
96
+ // 4. Localize
97
+ if (value && this.getDelegateProperty(this.displayDelegate, 'localize')) value = value.loc() ;
98
+
99
+ return value ;
100
+ }.property('value'),
101
+
102
+ /**
103
+ enables editing using the inline editor
104
+ */
105
+ isEditable: NO,
106
+
107
+ /**
108
+ YES if currently editing label view.
109
+ */
110
+ isEditing: NO,
20
111
 
21
112
 
22
113
  /**
@@ -29,24 +120,13 @@ SC.LabelView = SC.View.extend({
29
120
  */
30
121
  localize: false,
31
122
 
32
-
33
- /**
34
- * @constructor
35
- */
36
- init: function()
37
- {
38
- arguments.callee.base.call(this) ;
39
- if (this.get("localize"))
40
- {
41
- var inner = this.get("asHTML");
42
- if (inner !== "") this.set("content", inner);
43
- }
44
- },
45
123
 
46
124
  /**
47
- * Event dispatcher callback.
48
- * If isEditable is set to true, opens the inline text editor view.
49
- * @param {DOMMouseEvent} evt DOM event
125
+ Event dispatcher callback.
126
+ If isEditable is set to true, opens the inline text editor view.
127
+
128
+ @param {DOMMouseEvent} evt DOM event
129
+
50
130
  */
51
131
  doubleClick: function( evt )
52
132
  {
@@ -55,30 +135,32 @@ SC.LabelView = SC.View.extend({
55
135
 
56
136
 
57
137
  /**
58
- * Opens the inline text editor (closing it if it was already open for another view).
59
- * @return void
60
- **/
138
+ Opens the inline text editor (closing it if it was already open for another view).
139
+
140
+ @return void
141
+ */
61
142
  beginInlineEdit: function()
62
143
  {
63
144
  if ( !this.get('isEditable') ) return;
64
145
  if ( this.get('isEditing') ) return;
65
146
 
66
147
  this.set('isEditing', true);
67
- this.set("asHTML", ''); // blank out the label contents
148
+ this.set("innerHTML", ''); // blank out the label contents
68
149
  this.appendChild( SC.inlineTextEditor );
69
- SC.inlineTextEditor.field.set('value', this.get('content'));
150
+ SC.inlineTextEditor.field.set('value', this.get('value'));
70
151
  SC.inlineTextEditor.field.becomeFirstResponder();
71
152
  },
72
153
  /**
73
- * Closes the inline text editor.
74
- * @return void
75
- **/
154
+ Closes the inline text editor.
155
+
156
+ @return void
157
+ */
76
158
  endInlineEdit: function()
77
159
  {
78
160
  if ( !this.get('isEditing') ) return;
79
161
 
80
162
  // if there were changes, then commit them...
81
- if ( SC.inlineTextEditor.field.get('value') != this.get('content') )
163
+ if ( SC.inlineTextEditor.field.get('value') != this.get('value') )
82
164
  {
83
165
  this._inlineEditValue = SC.inlineTextEditor.field.get('value') ;
84
166
  this._closeInlineEditor(false) ;
@@ -103,78 +185,53 @@ SC.LabelView = SC.View.extend({
103
185
  this.removeChild( SC.inlineTextEditor );
104
186
  if(!canceled)
105
187
  {
106
- this.set('content',this._inlineEditValue) ;
188
+ this.set('value',this._inlineEditValue) ;
107
189
  this.commitInlineEdit();
108
190
  }
109
191
  else
110
192
  {
111
- this._updateValue() ; // restore value.
193
+ this._valueDidChange() ; // restore value.
112
194
  }
113
195
  },
114
196
 
115
197
  // abstract method... implement to persist changes made in the editor.
116
198
  commitInlineEdit: function() {},
117
-
118
-
119
- // setting this to a non-null value will cause the label to get the
120
- // property value and use that for display.
121
- property: function(key, value) {
122
- if ((value !== undefined) && (value != this._property)) {
123
- if (this._content) {
124
- var func = this._boundObserver() ;
125
- if (this._property && this._content && this._content.removeObserver) this._content.removeObserver(this._property,func);
126
- this._property = value ;
127
- if (this._property && this._content && this._content.addObserver) this._content.addObserver(this._property,func) ;
128
- } else this._property = value ;
129
- }
130
- return this._property ;
131
- }.property(),
132
199
 
133
- // set to a validator object to have your content converted using the
134
- // validator. The formatter will be applied before localization.
135
- formatter: null,
136
-
137
- // change this property value to update the content.
138
- content: function(key,value) {
139
- if ((value !== undefined) && (this._content != value)) {
140
- var prop = this.get('property') ;
141
- var func = this._boundObserver() ;
142
- if (prop && this._content && this._content.removeObserver) this._content.removeObserver(prop, func) ;
143
- this._content = value ;
144
- if (prop && this._content && this._content.addObserver) this._content.addObserver(prop, func) ;
145
- this._updateValue() ;
146
- }
147
- return this._content ;
148
- }.property(),
149
-
150
- contentBindingDefault: SC.Binding.Single,
151
-
152
- _updateValue: function() {
153
- var value = this._content ;
154
- var prop = this.get('property') ;
155
- if (prop && value && value.get) value = value.get(prop) ;
156
-
157
- // apply formatter
158
- var formatter = this.get('formatter') ;
159
- if (formatter) {
160
- var formattedValue = (SC.typeOf(formatter) == "function") ? formatter(value,this) : formatter.fieldValueForObject(value) ;
161
- if (formattedValue) value = formattedValue ;
200
+ /** @private */
201
+ init: function()
202
+ {
203
+ arguments.callee.base.call(this) ;
204
+
205
+ // if we are supposed to localize, get the content value
206
+ if (this.get("localize")) {
207
+ this.value = this._value = this.get('innerHTML').loc() ;
208
+ if (this.value != '') this.set('innerHTML', this.value) ;
162
209
  }
210
+ },
163
211
 
164
- if ($type(value) == 'number') value = value.toString() ; // handle 0
212
+ /**
213
+ @private
214
+
215
+ Invoked whenever the monitored value on the content object
216
+ changes.
165
217
 
166
- // localize
167
- if (value && this.get('localize')) value = value.loc() ;
168
- if (value && this.get('escapeHTML') && value.escapeHTML) value = value.escapeHTML() ;
218
+ The value processed is either the contentValueKey, if set, or
219
+ it is the content object itself.
220
+ */
221
+ _valueDidChange: function() {
222
+
223
+ var value = this.get('value') ;
224
+ if (value == this._value) return; // nothing to do
225
+
226
+ // get display value
227
+ var value = this.get('displayValue') ;
169
228
 
170
- // set
171
- this.set('asHTML',value || '') ;
229
+ // Escape HTML
230
+ if (this.getDelegateProperty(this.displayDelegate, 'escapeHtml')) {
231
+ this.set('innerText', value || '') ;
232
+ } else this.set('innerHTML', value || '') ;
172
233
 
173
- },
234
+ }.observes('value')
174
235
 
175
- _boundObserver: function() {
176
- if (!this._observer) this._observer = this._updateValue.bind(this) ;
177
- return this._observer ;
178
- }
179
236
 
180
237
  });