sproutcore 0.9.1 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
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
  });