bm-core-ui 2.10.5 → 2.11.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.
@@ -9,7 +9,7 @@ import {BMIndexPathNone} from '../Core/BMIndexPath'
9
9
  import {BMAnimateWithBlock, BMAnimationContextBeginStatic, BMAnimationContextGetCurrent, BMAnimationContextAddCompletionHandler, BMAnimationApply, __BMVelocityAnimate, BMHook} from '../Core/BMAnimationContext'
10
10
  import {BMView, BMViewLayoutQueue} from '../BMView/BMView_v2.5'
11
11
  import {BMCollectionViewLayoutAttributesMakeForCellAtIndexPath, BMCollectionViewLayoutAttributesType, BMCollectionViewLayoutAttributesStyleDefaults, _BMCollectionViewTransitionLayoutAttributesMakeWithSourceAttributes} from './BMCollectionViewLayoutAttributes'
12
- import {BMJQueryShim, BMCollectionViewCell} from './BMCollectionViewCell'
12
+ import {BMJQueryShim, BMCollectionViewCell, BMCollectionViewCellReuseState} from './BMCollectionViewCell'
13
13
  import {BMCollectionViewFlowLayout} from './BMCollectionViewFlowLayout'
14
14
  import {_BMCollectionViewTransitionLayout} from './BMCollectionViewLayout'
15
15
  import {IScroll} from '../iScroll/iscroll-probe'
@@ -271,20 +271,44 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
271
271
  * An optional delegate object that can receive various callbacks from the collection view.
272
272
  */
273
273
  delegate: undefined, // <BMCollectionViewDelegate, nullable>
274
+
275
+ /**
276
+ * Set to `YES` if a legacy data set is being used. When a legacy
277
+ */
278
+ _usesLegacyDataSet: NO,
274
279
 
275
280
  /**
276
- * A required data set object that specifies how many objects are in this collection view and configures their contents.
281
+ * @deprecated Use the `dataSource` property instead.
282
+ *
283
+ * ---
284
+ * A data set object that specifies how many objects are in this collection view and configures their contents.
277
285
  */
278
286
  _dataSet: undefined, // <BMCollectionViewDataSet>
279
287
  get dataSet() { return this._dataSet; },
280
288
  set dataSet(dataSet) {
281
- //this.dataSetWillChangeToDataSet(dataSet);
282
-
283
289
  var oldDataSet = this._dataSet;
290
+
291
+ this._usesLegacyDataSet = YES;
284
292
  this._dataSet = dataSet;
293
+ this._dataSource = BMCollectionViewDataSourceAdapter.adapterWithDataSet(dataSet);
285
294
 
286
295
  this.dataSetDidChangeFromDataSet(oldDataSet);
287
296
  },
297
+
298
+ /**
299
+ * A required data source object that specifies how many objects are in this collection view and configures their contents.
300
+ */
301
+ _dataSource: undefined, // <BMCollectionViewDataSource>
302
+ get dataSource() { return this._dataSource; },
303
+ set dataSource(source) {
304
+ const oldDataSet = this._dataSet;
305
+
306
+ this._usesLegacyDataSet = NO;
307
+ this._dataSource = source;
308
+ this._dataSet = BMCollectionViewDataSetAdapter.adapterWithDataSource(source);
309
+
310
+ this.dataSetDidChangeFromDataSet(oldDataSet);
311
+ },
288
312
 
