sproutcore 0.9.7 → 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,4 +1,8 @@
1
- == SVN HEAD
1
+ == SproutCore 0.9.8
2
+
3
+ * [FIX] Plugged memory leak in view_helper that would cause sc-server to slow down after repeated use.
4
+
5
+ == SproutCore 0.9.7
2
6
 
3
7
  * [FIX] build tools could puke on strings files that contains quotes. This should fix it.
4
8
 
@@ -1,4 +1,8 @@
1
- == SVN HEAD
1
+ == GIT HEAD
2
+
3
+ == 0.9.8
4
+
5
+ * [FIX] collection views now update group views appropriately.
2
6
 
3
7
  * [IE] offsetParent and viewportOffset() are now IE compliant.
4
8
 
@@ -13,3 +13,4 @@ http://www.sproutcore.com
13
13
  If you would like to contact the authors, you can reach the current maintainer
14
14
  at charles@sproutit.com
15
15
 
16
+
@@ -138,7 +138,7 @@ SC.Drag = SC.Object.extend(
138
138
  for(var key in this._data) {
139
139
  if (this.data.hasOwnProperty(key)) ret.push(key) ;
140
140
  }
141
- return key ;
141
+ return ret ;
142
142
  }
143
143
 
144
144
  // if that fails, then check to see if the source object is a dataSource.
@@ -100,10 +100,11 @@ view_helper :button_view do
100
100
  var :theme, :regular
101
101
  var :size, :normal
102
102
 
103
- attribute(:href) { |x| (x.nil? && (@tag.downcase.to_s == 'a')) ? 'javascript:;' : nil }
103
+ attribute(:href) { |x| (x.nil? && (@tag.downcase.to_s == 'a')) ? 'javascript:;' : x }
104
104
 
105
105
  # Add the theme to the CSS class.
106
106
  css_class_names << 'sc-button-view'
107
+ css_class_names << 'button'
107
108
  css_class_names << @theme unless @theme.nil? || @theme == false
108
109
  css_class_names << @size unless @size.nil? || @size == false
109
110
 
@@ -17,6 +17,16 @@
17
17
  */
