sproutcore 0.9.2 → 0.9.3
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.
- data/History.txt +33 -0
- data/Manifest.txt +3 -14
- data/clients/sc_docs/controllers/docs.js +1 -0
- data/clients/sc_docs/core.js +1 -1
- data/clients/sc_test_runner/controllers/runner.js +5 -0
- data/clients/sc_test_runner/core.js +1 -1
- data/frameworks/sproutcore/english.lproj/core.css +41 -0
- data/frameworks/sproutcore/english.lproj/theme.css +20 -0
- data/frameworks/sproutcore/foundation/animator.js +11 -2
- data/frameworks/sproutcore/foundation/date.js +2 -2
- data/frameworks/sproutcore/foundation/object.js +2 -2
- data/frameworks/sproutcore/foundation/server.js +4 -3
- data/frameworks/sproutcore/foundation/set.js +1 -1
- data/frameworks/sproutcore/foundation/unittest.js +12 -9
- data/frameworks/sproutcore/lib/collection_view.rb +1 -0
- data/frameworks/sproutcore/lib/core_views.rb +4 -0
- data/frameworks/sproutcore/mixins/editable.js +144 -0
- data/frameworks/sproutcore/mixins/inline_editor_delegate.js +72 -0
- data/frameworks/sproutcore/mixins/observable.js +45 -16
- data/frameworks/sproutcore/mixins/scrollable.js +0 -1
- data/frameworks/sproutcore/tests/controllers/controller.rhtml +12 -12
- data/frameworks/sproutcore/tests/controllers/object.rhtml +2 -2
- data/frameworks/sproutcore/views/collection/collection.js +122 -68
- data/frameworks/sproutcore/views/collection/source_list.js +5 -0
- data/frameworks/sproutcore/views/field/text_field.js +7 -1
- data/frameworks/sproutcore/views/inline_text_field.js +397 -0
- data/frameworks/sproutcore/views/label.js +78 -68
- data/frameworks/sproutcore/views/list_item.js +184 -31
- data/frameworks/sproutcore/views/view.js +41 -9
- data/generators/client/templates/core.js +1 -1
- data/generators/client/templates/english.lproj/body.css +74 -0
- data/generators/framework/templates/core.js +1 -1
- data/lib/sproutcore/version.rb +1 -1
- metadata +5 -16
- data/clients/view_builder/builders/builder.js +0 -339
- data/clients/view_builder/builders/button.js +0 -81
- data/clients/view_builder/controllers/document.js +0 -21
- data/clients/view_builder/core.js +0 -19
- data/clients/view_builder/english.lproj/body.css +0 -77
- data/clients/view_builder/english.lproj/body.rhtml +0 -41
- data/clients/view_builder/english.lproj/controls.css +0 -0
- data/clients/view_builder/english.lproj/strings.js +0 -14
- data/clients/view_builder/main.js +0 -38
- data/clients/view_builder/tests/controllers/document.rhtml +0 -20
- data/clients/view_builder/tests/views/builder.rhtml +0 -20
- data/clients/view_builder/views/builder.js +0 -23
- data/frameworks/sproutcore/english.lproj/inline_text_editor.css +0 -21
- 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
|
-
@
|
20
|
-
@
|
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.
|
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.
|
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.
|
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.
|
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.
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
180
|
+
@arguments {String} the label property based on your view's
|
181
|
+
contentValueKey
|
171
182
|
*/
|
172
|
-
|
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
|
-
|
182
|
-
for your list item. override this to return your
|
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
|
206
|
+
@arguments {Integer} the label property based on your view's
|
207
|
+
contentValueKey
|
185
208
|
*/
|
186
|
-
|
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
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
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
|
-
|
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
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
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
|
-
|
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('"> </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
|
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
|
-
|
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
|
|
@@ -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
|
+
|