289
313
  /**
290
314
  * The collection view's container element.
@@ -874,8 +898,6 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
874
898
 
875
899
  // Android is weird about handling touch events, so iScroll is required for it
876
900
  if (/android/i.test(window.navigator.userAgent)) useCustomScroll = YES;
877
-
878
- //var useCustomScroll = (false && this.customScrollRequired === undefined) || this.customScrollRequired;
879
901
 
880
902
  this._prepareFrame();
881
903
 
@@ -1008,6 +1030,11 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
1008
1030
  }
1009
1031
 
1010
1032
  if (shouldRunIntroAnimation) {
1033
+ this.isUpdatingData = YES;
1034
+
1035
+ let resolveLayoutUpdate;
1036
+ this._dataUpdatePromise = new Promise($1 => resolveLayoutUpdate = $1);
1037
+
1011
1038
  var visibleBounds = this._bounds.rectWithInset(BMInset.insetWithEqualInsets(this._offscreenBufferSize));
1012
1039
 
1013
1040
  var animatedCells = this.retainedCells.slice();
@@ -1046,6 +1073,20 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
1046
1073
  var cell = animatedCells[i];
1047
1074
  cell.attributes = cell.attributes.targetAttributes;
1048
1075
  }
1076
+
1077
+ const completionHandler = () => {
1078
+ self.isUpdatingData = NO;
1079
+ self._executeDataCompletionCallbacks();
1080
+
1081
+ resolveLayoutUpdate();
1082
+ };
1083
+
1084
+ if (animatedCells.length) {
1085
+ BMAnimationContextAddCompletionHandler(completionHandler);
1086
+ }
1087
+ else {
1088
+ completionHandler();
1089
+ }
1049
1090
  }, BMExtend({
1050
1091
  duration: _BMCollectionViewAnimationDurationDefault,
1051
1092
  easing: _BMCollectionViewAnimationEasingDefault,
@@ -1844,6 +1885,12 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
1844
1885
  var allCellsLength = this.allCells.length;
1845
1886
  for (var i = 0; i < allCellsLength; i++) {
1846
1887
  var cell = this.allCells[i];
1888
+
1889
+ // Don't manipulate cells that are in the process of being deleted, as they don't
1890
+ // have valid index paths
1891
+ if (cell._reuseState == BMCollectionViewCellReuseState.Deleting) {
1892
+ continue;
1893
+ }
1847
1894
 
1848
1895
  if (cell._exclusivelyRendered) {
1849
1896
  // If the cell was exclusively rendered, it should left alone
@@ -2485,15 +2532,12 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
2485
2532
 
2486
2533
  var cell = Object.create(cellClass.prototype).initWithCollectionView(this, {reuseIdentifier: identifier, node: node, kind: BMCollectionViewLayoutAttributesType.Cell});
2487
2534
  cell.layoutQueue = this._cellLayoutQueue;
2488
- //BMCollectionViewCellMakeForCollectionView(this, {withReuseIdentifier: identifier});
2489
-
2490
2535
 
2491
- //cell.element = $('<div style="position: absolute; left: 0px; top: 0px; visibility: hidden; overflow: visible;">');
2492
- //if (this.customScroll) cell.element.css({'will-change': 'transform'});
2493
2536
  // When using custom classes, it is no longer the data set object's responsibility to provide the contents for the cell
2494
- if (cellClass == BMCollectionViewCell) cell.element.append(this._dataSet.contentsForCellWithReuseIdentifier(identifier));
2537
+ if (cellClass == BMCollectionViewCell && this._usesLegacyDataSet) {
2538
+ cell.element.append(this._dataSet.contentsForCellWithReuseIdentifier(identifier));
2539
+ }
2495
2540
 
2496
-
2497
2541
  this._contentWrapper.append(cell.element);
2498
2542
 
2499
2543
  // Attach event handlers to the cells
@@ -2551,7 +2595,7 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
2551
2595
  const which = event.which || event.button;
2552
2596
 
2553
2597
  // Don't handle non-left clicks here
2554
- if (!BMIsTouchDevice && which != 1) return;
2598
+ if (event.originalEvent.type != 'touchstart' && which != 1) return;
2555
2599
 
2556
2600
  // Don't handle events originating from buttons and input elements or their direct descendants as well as several whitelisted class names
2557
2601
  if (event.target.nodeName == 'BUTTON' || event.target.nodeName == 'INPUT' || event.target.nodeName == 'LABEL' || event.target.nodeName == 'A' ||
@@ -2788,7 +2832,7 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
2788
2832
  const which = event.which || event.button;
2789
2833
 
2790
2834
  // Don't handle non-left clicks here
2791
- if (!BMIsTouchDevice && which != 1) return;
2835
+ if (event.originalEvent.type == 'mouseup' && which != 1) return;
2792
2836
 
2793
2837
  if (event.originalEvent.type == 'touchend') {
2794
2838
  // Don't handle other touches than the tracked touch
@@ -3774,7 +3818,9 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
3774
3818
  cell.layoutQueue = this._cellLayoutQueue;
3775
3819
 
3776
3820
  // When using custom classes, it is no longer the data set object's responsibility to provide the contents for the cell
3777
- if (cellClass == BMCollectionViewCell) cell.element.append(this._dataSet.contentsForSupplementaryViewWithIdentifier(identifier));
3821
+ if (cellClass == BMCollectionViewCell && this._usesLegacyDataSet) {
3822
+ cell.element.append(this._dataSet.contentsForSupplementaryViewWithIdentifier(identifier));
3823
+ }
3778
3824
  this._contentWrapper.append(cell.element);
3779
3825
 
3780
3826
  return cell;
@@ -3947,7 +3993,15 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
3947
3993
  for (var i = 0; i < this.allCells.length; i++) {
3948
3994
  var cell = this.allCells[i];
3949
3995
 
3950
- if (cell.itemType != options.ofType) continue;
3996
+ if (cell.itemType != options.ofType) {
3997
+ continue;
3998
+ }
3999
+
4000
+ // Cells that are in the process of being deleted cannot be returned by this method
4001
+ if (cell._reuseState == BMCollectionViewCellReuseState.Deleting) {
4002
+ continue;
4003
+ }
4004
+
3951
4005
  if (cell.indexPath.isLooselyEqualToIndexPath(indexPath, {usingComparator: this.identityComparator})) {
3952
4006
  return cell;
3953
4007
  }
@@ -4590,8 +4644,14 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
4590
4644
  var animationCells = [];
4591
4645
 
4592
4646
  for (var i = 0; i < retainedCellsLength; i++) {
4593
- currentAttributes.push(this.allCells[i].attributes);
4594
- animationCells.push(this.allCells[i]);
4647
+ const cell = this.allCells[i];
4648
+
4649
+ // Skip over any cells that are in the process of being deleted
4650
+ if (cell._reuseState == BMCollectionViewCellReuseState.Deleting) {
4651
+ continue;
4652
+ }
4653
+ currentAttributes.push(cell.attributes);
4654
+ animationCells.push(cell);
4595
4655
  }
4596
4656
 
4597
4657
  var oldOffset = this.scrollOffset;
@@ -4791,7 +4851,6 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
4791
4851
  var animationOptions = BMExtend({
4792
4852
  duration: _BMCollectionViewAnimationDurationDefault,
4793
4853
  easing: _BMCollectionViewAnimationEasingDefault,
4794
- queue: '_BMCollectionViewTransitionLayoutQueue'
4795
4854
  }, delegateOptions);
4796
4855
 
4797
4856
  /*animationOptions.progress = function (elements, complete, remaining, start, tween) {
@@ -4855,6 +4914,8 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
4855
4914
  }
4856
4915
  }
4857
4916
 
4917
+ self._applyOverflows();
4918
+
4858
4919
  self._collectionEnabled = YES;
4859
4920
  self.isUpdatingData = NO;
4860
4921
 
@@ -5055,6 +5116,14 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
5055
5116
  * This promise resolves resolves when the operation and its associated animations complete.
5056
5117
  */
