sproutcore 1.4.2 → 1.4.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/CHANGELOG +11 -0
- data/Rakefile +27 -436
- data/VERSION.yml +1 -1
- data/lib/frameworks/sproutcore/CHANGELOG +32 -2
- data/lib/frameworks/sproutcore/frameworks/animation/core.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/datastore/system/record_array.js +8 -2
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/nested_records/nested_record.js +42 -2
- data/lib/frameworks/sproutcore/frameworks/debug/invoke_once_last_debugging.js +7 -12
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/radio/ui.js +22 -1
- data/lib/frameworks/sproutcore/frameworks/desktop/views/collection.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/desktop/views/list.js +6 -2
- data/lib/frameworks/sproutcore/frameworks/desktop/views/list_item.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/desktop/views/radio.js +38 -10
- data/lib/frameworks/sproutcore/frameworks/desktop/views/scroller.js +8 -8
- data/lib/frameworks/sproutcore/frameworks/desktop/views/segmented.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/desktop/views/select_field.js +12 -5
- data/lib/frameworks/sproutcore/frameworks/foundation/mixins/button.js +3 -3
- data/lib/frameworks/sproutcore/frameworks/foundation/mixins/inline_text_field.js +14 -9
- data/lib/frameworks/sproutcore/frameworks/foundation/system/datetime.js +3 -1
- data/lib/frameworks/sproutcore/frameworks/foundation/system/root_responder.js +25 -17
- data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/inline_text_field/beginEditing.js +46 -36
- data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/validatable/ui.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/foundation/tests/system/datetime.js +5 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/tests/validators/not_empty.js +56 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/validators/date_time.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/foundation/validators/not_empty.js +7 -3
- data/lib/frameworks/sproutcore/frameworks/foundation/views/label.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/media/views/audio.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/media/views/controls.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/media/views/media_slider.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/media/views/mini_controls.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/media/views/simple_controls.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/media/views/video.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/runtime/private/observer_set.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/runtime/system/object.js +18 -23
- data/lib/frameworks/sproutcore/frameworks/runtime/tests/mixins/observable/observable.js +13 -0
- data/lib/sproutcore/builders/base.rb +4 -4
- data/lib/sproutcore/builders/javascript.rb +0 -7
- data/lib/sproutcore/builders/stylesheet.rb +0 -7
- data/lib/sproutcore/rack/proxy.rb +28 -13
- metadata +4 -4
- data/DISTRIBUTION.yml +0 -20
@@ -10,7 +10,8 @@
|
|
10
10
|
htmlbody('<style> .sc-static-layout { border: 1px red dotted; } </style>');
|
11
11
|
|
12
12
|
var itemList = [{ title: "Red", value: "red", enabled: YES }, { title: "Green", value: "green" }, { title: "Blue", value: "blue" }],
|
13
|
-
itemList2 = [{ title: "Cyan", value: "cyan", enabled: YES }, { title: "Magenta", value: "magenta" }, { title: "Yellow", value: "yellow" },{ title: "blacK", value: "black"}]
|
13
|
+
itemList2 = [{ title: "Cyan", value: "cyan", enabled: YES }, { title: "Magenta", value: "magenta" }, { title: "Yellow", value: "yellow" },{ title: "blacK", value: "black"}],
|
14
|
+
itemList3 = [{ title: "Red", value: "red", enabled: YES, width: 30 }, { title: "Green", value: "green", width: 50 }, { title: "Blue", value: "blue", width: 40 }];
|
14
15
|
|
15
16
|
var pane = SC.ControlTestPane.design()
|
16
17
|
.add("basic", SC.RadioView, {
|
@@ -56,6 +57,16 @@ var pane = SC.ControlTestPane.design()
|
|
56
57
|
items: 'Yes No'.w(),
|
57
58
|
// LAYOUT_VERTICAL is default
|
58
59
|
layoutDirection: SC.LAYOUT_HORIZONTAL
|
60
|
+
})
|
61
|
+
|
62
|
+
.add("horizontal widths", SC.RadioView, {
|
63
|
+
value: "",
|
64
|
+
isEnabled: YES,
|
65
|
+
items: itemList3,
|
66
|
+
layoutDirection: SC.LAYOUT_HORIZONTAL,
|
67
|
+
itemTitleKey: 'title',
|
68
|
+
itemValueKey: 'value',
|
69
|
+
itemWidthKey: 'width'
|
59
70
|
});
|
60
71
|
|
61
72
|
pane.show(); // add a test to show the test pane
|
@@ -230,3 +241,13 @@ test("enabled first", function() {
|
|
230
241
|
});
|
231
242
|
});
|
232
243
|
|
244
|
+
test("item widths", function() {
|
245
|
+
var radioButtons = pane.view('horizontal widths').$('.sc-radio-button'),
|
246
|
+
widths = [30, 50, 40],
|
247
|
+
idx = 0, radio;
|
248
|
+
|
249
|
+
radioButtons.forEach(function(elem) {
|
250
|
+
equals(SC.$(elem).width(), widths[idx], 'radio button %@ should width specified by itemWidthKey'.fmt(idx, widths[idx]));
|
251
|
+
idx++;
|
252
|
+
});
|
253
|
+
});
|
@@ -905,7 +905,7 @@ SC.CollectionView = SC.View.extend(
|
|
905
905
|
// to reuse it.
|
906
906
|
// (Charles Jolley personally guarantees this code)
|
907
907
|
layer = existing.get('layer');
|
908
|
-
layer.parentNode.removeChild(layer);
|
908
|
+
if (layer && layer.parentNode) layer.parentNode.removeChild(layer);
|
909
909
|
|
910
910
|
containerView.removeChild(existing);
|
911
911
|
}
|
@@ -217,7 +217,7 @@ SC.ListView = SC.CollectionView.extend(
|
|
217
217
|
// prefill the cache with custom rows.
|
218
218
|
cache = this._sclv_offsetCache;
|
219
219
|
if (!cache) {
|
220
|
-
cache =
|
220
|
+
cache = [];
|
221
221
|
delta = max = 0 ;
|
222
222
|
custom.forEach(function(idx) {
|
223
223
|
delta += this.rowHeightForContentIndex(idx)-rowHeight;
|
@@ -225,6 +225,8 @@ SC.ListView = SC.CollectionView.extend(
|
|
225
225
|
max = idx ;
|
226
226
|
}, this);
|
227
227
|
this._sclv_max = max+1;
|
228
|
+
// moved down so that the cache is not marked as initialized until it actually is
|
229
|
+
this._sclv_offsetCache = cache;
|
228
230
|
}
|
229
231
|
|
230
232
|
// now just get the delta for the last custom row before the current
|
@@ -259,11 +261,13 @@ SC.ListView = SC.CollectionView.extend(
|
|
259
261
|
if (del.customRowHeightIndexes && (indexes=del.get('customRowHeightIndexes'))) {
|
260
262
|
cache = this._sclv_heightCache ;
|
261
263
|
if (!cache) {
|
262
|
-
cache =
|
264
|
+
cache = [];
|
263
265
|
content = this.get('content');
|
264
266
|
indexes.forEach(function(idx) {
|
265
267
|
cache[idx] = del.contentIndexRowHeight(this, content, idx);
|
266
268
|
}, this);
|
269
|
+
// moved down so that the cache is not marked as initialized until it actually is
|
270
|
+
this._sclv_heightCache = cache;
|
267
271
|
}
|
268
272
|
|
269
273
|
ret = cache[idx];
|
@@ -500,7 +500,7 @@ SC.ListItemView = SC.View.extend(
|
|
500
500
|
*/
|
501
501
|
_isInsideRightIcon: function(evt) {
|
502
502
|
var del = this.displayDelegate ;
|
503
|
-
var rightIconKey = this.getDelegateProperty('hasContentRightIcon', del) ;
|
503
|
+
var rightIconKey = this.getDelegateProperty('hasContentRightIcon', del) || !SC.none(this.rightIcon);
|
504
504
|
return rightIconKey && this._isInsideElementWithClassName('right-icon', evt);
|
505
505
|
},
|
506
506
|
|
@@ -89,6 +89,17 @@ SC.RadioView = SC.View.extend(SC.Control,
|
|
89
89
|
the title with this itemTitleKey property.
|
90
90
|
*/
|
91
91
|
itemTitleKey: null,
|
92
|
+
|
93
|
+
/**
|
94
|
+
If items property is a hash, specify which property will function as
|
95
|
+
the item width with this itemWidthKey property. This is only used when
|
96
|
+
layoutDirection is set to SC.LAYOUT_HORIONZTAL and can be used to override
|
97
|
+
the default value provided by the framework or theme CSS.
|
98
|
+
|
99
|
+
@property {String}
|
100
|
+
@default null
|
101
|
+
*/
|
102
|
+
itemWidthKey: null,
|
92
103
|
|
93
104
|
/**
|
94
105
|
If items property is a hash, specify which property will function as
|
@@ -142,9 +153,12 @@ SC.RadioView = SC.View.extend(SC.Control,
|
|
142
153
|
displayProperties: ['value', '_displayItems'],
|
143
154
|
|
144
155
|
render: function(context, firstTime) {
|
145
|
-
var
|
146
|
-
|
147
|
-
|
156
|
+
var items = this.get('_displayItems'),
|
157
|
+
value = this.get('value'),
|
158
|
+
isArray = SC.isArray(value),
|
159
|
+
item, idx, icon, name, width, itemsLength, url,
|
160
|
+
className, disabled, sel, labelText,
|
161
|
+
selectionState, selectionStateClassNames;
|
148
162
|
|
149
163
|
context.addClass(this.get('layoutDirection'));
|
150
164
|
|
@@ -186,8 +200,11 @@ SC.RadioView = SC.View.extend(SC.Control,
|
|
186
200
|
|
187
201
|
labelText = this.escapeHTML ? SC.RenderContext.escapeHTML(item[0]) : item[0];
|
188
202
|
|
189
|
-
|
190
|
-
|
203
|
+
width = item[4];
|
204
|
+
|
205
|
+
context.push('<div class="sc-radio-button ',
|
206
|
+
selectionStateClassNames, '" ',
|
207
|
+
width ? 'style="width: ' + width + 'px;" ' : '',
|
191
208
|
'aria-checked="', sel ? 'true':'false','" ',
|
192
209
|
'role="radio"' , ' index="', idx,'">',
|
193
210
|
'<span class="button"></span>',
|
@@ -209,6 +226,10 @@ SC.RadioView = SC.View.extend(SC.Control,
|
|
209
226
|
} else {
|
210
227
|
sel = NO;
|
211
228
|
}
|
229
|
+
|
230
|
+
width = item[4];
|
231
|
+
if (width) button.width(width);
|
232
|
+
|
212
233
|
selectionState = this._getSelectionStateClassNames(item, sel, value, isArray, true);
|
213
234
|
button.attr('aria-checked', sel ? 'true': 'false');
|
214
235
|
// set class of label
|
@@ -232,11 +253,14 @@ SC.RadioView = SC.View.extend(SC.Control,
|
|
232
253
|
_displayItems: function() {
|
233
254
|
var items = this.get('items'),
|
234
255
|
loc = this.get('localize'),
|
235
|
-
titleKey = this.get('itemTitleKey'),
|
256
|
+
titleKey = this.get('itemTitleKey'),
|
257
|
+
valueKey = this.get('itemValueKey'),
|
258
|
+
widthKey = this.get('itemWidthKey'),
|
259
|
+
isHorizontal = this.get('layoutDirection') === SC.LAYOUT_HORIZONTAL,
|
236
260
|
isEnabledKey = this.get('itemIsEnabledKey'),
|
237
261
|
iconKey = this.get('itemIconKey'),
|
238
262
|
ret = [], max = (items)? items.get('length') : 0,
|
239
|
-
item, title, value, idx, isArray, isEnabled, icon;
|
263
|
+
item, title, width, value, idx, isArray, isEnabled, icon;
|
240
264
|
|
241
265
|
for(idx=0;idx<max;idx++) {
|
242
266
|
item = items.objectAt(idx);
|
@@ -253,7 +277,11 @@ SC.RadioView = SC.View.extend(SC.Control,
|
|
253
277
|
if (titleKey) {
|
254
278
|
title = item.get ? item.get(titleKey) : item[titleKey];
|
255
279
|
} else title = (item.toString) ? item.toString() : null;
|
256
|
-
|
280
|
+
|
281
|
+
if (widthKey && isHorizontal) {
|
282
|
+
width = item.get ? item.get(widthKey) : item[widthKey];
|
283
|
+
}
|
284
|
+
|
257
285
|
if (valueKey) {
|
258
286
|
value = item.get ? item.get(valueKey) : item[valueKey];
|
259
287
|
} else value = item;
|
@@ -274,11 +302,11 @@ SC.RadioView = SC.View.extend(SC.Control,
|
|
274
302
|
|
275
303
|
// localize title if needed
|
276
304
|
if (loc) title = title.loc();
|
277
|
-
ret.push([title, value, isEnabled, icon]);
|
305
|
+
ret.push([title, value, isEnabled, icon, width]);
|
278
306
|
}
|
279
307
|
|
280
308
|
return ret; // done!
|
281
|
-
}.property('items', 'itemTitleKey', 'itemValueKey', 'itemIsEnabledKey', 'localize', 'itemIconKey').cacheable(),
|
309
|
+
}.property('items', 'itemTitleKey', 'itemWidthKey', 'itemValueKey', 'itemIsEnabledKey', 'localize', 'itemIconKey').cacheable(),
|
282
310
|
|
283
311
|
/** @private -
|
284
312
|
Will figure out what class names to assign each radio button.
|
@@ -198,7 +198,7 @@ SC.ScrollerView = SC.View.extend(
|
|
198
198
|
@private
|
199
199
|
*/
|
200
200
|
render: function(context, firstTime) {
|
201
|
-
var classNames =
|
201
|
+
var classNames = {},
|
202
202
|
buttons = '',
|
203
203
|
thumbPosition, thumbLength, thumbCenterLength, thumbElement,
|
204
204
|
value, max, scrollerLength, length, pct;
|
@@ -207,21 +207,21 @@ SC.ScrollerView = SC.View.extend(
|
|
207
207
|
// style them differently using CSS.
|
208
208
|
switch (this.get('layoutDirection')) {
|
209
209
|
case SC.LAYOUT_VERTICAL:
|
210
|
-
classNames
|
210
|
+
classNames['sc-vertical'] = YES;
|
211
211
|
break;
|
212
212
|
case SC.LAYOUT_HORIZONTAL:
|
213
|
-
classNames
|
213
|
+
classNames['sc-horizontal'] = YES;
|
214
214
|
break;
|
215
215
|
}
|
216
216
|
|
217
217
|
// The appearance of the scroller changes if disabled
|
218
|
-
|
218
|
+
classNames['disabled'] = !this.get('isEnabled');
|
219
219
|
// Whether to hide the thumb and buttons
|
220
|
-
|
220
|
+
classNames['controls-hidden'] = this.get('controlsHidden');
|
221
221
|
|
222
222
|
// Change the class names of the DOM element all at once to improve
|
223
223
|
// performance
|
224
|
-
context.
|
224
|
+
context.setClass(classNames);
|
225
225
|
|
226
226
|
// Calculate the position and size of the thumb
|
227
227
|
thumbLength = this.get('thumbLength');
|
@@ -240,7 +240,7 @@ SC.ScrollerView = SC.View.extend(
|
|
240
240
|
context.push('<div class="track"></div>',
|
241
241
|
'<div class="cap"></div>',
|
242
242
|
buttons,
|
243
|
-
'<div class="thumb" style="height: '+thumbLength+'px;">',
|
243
|
+
'<div class="thumb" style="height: '+thumbLength+'px; top: ' + thumbPosition + 'px;">',
|
244
244
|
'<div class="thumb-center"></div>',
|
245
245
|
'<div class="thumb-top"></div>',
|
246
246
|
'<div class="thumb-bottom"></div></div>');
|
@@ -249,7 +249,7 @@ SC.ScrollerView = SC.View.extend(
|
|
249
249
|
context.push('<div class="track"></div>',
|
250
250
|
'<div class="cap"></div>',
|
251
251
|
buttons,
|
252
|
-
'<div class="thumb" style="width: '+thumbLength+'px;">',
|
252
|
+
'<div class="thumb" style="width: '+thumbLength+'px; left: ' + thumbPosition + 'px;">',
|
253
253
|
'<div class="thumb-center"></div>',
|
254
254
|
'<div class="thumb-top"></div>',
|
255
255
|
'<div class="thumb-bottom"></div></div>');
|
@@ -2,7 +2,7 @@
|
|
2
2
|
// Project: SproutCore - JavaScript Application Framework
|
3
3
|
// Copyright: ©2006-2010 Sprout Systems, Inc. and contributors.
|
4
4
|
// Portions ©2008-2010 Apple Inc. All rights reserved.
|
5
|
-
// License:
|
5
|
+
// License: Licensed under MIT license (see license.js)
|
6
6
|
// ==========================================================================
|
7
7
|
|
8
8
|
/**
|
@@ -122,7 +122,9 @@ SC.SelectFieldView = SC.FieldView.extend(
|
|
122
122
|
var objects = this.get('objects') ;
|
123
123
|
var fieldValue = this.get('value') ;
|
124
124
|
var el, selectElement;
|
125
|
-
|
125
|
+
|
126
|
+
if ( !this.get('isEnabled') ) context.attr('disabled','disabled');
|
127
|
+
|
126
128
|
// get the localization flag.
|
127
129
|
var shouldLocalize = this.get('localize');
|
128
130
|
|
@@ -208,12 +210,17 @@ SC.SelectFieldView = SC.FieldView.extend(
|
|
208
210
|
}
|
209
211
|
},
|
210
212
|
|
211
|
-
displayProperties: ['objects','nameKey','valueKey'],
|
213
|
+
displayProperties: ['objects','nameKey','valueKey','isEnabled'],
|
212
214
|
|
213
215
|
_objectsObserver: function() {
|
214
216
|
this.set('cpDidChange', YES);
|
215
217
|
}.observes('objects'),
|
216
|
-
|
218
|
+
|
219
|
+
_objectArrayObserver: function() {
|
220
|
+
this.set('cpDidChange', YES);
|
221
|
+
this.propertyDidChange('objects');
|
222
|
+
}.observes('*objects.[]'),
|
223
|
+
|
217
224
|
_nameKeyObserver: function() {
|
218
225
|
this.set('cpDidChange', YES);
|
219
226
|
}.observes('nameKey'),
|
@@ -247,7 +254,8 @@ SC.SelectFieldView = SC.FieldView.extend(
|
|
247
254
|
var value = sc_super(); // get raw value...
|
248
255
|
var valueKey = this.get('valueKey') ;
|
249
256
|
var objects = this.get('objects') ;
|
250
|
-
var found
|
257
|
+
var found = null; // matching object goes here.
|
258
|
+
var object;
|
251
259
|
|
252
260
|
// Handle empty selection.
|
253
261
|
if (value == '***') {
|
@@ -260,7 +268,6 @@ SC.SelectFieldView = SC.FieldView.extend(
|
|
260
268
|
|
261
269
|
var loc = (SC.typeOf(objects.length) === SC.T_FUNCTION) ? objects.length() : objects.length;
|
262
270
|
|
263
|
-
found = null ; // matching object goes here.
|
264
271
|
while(!found && (--loc >= 0)) {
|
265
272
|
object = objects.objectAt? objects.objectAt(loc) : objects[loc] ;
|
266
273
|
if (!object) continue; // null means placeholder; just skip
|
@@ -219,17 +219,17 @@ SC.Button = {
|
|
219
219
|
|
220
220
|
var valueKey = this.getDelegateProperty('contentValueKey', del) ;
|
221
221
|
if (valueKey && (key === valueKey || key === '*')) {
|
222
|
-
this.set('value', content ? content.get(valueKey) : null) ;
|
222
|
+
this.set('value', content ? (content.get ? content.get(valueKey) : content[valueKey]) : null) ;
|
223
223
|
}
|
224
224
|
|
225
225
|
var titleKey = this.getDelegateProperty('contentTitleKey', del) ;
|
226
226
|
if (titleKey && (key === titleKey || key === '*')) {
|
227
|
-
this.set('title', content ? content.get(titleKey) : null) ;
|
227
|
+
this.set('title', content ? (content.get ? content.get(titleKey) : content[titleKey]) : null) ;
|
228
228
|
}
|
229
229
|
|
230
230
|
var iconKey = this.getDelegateProperty('contentIconKey', del);
|
231
231
|
if (iconKey && (key === iconKey || key === '*')) {
|
232
|
-
this.set('icon', content ? content.get(iconKey) : null) ;
|
232
|
+
this.set('icon', content ? (content.get ? content.get(iconKey) : content[iconKey]) : null) ;
|
233
233
|
}
|
234
234
|
|
235
235
|
return this ;
|
@@ -54,7 +54,7 @@ sc_require('views/text_field') ;
|
|
54
54
|
editor expects your source view to implement the InlineTextFieldViewDelegate
|
55
55
|
protocol.
|
56
56
|
|
57
|
-
h2.
|
57
|
+
h2. Committing or Discarding Changes
|
58
58
|
|
59
59
|
Normally the editor will automatically commit or discard its changes
|
60
60
|
whenever the user exits the edit mode. If you need to force the editor to
|
@@ -66,13 +66,13 @@ sc_require('views/text_field') ;
|
|
66
66
|
}}}
|
67
67
|
|
68
68
|
Both methods will try to end the editing context and will call the
|
69
|
-
|
69
|
+
relevant delegate methods on the delegate you passed to beginEditing().
|
70
70
|
|
71
71
|
Note that it is possible an editor may not be able to commit editing
|
72
72
|
changes because either the delegate disallowed it or because its validator
|
73
73
|
failed. In this case commitEditing() will return NO. If you want to
|
74
74
|
end editing anyway, you can discard the editing changes instead by calling
|
75
|
-
discardEditing(). This method will generally
|
75
|
+
discardEditing(). This method will generally succeed unless your delegate
|
76
76
|
refuses it as well.
|
77
77
|
|
78
78
|
@extends SC.TextFieldView
|
@@ -133,7 +133,9 @@ SC.InlineTextFieldView = SC.TextFieldView.extend(SC.DelegateSupport,
|
|
133
133
|
throw "At least frame and delegate options are required for inline editor";
|
134
134
|
}
|
135
135
|
|
136
|
-
this._originalValue = options.value
|
136
|
+
this._originalValue = options.value;
|
137
|
+
if (SC.none(this._originalValue))
|
138
|
+
this._originalValue = "";
|
137
139
|
this._multiline = (options.multiline !== undefined) ? options.multiline : NO ;
|
138
140
|
if (this._multiline) {
|
139
141
|
this.set('isTextArea', YES);
|
@@ -420,10 +422,11 @@ SC.InlineTextFieldView = SC.TextFieldView.extend(SC.DelegateSupport,
|
|
420
422
|
// editable, begins editing.
|
421
423
|
/** @private */
|
422
424
|
insertTab: function(evt) {
|
425
|
+
var delegate = this._delegate; // removed by commitEditing()
|
423
426
|
this.resignFirstResponder();
|
424
427
|
this.commitEditing() ;
|
425
|
-
if(
|
426
|
-
var next =
|
428
|
+
if(delegate){
|
429
|
+
var next = delegate.get('nextValidKeyView');
|
427
430
|
if(next && next.beginEditing) next.beginEditing();
|
428
431
|
}
|
429
432
|
return YES ;
|
@@ -431,10 +434,12 @@ SC.InlineTextFieldView = SC.TextFieldView.extend(SC.DelegateSupport,
|
|
431
434
|
|
432
435
|
/** @private */
|
433
436
|
insertBacktab: function(evt) {
|
437
|
+
var delegate = this._delegate; // removed by commitEditing()
|
438
|
+
this.resignFirstResponder();
|
434
439
|
this.commitEditing() ;
|
435
|
-
if(
|
436
|
-
var prev =
|
437
|
-
if(prev) prev.beginEditing();
|
440
|
+
if(delegate){
|
441
|
+
var prev = delegate.get('previousValidKeyView');
|
442
|
+
if(prev && prev.beginEditing) prev.beginEditing();
|
438
443
|
}
|
439
444
|
return YES ;
|
440
445
|
},
|
@@ -893,7 +893,9 @@ SC.DateTime.mixin(SC.Comparable,
|
|
893
893
|
@returns {DateTime} the DateTime corresponding to the string parameter
|
894
894
|
*/
|
895
895
|
parse: function(str, fmt) {
|
896
|
-
|
896
|
+
// Declared as an object not a literal since in some browsers the literal
|
897
|
+
// retains state across function calls
|
898
|
+
var re = new RegExp('(?:%([aAbBcdHIjmMpSUWwxXyYZ%])|(.))', "g");
|
897
899
|
var d, parts, opts = {}, check = {}, scanner = SC.Scanner.create({string: str});
|
898
900
|
|
899
901
|
if (SC.none(fmt)) fmt = SC.DATETIME_ISO8601;
|
@@ -1808,29 +1808,37 @@ SC.RootResponder = SC.Object.extend({
|
|
1808
1808
|
} else {
|
1809
1809
|
var lh = this._lastHovered || [] , nh = [] , exited, loc, len,
|
1810
1810
|
view = this.targetViewForEvent(evt) ;
|
1811
|
-
|
1812
|
-
//
|
1813
|
-
//
|
1814
|
-
while(view && (view !== this)) {
|
1811
|
+
|
1812
|
+
// first collect all the responding view starting with the
|
1813
|
+
// target view from the given mouse move event
|
1814
|
+
while (view && (view !== this)) {
|
1815
|
+
nh.push(view);
|
1816
|
+
view = view.get('nextResponder');
|
1817
|
+
}
|
1818
|
+
|
1819
|
+
// next exit views that are no longer part of the
|
1820
|
+
// responding chain
|
1821
|
+
for (loc=0, len=lh.length; loc < len; loc++) {
|
1822
|
+
view = lh[loc] ;
|
1823
|
+
exited = view.respondsTo('mouseExited');
|
1824
|
+
if (exited && nh.indexOf(view) === -1) {
|
1825
|
+
view.tryToPerform('mouseExited', evt);
|
1826
|
+
}
|
1827
|
+
}
|
1828
|
+
|
1829
|
+
// finally, either perform mouse moved or mouse entered depending on
|
1830
|
+
// whether a responding view was or was not part of the last
|
1831
|
+
// hovered views
|
1832
|
+
for (loc=0, len=nh.length; loc < len; loc++) {
|
1833
|
+
view = nh[loc];
|
1815
1834
|
if (lh.indexOf(view) !== -1) {
|
1816
1835
|
view.tryToPerform('mouseMoved', evt);
|
1817
|
-
nh.push(view) ;
|
1818
1836
|
} else {
|
1819
1837
|
view.tryToPerform('mouseEntered', evt);
|
1820
|
-
nh.push(view) ;
|
1821
|
-
}
|
1822
|
-
|
1823
|
-
view = view.get('nextResponder');
|
1824
|
-
}
|
1825
|
-
// now find those views last hovered over that were no longer found
|
1826
|
-
// in this chain and notify of mouseExited.
|
1827
|
-
for(loc=0, len=lh.length; loc < len; loc++) {
|
1828
|
-
view = lh[loc] ;
|
1829
|
-
exited = view.respondsTo('mouseExited') ;
|
1830
|
-
if (exited && !(nh.indexOf(view) !== -1)) {
|
1831
|
-
view.tryToPerform('mouseExited',evt);
|
1832
1838
|
}
|
1833
1839
|
}
|
1840
|
+
|
1841
|
+
// Keep track of the view that were last hovered
|
1834
1842
|
this._lastHovered = nh;
|
1835
1843
|
|
1836
1844
|
// also, if a mouseDownView exists, call the mouseDragged action, if
|
data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/inline_text_field/beginEditing.js
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
// ==========================================================================
|
7
7
|
/*global module test htmlbody ok equals same stop start Q$ */
|
8
8
|
|
9
|
-
var pane, optionsForLabel1, optionsForLabel2, delegate;
|
9
|
+
var pane, optionsForLabel1, optionsForLabel2, delegate, optionsForLabelFromView;
|
10
10
|
|
11
11
|
pane = SC.ControlTestPane.design().add("label1", SC.LabelView, {
|
12
12
|
value: 'Some Text',
|
@@ -50,6 +50,30 @@ pane.resetView = function(view) {
|
|
50
50
|
view.set('notifiedDidBegin', NO);
|
51
51
|
};
|
52
52
|
|
53
|
+
|
54
|
+
optionsForLabelFromView = function(view) {
|
55
|
+
var el = view.$(),
|
56
|
+
f = SC.viewportOffset(el[0]),
|
57
|
+
frameTemp = view.convertFrameFromView(view.get('frame'), null);
|
58
|
+
|
59
|
+
f.width = frameTemp.width;
|
60
|
+
f.height = frameTemp.height;
|
61
|
+
|
62
|
+
var optionsForLabel = {
|
63
|
+
frame: f,
|
64
|
+
delegate: view,
|
65
|
+
exampleElement: view.$(),
|
66
|
+
value: view.get('value'),
|
67
|
+
multiline: view.get('isInlineEditorMultiline'),
|
68
|
+
isCollection: NO,
|
69
|
+
validator: view.get('validator'),
|
70
|
+
exampleInlineTextFieldView: view.get('exampleInlineTextFieldView')
|
71
|
+
};
|
72
|
+
|
73
|
+
return optionsForLabel;
|
74
|
+
};
|
75
|
+
|
76
|
+
|
53
77
|
/**
|
54
78
|
|
55
79
|
*/
|
@@ -64,41 +88,8 @@ module("Test the beginEditing() function of SC.InlineTextFieldView", {
|
|
64
88
|
// Reset view1 delegate functions
|
65
89
|
pane.resetView(view1);
|
66
90
|
|
67
|
-
|
68
|
-
|
69
|
-
frameTemp = view1.convertFrameFromView(view1.get('frame'), null);
|
70
|
-
|
71
|
-
f.width = frameTemp.width;
|
72
|
-
f.height = frameTemp.height;
|
73
|
-
|
74
|
-
optionsForLabel1 = {
|
75
|
-
frame: f,
|
76
|
-
delegate: view1,
|
77
|
-
exampleElement: view1.$(),
|
78
|
-
value: view1.get('value'),
|
79
|
-
multiline: view1.get('isInlineEditorMultiline'),
|
80
|
-
isCollection: NO,
|
81
|
-
validator: view1.get('validator'),
|
82
|
-
exampleInlineTextFieldView: view1.get('exampleInlineTextFieldView')
|
83
|
-
};
|
84
|
-
|
85
|
-
el = view2.$();
|
86
|
-
f = SC.viewportOffset(el[0]);
|
87
|
-
frameTemp = view2.convertFrameFromView(view2.get('frame'), null);
|
88
|
-
|
89
|
-
f.width = frameTemp.width;
|
90
|
-
f.height = frameTemp.height;
|
91
|
-
|
92
|
-
optionsForLabel2 = {
|
93
|
-
frame: f,
|
94
|
-
delegate: view2,
|
95
|
-
exampleElement: view2.$(),
|
96
|
-
value: view2.get('value'),
|
97
|
-
multiline: view2.get('isInlineEditorMultiline'),
|
98
|
-
isCollection: NO,
|
99
|
-
validator: view2.get('validator'),
|
100
|
-
exampleInlineTextFieldView: view2.get('exampleInlineTextFieldView')
|
101
|
-
};
|
91
|
+
optionsForLabel1 = optionsForLabelFromView(view1);
|
92
|
+
optionsForLabel2 = optionsForLabelFromView(view2);
|
102
93
|
},
|
103
94
|
|
104
95
|
teardown: function() {
|
@@ -225,3 +216,22 @@ function() {
|
|
225
216
|
|
226
217
|
ok(view1.get('notifiedDidBegin'), "the delegate should have been notified of begin editing at this point");
|
227
218
|
});
|
219
|
+
|
220
|
+
test("inline editor does not display the defaultValue if the label's value is the number 0",
|
221
|
+
function() {
|
222
|
+
var view1 = pane.view('label1');;
|
223
|
+
view1.set('value', 0);
|
224
|
+
optionsForLabel1 = optionsForLabelFromView(view1);
|
225
|
+
|
226
|
+
SC.RunLoop.begin();
|
227
|
+
SC.InlineTextFieldView.beginEditing(optionsForLabel1);
|
228
|
+
SC.RunLoop.end();
|
229
|
+
|
230
|
+
// The inline editor is the last view appended to the pane
|
231
|
+
var length = pane._pane.childViews.length,
|
232
|
+
editor = pane._pane.childViews[length - 1];
|
233
|
+
same(editor.get('value'), 0, "editor should have number 0 as value");
|
234
|
+
editor.blurEditor();
|
235
|
+
|
236
|
+
same(view1.get('value'), 0, "view should still have number 0 as value");
|
237
|
+
});
|
@@ -2,7 +2,7 @@
|
|
2
2
|
// Project: SproutCore - JavaScript Application Framework
|
3
3
|
// Copyright: ©2006-2010 Sprout Systems, Inc. and contributors.
|
4
4
|
// portions copyright @2009 Apple Inc.
|
5
|
-
// License:
|
5
|
+
// License: Licensed under MIT license (see license.js)
|
6
6
|
// ==========================================================================
|
7
7
|
|
8
8
|
/*global module test htmlbody ok equals same stop start */
|
@@ -302,6 +302,11 @@ test('parse without a format uses default ISO8601', function() {
|
|
302
302
|
equals(SC.DateTime.parse("2010-09-17T18:35:08Z").toISO8601(), "2010-09-17T18:35:08+00:00");
|
303
303
|
});
|
304
304
|
|
305
|
+
test('bad parsing', function() {
|
306
|
+
equals(SC.DateTime.parse(SC.DateTime.parse("foo")), null);
|
307
|
+
equals(SC.DateTime.parse("2010-09-17T18:35:08Z", SC.DATETIME_ISO8601).toISO8601(), "2010-09-17T18:35:08+00:00");
|
308
|
+
});
|
309
|
+
|
305
310
|
test('binding', function() {
|
306
311
|
var fromObject = SC.Object.create({value: dt});
|
307
312
|
var toObject = SC.Object.create({value: ''});
|
@@ -0,0 +1,56 @@
|
|
1
|
+
// ==========================================================================
|
2
|
+
// Project: SproutCore - JavaScript Application Framework
|
3
|
+
// Copyright: ©2006-2010 Apple Inc. and contributors.
|
4
|
+
// License: Licensed under MIT license (see license.js)
|
5
|
+
// ==========================================================================
|
6
|
+
|
7
|
+
/*global module test equals context ok same */
|
8
|
+
var notEmptyValidator, field;
|
9
|
+
|
10
|
+
module("SC.Validator.NotEmpty", {
|
11
|
+
setup: function () {
|
12
|
+
notEmptyValidator = SC.Validator.NotEmpty.create();
|
13
|
+
field = SC.Object.create();
|
14
|
+
},
|
15
|
+
teardown: function () {
|
16
|
+
notEmptyValidator.destroy();
|
17
|
+
notEmptyValidator = null;
|
18
|
+
}
|
19
|
+
});
|
20
|
+
|
21
|
+
test("Recognizes a non-empty string as valid",function(){
|
22
|
+
field.set('fieldValue', "fnord");
|
23
|
+
var isValid = notEmptyValidator.validate(undefined, field);
|
24
|
+
ok(isValid, "Not empty string is valid");
|
25
|
+
});
|
26
|
+
|
27
|
+
test("Recognizes empty string as invalid",function(){
|
28
|
+
field.set('fieldValue', "");
|
29
|
+
var isValid = notEmptyValidator.validate(undefined, field);
|
30
|
+
ok( ! isValid, "Empty string is not valid");
|
31
|
+
});
|
32
|
+
|
33
|
+
test("Recognizes null as empty",function(){
|
34
|
+
field.set('fieldValue', null);
|
35
|
+
var isValid = notEmptyValidator.validate(undefined, field);
|
36
|
+
ok( ! isValid, "null string is not valid");
|
37
|
+
});
|
38
|
+
|
39
|
+
test("Recognizes undefined as empty",function(){
|
40
|
+
field.set('fieldValue', undefined);
|
41
|
+
var isValid = notEmptyValidator.validate(undefined, field);
|
42
|
+
ok( ! isValid, "null string is not valid");
|
43
|
+
});
|
44
|
+
|
45
|
+
test("Recognizes some number as non-empty",function(){
|
46
|
+
field.set('fieldValue', 42);
|
47
|
+
var isValid = notEmptyValidator.validate(undefined, field);
|
48
|
+
ok(isValid, "42 string is not empty");
|
49
|
+
});
|
50
|
+
|
51
|
+
test("Recognizes zero as non-empty",function(){
|
52
|
+
field.set('fieldValue', 0);
|
53
|
+
var isValid = notEmptyValidator.validate(undefined, field);
|
54
|
+
ok(isValid, "0 string is not empty");
|
55
|
+
});
|
56
|
+
|
@@ -2,7 +2,7 @@
|
|
2
2
|
// Project: SproutCore - JavaScript Application Framework
|
3
3
|
// Copyright: ©2006-2010 Sprout Systems, Inc. and contributors.
|
4
4
|
// Portions ©2008-2010 Apple Inc. All rights reserved.
|
5
|
-
// License:
|
5
|
+
// License: Licensed under MIT license (see license.js)
|
6
6
|
// ==========================================================================
|
7
7
|
|
8
8
|
require('validators/validator');
|