@breakside/jskit 2021.44.0 → 2022.3.0

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.
Files changed (86) hide show
  1. package/Frameworks/DOM.jsframework/Info.json +2 -2
  2. package/Frameworks/DOM.jsframework/io.breakside.JSKit.DOM-bundle.js +2 -2
  3. package/Frameworks/FontKit.jsframework/Info.json +2 -2
  4. package/Frameworks/FontKit.jsframework/io.breakside.JSKit.FontKit-bundle.js +2 -2
  5. package/Frameworks/Foundation.jsframework/Info.json +2 -2
  6. package/Frameworks/Foundation.jsframework/JS/Deflate.js +2 -3
  7. package/Frameworks/Foundation.jsframework/JS/Error+JS.js +10 -0
  8. package/Frameworks/Foundation.jsframework/JS/JSColorSpace.js +106 -20
  9. package/Frameworks/Foundation.jsframework/JS/JSDateFormatter.js +2 -2
  10. package/Frameworks/Foundation.jsframework/JS/JSTimer.js +6 -0
  11. package/Frameworks/Foundation.jsframework/JS/JSURLResponse.js +60 -1
  12. package/Frameworks/Foundation.jsframework/JS/Zlib.js +2 -3
  13. package/Frameworks/Foundation.jsframework/io.breakside.JSKit.Foundation-bundle.js +2 -2
  14. package/Frameworks/SecurityKit.jsframework/Info.json +2 -2
  15. package/Frameworks/SecurityKit.jsframework/io.breakside.JSKit.SecurityKit-bundle.js +2 -2
  16. package/Info.json +2 -2
  17. package/Node/JavascriptCompilation.js +1 -1
  18. package/Node/io.breakside.jskit-bundle.js +2 -2
  19. package/Root/Frameworks/APIKit/APIError.js +2 -3
  20. package/Root/Frameworks/APIKit/Info.yaml +1 -1
  21. package/Root/Frameworks/APIKitTesting/Info.yaml +1 -1
  22. package/Root/Frameworks/AuthKit/Info.yaml +1 -1
  23. package/Root/Frameworks/CSSOM/Info.yaml +1 -1
  24. package/Root/Frameworks/ChartKit/Info.yaml +1 -1
  25. package/Root/Frameworks/ConferenceKit/Info.yaml +1 -1
  26. package/Root/Frameworks/DBKit/DBObjectDatabase.js +6 -5
  27. package/Root/Frameworks/DBKit/Info.yaml +1 -1
  28. package/Root/Frameworks/DOM/Info.yaml +1 -1
  29. package/Root/Frameworks/Dispatch/Info.yaml +1 -1
  30. package/Root/Frameworks/FontKit/Info.yaml +1 -1
  31. package/Root/Frameworks/Foundation/Deflate.js +2 -3
  32. package/Root/Frameworks/Foundation/Error+JS.js +10 -0
  33. package/Root/Frameworks/Foundation/Info.yaml +1 -1
  34. package/Root/Frameworks/Foundation/JSColorSpace.js +106 -20
  35. package/Root/Frameworks/Foundation/JSDateFormatter.js +2 -2
  36. package/Root/Frameworks/Foundation/JSTimer.js +6 -0
  37. package/Root/Frameworks/Foundation/JSURLResponse.js +60 -1
  38. package/Root/Frameworks/Foundation/Zlib.js +2 -3
  39. package/Root/Frameworks/ImageKit/IKColorProfile.js +979 -0
  40. package/Root/Frameworks/ImageKit/IKColorSpace.js +49 -198
  41. package/Root/Frameworks/ImageKit/IKDecoderPNG.js +1 -3
  42. package/Root/Frameworks/ImageKit/IKMatrix.js +124 -0
  43. package/Root/Frameworks/ImageKit/ImageKit.js +2 -0
  44. package/Root/Frameworks/ImageKit/Info.yaml +1 -1
  45. package/Root/Frameworks/MediaKit/Info.yaml +1 -1
  46. package/Root/Frameworks/MediaKitUI/Info.yaml +1 -1
  47. package/Root/Frameworks/NotificationKit/Info.yaml +1 -1
  48. package/Root/Frameworks/PDFKit/Info.yaml +1 -1
  49. package/Root/Frameworks/QRKit/Info.yaml +1 -1
  50. package/Root/Frameworks/SearchKit/Info.yaml +1 -1
  51. package/Root/Frameworks/SecurityKit/Info.yaml +1 -1
  52. package/Root/Frameworks/ServerKit/Info.yaml +1 -1
  53. package/Root/Frameworks/ServerKit/SKFileJobQueue.js +3 -1
  54. package/Root/Frameworks/ServerKit/SKHTTPError.js +2 -3
  55. package/Root/Frameworks/ServerKit/SKHTTPRequest.js +7 -0
  56. package/Root/Frameworks/ServerKit/SKHTTPResponder.js +9 -2
  57. package/Root/Frameworks/ServerKit/SKUserAgent.js +130 -0
  58. package/Root/Frameworks/ServerKit/SKValidatingObject.js +1 -3
  59. package/Root/Frameworks/ServerKit/ServerKit.js +1 -0
  60. package/Root/Frameworks/ServerKitTesting/Info.yaml +1 -1
  61. package/Root/Frameworks/TestKit/Info.yaml +1 -1
  62. package/Root/Frameworks/UIKit/Info.yaml +1 -1
  63. package/Root/Frameworks/UIKit/UICollectionReusableView.js +91 -0
  64. package/Root/Frameworks/UIKit/UICollectionView.js +1254 -0
  65. package/Root/Frameworks/UIKit/UICollectionViewCell.js +121 -0
  66. package/Root/Frameworks/UIKit/UICollectionViewGridLayout.js +425 -0
  67. package/Root/Frameworks/UIKit/UICollectionViewLayout.js +82 -0
  68. package/Root/Frameworks/UIKit/UIColorWell.js +12 -1
  69. package/Root/Frameworks/UIKit/UIDisplayServer.js +5 -1
  70. package/Root/Frameworks/UIKit/UIKit.js +7 -0
  71. package/Root/Frameworks/UIKit/UILayer.js +3 -0
  72. package/Root/Frameworks/UIKit/UIListView.js +39 -15
  73. package/Root/Frameworks/UIKit/UIMenu.js +1 -1
  74. package/Root/Frameworks/UIKit/UIMenuView.js +5 -1
  75. package/Root/Frameworks/UIKit/UINavigationBar.js +2 -2
  76. package/Root/Frameworks/UIKit/UIPopupButton.js +31 -3
  77. package/Root/Frameworks/UIKit/UIScrollView.js +2 -0
  78. package/Root/Frameworks/UIKit/UISplitViewController.js +52 -96
  79. package/Root/Frameworks/UIKit/UITabView.js +2 -2
  80. package/Root/Frameworks/UIKit/UITabViewController.js +6 -5
  81. package/Root/Frameworks/UIKit/UITextField.js +3 -0
  82. package/Root/Frameworks/UIKit/UIView.js +18 -0
  83. package/Root/Frameworks/UIKit/UIViewController.js +11 -0
  84. package/Root/Frameworks/UIKit/UIWindowServer.js +2 -2
  85. package/Root/Frameworks/UIKitTesting/Info.yaml +1 -1
  86. package/package.json +1 -1