5057
5118
  _dataUpdatePromise: undefined, // <Promise<void>, nullable>
5119
+
5120
+ /**
5121
+ * A promise initialized during data updates or similar operations such as animated layout updates.
5122
+ * This promise resolves resolves when the operation and its associated animations complete.
5123
+ */
5124
+ get dataUpdated() { // <Promise<void>, nullable>
5125
+ return this._dataUpdatePromise;
5126
+ },
5058
5127
 
5059
5128
  /**
5060
5129
  * Should be invoked when the entire data set is updated in bulk.
@@ -5088,6 +5157,7 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
5088
5157
  // Update the selection index paths
5089
5158
  this._updateSelectionIndexPaths();
5090
5159
 
5160
+ // When not animated, invalidate the layout, to obtain the new set of cells that should be displayed
5091
5161
  if (!animated) {
5092
5162
  this.layout.collectionViewWillStartUpdates(undefined);
5093
5163
 
@@ -5098,14 +5168,20 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
5098
5168
  self.layout.collectionViewDidStartUpdates();
5099
5169
 
5100
5170
  // Have the data set refresh the contents of each cell
5101
- for (var i = 0; i < this.allCells.length; i++) {
5102
- var cell = this.allCells[i];
5103
-
5104
- if (cell.itemType === BMCollectionViewLayoutAttributesType.Cell) {
5105
- if (this.dataSet.updateCell) this.dataSet.updateCell(cell, {atIndexPath: cell.indexPath});
5106
- }
5107
- else if (cell.itemType === BMCollectionViewLayoutAttributesType.SupplementaryView) {
5108
- if (this.dataSet.updateSupplementaryView) this.dataSet.updateSupplementaryView(cell, {withIdentifier: cell.reuseIdentifier, atIndexPath: cell.indexPath});
5171
+ if (this._usesLegacyDataSet) {
5172
+ for (let i = 0; i < this.allCells.length; i++) {
5173
+ let cell = this.allCells[i];
5174
+
5175
+ if (cell.itemType === BMCollectionViewLayoutAttributesType.Cell) {
5176
+ if (this.dataSet.updateCell) {
5177
+ this.dataSet.updateCell(cell, {atIndexPath: cell.indexPath});
5178
+ }
5179
+ }
5180
+ else if (cell.itemType === BMCollectionViewLayoutAttributesType.SupplementaryView) {
5181
+ if (this.dataSet.updateSupplementaryView) {
5182
+ this.dataSet.updateSupplementaryView(cell, {withIdentifier: cell.reuseIdentifier, atIndexPath: cell.indexPath});
5183
+ }
5184
+ }
5109
5185
  }
5110
5186
  }
5111
5187
 
@@ -5184,7 +5260,7 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
5184
5260
  this._size = currentSize;
5185
5261
 
5186
5262
  // Disable scrolling and interaction during update
5187
- this._container[0].style.pointerEvents = 'none'; //css({/*overflow: 'hidden', */'pointer-events': 'none'});
5263
+ this._container[0].style.pointerEvents = 'none';
5188
5264
  var containerScrollOffset = this.scrollOffset;
