sproutcore 0.9.2 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/History.txt +33 -0
  2. data/Manifest.txt +3 -14
  3. data/clients/sc_docs/controllers/docs.js +1 -0
  4. data/clients/sc_docs/core.js +1 -1
  5. data/clients/sc_test_runner/controllers/runner.js +5 -0
  6. data/clients/sc_test_runner/core.js +1 -1
  7. data/frameworks/sproutcore/english.lproj/core.css +41 -0
  8. data/frameworks/sproutcore/english.lproj/theme.css +20 -0
  9. data/frameworks/sproutcore/foundation/animator.js +11 -2
  10. data/frameworks/sproutcore/foundation/date.js +2 -2
  11. data/frameworks/sproutcore/foundation/object.js +2 -2
  12. data/frameworks/sproutcore/foundation/server.js +4 -3
  13. data/frameworks/sproutcore/foundation/set.js +1 -1
  14. data/frameworks/sproutcore/foundation/unittest.js +12 -9
  15. data/frameworks/sproutcore/lib/collection_view.rb +1 -0
  16. data/frameworks/sproutcore/lib/core_views.rb +4 -0
  17. data/frameworks/sproutcore/mixins/editable.js +144 -0
  18. data/frameworks/sproutcore/mixins/inline_editor_delegate.js +72 -0
  19. data/frameworks/sproutcore/mixins/observable.js +45 -16
  20. data/frameworks/sproutcore/mixins/scrollable.js +0 -1
  21. data/frameworks/sproutcore/tests/controllers/controller.rhtml +12 -12
  22. data/frameworks/sproutcore/tests/controllers/object.rhtml +2 -2
  23. data/frameworks/sproutcore/views/collection/collection.js +122 -68
  24. data/frameworks/sproutcore/views/collection/source_list.js +5 -0
  25. data/frameworks/sproutcore/views/field/text_field.js +7 -1
  26. data/frameworks/sproutcore/views/inline_text_field.js +397 -0
  27. data/frameworks/sproutcore/views/label.js +78 -68
  28. data/frameworks/sproutcore/views/list_item.js +184 -31
  29. data/frameworks/sproutcore/views/view.js +41 -9
  30. data/generators/client/templates/core.js +1 -1
  31. data/generators/client/templates/english.lproj/body.css +74 -0
  32. data/generators/framework/templates/core.js +1 -1
  33. data/lib/sproutcore/version.rb +1 -1
  34. metadata +5 -16
  35. data/clients/view_builder/builders/builder.js +0 -339
  36. data/clients/view_builder/builders/button.js +0 -81
  37. data/clients/view_builder/controllers/document.js +0 -21
  38. data/clients/view_builder/core.js +0 -19
  39. data/clients/view_builder/english.lproj/body.css +0 -77
  40. data/clients/view_builder/english.lproj/body.rhtml +0 -41
  41. data/clients/view_builder/english.lproj/controls.css +0 -0
  42. data/clients/view_builder/english.lproj/strings.js +0 -14
  43. data/clients/view_builder/main.js +0 -38
  44. data/clients/view_builder/tests/controllers/document.rhtml +0 -20
  45. data/clients/view_builder/tests/views/builder.rhtml +0 -20
  46. data/clients/view_builder/views/builder.js +0 -23
  47. data/frameworks/sproutcore/english.lproj/inline_text_editor.css +0 -21
  48. data/frameworks/sproutcore/views/inline_text_editor.js +0 -96
@@ -5,6 +5,7 @@
5
5
  require('Core') ;
6
6
  require('views/view') ;
7
7
  require('mixins/control');
8
+ require('mixins/inline_editor_delegate');
8
9
 
9
10
  SC.LIST_ITEM_ACTION_CANCEL = 'sc-list-item-cancel-action';
10
11
  SC.LIST_ITEM_ACTION_REFRESH = 'sc-list-item-cancel-refresh';
@@ -16,10 +17,12 @@ SC.LIST_ITEM_ACTION_EJECT = 'sc-list-item-cancel-eject';
16
17
 
17
18
  @extends SC.View
18
19
  @extends SC.Control
19
- @author AuthorName
20
- @version 0.1
20
+ @extends SC.InlineEditorDelegate
21
+ @extends SC.Editable
22
+ @author Charles Jolley
23
+ @since SproutCore 1.0
21
24
  */
22
- SC.ListItemView = SC.View.extend(SC.Control,
25
+ SC.ListItemView = SC.View.extend(SC.Control, SC.InlineEditorDelegate,
23
26
  /** @scope SC.ListItemView.prototype */ {
24
27
 
25
28
  /** A ListItemView has an img tag, label, count, optional right button, and
@@ -83,8 +86,13 @@ SC.ListItemView = SC.View.extend(SC.Control,
83
86
  */
84
87
  contentIsBranchKey: null,
85
88
 
89
+ /**
90
+ YES if the item view is currently editing.
91
+ */
92
+ isEditing: NO,
86
93
 
87
94
  contentPropertyDidChange: function() {
95
+ if (this.get('isEditing')) this.discardEditing() ;
88
96
  this.render() ;
89
97
  },
90
98
 
@@ -101,26 +109,26 @@ SC.ListItemView = SC.View.extend(SC.Control,
101
109
  if (this.getDelegateProperty(del, 'hasContentIcon')) {
102
110
  var iconKey = this.getDelegateProperty(del,'contentIconKey') ;
103
111
  var icon = (iconKey && content && content.get) ? content.get(iconKey) : null ;
104
- html.push(this.renderIconHTML(icon));
112
+ html.push(this.renderIconHtml(icon));
105
113
  }
106
114
 
107
115
  // handle label
108
116
  var labelKey = this.getDelegateProperty(del, 'contentValueKey') ;
109
117
  var label = (labelKey && content && content.get) ? content.get(labelKey) : null ;
110
- html.push(this.renderLabelHTML(label));
118
+ html.push(this.renderLabelHtml(label));
111
119
 
112
120
  // handle unread count
113
121
  var countKey = this.getDelegateProperty(del, 'contentUnreadCountKey') ;
114
122
  var count = (countKey && content && content.get) ? content.get(countKey) : null ;
115
123
  if ((count != null) && (count != 0)) {
116
- html.push(this.renderCountHTML(count));
124
+ html.push(this.renderCountHtml(count));
117
125
  }
118
126
 
119
127
  // handle action
120
128
  var actionKey = this.getDelegateProperty(del, 'listItemActionProperty') ;
121
129
  var actionClassName = (actionKey && content && content.get) ? content.get(actionKey) : null ;
122
130
  if (actionClassName) {
123
- html.push(this.renderActionHTML(actionClassName));
131
+ html.push(this.renderActionHtml(actionClassName));
124
132
  }
125
133
  this.setClassName('sc-has-action', actionClassName) ;
126
134
 
@@ -128,7 +136,7 @@ SC.ListItemView = SC.View.extend(SC.Control,
128
136
  if (this.getDelegateProperty(del, 'hasContentBranch')) {
129
137
  var branchKey = this.getDelegateProperty(del, 'contentIsBranchKey');
130
138
  var hasBranch = (branchKey && content && content.get) ? content.get(branchKey) : false ;
131
- html.push(this.renderBranchHTML(hasBranch));
139
+ html.push(this.renderBranchHtml(hasBranch));
132
140
  this.setClassName('sc-has-branch', true) ;
133
141
  } else this.setClassName('sc-has-branch', false) ;
134
142
 
@@ -140,12 +148,13 @@ SC.ListItemView = SC.View.extend(SC.Control,
140
148
  },
141
149
 
142
150
  /**
143
- renderIconHTML generates the html string used to represent the icon for your
144
- list item. override this to return your own custom HTML
151
+ renderIconHtml generates the html string used to represent the icon for
152
+ your list item. override this to return your own custom HTML
153
+
145
154
  @returns {String}
146
155
  @arguments {String} the icon property based on your view's contentIconKey
147
156
  */
148
- renderIconHTML: function(icon){
157
+ renderIconHtml: function(icon){
149
158
  var html = [];
150
159
  // get a class name and url to include if relevant
151
160
  var url = null, className = null ;
@@ -164,12 +173,14 @@ SC.ListItemView = SC.View.extend(SC.Control,
164
173
  },
165
174
 
166
175
  /**
167
- renderLabelHTML generates the html string used to represent the label for your
168
- list item. override this to return your own custom HTML
176
+ renderLabelHtml generates the html string used to represent the label
177
+ for your list item. override this to return your own custom HTML
178
+
169
179
  @returns {String}
170
- @arguments {String} the label property based on your view's contentValueKey
180
+ @arguments {String} the label property based on your view's
181
+ contentValueKey
171
182
  */
172
- renderLabelHTML: function(label){
183
+ renderLabelHtml: function(label){
173
184
  var html = [];
174
185
  html.push('<span class="sc-label">') ;
175
186
  html.push(label || '') ;
@@ -177,13 +188,25 @@ SC.ListItemView = SC.View.extend(SC.Control,
177
188
  return html.join('');
178
189
  },
179
190
 
191
+ /**
192
+ Finds and retrieves the element containing the label. This is used
193
+ for inline editing. If you override renderLabelHtml() you probably
194
+ need to override this as well.
195
+ */
196
+ findLabelElement: function() {
197
+ return this.$class('sc-label') ;
198
+ },
199
+
180
200
  /**
181
- renderCountHTML generates the html string used to represent the count (like unread count)
182
- for your list item. override this to return your own custom HTML
201
+ renderCountHtml generates the html string used to represent the count
202
+ (like unread count) for your list item. override this to return your
203
+ own custom HTML
204
+
183
205
  @returns {String}
184
- @arguments {Integer} the label property based on your view's contentValueKey
206
+ @arguments {Integer} the label property based on your view's
207
+ contentValueKey
185
208
  */
186
- renderCountHTML: function(count) {
209
+ renderCountHtml: function(count) {
187
210
  var html= [];
188
211
  html.push('<span class="sc-count"><span class="inner">') ;
189
212
  html.push(count.toString()) ;
@@ -192,12 +215,14 @@ SC.ListItemView = SC.View.extend(SC.Control,
192
215
  },
193
216
 
194
217
  /**
195
- renderActiontHTML generates the html string used to represent the action item
196
- for your list item. override this to return your own custom HTML
197
- @returns {String}
198
- @arguments {String} the name of the action item.
218
+ renderActionHtml generates the html string used to represent the
219
+ action item for your list item. override this to return your own
220
+ custom HTML
221
+
222
+ @returns {String}
223
+ @param actionClassName {String} the name of the action item.
199
224
  */
200
- renderActionHTML: function(actionClassName){
225
+ renderActionHtml: function(actionClassName){
201
226
  var html = [];
202
227
  html.push('<img src="') ;
203
228
  html.push(static_url('blank.gif')) ;
@@ -206,20 +231,148 @@ SC.ListItemView = SC.View.extend(SC.Control,
206
231
  },
207
232
 
208
233
  /**
209
- renderBranchHTML generates the html string used to represent the branch arrow.
210
- override this to return your own custom HTML
211
- @returns {String}
212
- @arguments {Boolean} whehter the branch is
234
+ renderBranchHtml generates the html string used to represent the
235
+ branch arrow. override this to return your own custom HTML
236
+ @returns {String}
237
+ @arguments {Boolean} whehter the branch is
213
238
  */
214
239
 
215
- renderBranchHTML: function(hasBranch) {
240
+ renderBranchHtml: function(hasBranch) {
216
241
  var html = [];
217
242
  html.push('<span class="sc-branch ');
218
243
  html.push(hasBranch ? 'sc-branch-visible' : 'sc-branch-hidden') ;
219
244
  html.push('">&nbsp;</span>');
220
245
  return html.join('');
221
- }
222
-
246
+ },
247
+
248
+ /**
249
+ Returns true if a click is on the label text itself to enable editing.
250
+
251
+ Note that if you override renderLabelHtml(), you probably need to override
252
+ this as well.
223
253
 
254
+ @param evt {Event} the mouseUp event.
255
+ @returns {Boolean} YES if the mouse was on the content element itself.
256
+ */
257
+ contentHitTest: function(evt) {
258
+
259
+ // if not content value is returned, not much to do.
260
+ var del = this.displayDelegate ;
261
+ var labelKey = this.getDelegateProperty(del, 'contentValueKey') ;
262
+ if (!labelKey) return NO ;
263
+
264
+ // get the element to check for.
265
+ var el = this.findLabelElement() ;
266
+ if (!el) return NO ; // no label to check for.
267
+
268
+ var cur = Event.element(evt) ;
269
+ while(cur && (cur != (this.rootElement)) && (cur != window)) {
270
+ if (cur === el) return YES ;
271
+ cur = cur.parentNode ;
272
+ }
273
+
274
+ return NO;
275
+ },
276
+
277
+ beginEditing: function() {
278
+
279
+ if (this.get('isEditing')) return YES ;
280
+
281
+ var content = this.get('content') ;
282
+ var del = this.displayDelegate ;
283
+ var labelKey = this.getDelegateProperty(del, 'contentValueKey') ;
284
+ var v = (labelKey && content && content.get) ? content.get(labelKey) : null ;
285
+
286
+ var f = this.get('frame') ;
287
+ var el = this.findLabelElement() ;
288
+ if (!el) return NO ;
289
+
290
+ // if the label has a large line height, try to adjust it to something
291
+ // more reasonable so that it looks right when we show the popup editor.
292
+ var oldLineHeight = Element.getStyle(el, 'lineHeight') ;
293
+ var fontSize = parseInt(Element.getStyle(el, 'fontSize'), 0) ;
294
+ var lineHeight = parseInt(oldLineHeight, 0) ;
295
+ var lineHeightShift = 0;
296
+
297
+ if (fontSize && lineHeight) {
298
+ var targetLineHeight = fontSize * 1.5 ;
299
+ if (targetLineHeight < lineHeight) {
300
+ Element.setStyle(el, { lineHeight: '1.5' }) ;
301
+ lineHeightShift = (lineHeight - targetLineHeight) / 2;
302
+ } else oldLineHeight = null ;
303
+ }
304
+
305
+ f.x += el.offsetLeft ;
306
+ f.y += el.offsetTop + lineHeightShift - 2;
307
+ f.height = el.offsetHeight ;
308
+ f.width = (f.width - 30 - el.offsetLeft) ;
309
+ f = this.convertFrameToView(f, null) ;
310
+
311
+ var ret = SC.InlineTextFieldView.beginEditing({
312
+ frame: f,
313
+ exampleElement: el,
314
+ delegate: this,
315
+ value: v
316
+ }) ;
317
+
318
+ // restore old line height for original item if the old line height
319
+ // was saved.
320
+ if (oldLineHeight) Element.setStyle(el, { lineHeight: oldLineHeight }) ;
321
+
322
+ // Done! If this failed, then set editing back to no.
323
+ return ret ;
324
+ },
325
+
326
+ commitEditing: function() {
327
+ if (!this.get('isEditing')) return YES ;
328
+ return SC.InlineTextFieldView.commitEditing();
329
+ },
330
+
331
+ discardEditing: function() {
332
+ if (!this.get('isEditing')) return YES ;
333
+ return SC.InlineTextFieldView.discardEditing();
334
+ },
335
+
336
+ /** @private
337
+ Set editing to true so edits will no longer be allowed.
338
+ */
339
+ inlineEditorWillBeginEditing: function(inlineEditor) {
340
+ this.set('isEditing', YES);
341
+ },
342
+
343
+ /** @private
344
+ Hide the label view while the inline editor covers it.
345
+ */
346
+ inlineEditorDidBeginEditing: function(inlineEditor) {
347
+ var el = this.findLabelElement() ;
348
+ this._oldOpacity = Element.getStyle(el, 'opacity') ;
349
+ Element.setStyle(el, { opacity: 0.0 }) ;
350
+ },
351
+
352
+ /** @private
353
+ Could check with a validator someday...
354
+ */
355
+ inlineEditorShouldEndEditing: function(inlineEditor, finalValue) {
356
+ return YES ;
357
+ },
358
+
359
+ /** @private
360
+ Update the field value and make it visible again.
361
+ */
362
+ inlineEditorDidEndEditing: function(inlineEditor, finalValue) {
363
+ this.set('isEditing', NO) ;
364
+
365
+ var content = this.get('content') ;
366
+ var del = this.displayDelegate ;
367
+ var labelKey = this.getDelegateProperty(del, 'contentValueKey') ;
368
+ if (labelKey && content && content.set) {
369
+ content.set(labelKey, finalValue) ;
370
+ }
371
+
372
+ // force a refresh, otherwise the label will never be visible again
373
+ // b/c its opacity is 0.
374
+ this._lastRenderedHtml = null;
375
+ this.render() ;
376
+ }
224
377
 
225
378
  }) ;
@@ -525,22 +525,16 @@ SC.View = SC.Responder.extend(SC.PathModule, SC.DelegateSupport,
525
525
  }
526
526
 
527
527
  //if (style == 'float') style = 'cssFloat' ;
528
- style = (style == 'float') ? 'cssFloat' : style.camelize() ;
528
+ style = (style === 'float') ? 'cssFloat' : style.camelize() ;
529
529
  var value = element.style[style];
530
530
  if (!value) {
531
531
  value = this._computedStyle ? this._computedStyle[style] : null ;
532
532
  }
533
533
 
534
- switch(style) {
535
- case 'opacity':
534
+ if (style === 'opacity') {
536
535
  value = value ? parseFloat(value) : 1.0;
537
- break ;
538
- case 'auto':
539
- value = null;
540
- break ;
541
- default:
542
- break ;
543
536
  }
537
+ if (value === 'auto') value = null ;
544
538
 
545
539
  return value ;
546
540
  },
@@ -2059,6 +2053,44 @@ SC.View.mixin({
2059
2053
 
2060
2054
  }) ;
2061
2055
 
2056
+ // IE Specfic Overrides
2057
+ console.log('SC.Platform.IE = %@'.fmt(SC.Platform.IE));
2058
+ if (SC.Platform.IE) {
2059
+ SC.View.prototype.getStyle = function(style) {
2060
+ var element = this.rootElement ;
2061
+
2062
+ // collect value
2063
+ style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
2064
+ var value = element.style[style];
2065
+ if (!value && element.currentStyle) value = element.currentStyle[style];
2066
+
2067
+ // handle opacity
2068
+ if (style === 'opacity') {
2069
+ if (value = (this.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) {
2070
+ if (value[1]) value = parseFloat(value[1]) / 100;
2071
+ }
2072
+ value = 1.0;
2073
+ }
2074
+
2075
+ // handle auto
2076
+ if (value === 'auto') {
2077
+ switch(style) {
2078
+ case 'width':
2079
+ value = (this.getStyle('display') != 'none') ? (element.offsetWidth + 'px') : null;
2080
+ break ;
2081
+ case 'height':
2082
+ value = (this.getStyle('display') != 'none') ? (element.offsetHeight + 'px') : null;
2083
+ break ;
2084
+ default:
2085
+ value = null ;
2086
+ }
2087
+ }
2088
+
2089
+ return value;
2090
+ };
2091
+ }
2092
+
2093
+
2062
2094
  // this handler goes through the guid to avoid any potential memory leaks
2063
2095
  SC.View._onscroll = function(evt) { $view(this)._onscroll(evt); } ;
2064
2096
 
@@ -14,6 +14,6 @@
14
14
  FIXTURES: [],
15
15
 
16
16
  // Any keys in this array will be instantiated automatically from main.
17
- controllers: [],
17
+ controllers: []
18
18
 
19
19
  }) ;
@@ -73,3 +73,77 @@
73
73
  }
74
74
 
75
75
  /* @end */
76
+
77
+ /* @group For Tutorial */
78
+
79
+ body {
80
+ position: absolute ;
81
+ left: 0;
82
+ right: 0;
83
+ top: 0;
84
+ bottom: 0;
85
+ padding: 0;
86
+ margin: 0;
87
+ overflow: hidden ;
88
+ }
89
+
90
+ .workspace .sidebar {
91
+ position: absolute;
92
+ left: 0;
93
+ top: 0;
94
+ width: 200px;
95
+ bottom: 0;
96
+ }
97
+
98
+ .workspace .sidebar .master_list {
99
+ position: absolute;
100
+ left: 0;
101
+ top: 0;
102
+ right: 0;
103
+ bottom: 0;
104
+ }
105
+
106
+ .workspace .sc-split-divider-view {
107
+ position: absolute;
108
+ left: 200px;
109
+ top: 0;
110
+ bottom: 0;
111
+ }
112
+
113
+ .workspace .detail_view {
114
+ position: absolute;
115
+ left: 205px;
116
+ right: 0;
117
+ top: 0;
118
+ bottom: 0;
119
+ border: none ;
120
+ background-color: #aaa;
121
+ }
122
+
123
+ .workspace .detail_view .card-detail {
124
+ margin-left: auto;
125
+ margin-right: auto;
126
+ top: 100px;
127
+ position: relative;
128
+ border: 4px #888 solid;
129
+ background: #f0f0f0;
130
+ padding-top: 10px;
131
+ padding-bottom: 10px;
132
+ }
133
+
134
+ .workspace .detail_view .card-detail td {
135
+ padding: 0 10px;
136
+ }
137
+
138
+ .workspace .detail_view .card-detail .buttons {
139
+ text-align: right;
140
+ padding-top: 10px;
141
+ }
142
+
143
+ .workspace .detail_view .card-detail input {
144
+ font-size: 14px;
145
+ width: 300px;
146
+ }
147
+
148
+ /* @end */
149
+