@@ -201,6 +201,9 @@ JSClass("UILayer", JSObject, {
201
201
  },
202
202
 
203
203
  setTransform: function(transform){
204
+ if (transform.isEqual(this.model.transform)){
205
+ return;
206
+ }
204
207
  // When the transform changes, the frame needs to be recalculated. The position, however, does
205
208
  // not change. The transform essentially defines a new relationship between the position and frame
206
209
  this._addImplicitAnimationForKey('transform');
@@ -126,7 +126,7 @@ JSClass("UIListView", UIScrollView, {
126
126
  if (typeof(reuse) === 'string'){
127
127
  this.registerHeaderFooterClassForReuseIdentifier(JSClass.FromName(reuse), identifier);
128
128
  }else{
129
- this.registerCellClassForReuseIdentifier(JSClass.FromName(reuse.valueForKey('className')), identifier);
129
+ this.registerHeaderFooterClassForReuseIdentifier(JSClass.FromName(reuse.valueForKey('className')), identifier);
130
130
  }
131
131
  }
132
132
  }
@@ -140,7 +140,7 @@ JSClass("UIListView", UIScrollView, {
140
140
  this._headersStickToTop = spec.valueForKey("headersStickToTop");
141
141
  }
142
142
  if (spec.containsKey("showsFocusRing")){
143
- this._showsFocusRing = spec.valueForKey("showsFocusRing");
143
+ this.showsFocusRing = spec.valueForKey("showsFocusRing");
144
144
  }
145
145
  if (spec.containsKey("listHeaderView")){
146
146
  this.listHeaderView = spec.valueForKey("listHeaderView", UIView);
@@ -339,7 +339,6 @@ JSClass("UIListView", UIScrollView, {
339
339
  var lastVisibleItem = this._visibleItems[this._visibleItems.length - 1];
340
340
  var searcher = JSBinarySearcher(this._visibleItems, VisibleItem.cellIndexPathCompare);
341
341
  var visibleSizeChanged = false;
342
- var listView = this;
343
342
  var contentSize = JSSize(this.contentSize);
344
343
  var contentOffset = JSPoint(this.contentOffset);
345
344
 
@@ -391,13 +390,13 @@ JSClass("UIListView", UIScrollView, {
391
390
 
392
391
  if (animator && visibleSizeChanged){
393
392
  animator.addAnimations(function(){
394
- listView.contentSize = contentSize;
395
- listView.contentOffset = contentOffset;
396
- listView._layoutVisibleItems(this._visibleItems, y0);
397
- });
393
+ this.contentSize = contentSize;
394
+ this.contentOffset = contentOffset;
395
+ this._layoutVisibleItems(this._visibleItems, y0);
396
+ }, this);
398
397
  }else{
399
- listView.contentSize = contentSize;
400
- listView.contentOffset = contentOffset;
398
+ this.contentSize = contentSize;
399
+ this.contentOffset = contentOffset;
401
400
  }
402
401
 
403
402
  },
@@ -1561,9 +1560,12 @@ JSClass("UIListView", UIScrollView, {
1561
1560
 
1562
1561
  _createCellAtIndexPath: function(indexPath, rect){
1563
1562
  indexPath = JSIndexPath(indexPath);
1563
+ if (!this.delegate.cellForListViewAtIndexPath){
1564
+ throw new Error("%s must implement cellForListViewAtIndexPath()".sprintf(this.delegate.$class.className));
1565
+ }
1564
1566
  var cell = this.delegate.cellForListViewAtIndexPath(this, indexPath);
1565
1567
  if (cell === null || cell === undefined){
1566
- throw new Error("Got null/undefined cell for indexPath: %s".sprintf(indexPath));
1568
+ throw new Error("%s.cellForListViewAtIndexPath() returned null/undefined cell for indexPath: %s".sprintf(this.delegate.$class.className, indexPath));
1567
1569
  }
1568
1570
  this._adoptCell(cell, indexPath);
1569
1571
  cell.bounds = JSRect(JSPoint.Zero, rect.size);
@@ -1588,9 +1590,12 @@ JSClass("UIListView", UIScrollView, {
1588
1590
  header = this._stickyHeader;
1589
1591
  this._stickyHeader = null;
1590
1592
  }else{
1593
+ if (!this.delegate.headerViewForListViewSection){
1594
+ throw new Error("%s must implement headerViewForListViewSection() when headerHeight is non-zero".sprintf(this.delegate.$class.className));
1595
+ }
1591
1596
  header = this.delegate.headerViewForListViewSection(this, section);
1592
1597
  if (header === null || header === undefined){
1593
- throw new Error("Got null/undefined header for section: %d".sprintf(section));
1598
+ throw new Error("%s.headerViewForListViewSection() returned null/undefined header for section: %d".sprintf(this.delegate.$class.className, section));
1594
1599
  }
1595
1600
  }
1596
1601
  header.kind = UIListViewHeaderFooterView.Kind.header;
@@ -1598,19 +1603,24 @@ JSClass("UIListView", UIScrollView, {
1598
1603
  header.bounds = JSRect(JSPoint.Zero, rect.size);
1599
1604
  header.position = JSPoint(rect.origin.x + header.bounds.size.width * header.anchorPoint.x, rect.origin.y + header.bounds.size.height * header.anchorPoint.y);
1600
1605
  this._styler.updateHeader(header, section);
1606
+ header.setNeedsLayout();
1601
1607
  return header;
1602
1608
  },
1603
1609
 
1604
1610
  _createFooterAtSection: function(section, rect){
1611
+ if (!this.delegate.footerViewForListViewSection){
1612
+ throw new Error("%s must implement footerViewForListViewSection() when footerHeight is non-zero".sprintf(this.delegate.$class.className));
1613
+ }
1605
1614
  var footer = this.delegate.footerViewForListViewSection(this, section);
1606
1615
  if (footer === null || footer === undefined){
1607
- throw new Error("Got null/undefined footer for section: %d".sprintf(section));
1616
+ throw new Error("%s.headerViewForListViewSection() returned null/undefined header for section: %d".sprintf(this.delegate.$class.className, section));
1608
1617
  }
1609
1618
  footer.kind = UIListViewHeaderFooterView.Kind.footer;
1610
1619
  footer.section = section;
1611
1620
  footer.bounds = JSRect(JSPoint.Zero, rect.size);
1612
1621
  footer.position = JSPoint(rect.origin.x + footer.bounds.size.width * footer.anchorPoint.x, rect.origin.y + footer.bounds.size.height * footer.anchorPoint.y);
1613
1622
  this._styler.updateFooter(footer, section);
1623
+ footer.setNeedsLayout();
1614
1624
  return footer;
1615
1625
  },
1616
1626
 
@@ -2592,6 +2602,20 @@ JSClass("UIListView", UIScrollView, {
2592
2602
  return indexPaths;
2593
2603
  },
2594
2604
 
2605
+ visibleCells: JSReadOnlyProperty(),
2606
+
2607
+ getVisibleCells: function(){
2608
+ var cells = [];
2609
+ var item;
2610
+ for (var i = 0, l = this._visibleItems.length; i < l; ++i){
2611
+ item = this._visibleItems[i];
2612
+ if (item.kind === VisibleItem.Kind.cell){
2613
+ cells.push(item.view);
2614
+ }
2615
+ }
2616
+ return cells;
2617
+ },
2618
+
2595
2619
  // --------------------------------------------------------------------
2596
2620
  // MARK: - Scrolling
2597
2621
 
@@ -2780,7 +2804,7 @@ VisibleItemIterator.prototype = Object.create({}, {
2780
2804
  value: function(){
2781
2805
  var height;
2782
2806
  var item;
2783
- if (this.item !== null && this.item.Kind === VisibleItem.Kind.footer){
2807
+ if (this.item !== null && this.item.kind === VisibleItem.Kind.footer){
2784
2808
  ++this.section;
2785
2809
  }
2786
2810
  while (this.section < this.listView.__numberOfSections){
@@ -2801,7 +2825,7 @@ VisibleItemIterator.prototype = Object.create({}, {
2801
2825
  item = new VisibleItem(VisibleItem.Kind.cell, JSRect(0, this.y, this.width, height), this.cellIterator.indexPath);
2802
2826
  return item;
2803
2827
  }
2804
- if (this.item === null || this.item.section <= this.section){
2828
+ if (this.item === null || this.item.indexPath.section <= this.section){
2805
2829
  height = this.listView._heightForFooterInSection(this.section);
2806
2830
  if (height > 0){
2807
2831
  item = new VisibleItem(VisibleItem.Kind.footer, JSRect(0, this.y, this.width, height), JSIndexPath([this.section]));
@@ -3226,7 +3250,7 @@ JSClass("UIListViewDefaultStyler", UIListViewStyler, {
3226
3250
 
3227
3251
  layoutCell: function(cell){
3228
3252
  cell._contentView.frame = cell.bounds.rectWithInsets(this.cellContentInsets);
3229
- var size = JSSize(cell.bounds.size.width - cell._titleInsets.left - cell._titleInsets.right, 0);
3253
+ var size = JSSize(cell._contentView.bounds.size.width - cell._titleInsets.width, 0);
3230
3254
  var origin = JSPoint(cell._titleInsets.left, 0);
3231
3255
  var indent = this._indentationForCell(cell);
3232
3256
  origin.x += indent;
@@ -894,7 +894,7 @@ JSClass("UIMenuWindowStyler", UIMenuStyler, {
894
894
  var item = menu.items[itemIndex];
895
895
  var window = this.windowForMenu(menu);
896
896
  if (window !== null){
897
- return window.viewForITem(item);
897
+ return window.viewForItem(item);
898
898
  }
899
899
  return null;
900
900
  }
@@ -214,7 +214,11 @@ JSClass("UIMenuWindow", UIWindow, {
214
214
  },
215
215
 
216
216
  viewForItem: function(item){
217
- return this._itemViewIndexesByItemId[item.objectID] || null;
217
+ var index = this._itemViewIndexesByItemId[item.objectID];
218
+ if (index !== undefined){
219
+ return this.menuView.itemViews[index];
220
+ }
221
+ return null;
218
222
  },
219
223
 
220
224
  // -----------------------------------------------------------------------
@@ -490,9 +490,9 @@ JSClass("UINavigationBarDefaultStyler", UINavigationBarStyler, {
490
490
  props.backBarItemView.alpha = 0;
491
491
  var backTitleFrame = props.backBarItemView.titleLabel.convertRectToView(props.backBarItemView.titleLabel.bounds, props.backBarItemView.superview);
492
492
  if (removingCustomView){
493
- props.backBarItemView.titleLabel.transform = JSAffineTransform.Translated(removingCustomView.frame.origin.x - backTitleFrame.origin.x, 0).scaledBy(backToTitleScale);
493
+ props.backBarItemView.titleLabel.transform = JSAffineTransform.Translated(Math.max(0, removingCustomView.frame.origin.x - backTitleFrame.origin.x), 0).scaledBy(backToTitleScale);
494
494
  }else{
495
- props.backBarItemView.titleLabel.transform = JSAffineTransform.Translated(removingTitleLabel.frame.origin.x - backTitleFrame.origin.x, 0).scaledBy(backToTitleScale);
495
+ props.backBarItemView.titleLabel.transform = JSAffineTransform.Translated(Math.max(0, removingTitleLabel.frame.origin.x - backTitleFrame.origin.x), 0).scaledBy(backToTitleScale);
496
496
  }
497
497
  animator.addAnimations(function(){
498
498
  var i, l;
@@ -467,18 +467,21 @@ JSClass("UIPopupButtonStyler", UIControlStyler, {
467
467
 
468
468
  JSClass("UIPopupButtonCustomStyler", UIPopupButtonStyler, {
469
469
 
470
- showsOverState: false,
471
470
  titleInsets: null,
472
471
  normalBackgroundColor: null,
473
472
  disabledBackgroundColor: null,
473
+ overBackgroundColor: null,
474
474
  activeBackgroundColor: null,
475
475
  normalBackgroundGradient: null,
476
+ overBackgroundGradient: null,
476
477
  disabledBackgroundGradient: null,
477
478
  activeBackgroundGradient: null,
478
479
  normalBorderColor: null,
479
480
  disabledBorderColor: null,
481
+ overBorderColor: null,
480
482
  activeBorderColor: null,
481
483
  normalTitleColor: null,
484
+ overTitleColor: null,
482
485
  disabledTitleColor: null,
483
486
  activeTitleColor: null,
484
487
  borderWidth: 0,
@@ -508,7 +511,7 @@ JSClass("UIPopupButtonCustomStyler", UIPopupButtonStyler, {
508
511
  },
509
512
 
510
513
  initWithSpec: function(spec){
511
- UIPopupButtonCustomStyler.$super.initWithSpec(spec);
514
+ UIPopupButtonCustomStyler.$super.initWithSpec.call(this, spec);
512
515
 
513
516
  this._populateDefaults();
514
517
 
@@ -518,6 +521,9 @@ JSClass("UIPopupButtonCustomStyler", UIPopupButtonStyler, {
518
521
  if (spec.containsKey("normalBackgroundColor")){
519
522
  this.normalBackgroundColor = spec.valueForKey("normalBackgroundColor", JSColor);
520
523
  }
524
+ if (spec.containsKey("overBackgroundColor")){
525
+ this.overBackgroundColor = spec.valueForKey("overBackgroundColor", JSColor);
526
+ }
521
527
  if (spec.containsKey("disabledBackgroundColor")){
522
528
  this.disabledBackgroundColor = spec.valueForKey("disabledBackgroundColor", JSColor);
523
529
  }
@@ -527,6 +533,9 @@ JSClass("UIPopupButtonCustomStyler", UIPopupButtonStyler, {
527
533
  if (spec.containsKey("normalBackgroundGradient")){
528
534
  this.normalBackgroundGradient = spec.valueForKey("normalBackgroundGradient", JSGradient);
529
535
  }
536
+ if (spec.containsKey("overBackgroundGradient")){
537
+ this.overBackgroundGradient = spec.valueForKey("overBackgroundGradient", JSGradient);
538
+ }
530
539
  if (spec.containsKey("disabledBackgroundGradient")){
531
540
  this.disabledBackgroundGradient = spec.valueForKey("disabledBackgroundGradient", JSGradient);
532
541
  }
@@ -536,6 +545,9 @@ JSClass("UIPopupButtonCustomStyler", UIPopupButtonStyler, {
536
545
  if (spec.containsKey("normalBorderColor")){
537
546
  this.normalBorderColor = spec.valueForKey("normalBorderColor", JSColor);
538
547
  }
548
+ if (spec.containsKey("overBorderColor")){
549
+ this.overBorderColor = spec.valueForKey("overBorderColor", JSColor);
550
+ }
539
551
  if (spec.containsKey("disabledBorderColor")){
540
552
  this.disabledBorderColor = spec.valueForKey("disabledBorderColor", JSColor);
541
553
  }
@@ -545,6 +557,9 @@ JSClass("UIPopupButtonCustomStyler", UIPopupButtonStyler, {
545
557
  if (spec.containsKey("normalTitleColor")){
546
558
  this.normalTitleColor = spec.valueForKey("normalTitleColor", JSColor);
547
559
  }
560
+ if (spec.containsKey("overTitleColor")){
561
+ this.overTitleColor = spec.valueForKey("overTitleColor", JSColor);
562
+ }
548
563
  if (spec.containsKey("disabledTitleColor")){
549
564
  this.disabledTitleColor = spec.valueForKey("disabledTitleColor", JSColor);
550
565
  }
@@ -595,6 +610,9 @@ JSClass("UIPopupButtonCustomStyler", UIPopupButtonStyler, {
595
610
  if (this.activeBorderColor === null){
596
611
  this.activeBorderColor = this.normalBorderColor.colorDarkenedByPercentage(0.2);
597
612
  }
613
+ if (this.overBorderColor === null){
614
+ this.overBorderColor = this.normalBorderColor.colorDarkenedByPercentage(0.2);
615
+ }
598
616
  if (this.disabledBorderColor === null){
599
617
  this.disabledBorderColor = this.normalBorderColor.colorWithAlpha(0.5);
600
618
  }
@@ -602,6 +620,9 @@ JSClass("UIPopupButtonCustomStyler", UIPopupButtonStyler, {
602
620
  if (this.normalTitleColor === null){
603
621
  this.normalTitleColor = JSColor.text;
604
622
  }
623
+ if (this.overTitleColor === null){
624
+ this.overTitleColor = this.normalTitleColor.colorDarkenedByPercentage(0.2);
625
+ }
605
626
  if (this.activeTitleColor === null){
606
627
  this.activeTitleColor = this.normalTitleColor.colorDarkenedByPercentage(0.2);
607
628
  }
@@ -628,6 +649,13 @@ JSClass("UIPopupButtonCustomStyler", UIPopupButtonStyler, {
628
649
  button._titleLabel.textColor = this.disabledTitleColor;
629
650
  button._imageView.templateColor = this.disabledTitleColor;
630
651
  button._indicatorView.templateColor = this.disabledTitleColor;
652
+ }else if (button.over){
653
+ button.layer.backgroundColor = this.overBackgroundColor;
654
+ button.layer.backgroundGradient = this.overBackgroundGradient;
655
+ button.layer.borderColor = this.overBorderColor;
656
+ button._titleLabel.textColor = this.overTitleColor;
657
+ button._imageView.templateColor = this.overTitleColor;
658
+ button._indicatorView.templateColor = this.overTitleColor;
631
659
  }else if (button.active){
632
660
  button.layer.backgroundColor = this.activeBackgroundColor;
633
661
  button.layer.backgroundGradient = this.activeBackgroundGradient;
@@ -766,7 +794,7 @@ JSClass("UIPopupButtonImageStyler", UIPopupButtonStyler, {
766
794
  },
767
795
 
768
796
  initWithSpec: function(spec){
769
- UIPopupButtonCustomStyler.$super.initWithSpec(spec);
797
+ UIPopupButtonCustomStyler.$super.initWithSpec.call(this, spec);
770
798
  if (spec.containsKey("normalColor")){
771
799
  this.normalColor = spec.valueForKey("normalColor", JSColor);
772
800
  }
@@ -276,6 +276,8 @@ JSClass('UIScrollView', UIView, {
276
276
 
277
277
  _sanitizedOffset: function(offset){
278
278
  offset = JSPoint(offset);
279
+ offset.x = Math.round(offset.x);
280
+ offset.y = Math.round(offset.y);
279
281
  if (!this.scrollsHorizontally){
280
282
  offset.x = this._contentOffset.x;
281
283
  }else if (offset.x < this._minContentOffset.x){
@@ -120,70 +120,18 @@ JSClass("UISplitViewController", UIViewController, {
120
120
  },
121
121
 
122
122
  setLeadingViewController: function(leadingViewController){
123
- var callAppearanceMethods = this.isViewVisible && this.leadingViewOpen;
124
- var disappearingViewController = null;
125
- if (this._leadingViewController !== null){
126
- if (callAppearanceMethods){
127
- this._leadingViewController.viewWillDisappear(false);
128
- disappearingViewController = this._leadingViewController;
129
- }
130
- this._leadingViewController.removeFromParentViewController();
131
- }
123
+ this.replaceChildViewController(this._leadingViewController, leadingViewController);
132
124
  this._leadingViewController = leadingViewController;
133
- if (this._leadingViewController){
134
- if (callAppearanceMethods){
135
- this._leadingViewController.viewWillAppear(false);
136
- }
137
- this.addChildViewController(this._leadingViewController);
138
- }
139
- if (this._view !== null){
140
- var view = null;
141
- if (this._leadingViewController !== null){
142
- view = this._leadingViewController.view;
143
- }
144
- this._view.leadingView = view;
145
- }
146
- if (callAppearanceMethods){
147
- if (disappearingViewController !== null){
148
- disappearingViewController.enqueueDidDisappear();
149
- }
150
- if (this._leadingViewController !== null){
151
- this._leadingViewController.enqueueDidAppear();
152
- }
125
+ if (this.isViewLoaded){
126
+ this.view.leadingView = leadingViewController !== null ? leadingViewController.view : null;
153
127
  }
154
128
  },
155
129
 
156
130
  setTrailingViewController: function(trailingViewController){
157
- var callAppearanceMethods = this.isViewVisible && this.trailingViewOpen;
158
- var disappearingViewController = null;
159
- if (this._trailingViewController !== null){
160
- if (callAppearanceMethods){
161
- this._trailingViewController.viewWillDisappear(false);
162
- disappearingViewController = this._trailingViewController;
163
- }
164
- this._trailingViewController.removeFromParentViewController();
165
- }
131
+ this.replaceChildViewController(this._trailingViewController, trailingViewController);
166
132
  this._trailingViewController = trailingViewController;
167
- if (this._trailingViewController){
168
- if (callAppearanceMethods){
169
- this._trailingViewController.viewWillAppear(false);
170
- }
171
- this.addChildViewController(this._trailingViewController);
172
- }
173
- if (this._view !== null){
174
- var view = null;
175
- if (this._trailingViewController !== null){
176
- view = this._trailingViewController.view;
177
- }
178
- this._view.trailingView = view;
179
- }
180
- if (callAppearanceMethods){
181
- if (disappearingViewController !== null){
182
- disappearingViewController.enqueueDidDisappear();
183
- }
184
- if (this._trailingViewController !== null){
185
- this._trailingViewController.enqueueDidAppear();
186
- }
133
+ if (this.isViewLoaded){
134
+ this.view.trailingView = trailingViewController !== null ? trailingViewController.view : null;
187
135
  }
188
136
  },
189
137
 
@@ -192,56 +140,64 @@ JSClass("UISplitViewController", UIViewController, {
192
140
  this._setMainViewControllerCollapsed(mainViewController);
193
141
  return;
194
142
  }
195
- var callAppearanceMethods = this.isViewVisible;
196
- var disappearingViewController = null;
197
- if (this._mainViewController !== null && this._mainViewController.parentViewController === this){
198
- if (callAppearanceMethods){
199
- this._mainViewController.viewWillDisappear(false);
200
- disappearingViewController = this._mainViewController;
201
- }
202
- this._mainViewController.removeFromParentViewController();
203
- }
143
+ this.replaceChildViewController(this._mainViewController, mainViewController);
204
144
  this._mainViewController = mainViewController;
205
- if (this._mainViewController){
206
- if (callAppearanceMethods){
207
- this._mainViewController.viewWillAppear(false);
208
- }
209
- this.addChildViewController(this._mainViewController);
210
- }
211
- if (this._view !== null){
212
- var view = null;
213
- if (this._mainViewController !== null){
214
- view = this._mainViewController.view;
215
- }
216
- this._view.mainView = view;
217
- }
218
- if (callAppearanceMethods){
219
- if (disappearingViewController !== null){
220
- disappearingViewController.enqueueDidDisappear();
221
- }
222
- if (this._mainViewController !== null){
223
- this._mainViewController.enqueueDidAppear();
224
- }
145
+ if (this.isViewLoaded){
146
+ this.view.mainView = mainViewController !== null ? mainViewController.view : null;
225
147
  }
226
148
  },
227
149
 
228
150
  _setMainViewControllerCollapsed: function(mainViewController){
151
+ if (this._leadingViewController.isKindOfClass(UINavigationController)){
152
+ this._pushMainViewControllerOnNavigationController(mainViewController, this._leadingViewController);
153
+ }else{
154
+ this._presentMainViewControllerOnViewController(mainViewController, this._leadingViewController);
155
+ }
156
+ },
157
+
158
+ _pushMainViewControllerOnNavigationController: function(mainViewController, navigationController){
159
+ var i = navigationController.viewControllers.length - 1;
160
+ // 1. Pop off all view controllers up to and including our current mainViewController
229
161
  if (this._mainViewController !== null){
230
- if (this._leadingViewController.isKindOfClass(UINavigationController)){
231
- if (this._mainViewController === this._leadingViewController.topViewController){
232
- this._leadingViewController.popViewController(false);
233
- }
234
- }else{
235
- if (this._mainViewController === this._leadingViewController.presentedViewController){
236
- this._leadingViewController.dismiss(false);
162
+ while (i >= 1 && navigationController.viewControllers[i] !== this._mainViewController){
163
+ --i;
164
+ }
165
+ if (i > 0){
166
+ if (mainViewController === this._mainViewController){
167
+ // Bail if we're being asked to show the same view controller that's already shown
168
+ // NOTE: this check only comes after finding that the view controller
169
+ // is indeed part of the presentation tree becuase without a notification
170
+ // from the navigation controller when views are popped by the user,
171
+ // we may be in a situation where this._mainViewController is set, but
172
+ // is not part of the navigation stack
173
+ return;
237
174
  }
175
+ navigationController.popToViewController(navigationController.viewControllers[i - 1], false);
238
176
  }
239
- this._leadingViewController.view.layoutIfNeeded();
177
+ }
178
+ // 2. Push the new new mainViewController, animating if we're not currently changing traits
179
+ if (mainViewController !== null){
180
+ navigationController.pushViewController(mainViewController, !this.isChangingTraits);
240
181
  }
241
182
  this._mainViewController = mainViewController;
183
+ },
184
+
185
+ _presentMainViewControllerOnViewController: function(mainViewController, viewController){
186
+ // Bail if we're being asked to show the same view controller that's already shown
187
+ if (mainViewController === this._mainViewController){
188
+ return;
189
+ }
190
+ // 1. Dismiss the current mainViewController
242
191
  if (this._mainViewController !== null){
243
- this._leadingViewController.show(this._mainViewController, this);
192
+ if (this._mainViewController === viewController.presentedViewController){
193
+ viewController.dismiss();
194
+ }
195
+ }
196
+ // 2. Present the new mainViewController
197
+ if (mainViewController !== null){
198
+ viewController.presentViewController(mainViewController);
244
199
  }
200
+ this._mainViewController = mainViewController;
245
201
  },
246
202
 
247
203
  getSplitView: function(){
@@ -790,10 +790,10 @@ JSClass("UITabViewDefaultStyler", UITabViewStyler, {
790
790
  this.activeSelectedTitleColor = this.selectedTitleColor;
791
791
  }
792
792
  if (this.normalItemColor === null){
793
- this.normalItemColor = JSColor.highlight;
793
+ this.normalItemColor = JSColor.controlBackground;
794
794
  }
795
795
  if (this.selectedItemColor === null){
796
- this.selectedItemColor = JSColor.highlight.colorDarkenedByPercentage(0.2);
796
+ this.selectedItemColor = JSColor.highlight;
797
797
  }
798
798
  if (this.activeItemColor === null){
799
799
  this.activeItemColor = this.normalItemColor.colorDarkenedByPercentage(0.1);
@@ -30,11 +30,12 @@ JSClass("UITabViewController", UIViewController, {
30
30
  initWithViewControllers: function(viewControllers, styler){
31
31
  UITabViewController.$super.init.call(this);
32
32
  this._viewControllers = JSCopy(viewControllers);
33
- this._styler = styler || null;
33
+ this._tabViewStyler = styler || null;
34
34
  },
35
35
 
36
36
  initWithSpec: function(spec){
37
37
  this._viewControllers = [];
38
+ this._tabViewStyler = null;
38
39
  var viewController;
39
40
  var i, l;
40
41
  if (spec.containsKey('viewControllers')){
@@ -51,7 +52,7 @@ JSClass("UITabViewController", UIViewController, {
51
52
  },
52
53
 
53
54
  loadView: function(){
54
- this._view = UITabView.initWithStyler(this._styler);
55
+ this._view = UITabView.initWithStyler(this._tabViewStyler);
55
56
  },
56
57
 
57
58
  viewDidLoad: function(){
@@ -85,9 +86,9 @@ JSClass("UITabViewController", UIViewController, {
85
86
  selectedViewController.viewWillDisappear(animated);
86
87
  }
87
88
  },
88
-
89
- viewDisDisappear: function(animated){
90
- UITabViewController.$super.viewDisDisappear.call(this, animated);
89
+
90
+ viewDidDisappear: function(animated){
91
+ UITabViewController.$super.viewDidDisappear.call(this, animated);
91
92
  var selectedViewController = this.selectedViewController;
92
93
  if (selectedViewController !== null){
93
94
  selectedViewController.viewDidDisappear(animated);
@@ -788,6 +788,9 @@ JSClass("UITextField", UIControl, {
788
788
  this.delegate.textFieldDidChange(this);
789
789
  }
790
790
  this._didChange = true;
791
+ if (this._textLayer.textAlignment !== JSTextAlignment.left){
792
+ this.setNeedsLayout();
793
+ }
791
794
  },
792
795
 
793
796
  _adjustCursorPositionToCenterIfNeeded: function(){
@@ -145,6 +145,9 @@ JSClass('UIView', UIResponder, {
145
145
  this.addSubview(subview);
146
146
  }
147
147
  }
148
+ if (spec.containsKey("clipsToBounds")){
149
+ this.clipsToBounds = spec.valueForKey("clipsToBounds");
150
+ }
148
151
  // NOTE: constraints are still and work in progress, and aren't actually
149
152
  // used yet during layout
150
153
  if (spec.containsKey("constraints")){
@@ -211,10 +214,16 @@ JSClass('UIView', UIResponder, {
211
214
  subviews: null,
212
215
 
213
216
  addSubview: function(subview){
217
+ if (!(subview instanceof UIView)){
218
+ throw new TypeError("addSubview() given view is not a UIView");
219
+ }
214
220
  return this._insertSubviewAtIndex(subview, this.subviews.length, this.layer.sublayers.length);
215
221
  },
216
222
 
217
223
  insertSubviewAtIndex: function(subview, index){
224
+ if (!(subview instanceof UIView)){
225
+ throw new TypeError("insertSubviewAtIndex() given view is not a UIView");
226
+ }
218
227
  var layerIndex;
219
228
  if (index < this.subviews.length){
220
229
  layerIndex = this.subviews[index].layer.sublayerIndex;
@@ -225,6 +234,9 @@ JSClass('UIView', UIResponder, {
225
234
  },
226
235
 
227
236
  insertSubviewBelowSibling: function(subview, sibling){
237
+ if (!(subview instanceof UIView)){
238
+ throw new TypeError("insertSubviewBelowSibling() given view is not a UIView");
239
+ }
228
240
  if (sibling.superview !== this){
229
241
  throw Error('Cannot insert subview [%s] in view [%s] because sibling view [%s] is not a valid subview.');
230
242
  }
@@ -232,6 +244,9 @@ JSClass('UIView', UIResponder, {
232
244
  },
233
245
 
234
246
  insertSubviewAboveSibling: function(subview, sibling){
247
+ if (!(subview instanceof UIView)){
248
+ throw new TypeError("insertSubviewAboveSibling() given view is not a UIView");
249
+ }
235
250
  if (sibling.superview !== this){
236
251
  throw Error('Cannot insert subview [%s] in view [%s] because sibling view [%s] is not a valid subview.');
237
252
  }
@@ -239,6 +254,9 @@ JSClass('UIView', UIResponder, {
239
254
  },
240
255
 
241
256
  removeSubview: function(subview){
257
+ if (!(subview instanceof UIView)){
258
+ throw new TypeError("removeSubview() given subview is not a UIView");
259
+ }
242
260
  if (subview.superview === this){
243
261
  this.layer.removeSublayer(subview.layer);
244
262
  for (var i = subview.subviewIndex + 1, l = this.subviews.length; i < l; ++i){
@@ -162,6 +162,9 @@ JSClass("UIViewController", UIResponder, {
162
162
  this._isViewVisible = false;
163
163
  },
164
164
 
165
+ // -------------------------------------------------------------------------
166
+ // MARK: - Layout
167
+
165
168
  viewDidLayoutSubviews: function(){
166
169
  },
167
170
 
@@ -169,6 +172,11 @@ JSClass("UIViewController", UIResponder, {
169
172
  this.view.sizeToFitSize(size);
170
173
  },
171
174
 
175
+ contentSizeThatFitsSize: function(maxSize){
176
+ this.view.sizeToFitSize(maxSize);
177
+ return JSSize(this.view.bounds.size);
178
+ },
179
+
172
180
  // -------------------------------------------------------------------------
173
181
  // MARK: - Child View Controllers
174
182
 
@@ -193,6 +201,9 @@ JSClass("UIViewController", UIResponder, {
193
201
  },
194
202
 
195
203
  replaceChildViewController: function(previousChildViewController, childViewController, animator){
204
+ if (previousChildViewController === childViewController){
205
+ return;
206
+ }
196
207
  if (this.isViewLoaded && this.isViewVisible){
197
208
  var animated = animator !== undefined && animator !== null;
198
209
  if (previousChildViewController !== null){
@@ -580,7 +580,7 @@ JSClass("UIWindowServer", JSObject, {
580
580
  }
581
581
 
582
582
  if (ignore){
583
- logger.warn("Ignoring mouse event: %d".sprintf(type));
583
+ logger.info("Ignoring mouse event: %d".sprintf(type));
584
584
  return;
585
585
  }
586
586
 
@@ -904,7 +904,7 @@ JSClass("UIWindowServer", JSObject, {
904
904
  // Create or update the active touch event
905
905
  if (this.activeTouchEvent === null){
906
906
  if (type != UIEvent.Type.touchesBegan){
907
- logger.warn("Ignoring touch event: %d", type);
907
+ logger.info("Ignoring touch event: %d", type);
908
908
  return;
909
909
  }
910
910
  this.activeTouchEvent = UIEvent.initTouchEventWithType(type, timestamp);