5189
5265
  if (!this.iScroll) this._container[0].scrollTo(containerScrollOffset.x, containerScrollOffset.y);
5190
5266
  if (this.scrollView) this.scrollView.scrollingEnabled = NO;
@@ -5214,6 +5290,12 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
5214
5290
  // Compare the current content to the new content and data set
5215
5291
  for (var i = 0; i < oldCells.length; i++) {
5216
5292
  var cell = oldCells[i];
5293
+
5294
+ // If this cell is in the process of being deleted by a previous data update, don't do any
5295
+ // additional processing on it
5296
+ if (cell._reuseState == BMCollectionViewCellReuseState.Deleting) {
5297
+ continue;
5298
+ }
5217
5299
 
5218
5300
  var foundCell = NO;
5219
5301
 
@@ -5592,7 +5674,13 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
5592
5674
 
5593
5675
  let animationBlock = function () {
5594
5676
 
5595
- // Apply the animations
5677
+ // Apply the animations that have been previously prepared on each cell
5678
+
5679
+ // Update the state of the cells that are being deleted, this will allow future animations
5680
+ // to skip animating them
5681
+ for (const cell of deletedCells) {
5682
+ cell._reuseState = BMCollectionViewCellReuseState.Deleting;
5683
+ }
5596
5684
 
5597
5685
  // Apply the drop shadow animations if needed
5598
5686
  if (self._droppedShadows) {
@@ -5983,7 +6071,7 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
5983
6071
  animation.targets.push({element: self._container[0], properties: {tween: 1}, complete: _ => {
5984
6072
  self._container[0].style.pointerEvents = 'inherit';
5985
6073
  self._isPerformingAnimatedScrolling = NO;
5986
- }, options: {progress: progress, queue: self._UUID}});
6074
+ }, options: {progress: progress}});
5987
6075
  },
5988
6076
  targetOffset: offset.copy(),
5989
6077
  startingOffset: self.scrollOffset.copy()
@@ -6266,4 +6354,154 @@ export function BMCollectionViewMakeWithContainer(container, options) {
6266
6354
  return new BMCollectionView().initWithDOMNode(container[0], options);
6267
6355
  }
6268
6356
 
