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
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/inline_text_editor.js
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') ;
@@ -14,6 +14,6 @@ Docs = SC.Object.create({
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
  }) ;
@@ -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
@@ -14,6 +14,6 @@ TestRunner = SC.Object.create({
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
  }) ;
@@ -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
- this.intervalId = window.setInterval(this.timerDelegate, this.options.interval);
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
- window.clearInterval(this.intervalId);
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.getYear();
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.getYear()+"";
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 == SC.Object._noinit_) return ;
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)) ;
@@ -69,7 +69,7 @@ SC.Set = SC.Object.extend(SC.Array,
69
69
  _each: function(iterator) {
70
70
  for (var key in this) {
71
71
  if (!this.hasOwnProperty(key)) continue ;
72
- if (key[0] == '@') iterator(this[key]) ;
72
+ if (key.match(/^@/)) iterator(this[key]) ;
73
73
  }
74
74
  }
75
75
 
@@ -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
- } finally {
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
+ } ;