sproutcore 0.9.2 → 0.9.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/History.txt
CHANGED
@@ -1,5 +1,38 @@
|
|
1
1
|
== SVN HEAD
|
2
2
|
|
3
|
+
* Basic changes to get IE working. All non-view tests now pass and the doc app and test runner both load and run in IE7. Lots of visual fixes are still required for the sc-theme as well as IE-specific perf optimization and bug fixes.
|
4
|
+
|
5
|
+
* [BUG] Default template for both client and template included a stray comma in their core.js file that breaks IE and Safari 2. This is fixed in the templates and in the clients included with the framework, though you will need to make this change manually in your own apps.
|
6
|
+
|
7
|
+
* beginInlineEdit() and endInlineEdit() on SC.LabelView were renamed to comply
|
8
|
+
with the SC.Editable protocol. Use beginEditing() and commitEditing() or
|
9
|
+
discardEditing() instead.
|
10
|
+
|
11
|
+
* Added SC.Editable mixin. This provides a standard protocol for begining
|
12
|
+
and ending keyboard editing sessions on views. SC.Editable is now used
|
13
|
+
by SC.LabelView, SC.ListItemView, SC.TextFieldView, and SC.TextareaFieldView.
|
14
|
+
|
15
|
+
* Collection view now supports the default behavior to begin editing when you
|
16
|
+
click on a selected item for a second time. If you hit return it will also
|
17
|
+
begin editing. To support this, you must set contentValueIsEditable to YES
|
18
|
+
and implement beginEditing() on your item view.
|
19
|
+
|
20
|
+
* Inline editor is now supported in both SC.ListItemView and SC.LabelView.
|
21
|
+
|
22
|
+
* Improved inline editor (now renamed SC.InlineTextFieldView for consistancy).
|
23
|
+
The new editor can be used with basically any view now in addition to just the
|
24
|
+
label view. It also automatically inherits the font size and style of any
|
25
|
+
underlying DOM element that you hand it. To work with an inline editor you
|
26
|
+
will need to implement the InlineEditorDelegate (see documentation).
|
27
|
+
|
28
|
+
* Inline editor now displays with a fixed width and grows downward as you type instead of stretching out to the end.
|
29
|
+
|
30
|
+
--
|
31
|
+
|
32
|
+
* Added hello world sample app.
|
33
|
+
|
34
|
+
* Updated contacts sample app. It is much nicer now.
|
35
|
+
|
3
36
|
* Add sproutcore freeze:gems command to freeze latest SproutCore in your local project.
|
4
37
|
|
5
38
|
* Updated copyright to 2008.
|
data/Manifest.txt
CHANGED
@@ -39,18 +39,6 @@ clients/sc_test_runner/main.js
|
|
39
39
|
clients/sc_test_runner/models/test.js
|
40
40
|
clients/sc_test_runner/views/runner_frame.js
|
41
41
|
clients/sc_test_runner/views/test_label.js
|
42
|
-
clients/view_builder/builders/builder.js
|
43
|
-
clients/view_builder/builders/button.js
|
44
|
-
clients/view_builder/controllers/document.js
|
45
|
-
clients/view_builder/core.js
|
46
|
-
clients/view_builder/english.lproj/body.css
|
47
|
-
clients/view_builder/english.lproj/body.rhtml
|
48
|
-
clients/view_builder/english.lproj/controls.css
|
49
|
-
clients/view_builder/english.lproj/strings.js
|
50
|
-
clients/view_builder/main.js
|
51
|
-
clients/view_builder/tests/controllers/document.rhtml
|
52
|
-
clients/view_builder/tests/views/builder.rhtml
|
53
|
-
clients/view_builder/views/builder.js
|
54
42
|
config/hoe.rb
|
55
43
|
config/requirements.rb
|
56
44
|
frameworks/prototype/prototype.js
|
@@ -74,7 +62,6 @@ frameworks/sproutcore/english.lproj/images/sc-theme-ysprite.png
|
|
74
62
|
frameworks/sproutcore/english.lproj/images/shared-icons.png
|
75
63
|
frameworks/sproutcore/english.lproj/images/sproutcore-logo.png
|
76
64
|
frameworks/sproutcore/english.lproj/images/sticky-note.png
|
77
|
-
frameworks/sproutcore/english.lproj/inline_text_editor.css
|
78
65
|
frameworks/sproutcore/english.lproj/menu.css
|
79
66
|
frameworks/sproutcore/english.lproj/panels/background-fat.jpg
|
80
67
|
frameworks/sproutcore/english.lproj/panels/background-thin.jpg
|
@@ -128,6 +115,8 @@ frameworks/sproutcore/lib/menu_views.rb
|
|
128
115
|
frameworks/sproutcore/mixins/array.js
|
129
116
|
frameworks/sproutcore/mixins/control.js
|
130
117
|
frameworks/sproutcore/mixins/delegate_support.js
|
118
|
+
frameworks/sproutcore/mixins/editable.js
|
119
|
+
frameworks/sproutcore/mixins/inline_editor_delegate.js
|
131
120
|
frameworks/sproutcore/mixins/observable.js
|
132
121
|
frameworks/sproutcore/mixins/scrollable.js
|
133
122
|
frameworks/sproutcore/mixins/selection_support.js
|
@@ -199,7 +188,7 @@ frameworks/sproutcore/views/field/textarea_field.js
|
|
199
188
|
frameworks/sproutcore/views/filter_button.js
|
200
189
|
frameworks/sproutcore/views/form.js
|
201
190
|
frameworks/sproutcore/views/image.js
|
202
|
-
frameworks/sproutcore/views/
|
191
|
+
frameworks/sproutcore/views/inline_text_field.js
|
203
192
|
frameworks/sproutcore/views/label.js
|
204
193
|
frameworks/sproutcore/views/list_item.js
|
205
194
|
frameworks/sproutcore/views/menu_item.js
|
@@ -131,6 +131,7 @@ Docs.docsController = SC.Object.create({
|
|
131
131
|
var clientName = this.get('clientName') ;
|
132
132
|
var clientRoot = this.get('clientRoot') ;
|
133
133
|
Docs.server.request(clientRoot, null, null, {
|
134
|
+
nonce: Date.now().toString(),
|
134
135
|
onSuccess: this._rebuildSuccess.bind(this),
|
135
136
|
onFailure: this._rebuildFailure.bind(this)
|
136
137
|
}, 'post') ;
|
data/clients/sc_docs/core.js
CHANGED
@@ -84,6 +84,7 @@ TestRunner.runnerController = SC.Object.create({
|
|
84
84
|
// current client.
|
85
85
|
var urlRoot = this.get('urlRoot') ;
|
86
86
|
TestRunner.server.request(urlRoot, 'index.js', null, {
|
87
|
+
nonce: Date.now().toString(),
|
87
88
|
onSuccess: this._reloadSuccess.bind(this),
|
88
89
|
onFailure: this._reloadFailure.bind(this)
|
89
90
|
}) ;
|
@@ -92,6 +93,9 @@ TestRunner.runnerController = SC.Object.create({
|
|
92
93
|
_reloadSuccess: function(status, transport) {
|
93
94
|
var json = transport.responseText ;
|
94
95
|
var records = eval(json) ;
|
96
|
+
|
97
|
+
console.log('JSON: %@'.fmt(json)) ;
|
98
|
+
|
95
99
|
if ($type(records) != T_ARRAY) {
|
96
100
|
return this._reloadFailure(status, transport) ;
|
97
101
|
}
|
@@ -100,6 +104,7 @@ TestRunner.runnerController = SC.Object.create({
|
|
100
104
|
// the records included in the list. This is what will become our new
|
101
105
|
// list.
|
102
106
|
var recs = SC.Store.updateRecords(records, this, TestRunner.Test, true);
|
107
|
+
console.log('retrieved records: %@'.fmt(recs.join(','))) ;
|
103
108
|
|
104
109
|
// show warning panel if the records are empty. Also reload tests
|
105
110
|
// periodically so that when the user resolves the problem, we can start
|
@@ -1,6 +1,7 @@
|
|
1
1
|
/* @override
|
2
2
|
http://localhost:4020/static/sproutcore/en/_cache/core-1207528979.css
|
3
3
|
http://localhost:4020/static/sproutcore/en/_cache/core-1207680408.css
|
4
|
+
http://localhost:4020/static/sproutcore/en/_cache/core-1208585577.css
|
4
5
|
*/
|
5
6
|
|
6
7
|
/* =============================================
|
@@ -58,6 +59,10 @@
|
|
58
59
|
|
59
60
|
/* @group SC.ListItemView */
|
60
61
|
|
62
|
+
.sc-list-item-view {
|
63
|
+
overflow: hidden;
|
64
|
+
}
|
65
|
+
|
61
66
|
.sc-list-item-view .sc-icon {
|
62
67
|
width: 16px;
|
63
68
|
height: 16px;
|
@@ -85,6 +90,10 @@
|
|
85
90
|
right: 14px;
|
86
91
|
}
|
87
92
|
|
93
|
+
.sc-list-item-view .sc-label {
|
94
|
+
text-overflow: ellipse;
|
95
|
+
}
|
96
|
+
|
88
97
|
/* @end */
|
89
98
|
|
90
99
|
/* @group SC.SourceListView */
|
@@ -111,5 +120,37 @@
|
|
111
120
|
|
112
121
|
/* @end */
|
113
122
|
|
123
|
+
/* @group SC.InlineTextFieldView */
|
124
|
+
|
125
|
+
.sc-inline-text-field-view {
|
126
|
+
position: absolute ;
|
127
|
+
z-index: 10000000;
|
128
|
+
padding: 0;
|
129
|
+
margin: 0;
|
130
|
+
}
|
131
|
+
|
132
|
+
/* sizer needs to be able to resize
|
133
|
+
vertically so that we can compute the
|
134
|
+
new size for the text. */
|
135
|
+
.sc-inline-text-field-view .sizer {
|
136
|
+
position: absolute;
|
137
|
+
left: 0;
|
138
|
+
top: 0;
|
139
|
+
width: 100%;
|
140
|
+
}
|
141
|
+
|
142
|
+
.sc-inline-text-field-view .inner-field {
|
143
|
+
position: absolute ;
|
144
|
+
left: 0;
|
145
|
+
top: 0;
|
146
|
+
width: 100%;
|
147
|
+
height: 100%;
|
148
|
+
border: none ;
|
149
|
+
overflow: hidden ;
|
150
|
+
resize: none;
|
151
|
+
}
|
152
|
+
|
153
|
+
/* @end */
|
154
|
+
|
114
155
|
|
115
156
|
|
@@ -456,5 +456,25 @@ input.show-hint {
|
|
456
456
|
|
457
457
|
/* @end */
|
458
458
|
|
459
|
+
/* @group SC.InlineTextFieldView */
|
460
|
+
|
461
|
+
.sc-theme .sc-inline-text-field-view {
|
462
|
+
}
|
463
|
+
|
464
|
+
.sc-theme .sc-inline-text-field-view .inner-field {
|
465
|
+
border: 1px solid #888;
|
466
|
+
-webkit-box-shadow: #555 0px 1px 5px ;
|
467
|
+
background-color: white ;
|
468
|
+
}
|
469
|
+
|
470
|
+
.sc-theme .sc-inline-text-field-view .inner-field.invalid {
|
471
|
+
outline: 2px red solid;
|
472
|
+
}
|
473
|
+
|
474
|
+
/* @end */
|
475
|
+
|
476
|
+
|
477
|
+
|
478
|
+
|
459
479
|
|
460
480
|
|
@@ -63,7 +63,15 @@ Animator.prototype = {
|
|
63
63
|
this.state = Math.max(0, Math.min(1, from));
|
64
64
|
this.lastTime = new Date().getTime();
|
65
65
|
if (!this.intervalId) {
|
66
|
-
|
66
|
+
// this.intervalId = this.setInterval(this.timerDelegate, this.options.interval);
|
67
|
+
|
68
|
+
this.intervalId = SC.Timer.schedule({
|
69
|
+
target: this,
|
70
|
+
action: this.timerDelegate,
|
71
|
+
interval: this.options.interval,
|
72
|
+
repeats: YES
|
73
|
+
}) ;
|
74
|
+
|
67
75
|
}
|
68
76
|
},
|
69
77
|
// animate from the current state to provided value
|
@@ -113,7 +121,8 @@ Animator.prototype = {
|
|
113
121
|
} finally {
|
114
122
|
this.options.onStep.call(this);
|
115
123
|
if (this.target == this.state) {
|
116
|
-
|
124
|
+
// window.clearInterval(this.intervalId);
|
125
|
+
this.intervalId.invalidate();
|
117
126
|
this.intervalId = null;
|
118
127
|
this.options.onComplete.call(this);
|
119
128
|
}
|
@@ -97,7 +97,7 @@ Object.extend(Date,{
|
|
97
97
|
var token2="";
|
98
98
|
var x,y;
|
99
99
|
var now=new Date();
|
100
|
-
var year=now.
|
100
|
+
var year=now.getFullYear();
|
101
101
|
var month=now.getMonth()+1;
|
102
102
|
var date=1;
|
103
103
|
var hh=now.getHours();
|
@@ -302,7 +302,7 @@ Object.extend(Date.prototype, {
|
|
302
302
|
var i_format=0;
|
303
303
|
var c="";
|
304
304
|
var token="";
|
305
|
-
var y=date.
|
305
|
+
var y=date.getFullYear()+"";
|
306
306
|
var M=date.getMonth()+1;
|
307
307
|
var d=date.getDate();
|
308
308
|
var E=date.getDay();
|
@@ -49,7 +49,7 @@ SC.BENCHMARK_OBJECTS = NO;
|
|
49
49
|
|
50
50
|
*/
|
51
51
|
SC.Object = function(noinit) {
|
52
|
-
if (noinit
|
52
|
+
if (noinit === SC.Object._noinit_) return ;
|
53
53
|
var ret = SC.Object._init.apply(this,$A(arguments)) ;
|
54
54
|
return ret ;
|
55
55
|
};
|
@@ -176,7 +176,7 @@ Object.extend(SC.Object,
|
|
176
176
|
if (this._objectClassName) return this._objectClassName ;
|
177
177
|
var ret = this ;
|
178
178
|
while(ret && !ret._objectClassName) ret = ret._type;
|
179
|
-
return (ret._objectClassName) ? ret._objectClassName : 'Anonymous' ;
|
179
|
+
return (ret && ret._objectClassName) ? ret._objectClassName : 'Anonymous' ;
|
180
180
|
},
|
181
181
|
|
182
182
|
/** @private
|
@@ -98,6 +98,7 @@ SC.Server = SC.Object.extend({
|
|
98
98
|
if (onFailure) onFailure(transport.status, transport, cacheCode,context);
|
99
99
|
} ;
|
100
100
|
|
101
|
+
console.log('REQUEST: %@'.fmt(url)) ;
|
101
102
|
request = new Ajax.Request(url,opts) ;
|
102
103
|
},
|
103
104
|
|
@@ -379,7 +380,7 @@ SC.Server = SC.Object.extend({
|
|
379
380
|
|
380
381
|
// find the recordType
|
381
382
|
if (data.type) {
|
382
|
-
var recordName = data.type.capitalize()
|
383
|
+
var recordName = data.type.capitalize() ;
|
383
384
|
if (server.prefix) for(var prefixLoc=0;prefixLoc < server.prefix.length; prefixLoc++) {
|
384
385
|
var namespace = window[server.prefix[prefixLoc]] ;
|
385
386
|
if (namespace) data.recordType = namespace[recordName] ;
|
@@ -404,7 +405,7 @@ SC.Server = SC.Object.extend({
|
|
404
405
|
var ret = {} ;
|
405
406
|
records.each(function(rec) {
|
406
407
|
var recs = ret[rec.resourceURL || '*'] || [] ;
|
407
|
-
recs.push(rec)
|
408
|
+
recs.push(rec) ;
|
408
409
|
ret[rec.resourceURL || '*'] = recs ;
|
409
410
|
}) ;
|
410
411
|
return ret ;
|
@@ -477,7 +478,7 @@ SC.Server = SC.Object.extend({
|
|
477
478
|
|
478
479
|
// handle objects
|
479
480
|
} else if (typeof(params) == "object") {
|
480
|
-
var ret = []
|
481
|
+
var ret = [];
|
481
482
|
for(var cur in params) {
|
482
483
|
var key = (rootKey) ? (rootKey + '['+cur+']') : cur ;
|
483
484
|
ret.push(this._toQueryString(params[cur],key)) ;
|
@@ -166,7 +166,7 @@ Test.Unit.Runner.prototype = {
|
|
166
166
|
if (!rootLog) {
|
167
167
|
var el = document.createElement('div') ;
|
168
168
|
el.id = 'test-log' ;
|
169
|
-
el.addClassName('testlog') ;
|
169
|
+
$(el).addClassName('testlog') ;
|
170
170
|
var body = document.getElementsByTagName('body')[0] ;
|
171
171
|
body.insertBefore(el, body.firstChild) ;
|
172
172
|
rootLog = el ;
|
@@ -530,18 +530,20 @@ Object.extend(Object.extend(Test.Unit.Testcase.prototype, Test.Unit.Assertions.p
|
|
530
530
|
this.timeToWait = time;
|
531
531
|
},
|
532
532
|
run: function() {
|
533
|
-
try {
|
534
|
-
try {
|
533
|
+
//try {
|
534
|
+
//try {
|
535
535
|
if (!this.isWaiting) this.setup.bind(this)();
|
536
536
|
this.isWaiting = false;
|
537
537
|
this.test.bind(this)();
|
538
|
-
}
|
538
|
+
//} catch(e) {
|
539
|
+
// throw e; // required for IE compatibility.
|
540
|
+
//} finally {
|
539
541
|
if(!this.isWaiting) {
|
540
542
|
this.teardown.bind(this)();
|
541
543
|
}
|
542
|
-
}
|
543
|
-
}
|
544
|
-
catch(e) { this.error(e); }
|
544
|
+
//}
|
545
|
+
//}
|
546
|
+
//catch(e) { this.error(e); }
|
545
547
|
}
|
546
548
|
});
|
547
549
|
|
@@ -595,7 +597,7 @@ Test.context = function(name, spec, log){
|
|
595
597
|
default:
|
596
598
|
var testName = 'test'+specName.gsub(/\s+/,'-').camelize();
|
597
599
|
var body = spec[specName].toString().split('\n').slice(1);
|
598
|
-
if(/^\{/.test(body[0])) body = body.slice(1);
|
600
|
+
if(/^\s*\{/.test(body[0])) body = body.slice(1);
|
599
601
|
body.pop();
|
600
602
|
body = body.map(function(statement){
|
601
603
|
return statement.strip() ;
|
@@ -618,5 +620,6 @@ Test.Observer = function()
|
|
618
620
|
if (!arguments.callee.notified) arguments.callee.notified = 0;
|
619
621
|
return ++arguments.callee.notified;
|
620
622
|
};
|
621
|
-
}
|
623
|
+
} ;
|
624
|
+
|
622
625
|
|
@@ -26,6 +26,7 @@ view_helper :collection_view do
|
|
26
26
|
property :content_value_key
|
27
27
|
property :group_visible_key
|
28
28
|
property :group_title_key
|
29
|
+
property :content_value_editable, :key => 'contentValueIsEditable'
|
29
30
|
property :accepts_first_responder, true
|
30
31
|
property :can_reorder_content
|
31
32
|
|
@@ -123,13 +123,17 @@ end
|
|
123
123
|
view_helper :label_view do
|
124
124
|
property(:formatter) { |v| v }
|
125
125
|
property :localize, false
|
126
|
+
property :editable, :key => 'isEditable'
|
126
127
|
property :escape_html, true, :key => 'escapeHTML'
|
128
|
+
property :value
|
127
129
|
|
128
130
|
var :label, nil
|
131
|
+
var :value, nil
|
129
132
|
view 'SC.LabelView'
|
130
133
|
|
131
134
|
css_class_names << 'sc-label-view'
|
132
135
|
@inner_html = @label unless @label.nil?
|
136
|
+
@inner_html = @value unless @value.nil?
|
133
137
|
end
|
134
138
|
|
135
139
|
# Render an SC.SpinnerView. Inherits from SC.View. You should bind
|
@@ -0,0 +1,144 @@
|
|
1
|
+
// ========================================================================
|
2
|
+
// SproutCore
|
3
|
+
// copyright 2006-2008 Sprout Systems, Inc.
|
4
|
+
// ========================================================================
|
5
|
+
|
6
|
+
/**
|
7
|
+
@namespace
|
8
|
+
|
9
|
+
The Editable mixin is a standard protocol used to activate keyboard editing
|
10
|
+
on views that are editable such as text fields, label views and item views.
|
11
|
+
|
12
|
+
You should apply this mixin, or implement the methods, if you are
|
13
|
+
designing an item view for a collection and you want to automatically
|
14
|
+
trigger editing.
|
15
|
+
|
16
|
+
h2. Using Editable Views
|
17
|
+
|
18
|
+
To use a view that includes the Editable mixin, you simply call three
|
19
|
+
methods on the view:
|
20
|
+
|
21
|
+
- To begin editing, call beginEditing(). This will make the view first responder and allow the user to make changes to it. If the view cannot begin editing for some reason, it will return NO.
|
22
|
+
|
23
|
+
- If you want to cancel editing, you should try calling discardEditing(). This will cause the editor to discard its changed value and resign first responder. Some editors do not support cancelling editing and will return NO. If this is the case, you may optionally try calling commitEditing() instead to force the view to resign first responder, even though this will commit the changes.
|
24
|
+
|
25
|
+
- If you want to end editing, while saving any changes that were made, try calling commitEditing(). This will cause the editor to validate and apply its changed value and resign first responder. If the editor cannot validate its contents for some reason, it will return NO. In this case you may optionally try calling discardEditing() instead to force the view to resign first responder, even though this will discard the changes.
|
26
|
+
|
27
|
+
|
28
|
+
h2. Implementing an Editable View
|
29
|
+
|
30
|
+
To implement a new view that is editable, you should implement the three
|
31
|
+
methods defined below: beginEditing(), discardEditing(), and
|
32
|
+
commitEditing(). If you already allow editing when your view becomes first
|
33
|
+
responder and commit your changes when the view loses first responder status
|
34
|
+
then you can simply apply this mixin and not override any methods.
|
35
|
+
|
36
|
+
|
37
|
+
@since SproutCore 1.0
|
38
|
+
|
39
|
+
*/
|
40
|
+
SC.Editable = {
|
41
|
+
|
42
|
+
/**
|
43
|
+
Indicates whether a view is editable or not. You can optionally
|
44
|
+
implement the methods in this mixin to disallow editing is isEditable is
|
45
|
+
NO.
|
46
|
+
*/
|
47
|
+
isEditable: NO,
|
48
|
+
|
49
|
+
/**
|
50
|
+
Indicates whether editing is currently in progress. The methods you
|
51
|
+
implement should generally up this property as appropriate when you
|
52
|
+
begin and end editing.
|
53
|
+
*/
|
54
|
+
isEditing: NO,
|
55
|
+
|
56
|
+
/**
|
57
|
+
Begins editing on the view.
|
58
|
+
|
59
|
+
This method is called by other views when they want you to begin editing.
|
60
|
+
You should write this method to become first responder, perform any
|
61
|
+
additional setup needed to begin editing and then return YES.
|
62
|
+
|
63
|
+
If for some reason you do not want to allow editing right now, you can
|
64
|
+
also return NO. If your view is already editing, then you should not
|
65
|
+
restart editing again but just return YES.
|
66
|
+
|
67
|
+
The default implementation checks to see if editing is allowed, then
|
68
|
+
becomes first responder and updates the isEditing property if appropriate.
|
69
|
+
Generally you will want to replace this method with your own
|
70
|
+
implementation and not call the default.
|
71
|
+
|
72
|
+
@returns {Boolean} YES if editing began or is in progress, NO otherwise
|
73
|
+
*/
|
74
|
+
beginEditing: function() {
|
75
|
+
if (!this.get('isEditable')) return NO ;
|
76
|
+
if (this.get('isEditing')) return YES ;
|
77
|
+
|
78
|
+
// begin editing
|
79
|
+
this.set('isEditing', YES) ;
|
80
|
+
this.becomeFirstResponder() ;
|
81
|
+
return YES ;
|
82
|
+
},
|
83
|
+
|
84
|
+
/**
|
85
|
+
Ends editing on the view, discarding any changes that were made to the
|
86
|
+
view value in the meantime.
|
87
|
+
|
88
|
+
This method is called by other views when they want to cancel editing
|
89
|
+
that began earlier. When this method is called you should resign first
|
90
|
+
responder, restore the original value of the view and return YES.
|
91
|
+
|
92
|
+
If your view cannot revert back to its original state before editing began
|
93
|
+
then you can implement this method to simply return NO. A properly
|
94
|
+
implemented client may try to call commitEditing() instead to force your
|
95
|
+
view to end editing anyway.
|
96
|
+
|
97
|
+
If this method is called on a view that is not currently editing, you
|
98
|
+
should always just return YES.
|
99
|
+
|
100
|
+
The default implementation does not support discarding changes and always
|
101
|
+
returns NO.
|
102
|
+
|
103
|
+
@returns {Boolean} YES if changes were discarded and editing ended.
|
104
|
+
*/
|
105
|
+
discardEditing: function() {
|
106
|
+
// if we are not editing, return YES, otherwise NO.
|
107
|
+
return !this.get('isEditing') ;
|
108
|
+
},
|
109
|
+
|
110
|
+
/**
|
111
|
+
Ends editing on the view, committing any changes that were made to the
|
112
|
+
view value in the meantime.
|
113
|
+
|
114
|
+
This method is called by other views when they want to end editing,
|
115
|
+
saving any changes that were made to the view in the meantime. When this
|
116
|
+
method is called you should resign first responder, save the latest
|
117
|
+
value of the view and return YES.
|
118
|
+
|
119
|
+
If your view cannot save the current state of the view for some reason
|
120
|
+
(for example if validation fails), then you should return NO. Properly
|
121
|
+
implemented clients may then try to call discardEditing() to force your
|
122
|
+
view to resign first responder anyway.
|
123
|
+
|
124
|
+
Some views apply changes to their value immediately during an edit instead
|
125
|
+
of waiting for the view to end editing. If this is the case, you should
|
126
|
+
still implement commitEditing but you simply may not save any value
|
127
|
+
changes.
|
128
|
+
|
129
|
+
If this method is called on a view that is not currently editing, you
|
130
|
+
should always just reutrn YES.
|
131
|
+
|
132
|
+
The default implementation sets isEditing to NO, resigns first responder
|
133
|
+
and returns YES.
|
134
|
+
|
135
|
+
@returns {Boolean} YES if changes were discarded and editing ended.
|
136
|
+
*/
|
137
|
+
commitEditing: function() {
|
138
|
+
if (!this.get('isEditing')) return YES;
|
139
|
+
this.set('isEditing', NO) ;
|
140
|
+
this.resignFirstResponder() ;
|
141
|
+
return YES ;
|
142
|
+
}
|
143
|
+
|
144
|
+
} ;
|