6269
- // @endtype
6357
+ // @endtype
6358
+
6359
+ // #region Data Set Adapter
6360
+
6361
+ // A class that makes it possible to use the data source interface for collection views
6362
+ // that are still configured using the deprecated data set objects. These objects are automatically
6363
+ // created by collection views when the `dataSet` property is set.
6364
+ class BMCollectionViewDataSourceAdapter {
6365
+ constructor(dataSet) {
6366
+ this._dataSet = dataSet;
6367
+ }
6368
+
6369
+ collectionViewNumberOfSections(collectionView) {
6370
+ return this._dataSet.numberOfSections();
6371
+ }
6372
+
6373
+ collectionViewNumberOfObjectsInSectionAtIndex(collectionView, index) {
6374
+ return this._dataSet.numberOfObjectsInSectionAtIndex(index);
6375
+ }
6376
+
6377
+ collectionViewIndexPathForObjectAtRow(collectionView, row, args) {
6378
+ return this._dataSet.indexPathForObjectAtRow(row, args);
6379
+ }
6380
+
6381
+ collectionViewIndexPathForObject(collectionView, object) {
6382
+ return this._dataSet.indexPathForObject(object);
6383
+ }
6384
+
6385
+ collectionViewCellForItemAtIndexPath(collectionView, indexPath) {
6386
+ return this._dataSet.cellForItemAtIndexPath(indexPath);
6387
+ }
6388
+
6389
+ collectionViewCellForSupplementaryViewWithIdentifier(collectionView, identifier, args) {
6390
+ return this._dataSet.cellForSupplementaryViewWithIdentifier(identifier, args);
6391
+ }
6392
+
6393
+ collectionViewUseOldData(collectionView, use) {
6394
+ return this._dataSet.useOldData(use);
6395
+ }
6396
+
6397
+ collectionViewIsUsingOldData(collectionView) {
6398
+ return this._dataSet.isUsingOldData();
6399
+ }
6400
+
6401
+ collectionViewMoveItemFromIndexPath(collectionView, indexPath, args) {
6402
+ return this._dataSet.moveItemFromIndexPath(indexPath, args);
6403
+ }
6404
+
6405
+ collectionViewMoveItemsFromIndexPaths(collectionView, indexPaths, args) {
6406
+ return this._dataSet.moveItemsFromIndexPaths(indexPaths, args);
6407
+ }
6408
+
6409
+ collectionViewRemoveItemsAtIndexPaths(collectionView, indexPaths) {
6410
+ return this._dataSet.removeItemsAtIndexPaths(indexPaths);
6411
+ }
6412
+
6413
+ collectionViewInsertItems(collectionView, items, args) {
6414
+ return this._dataSet.insertItems(items, args);
6415
+ }
6416
+
6417
+ static adapterWithDataSet(dataSet) {
6418
+ return new this(dataSet);
6419
+ }
6420
+ }
6421
+
6422
+ // #endregion
6423
+
6424
+
6425
+
6426
+ // #region Data Set Adapter
6427
+
6428
+ // A class that makes it possible to use the old data set interface for collection views
6429
+ // that are configured using data source objects for compatibility with older code that still
6430
+ // references the deprecated data set property. These objects are automatically
6431
+ // created by collection views when the `dataSource` property is set.
6432
+ class BMCollectionViewDataSetAdapter {
6433
+ constructor(collectionView, dataSource) {
6434
+ this._collectionView = collectionView;
6435
+ this._dataSource = dataSource;
6436
+ }
6437
+
6438
+ numberOfSections() {
6439
+ return this._dataSource.collectionViewNumberOfSections(this._collectionView);
6440
+ }
6441
+
6442
+ numberOfObjectsInSectionAtIndex(index) {
6443
+ return this._dataSource.collectionViewNumberOfObjectsInSectionAtIndex(this._collectionView, index);
6444
+ }
6445
+
6446
+ indexPathForObjectAtRow(row, args) {
6447
+ return this._dataSource.collectionViewNumberOfObjectsInSectionAtIndex(this._collectionView, row, args);
6448
+ }
6449
+
6450
+ indexPathForObject(object) {
6451
+ return this._dataSource.collectionViewIndexPathForObject(this._collectionView, object);
6452
+ }
6453
+
6454
+ contentsForCellWithReuseIdentifier(identifier) {
6455
+ throw new Error(`contentsForCellWithReuseIdentifier is unsupported when using data source objects`);
6456
+ }
6457
+
6458
+ cellForItemAtIndexPath(indexPath) {
6459
+ return this._dataSource.collectionViewCellForItemAtIndexPath(this._collectionView, indexPath);
6460
+ }
6461
+
6462
+ contentsForSupplementaryViewWithIdentifier(identifier) {
6463
+ throw new Error(`contentsForSupplementaryViewWithIdentifier is unsupported when using data source objects`);
6464
+ }
6465
+
6466
+ cellForSupplementaryViewWithIdentifier(identifier, args) {
6467
+ return this._dataSource.collectionViewCellForSupplementaryViewWithIdentifier(this._collectionView, identifier, args);
6468
+ }
6469
+
6470
+ updateCell(cell, {atIndexPath: indexPath}) {
6471
+ throw new Error(`updateCell is unsupported when using data source objects`);
6472
+ }
6473
+
6474
+ updateSupplementaryView(view, {withIdentifier: identifier, atIndexPath: indexPath}) {
6475
+ throw new Error(`updateSupplementaryView is unsupported when using data source objects`);
6476
+ }
6477
+
6478
+ useOldData(use) {
6479
+ return this._dataSource.collectionViewUseOldData(this._collectionView, use);
6480
+ }
6481
+
6482
+ isUsingOldData() {
6483
+ return this._dataSource.collectionViewIsUsingOldData(this._collectionView);
6484
+ }
6485
+
6486
+ moveItemFromIndexPath(indexPath, args) {
6487
+ return this._dataSource.collectionViewMoveItemFromIndexPath(this._collectionView, indexPath, args);
6488
+ }
6489
+
6490
+ moveItemsFromIndexPaths(indexPaths, args) {
6491
+ return this._dataSource.collectionViewMoveItemsFromIndexPaths(this._collectionView, indexPaths, args);
6492
+ }
6493
+
6494
+ removeItemsAtIndexPaths(indexPaths) {
6495
+ return this._dataSource.collectionViewRemoveItemsAtIndexPaths(this._collectionView, indexPaths);
6496
+ }
6497
+
6498
+ insertItems(items, args) {
6499
+ return this._dataSource.collectionViewInsertItems(this._collectionView, items, args);
6500
+ }
6501
+
6502
+ static adapterWithDataSource(collectionView, dataSource) {
6503
+ return new this(collectionView, dataSource);
6504
+ }
6505
+ }
6506
+
6507
+ // #endregion
@@ -114,6 +114,39 @@ BMJQueryShim.shimWithDOMNode = function (node) {
114
114
  // When set to YES, this will cause collection view cells to extend view
115
115
  const BM_USE_BMVIEW_SUBCLASS = YES;
116
116
 
117
+ // @type BMCollectionViewCellReuseState
118
+
119
+ /**
120
+ * Constants describing the various reuse states that a collection view cell may be in.
121
+ */
122
+ export const BMCollectionViewCellReuseState = Object.freeze({ // <enum>
123
+
124
+ /**
125
+ * Indicates that this cell is currently bound to a data source object and retained
126
+ * or managed by the collection view.
127
+ */
128
+ InUse: "InUse", // <enum>
129
+
130
+ /**
131
+ * Indicates that this cell is not currently in use, but may be reused in the future.
132
+ */
133
+ InQueue: "InQueue", // <enum>
134
+
135
+ /**
136
+ * Indicates that this cell is in the process of being deleted and is bound to a data
137
+ * source object that no longer has a valid index path.
138
+ */
139
+ Deleting: "Deleting", // <enum>
140
+
141
+ /**
142
+ * Indicates that this cell is not currently in use and cannot be reused in the future.
143
+ * References to cells in this state should be cleared as they are no longer valid.
144
+ */
145
+ Discarded: "Discarded" // <enum>
146
+ });
147
+
148
+ // @endtype
149
+
117
150
  // @type BMCollectionViewCell extends BMView
118
151
 
119
152
  /**
@@ -156,16 +189,13 @@ BMCollectionViewCell.prototype = BMExtend(BM_USE_BMVIEW_SUBCLASS ? Object.create
156
189
  return this.retainCount > 0;
157
190
  },
158
191
 
159
- // #FLAG BM_USE_BMVIEW_SUBCLASS
160
192
  get _frame() {
161
193
  return this._attributes && this._attributes.frame;
162
194
  },
163
195
 
164
- // #FLAG BM_USE_BMVIEW_SUBCLASS
165
196
  get frame() {
166
197
  return this._attributes && this._attributes.frame;
167
198
  },
168
- // #FLAG BM_USE_BMVIEW_SUBCLASS
169
199
  set frame(frame) {
170
200
  // NOTE: A cell's frame is controlled by its layout attributes, therefore this operation is a no-op
171
201
  },
@@ -192,12 +222,6 @@ BMCollectionViewCell.prototype = BMExtend(BM_USE_BMVIEW_SUBCLASS ? Object.create
192
222
  */
193
223
  _element: undefined, // <BMJQueryShim>
194
224
  get element() { return this._element || (this._element = BMJQueryShim.shimWithDOMNode(this.node)); },
195
-
196
- // #FLAG BM_USE_BMVIEW_SUBCLASS
197
- /**
198
- * The DOM node managed by this cell.
199
- */
200
- //node: undefined, // <DOMNode>
201
225
 
202
226
  /**
203
227
  * The type of item this cell represents.
@@ -206,7 +230,8 @@ BMCollectionViewCell.prototype = BMExtend(BM_USE_BMVIEW_SUBCLASS ? Object.create
206
230
  itemType: BMCollectionViewLayoutAttributesType.Cell, // <BMCollectionViewLayoutAttributesType>
207
231
 
208
232
  /**
209
- * The cell's reuse identifier which corresponds to the template's reuse identifier.
233
+ * The cell's reuse identifier which controls when this cell is reused when data source objects
234
+ * request cell instances from the associated collection view.
210
235
  */
211
236
  _reuseIdentifier: undefined, // <String>
212
237
 
@@ -396,10 +421,8 @@ BMCollectionViewCell.prototype = BMExtend(BM_USE_BMVIEW_SUBCLASS ? Object.create
396
421
  recycle: function () {
397
422
  this._unmanage();
398
423
 
399
- this.invalidate();
400
-
401
- //this.collectionView.cellWasUnmanaged(this);
402
424
  if (this.retainCount > 0) {
425
+ this.invalidate();
403
426
  this.collectionView.cellWasInvalidated(this);
404
427
  this.destroy();
405
428
 
@@ -422,9 +445,8 @@ BMCollectionViewCell.prototype = BMExtend(BM_USE_BMVIEW_SUBCLASS ? Object.create
422
445
  releaseRecycledCell: function () {
423
446
  this.release();
424
447
 
425
- this.invalidate();
426
-
427
448
  if (this.retainCount > 0) {
449
+ this.invalidate();
428
450
  this.collectionView.cellWasInvalidated(this);
429
451
  this.destroy();
430
452
 
@@ -438,6 +460,15 @@ BMCollectionViewCell.prototype = BMExtend(BM_USE_BMVIEW_SUBCLASS ? Object.create
438
460
  }
439
461
  },
440
462
 
463
+ /**
464
+ * The cell's current reuse state.
465
+ */
466
+ _reuseState: BMCollectionViewCellReuseState.InQueue, // <BMCollectionViewCellReuseState>
467
+
468
+ get reuseState() {
469
+ return this._reuseState;
470
+ },
471
+
441
472
  /**
442
473
  * Should be set to YES to hide the cell, or NO to reveal it.
443
474
  */
@@ -475,7 +506,6 @@ BMCollectionViewCell.prototype = BMExtend(BM_USE_BMVIEW_SUBCLASS ? Object.create
475
506
  this.node.classList.remove('BMCollectionViewCellHidden');
476
507
  },
477
508
 
478
- // #FLAG BM_USE_BMVIEW_SUBCLASS
479
509
  _prepareForAutomaticIntrinsicSize() {
480
510
  for (let subview of this._subviews) {
481
511
  subview._prepareForAutomaticIntrinsicSize();
@@ -489,27 +519,25 @@ BMCollectionViewCell.prototype = BMExtend(BM_USE_BMVIEW_SUBCLASS ? Object.create
489
519
  }
490
520
  else {
491
521
  if (this._requiredWidth) {
492
- // Otherwise derive the measured size using the instrinsic CSS size
522
+ // Otherwise derive the measured size using the intrinsic CSS size
493
523
  BMCopyProperties(this._node.style, {width: this._requiredWidth + 'px', height: 'auto'});
494
524
  }
495
525
  else {
496
- // Otherwise derive the measured size using the instrinsic CSS size
526
+ // Otherwise derive the measured size using the intrinsic CSS size
497
527
  BMCopyProperties(this._node.style, {width: 'auto', height: 'auto'});
498
528
  }
499
529
  }
500
530
  }
501
531
  },
502
532
 
503
- // #FLAG BM_USE_BMVIEW_SUBCLASS
504
533
  _supportsAutomaticIntrinsicSize: NO,
505
534
 
506
- // #FLAG BM_USE_BMVIEW_SUBCLASS
507
535
  /**
536
+ * @protected
508
537
  * Temporarily set to `YES` while this cell is being measured.
509
538
  */
510
539
  _isMeasuring: NO,
511
540
 
512
- // #FLAG BM_USE_BMVIEW_SUBCLASS
513
541
  internalConstraints() {
514
542
  var constraints = [];
515
543
 
@@ -550,19 +578,19 @@ BMCollectionViewCell.prototype = BMExtend(BM_USE_BMVIEW_SUBCLASS ? Object.create
550
578
  /**
551
579
  * Invoked prior to this cell being collected for reuse by the collection view.
552
580
  * Subclasses can override this method to perform any changes necessary for reusing this cell.
553
- * Subclasses should invoke the superclass method at some point in their implementation.
581
+ * Subclasses must invoke the superclass method at some point in their implementation.
554
582
  */
555
583
  prepareForReuse() {
556
-
584
+ this._reuseState = BMCollectionViewCellReuseState.InQueue;
557
585
  },
558
586
 
559
587
  /**
560
588
  * Invoked prior to this cell being shown on the screen either after being initialized or after having been previously collected.
561
- * Subclasses can override this method to perform any changes necesarry for displaying this cell.
562
- * Subclasses should invoke the superclass method at some point in their implementaiton.
589
+ * Subclasses can override this method to perform any changes necessary for displaying this cell.
590
+ * Subclasses must invoke the superclass method at some point in their implementation.
563
591
  */
564
592
  prepareForDisplay() {
565
-
593
+ this._reuseState = BMCollectionViewCellReuseState.InUse;
566
594
  },
567
595
 
568
596
  /**
@@ -625,7 +653,6 @@ BMCollectionViewCell.prototype = BMExtend(BM_USE_BMVIEW_SUBCLASS ? Object.create
625
653
 
626
654
  this.collectionView = collectionView;
627
655
 
628
- // #FLAG BM_USE_BMVIEW_SUBCLASS
629
656
  if (BM_USE_BMVIEW_SUBCLASS) {
630
657
  BMView.prototype.initWithDOMNode.call(this, args.node);
631
658
  }
@@ -41,6 +41,7 @@ export var BMCollectionViewTableLayoutSupplementaryView = Object.freeze({ // <en
41
41
 
42
42
  /**
43
43
  * @deprecated Use `BMCollectionViewFlowLayout` with the `maximumCellsPerRow` property set to `1`.
44
+ *
44
45
  * --------------------------------------
45
46
  * A basic layout implementation, the BMCollectionViewTableLayout will lay out its elements as a list where each row can have
46
47
  * either a fixed height or a variable height.
@@ -4964,7 +4965,7 @@ BMCollectionViewFlowLayout.prototype = BMExtend(Object.create(BMCollectionViewLa
4964
4965
  * @return <BMCollectionViewFlowLayout> A flow layout.
4965
4966
  */
4966
4967
  BMCollectionViewFlowLayout.flowLayout = function () {
4967
- return new BMCollectionViewFlowLayout();
4968
+ return new this();
4968
4969
  }
4969
4970
 
4970
4971
  // @endtype
@@ -625,7 +625,7 @@ BMCollectionViewMasonryLayout.prototype = BMExtend({}, BMCollectionViewLayout.pr
625
625
  * @returns <BMCollectionViewMasonryLayout> A masonry layout.
626
626
  */
627
627
  BMCollectionViewMasonryLayout.masonryLayout = function () {
628
- return new BMCollectionViewMasonryLayout();
628
+ return new this();
629
629
  };
630
630
 
631
631
  // @endtype
@@ -628,7 +628,7 @@ BMCollectionViewStackLayout.prototype = BMExtend({}, BMCollectionViewLayout.prot
628
628
  * @returns <BMCollectionViewStackLayout> A stack layout.
629
629
  */
630
630
  BMCollectionViewStackLayout.stackLayout = function () {
631
- return new BMCollectionViewStackLayout();
631
+ return new this();
632
632
  }
633
633
 
634
634
  // @endtype