18
18
  SC.InlineEditorDelegate = {
19
19
 
20
+ /**
21
+ This is a classname you can apply to the inline editor field
22
+ to configure it's styling, in addition to the the editor's
23
+ default style-cloning behavior.
24
+
25
+ @property inlineEditorClassName {String} A class name to use with the inline editor.
26
+ */
27
+ inlineEditorClassName: "",
28
+
29
+
20
30
  /**
21
31
  Called just before the inline edit displays itself but after it has been
22
32
  configured for display.
@@ -130,7 +130,7 @@ SC.OverlayPaneView = SC.PaneView.extend({
130
130
  },
131
131
 
132
132
  cancel: function(sender, evt) {
133
- var button = this._findViewWithKeyIn('isDefault', SC.ButtonView, this) ;
133
+ var button = this._findViewWithKeyIn('isCancel', SC.ButtonView, this) ;
134
134
  if (button) {
135
135
  button.triggerAction(evt) ;
136
136
  return true ;
@@ -44,6 +44,7 @@ Test.context("CASE 1: Auto-layout view with no padding & no border", {
44
44
 
45
45
  });
46
46
 
47
+
47
48
  // CASE 2: Auto-layout of view with padding
48
49
  // - same as Case 1, except innerFrame = frame less padding
49
50
  CASE2_OFFSET = 2;
@@ -222,6 +222,9 @@ SC.ButtonView = SC.View.extend(SC.Control,
222
222
  */
223
223
  keyEquivalent: null,
224
224
 
225
+ /** @private {String} used to store a previously defined key equiv */
226
+ _lastKeyEquivalent: null,
227
+
225
228
  performKeyEquivalent: function( keystring, evt )
226
229
  {
227
230
  if (!this.get('isEnabled')) return false;
@@ -329,12 +332,26 @@ SC.ButtonView = SC.View.extend(SC.Control,
329
332
  _isDefaultOrCancelObserver: function() {
330
333
  var isDef = !!this.get('isDefault') ;
331
334
  var isCancel = !isDef && this.get('isCancel') ;
332
-
333
- this.setClassName('def', isDef) ;
334
-
335
- var key = this.get('keyEquivalent') ;
336
- if (isDef && key != 'return') this.set('keyEquivalent', 'return') ;
337
- if (isCancel && key != 'escape') this.set('keyEquivalent', 'escape') ;
335
+ if(this.didChangeFor('defaultCancelChanged','isDefault','isCancel')) {
336
+ this.setClassName('def', isDef) ;
337
+ var key = this.get('keyEquivalent') ;
338
+ if (isDef) {
339
+ //cache the previously defined key equivalent
340
+ this._lastKeyEquivalent = key;
341
+ this.setIfChanged('keyEquivalent', 'return');
342
+ }
343
+ else if (isCancel)
344
+ {
345
+ //cache the previously defined key equivalent
346
+ this._lastKeyEquivalent = key;
347
+ this.setIfChanged('keyEquivalent', 'escape') ;
348
+ }
349
+ else
350
+ {
351
+ this.setIfChanged("keyEquivalent",this._lastKeyEquivalent);
352
+ }
353
+ }
354
+
338
355
  }.observes('isDefault', 'isCancel'),
339
356
 
340
357
  // on mouse down, set active only if enabled.
@@ -691,7 +691,7 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
691
691
  var didChange = false ;
692
692
 
693
693
  // If this is a fullUpdate, then rebuild the itemViewsByContent hash
694
- // from scratch. This is necessary of the content of the visible range
694
+ // from scratch. This is necessary if the content or the visible range
695
695
  // might have changed.
696
696
  if (fullUpdate) {
697
697
 
@@ -1059,9 +1059,27 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
1059
1059
  if (!ret) throw "Could not create itemView for content: %@".fmt(content);
1060
1060
 
1061
1061
  // Determine proper parent view and insert itemView if needed.
1062
- // Also update count of itemViews.
1063
- var parentView = (groupBy && content) ? this._insertGroupViewFor(content.get(groupBy), contentIndex) : this ;
1064
- if (ret.get('parentNode') != parentView) {
1062
+ // Also update count of itemViews.
1063
+ var canGroup = !!(groupBy && content) ;
1064
+ var groupValue = (canGroup) ? content.get(groupBy) : null;
1065
+ var parentView = (canGroup) ? this._insertGroupViewFor(groupValue, contentIndex) : this ;
1066
+ var curParentView = ret.get('parentNode') ;
1067
+
1068
+ if (curParentView != parentView) {
1069
+
1070
+ // if the item is already inside of another group, then it is probably
1071
+ // just being moved, so remove it from its parent group first...
1072
+ if (groupBy && curParentView) {
1073
+
1074
+ // reduce the group view count. If this it the last item in the
1075
+ // group view, the count will be <= 0 and we will need to remove t
1076
+ // the group view itself.
1077
+ if (--this._groupViewCounts[SC.guidFor(curParentView)] <= 0) {
1078
+ this._removeGroupView(curParentView, groupValue) ;
1079
+ }
1080
+
1081
+ }
1082
+
1065
1083
  parentView.appendChild(ret) ;
1066
1084
  if (groupBy) this._groupViewCounts[SC.guidFor(parentView)]++ ;
1067
1085
  }
@@ -2494,7 +2512,10 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
2494
2512
  while(--idx >= 0) {
2495
2513
  var itemView = this.itemViewForContent(dragContent[idx]) ;
2496
2514
  if (!itemView) continue ;
2515
+
2497
2516
  var f = itemView.get('frame') ;
2517
+ f = this.convertFrameFromView(f, itemView) ;
2518
+
2498
2519
  var dom = itemView.rootElement ;
2499
2520
  if (!dom) continue ;
2500
2521
 
@@ -2510,6 +2531,7 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
2510
2531
  // even if the CSS styles do not match. Make sure the items are
2511
2532
  // properly positioned.
2512
2533
  dom = dom.cloneNode(true) ;
2534
+
2513
2535
  Element.setStyle(dom, { position: "absolute", left: "%@px".fmt(f.x), top: "%@px".fmt(f.y), width: "%@px".fmt(f.width), height: "%@px".fmt(f.height) }) ;
2514
2536
  view.rootElement.appendChild(dom) ;
2515
2537
  }
@@ -367,7 +367,7 @@ SC.SourceListView = SC.CollectionView.extend(
367
367
  } ;
368
368
 
369
369
  var insertionPoint = this._insertionPointView ;
370
- f = { height: 0, x: 8, y: itemView.get('frame').y, width: itemView.owner.get('frame').width };
370
+ var f = this.calculateInsertionPointFrame(itemView);
371
371
  insertionPoint.set('frame', f) ;
372
372
 
373
373
  if (insertionPoint.parentNode != itemView.parentNode) {
@@ -377,6 +377,16 @@ SC.SourceListView = SC.CollectionView.extend(
377
377
 
378
378
  },
379
379
 
380
+ /**
381
+ This is the default frame for the insertion point. Override this method
382
+ if your insertion point's styling needs to be customized, or if you need
383
+ more control of the insertion point's positioning (i.e., heirarchical
384
+ placement)
385
+ */
386
+ calculateInsertionPointFrame: function(itemView) {
387
+ return { height: 0, x: 8, y: itemView.get('frame').y, width: itemView.owner.get('frame').width };
388
+ },
389
+
380
390
  hideInsertionPoint: function() {
381
391
  var insertionPoint = this._insertionPointView ;
382
392
  if (insertionPoint) insertionPoint.removeFromParent() ;
@@ -401,7 +411,7 @@ SC.SourceListView = SC.CollectionView.extend(
401
411
  var retOp = SC.DROP_BEFORE ;
402
412
 
403
413
  // search groups until we find one that matches
404
- var top = 0;
414
+ var top = 0 ;
405
415
  var idx = 0 ;
406
416
  while((ret<0) && (range = this.groupRangeForContentIndex(idx)).length>0){
407
417
  var max = top + ((range.length+headerRowCount) * rowHeight) ;
@@ -100,9 +100,7 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
100
100
  this._isFocused = true ;
101
101
  if (this.get('isVisibleInWindow')) {
102
102
  this.rootElement.focus();
103
-
104
- this.invokeLater(this._selectRootElement, 1) ;
105
-
103
+ this.invokeLater(this._selectRootElement, 1) ;
106
104
  }
107
105
  }
108
106
 
@@ -110,8 +108,8 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
110
108
  this._updateFieldHint() ;
111
109
  },
112
110
 
113
- // In IE, you can't modify functions on DOM elements so we need to wrap the call to select()
114
- // like this.
111
+ // In IE, you can't modify functions on DOM elements so we need to wrap the
112
+ // call to select() like this.
115
113
  _selectRootElement: function() {
116
114
  this.rootElement.select() ;
117
115
  },
@@ -125,8 +123,7 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
125
123
  this._isFocused = false ;
126
124
  this._updateFieldHint() ;
127
125
  return this.rootElement.blur() ;
128
- }
129
- else {
126
+ } else {
130
127
  this._value = this.rootElement.value ;
131
128
  this.fieldValueDidChange() ;
132
129
  this._updateFieldHint() ;
@@ -131,6 +131,12 @@ SC.InlineTextFieldView = SC.View.extend(SC.DelegateSupport, SC.InlineEditorDeleg
131
131
  this.updateViewStyle() ;
132
132
 
133
133
  var del = this._delegate ;
134
+
135
+ this._className = this.getDelegateProperty(del,"inlineEditorClassName");
136
+ if(this._className && !this.hasClassName(this._className)) {
137
+ this.setClassName(this._className,true);
138
+ }
139
+
134
140
  this.invokeDelegateMethod(del, 'inlineEditorWillBeginEditing', this) ;
135
141
  this.resizeToFit(field.getFieldValue()) ;
136
142
 
@@ -190,8 +196,11 @@ SC.InlineTextFieldView = SC.View.extend(SC.DelegateSupport, SC.InlineEditorDeleg
190
196
  // and clean up.
191
197
  this.invokeDelegateMethod(del, 'inlineEditorDidEndEditing', this, finalValue) ;
192
198
 
199
+ // If the delegate set a class name, let's clean it up:
200
+ if(this._className) this.setClassName(this._className, false);
201
+
193
202
  // cleanup cached values
194
- this._originalValue = this._delegate = this._exampleElement = this._optframe = null ;
203
+ this._originalValue = this._delegate = this._exampleElement = this._optframe = this._className = null ;
195
204
  this.set('isEditing', NO) ;
196
205
 
197
206
  // resign first responder if not done already. This may call us in a
@@ -328,6 +337,25 @@ SC.InlineTextFieldView = SC.View.extend(SC.DelegateSupport, SC.InlineEditorDeleg
328
337
  this.owner.commitEditing() ;
329
338
  return YES ;
330
339
  }
340
+ },
341
+
342
+ // Tries to find the next key view when tabbing. If the next view is
343
+ // editable, begins editing.
344
+
345
+ insertTab: function(evt)
346
+ {
347
+ var next = this.get("owner")._delegate.nextValidKeyView();
348
+ this.owner.commitEditing() ;
349
+ if(next) next.beginEditing();
350
+ return YES ;
351
+ },
352
+
353
+ insertBacktab: function(evt)
354
+ {
355
+ var prev = this.get("owner")._delegate.previousValidKeyView();
356
+ this.owner.commitEditing() ;
357
+ if(prev) prev.beginEditing();
358
+ return YES ;
331
359
  }
332
360
 
333
361
  }).outletFor('.inner-field?'),
@@ -385,6 +413,8 @@ SC.InlineTextFieldView.mixin(
385
413
  return (this.sharedEditor) ? this.sharedEditor.discardEditing() : YES ;
386
414
  },
387
415
 
416
+
417
+
388
418
  /**
389
419
  The current shared inline editor. This property will often remain NULL
390
420
  until you actually begin editing for the first time.
@@ -470,12 +470,19 @@ SC.View = SC.Responder.extend(SC.PathModule, SC.DelegateSupport,
470
470
  //
471
471
 
472
472
  /**
473
- Read-only array of currently applied classNames.
473
+ An array of currently applied classNames.
474
474
 
475
475
  @field
476
476
  @type {Array}
477
+ @param value {Array} Array of class names to apply to the element
477
478
  */
478
- classNames: function() {
479
+ classNames: function(key, value) {
480
+ if (value !== undefined) {
481
+ value = Array.from(value) ;
482
+ if (this.rootElement) this.rootElement.className = value.join(' ') ;
483
+ this._classNames = value.slice() ;
484
+ }
485
+
479
486
  if (!this._classNames) {
480
487
  var classNames = this.rootElement.className;
481
488
  this._classNames = (classNames && classNames.length > 0) ? classNames.split(' ') : [] ;
@@ -502,11 +509,9 @@ SC.View = SC.Responder.extend(SC.PathModule, SC.DelegateSupport,
502
509
  addClassName: function(className) {
503
510
  if (this.hasClassName(className)) return ; // nothing to do
504
511
 
505
- this.propertyWillChange('classNames') ;
506
512
  var classNames = this._classNames || this.get('classNames') ;
507
513
  classNames.push(className) ;
508
- if (this.rootElement) this.rootElement.className = classNames.join(' ');
509
- this.propertyDidChange('classNames') ;
514
+ this.set('classNames', classNames) ;
510
515
  return className ;
511
516
  },
512
517
 
@@ -519,11 +524,9 @@ SC.View = SC.Responder.extend(SC.PathModule, SC.DelegateSupport,
519
524
  removeClassName: function(className) {
520
525
  if (!this.hasClassName(className)) return ; // nothing to do
521
526
 
522
- this.propertyWillChange('classNames') ;
523
527
  var classNames = this._classNames || this.get('classNames') ;
524
528
  classNames = this._classNames = classNames.without(className) ;
525
- if (this.rootElement) this.rootElement.className = classNames.join(' ');
526
- this.propertyDidChange('classNames') ;
529
+ this.set('classNames', classNames) ;
527
530
  return className ;
528
531
  },
529
532
 
@@ -543,7 +543,7 @@ module SproutCore
543
543
 
544
544
  return cached[:contents]
545
545
  end
546
-
546
+
547
547
  ######################################################
548
548
  ## LOCALIZATION
549
549
  ##
@@ -2,7 +2,7 @@ module SproutCore #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 9
5
- TINY = 7
5
+ TINY = 8
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -605,16 +605,11 @@ module SproutCore
605
605
  SproutCore::ViewHelperSupport.set_helper(helper_name, hs)
606
606
 
607
607
  ## install the helper method
608
- SproutCore::ViewHelpers.class_eval %{
608
+ eval %{
609
609
  def #{helper_name}(item_id=nil, opts={}, &block)
610
610
  SproutCore::ViewHelperSupport.render_view(:#{helper_name}, item_id, opts, bundle, self, &block)
611
611
  end }
612
612
 
613
- SproutCore::ViewHelpers.class_eval %{
614
- def self.#{helper_name}(item_id=nil, opts={}, &block)
615
- SproutCore::ViewHelperSupport.render_view(:#{helper_name}, item_id, opts, bundle, self, &block)
616
- end }
617
-
618
613
  end
619
614
 
620
615
  def render_page_views
@@ -654,7 +649,7 @@ module SproutCore
654
649
 
655
650
  # restore old bundle helper.
656
651
  unless bundle.nil?
657
- @helper_bundler = old_helper_bundle
652
+ @helper_bundle = old_helper_bundle
658
653
  end
659
654
  end
660
655
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sproutcore
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.7
4
+ version: 0.9.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Charles Jolley
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-05-27 00:00:00 -07:00
12
+ date: 2008-06-01 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency