bm-core-ui 2.11.9-beta.2 → 2.12.0-beta.4
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.
- package/README.md +1 -1
- package/build/@types/index.d.ts +2194 -94
- package/build/BMCollectionView/BMCollectionView.js +977 -196
- package/build/BMCollectionView/BMCollectionViewFlowLayout.js +11 -4
- package/build/BMCoreUI.css +133 -2
- package/build/BMView/BMDragSession.js +1150 -0
- package/build/BMView/BMDragSessionActions.js +121 -0
- package/build/BMView/BMDragSessionPreview.js +1631 -0
- package/build/BMView/BMLayoutConstraint_v2.5.js +14 -59
- package/build/BMView/BMView_v2.5.js +34 -3
- package/build/BMWindow/BMPopover/BMPopover.js +35 -20
- package/build/BMWindow/BMToolWindow.js +29 -1
- package/build/BMWindow/BMWindow.js +128 -65
- package/build/images/AlignBottom.png +0 -0
- package/build/images/AlignCenterX.png +0 -0
- package/build/images/AlignCenterY.png +0 -0
- package/build/images/AlignLeading.png +0 -0
- package/build/images/AlignTop.png +0 -0
- package/build/images/AlignTrailing.png +0 -0
- package/build/images/AllConstraints.png +0 -0
- package/build/images/BottomConstraint.png +0 -0
- package/build/images/CenterXConstraint.png +0 -0
- package/build/images/CenterYConstraint.png +0 -0
- package/build/images/CoreUI2.png +0 -0
- package/build/images/CoreUI2@2x.png +0 -0
- package/build/images/Desktop.png +0 -0
- package/build/images/DesktopMini.png +0 -0
- package/build/images/EqualHeight.png +0 -0
- package/build/images/EqualHorizontalSpacing.png +0 -0
- package/build/images/EqualHorizontalSpacingInSuperview.png +0 -0
- package/build/images/EqualVerticalSpacing.png +0 -0
- package/build/images/EqualVerticalSpacingInSuperview.png +0 -0
- package/build/images/EqualWidth.png +0 -0
- package/build/images/HeightConstraint.png +0 -0
- package/build/images/InactiveConstraints.png +0 -0
- package/build/images/Layout.png +0 -0
- package/build/images/LayoutVariables.png +0 -0
- package/build/images/LeftConstraint.png +0 -0
- package/build/images/OwnConstraints.png +0 -0
- package/build/images/Phone.png +0 -0
- package/build/images/PhoneLandscape.png +0 -0
- package/build/images/PhoneLandscapeMini.png +0 -0
- package/build/images/PhoneMini.png +0 -0
- package/build/images/PhonePortrait.png +0 -0
- package/build/images/PhonePortraitMini.png +0 -0
- package/build/images/Properties.png +0 -0
- package/build/images/RightConstraint.png +0 -0
- package/build/images/SubviewConstraints.png +0 -0
- package/build/images/Tablet.png +0 -0
- package/build/images/TabletLandscape.png +0 -0
- package/build/images/TabletLandscapeMini.png +0 -0
- package/build/images/TabletMini.png +0 -0
- package/build/images/TabletPortrait.png +0 -0
- package/build/images/TabletPortraitMini.png +0 -0
- package/build/images/TopConstraint.png +0 -0
- package/build/images/WidthConstraint.png +0 -0
- package/build/index.js +4 -0
- package/lib/@types/BMCoreUI.min.d.ts +2194 -94
- package/lib/BMCoreUI.min.js +1 -1
- package/package.json +2 -2
|
@@ -5,8 +5,8 @@ import {BMInset} from '../Core/BMInset'
|
|
|
5
5
|
import {BMPointMake} from '../Core/BMPoint'
|
|
6
6
|
import {BMSizeMake} from '../Core/BMSize'
|
|
7
7
|
import {BMRect, BMRectMake, BMRectMakeWithNodeFrame, BMRectMakeWithOrigin, BMRectByInterpolatingRect} from '../Core/BMRect'
|
|
8
|
-
import {BMIndexPathNone} from '../Core/BMIndexPath'
|
|
9
|
-
import {BMAnimateWithBlock, BMAnimationContextBeginStatic, BMAnimationContextGetCurrent, BMAnimationContextAddCompletionHandler, BMAnimationApply, __BMVelocityAnimate, BMHook} from '../Core/BMAnimationContext'
|
|
8
|
+
import {BMIndexPathMakeWithRow, BMIndexPathNone} from '../Core/BMIndexPath'
|
|
9
|
+
import {BMAnimateWithBlock, BMAnimationContextBeginStatic, BMAnimationContextGetCurrent, BMAnimationContextAddCompletionHandler, BMAnimationApply, __BMVelocityAnimate, BMHook, BMAnimationBeginWithDuration} from '../Core/BMAnimationContext'
|
|
10
10
|
import {BMView, BMViewLayoutQueue} from '../BMView/BMView_v2.5'
|
|
11
11
|
import {BMCollectionViewLayoutAttributesMakeForCellAtIndexPath, BMCollectionViewLayoutAttributesType, BMCollectionViewLayoutAttributesStyleDefaults, _BMCollectionViewTransitionLayoutAttributesMakeWithSourceAttributes} from './BMCollectionViewLayoutAttributes'
|
|
12
12
|
import {BMJQueryShim, BMCollectionViewCell, BMCollectionViewCellReuseState} from './BMCollectionViewCell'
|
|
@@ -16,6 +16,9 @@ import {IScroll} from '../iScroll/iscroll-probe'
|
|
|
16
16
|
import { BMLayoutAttribute } from '../BMView/BMLayoutConstraint_v2.5'
|
|
17
17
|
import { BMMenuSourceNodeCSSClass } from '../BMView/BMMenu'
|
|
18
18
|
import { BMKeyboardShortcut, BMKeyboardShortcutModifier } from '../BMWindow/BMKeyboardShortcut'
|
|
19
|
+
import { BMDragSession, BMDragSessionAction, BMDragTransferKind, BMDropSessionAction } from '../BMView/BMDragSession'
|
|
20
|
+
import { BMDragPreview } from '../BMView/BMDragSessionPreview'
|
|
21
|
+
import { BMDragSessionActionKind, BMDropSessionActionKind } from '../BMView/BMDragSessionActions'
|
|
19
22
|
|
|
20
23
|
// When set to YES, this will cause collection view to use static animation contexts when setting up animations
|
|
21
24
|
const BM_COLLECTION_VIEW_USE_STATIC_CONTEXT = YES;
|
|
@@ -78,6 +81,45 @@ export var BMCollectionViewAcceptPolicy = Object.freeze({ // <enum>
|
|
|
78
81
|
|
|
79
82
|
// @endtype
|
|
80
83
|
|
|
84
|
+
// @type BMCollectionViewAcceptRegion
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Constants which describe the region by which a drag and drop gesture can be accepted as it
|
|
88
|
+
* enters the collection view's frame.
|
|
89
|
+
*/
|
|
90
|
+
export const BMCollectionViewAcceptRegion = Object.freeze({ // <enum>
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Indicates that the drop session will have the same drop action regardless of where
|
|
94
|
+
* in the collection view's frame it is.
|
|
95
|
+
*/
|
|
96
|
+
Anywhere: 'Accept', // <enum>
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Indicates that the drop session's drop action changes based on the cell in which the
|
|
100
|
+
* drop occurs. Drops outside of any cell's frame are rejected. The delegate object is
|
|
101
|
+
* expected to implement the {@link BMCollectionViewDelegate.collectionViewDropSessionDidEnterCell} method
|
|
102
|
+
* provide the appropriate drop action for each cell.
|
|
103
|
+
*/
|
|
104
|
+
Cell: 'Cell', // <enum>
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Indicates the drop session's drop action depends on the specific position in which the drop occurs.
|
|
108
|
+
* The delegate object is expected to implement the {@link BMCollectionViewDelegate.collectionViewDropSessionDidUpdate}
|
|
109
|
+
* method to provide the appropriate action as the drop session's position updates.
|
|
110
|
+
*/
|
|
111
|
+
Position: 'Position', // <enum>
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Indicates that the collection view cannot process the session's items and no further updates will
|
|
115
|
+
* be provided regarding this drop session.
|
|
116
|
+
*/
|
|
117
|
+
Nowhere: 'Reject', // <enum>
|
|
118
|
+
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// @endtype
|
|
122
|
+
|
|
81
123
|
// @type BMCollectionView Global Symbols
|
|
82
124
|
|
|
83
125
|
// Set to YES during a drag & drop operation
|
|
@@ -128,6 +170,24 @@ var _BMCollectionViewSnappingScrollThreshold = 200; // <Number>
|
|
|
128
170
|
*/
|
|
129
171
|
var _BMCollectionViewIdentityComparator = function (o1, o2) { return o1 == o2; }; // <Boolean ^ (AnyObject, AnyObject)>
|
|
130
172
|
|
|
173
|
+
/**
|
|
174
|
+
* The number of pixels determining how close to an edge the drag session position must be
|
|
175
|
+
* for a collection view to start scrolling.
|
|
176
|
+
*/
|
|
177
|
+
const _BMCollectionViewDragScrollDistance = 32;
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* How much to multiply the distance to the edge to obtain the final scrolling speed during
|
|
181
|
+
* a drag and drop gesture.
|
|
182
|
+
*/
|
|
183
|
+
const _BMCollectionViewDragScrollMultiplier = 20;
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* The number of milliseconds to wait for a data source to insert items asynchronously after a drop
|
|
187
|
+
* before playing the generic drop animation for the drop previews.
|
|
188
|
+
*/
|
|
189
|
+
const _BMCollectionViewAsynchronousDropDelay = 200;
|
|
190
|
+
|
|
131
191
|
// @endtype
|
|
132
192
|
|
|
133
193
|
// @type BMCollectionViewScrollingDirection
|
|
@@ -239,7 +299,6 @@ export function BMCollectionView() { // <constructor>
|
|
|
239
299
|
BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? Object.create(BMView.prototype) : {}, {
|
|
240
300
|
constructor: BMCollectionView,
|
|
241
301
|
|
|
242
|
-
// MARK: BMView overrides
|
|
243
302
|
//#region BMView overrides
|
|
244
303
|
|
|
245
304
|
// @override - BMView
|
|
@@ -809,6 +868,7 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
809
868
|
var customScrollRequired = args && args.customScroll;
|
|
810
869
|
|
|
811
870
|
_BMCollectionViews.set(this, true);
|
|
871
|
+
BMDragSession._dropTargets.set(this, this);
|
|
812
872
|
|
|
813
873
|
this._container = BMJQueryShim.shimWithDOMNode(node);
|
|
814
874
|
this.layout = new BMCollectionViewFlowLayout();
|
|
@@ -2071,6 +2131,30 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
2071
2131
|
* @param indexPaths <[BMIndexPath<T>]> The index paths of the cell whose size should be measured.
|
|
2072
2132
|
*/
|
|
2073
2133
|
measureSizesOfCellsAtIndexPaths(indexPaths) {
|
|
2134
|
+
// Skip index paths that have already been measured
|
|
2135
|
+
indexPaths = indexPaths.filter(indexPath => {
|
|
2136
|
+
// Return the cached size if it is available.
|
|
2137
|
+
let identifier;
|
|
2138
|
+
if (this._dataSet.identifierForIndexPath) {
|
|
2139
|
+
identifier = this._dataSet.identifierForIndexPath(indexPath);
|
|
2140
|
+
|
|
2141
|
+
if (this._measures[identifier]) {
|
|
2142
|
+
return NO;
|
|
2143
|
+
}
|
|
2144
|
+
}
|
|
2145
|
+
else {
|
|
2146
|
+
let length = this._measuredIndexPaths.length;
|
|
2147
|
+
for (let i = 0; i < length; i++) {
|
|
2148
|
+
let measure = this._measuredIndexPaths[i];
|
|
2149
|
+
if (measure.indexPath.isEqualToIndexPath(indexPath, {usingComparator: this.identityComparator})) {
|
|
2150
|
+
return NO;
|
|
2151
|
+
}
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
2154
|
+
|
|
2155
|
+
return YES;
|
|
2156
|
+
});
|
|
2157
|
+
|
|
2074
2158
|
const queue = BMViewLayoutQueue.layoutQueue();
|
|
2075
2159
|
const iterators = indexPaths.map(p => this._measuredSizeOfCellAtIndexPathGenerator(p, {layoutQueue: queue, dequeue: NO}));
|
|
2076
2160
|
|
|
@@ -2094,23 +2178,6 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
2094
2178
|
if (result.done) return result.value;
|
|
2095
2179
|
}
|
|
2096
2180
|
|
|
2097
|
-
// Return the cached size if it is available.
|
|
2098
|
-
let identifier;
|
|
2099
|
-
if (this._dataSet.identifierForIndexPath) {
|
|
2100
|
-
identifier = this._dataSet.identifierForIndexPath(indexPath);
|
|
2101
|
-
|
|
2102
|
-
if (this._measures[identifier]) return this._measures[identifier];
|
|
2103
|
-
}
|
|
2104
|
-
else {
|
|
2105
|
-
let length = this._measuredIndexPaths.length;
|
|
2106
|
-
for (let i = 0; i < length; i++) {
|
|
2107
|
-
let measure = this._measuredIndexPaths[i];
|
|
2108
|
-
if (measure.indexPath.isEqualToIndexPath(indexPath, {usingComparator: this.identityComparator})) {
|
|
2109
|
-
return this._measuredIndexPaths[i].size;
|
|
2110
|
-
}
|
|
2111
|
-
}
|
|
2112
|
-
}
|
|
2113
|
-
|
|
2114
2181
|
if (BM_COLLECTION_VIEW_DEBUG_MEASURE) {
|
|
2115
2182
|
if (!this.__debug__measuring) {
|
|
2116
2183
|
this.__debug__measuring = YES;
|
|
@@ -2682,7 +2749,7 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
2682
2749
|
|
|
2683
2750
|
cellEventCanDoubleClick = NO;
|
|
2684
2751
|
if (self.delegate && self.delegate.collectionViewCanDoubleClickCell) {
|
|
2685
|
-
cellEventCanDoubleClick = self.delegate.collectionViewCanDoubleClickCell(self, cell);
|
|
2752
|
+
cellEventCanDoubleClick = self.delegate.collectionViewCanDoubleClickCell(self, cell, {withEvent: event});
|
|
2686
2753
|
}
|
|
2687
2754
|
|
|
2688
2755
|
if (cellEventCanDoubleClick) cellEventDoubleClickTimeout = window.setTimeout(function () {
|
|
@@ -2909,6 +2976,8 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
2909
2976
|
return cell;
|
|
2910
2977
|
|
|
2911
2978
|
},
|
|
2979
|
+
|
|
2980
|
+
// #region Drag and drop
|
|
2912
2981
|
|
|
2913
2982
|
isDragging: NO,
|
|
2914
2983
|
|
|
@@ -2954,6 +3023,8 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
2954
3023
|
* @param toIndexPath <BMIndexPath<T>> The suggested index path at which to add the items.
|
|
2955
3024
|
* @param withDropShadows <Map<AnyObject, DOMNode>> A map containing the link between drop shadows and the items.
|
|
2956
3025
|
* }
|
|
3026
|
+
* @return <Promise<void>> A promise that resolves when the associated data update
|
|
3027
|
+
* has completed.
|
|
2957
3028
|
*/
|
|
2958
3029
|
_insertItems: async function (items, args) {
|
|
2959
3030
|
this._droppedShadows = args.withDropShadows;
|
|
@@ -2965,6 +3036,605 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
2965
3036
|
});
|
|
2966
3037
|
},
|
|
2967
3038
|
|
|
3039
|
+
/**
|
|
3040
|
+
* An array containing the cells whose index paths are part of the current drag session, or
|
|
3041
|
+
* `undefined` while there is no drag session in progress for this collection view.
|
|
3042
|
+
*/
|
|
3043
|
+
_draggingCells: undefined, // <[BMCollectionViewCell], nullable>
|
|
3044
|
+
|
|
3045
|
+
/**
|
|
3046
|
+
* A map that keeps track of the association between drag items in a drag session and the cells
|
|
3047
|
+
* whose items they represent.
|
|
3048
|
+
*/
|
|
3049
|
+
_cellItemMap: undefined, // <Map<BMDragItem, BMCollectionViewCell>>
|
|
3050
|
+
|
|
3051
|
+
/**
|
|
3052
|
+
* Begins a drag gesture from the specified event. The drag event will move the cell from which
|
|
3053
|
+
* the event originates, or all selected cells if that cell is selected.
|
|
3054
|
+
* @param event <Event> The event triggering this action.
|
|
3055
|
+
* {
|
|
3056
|
+
* @param forCell <BMCollectionViewCell> The cell from which this event originates.
|
|
3057
|
+
* @param touchIdentifier <AnyObject> If this event is a `TouchEvent`, this represents the identifier
|
|
3058
|
+
* of the touch point that will control this drag & drop operation.
|
|
3059
|
+
* }
|
|
3060
|
+
*/
|
|
3061
|
+
beginDragWithEvent(event, args) {
|
|
3062
|
+
const cell = args.forCell;
|
|
3063
|
+
|
|
3064
|
+
let cells;
|
|
3065
|
+
|
|
3066
|
+
if (this.isCellAtIndexPathSelected(cell.indexPath)) {
|
|
3067
|
+
cells = [cell];
|
|
3068
|
+
// Sort the index paths in ascending order
|
|
3069
|
+
this._selectedIndexPaths.sort((i1, i2) => i2.section == i1.section ? i1.row - i2.row : i1.section - i2.section).forEach(indexPath => {
|
|
3070
|
+
let retainedCell = this.retainCellForIndexPath(indexPath);
|
|
3071
|
+
|
|
3072
|
+
if (retainedCell != cell) {
|
|
3073
|
+
cells.push(retainedCell);
|
|
3074
|
+
}
|
|
3075
|
+
retainedCell.isDragging = YES;
|
|
3076
|
+
|
|
3077
|
+
retainedCell.node.classList.add('BMCollectionViewCellDragging');
|
|
3078
|
+
});
|
|
3079
|
+
}
|
|
3080
|
+
else {
|
|
3081
|
+
cells = [cell];
|
|
3082
|
+
cell.isDragging = YES;
|
|
3083
|
+
cell.retain();
|
|
3084
|
+
|
|
3085
|
+
cell.node.classList.add('BMCollectionViewCellDragging');
|
|
3086
|
+
}
|
|
3087
|
+
|
|
3088
|
+
this._draggingCells = cells;
|
|
3089
|
+
this._cellItemMap = new Map();
|
|
3090
|
+
|
|
3091
|
+
BMDragSession._beginDragWithEvent(event, {dragDelegate: this, view: this, touchIdentifier: args.touchIdentifier});
|
|
3092
|
+
},
|
|
3093
|
+
|
|
3094
|
+
/**
|
|
3095
|
+
* Creates and returns a fallback drag item for the specified index path if the data source
|
|
3096
|
+
* object cannot provide a customized drag item.
|
|
3097
|
+
* @param indexPath <BMIndexPath> The index path for which to return a drag item.
|
|
3098
|
+
* @return <BMDragItem> A drag item;
|
|
3099
|
+
*/
|
|
3100
|
+
_defaultDragItemForIndexPath(indexPath) {
|
|
3101
|
+
const object = this.dataSet.copyOfItem?.(indexPath.object) ?? JSON.parse(JSON.stringify(indexPath.object));
|
|
3102
|
+
|
|
3103
|
+
return {
|
|
3104
|
+
canConformToType(type) {
|
|
3105
|
+
return type == 'default' || type == 'object';
|
|
3106
|
+
},
|
|
3107
|
+
|
|
3108
|
+
itemOfType(type) {
|
|
3109
|
+
if (type != 'default' && type != 'object') {
|
|
3110
|
+
throw new Error(`Cannot provide an item representation of type "${type}"`);
|
|
3111
|
+
}
|
|
3112
|
+
|
|
3113
|
+
return object;
|
|
3114
|
+
}
|
|
3115
|
+
}
|
|
3116
|
+
},
|
|
3117
|
+
|
|
3118
|
+
dragSessionInitialItems(session) {
|
|
3119
|
+
this._draggingIndexPaths = [];
|
|
3120
|
+
|
|
3121
|
+
const items = this._draggingCells.map(cell => {
|
|
3122
|
+
const item = this.dataSet.dragItemForIndexPath?.(cell.indexPath, {session}) ?? this._defaultDragItemForIndexPath(cell.indexPath);
|
|
3123
|
+
this._cellItemMap.set(item, cell);
|
|
3124
|
+
this._draggingIndexPaths.push(cell.indexPath);
|
|
3125
|
+
return item;
|
|
3126
|
+
});
|
|
3127
|
+
|
|
3128
|
+
this._draggingIndexPaths.sort((i1, i2) => i1.section == i2.section ? i1.row - i2.row : i1.section - i2.section);
|
|
3129
|
+
|
|
3130
|
+
return items;
|
|
3131
|
+
},
|
|
3132
|
+
|
|
3133
|
+
dragSessionPreviewForItem(session, item) {
|
|
3134
|
+
const cell = this._cellItemMap.get(item);
|
|
3135
|
+
|
|
3136
|
+
cell.node.classList.remove('BMCollectionViewCellDragging');
|
|
3137
|
+
const preview = BMDragPreview.dragPreviewWithCopyOfSourceNode(cell.node, {forItem: item});
|
|
3138
|
+
cell.node.classList.add('BMCollectionViewCellDragging');
|
|
3139
|
+
|
|
3140
|
+
return preview;
|
|
3141
|
+
},
|
|
3142
|
+
|
|
3143
|
+
/**
|
|
3144
|
+
* The current drag action to use based on the current drag position.
|
|
3145
|
+
*/
|
|
3146
|
+
_dragAction: undefined, // <BMDragSessionAction, nullable>
|
|
3147
|
+
|
|
3148
|
+
/**
|
|
3149
|
+
* Set to `YES` while a drag session started by this collection view is in its frame.
|
|
3150
|
+
*/
|
|
3151
|
+
_dragSessionInFrame: NO, // <Boolean>
|
|
3152
|
+
|
|
3153
|
+
/**
|
|
3154
|
+
* The amount by which to scroll on the Y axis during the current drag session.
|
|
3155
|
+
*/
|
|
3156
|
+
_dragScrollDirectionY: 0, // <Number>
|
|
3157
|
+
|
|
3158
|
+
/**
|
|
3159
|
+
* The amount by which to scroll on the X axis during the current drag session.
|
|
3160
|
+
*/
|
|
3161
|
+
_dragScrollDirectionX: 0, // <Number>
|
|
3162
|
+
|
|
3163
|
+
/**
|
|
3164
|
+
* Whenever the pointer moves to the edges of this collection view during a drag session,
|
|
3165
|
+
* this method periodically scrolls the collection view's contents appropriately.
|
|
3166
|
+
*/
|
|
3167
|
+
_dragScroll() {
|
|
3168
|
+
// This callback runs continuously during the drag & drop operation - it is removed upon the operation finishing
|
|
3169
|
+
this._scrollFrameIdentifier = window.requestAnimationFrame(() => this._dragScroll());
|
|
3170
|
+
|
|
3171
|
+
// Don't perform the scroll during data updates
|
|
3172
|
+
if (this.isUpdatingData) {
|
|
3173
|
+
return;
|
|
3174
|
+
}
|
|
3175
|
+
|
|
3176
|
+
if (this._dragScrollDirectionX || this._dragScrollDirectionY) {
|
|
3177
|
+
const offset = this.scrollOffset;
|
|
3178
|
+
offset.x = offset.x + this._dragScrollDirectionX;
|
|
3179
|
+
offset.y = offset.y + this._dragScrollDirectionY;
|
|
3180
|
+
|
|
3181
|
+
offset.x = Math.max(0, Math.min(offset.x, this.size.width - this.frame.size.width));
|
|
3182
|
+
offset.y = Math.max(0, Math.min(offset.y, this.size.height - this.frame.size.height));
|
|
3183
|
+
|
|
3184
|
+
this.scrollOffset = offset;
|
|
3185
|
+
}
|
|
3186
|
+
},
|
|
3187
|
+
|
|
3188
|
+
/**
|
|
3189
|
+
* The identifier of the animation frame callback used to scroll this collection during a drag session while the
|
|
3190
|
+
* mouse pointer
|
|
3191
|
+
*/
|
|
3192
|
+
_scrollFrameIdentifier: undefined, // <Number, nullable>
|
|
3193
|
+
|
|
3194
|
+
dragSessionDidEnter(session) {
|
|
3195
|
+
this._dragSessionInFrame = YES;
|
|
3196
|
+
this._dragAction = BMDragSessionAction.actionWithKind(BMDragSessionActionKind.Ignore);
|
|
3197
|
+
this._scrollFrameIdentifier = window.requestAnimationFrame(() => this._dragScroll());
|
|
3198
|
+
},
|
|
3199
|
+
|
|
3200
|
+
dragSessionDidUpdate(session) {
|
|
3201
|
+
if (this._dragSessionInFrame) {
|
|
3202
|
+
if (this.delegate?.collectionViewCanReorderItemsAtIndexPaths?.(this, this._draggingIndexPaths, {session}) ?? YES) {
|
|
3203
|
+
// If item movement is supported, determine the new index path to which the items should move
|
|
3204
|
+
// Instruct the data set to move the item, if the new index path does not match the index path of any dragging item
|
|
3205
|
+
const localPoint = this.positionOfDragSession(session);
|
|
3206
|
+
const targetIndexPath = this.indexPathAtPoint(localPoint);
|
|
3207
|
+
|
|
3208
|
+
let canMoveItem = YES;
|
|
3209
|
+
if (!targetIndexPath) {
|
|
3210
|
+
return;
|
|
3211
|
+
}
|
|
3212
|
+
|
|
3213
|
+
// If the target index path is an index path of an item that's part of the session, don't perform the reorder
|
|
3214
|
+
this._draggingIndexPaths.forEach(indexPath => {
|
|
3215
|
+
if (targetIndexPath.row == indexPath.row && targetIndexPath.section == indexPath.section) {
|
|
3216
|
+
canMoveItem = NO;
|
|
3217
|
+
}
|
|
3218
|
+
});
|
|
3219
|
+
|
|
3220
|
+
if (canMoveItem) {
|
|
3221
|
+
if (this.dataSet.moveItemsFromIndexPaths && this._draggingIndexPaths.length > 1) {
|
|
3222
|
+
// Instruct the data set to move the items in bulk if possible
|
|
3223
|
+
const newIndexPaths = this.dataSet.moveItemsFromIndexPaths(this._draggingIndexPaths, {toIndexPath: targetIndexPath});
|
|
3224
|
+
this._draggingIndexPaths = newIndexPaths.sort((i1, i2) => i1.section == i2.section ? i1.row - i2.row : i1.section - i2.section);
|
|
3225
|
+
}
|
|
3226
|
+
else {
|
|
3227
|
+
// Otherwise move them one by one
|
|
3228
|
+
this._draggingIndexPaths.forEach((indexPath, index) => {
|
|
3229
|
+
let destinationIndexPath = targetIndexPath.copy();
|
|
3230
|
+
destinationIndexPath.object = indexPath.object;
|
|
3231
|
+
destinationIndexPath.row += index;
|
|
3232
|
+
if (this.dataSet.moveItemFromIndexPath(indexPath, {toIndexPath: destinationIndexPath})) {
|
|
3233
|
+
this._draggingIndexPaths[index] = destinationIndexPath;
|
|
3234
|
+
}
|
|
3235
|
+
});
|
|
3236
|
+
}
|
|
3237
|
+
}
|
|
3238
|
+
}
|
|
3239
|
+
|
|
3240
|
+
// Determine the scrolling direction
|
|
3241
|
+
const viewportFrame = BMRectMakeWithNodeFrame(this.node);
|
|
3242
|
+
const slope = _BMCollectionViewDragScrollDistance;
|
|
3243
|
+
const multi = _BMCollectionViewDragScrollMultiplier;
|
|
3244
|
+
if (session.position.x - viewportFrame.origin.x < slope) {
|
|
3245
|
+
this._dragScrollDirectionX =
|
|
3246
|
+
(session.position.x - viewportFrame.origin.x - slope) / slope * multi;
|
|
3247
|
+
}
|
|
3248
|
+
else if (viewportFrame.right - session.position.x < slope) {
|
|
3249
|
+
this._dragScrollDirectionX = (slope - viewportFrame.right + session.position.x) / slope * multi;
|
|
3250
|
+
}
|
|
3251
|
+
else {
|
|
3252
|
+
this._dragScrollDirectionX = 0;
|
|
3253
|
+
}
|
|
3254
|
+
|
|
3255
|
+
if (session.position.y - viewportFrame.origin.y < slope) {
|
|
3256
|
+
this._dragScrollDirectionY = (session.position.y - viewportFrame.origin.y - slope) / slope * multi;
|
|
3257
|
+
}
|
|
3258
|
+
else if (viewportFrame.bottom - session.position.y < slope) {
|
|
3259
|
+
this._dragScrollDirectionY = (slope - viewportFrame.bottom + session.position.y) / slope * multi;
|
|
3260
|
+
}
|
|
3261
|
+
else {
|
|
3262
|
+
this._dragScrollDirectionY = 0;
|
|
3263
|
+
}
|
|
3264
|
+
}
|
|
3265
|
+
|
|
3266
|
+
return this._dragAction;
|
|
3267
|
+
},
|
|
3268
|
+
|
|
3269
|
+
dragSessionDidExit(session) {
|
|
3270
|
+
this._dragSessionInFrame = NO;
|
|
3271
|
+
if (this.delegate?.collectionViewCanRemoveItemsAtIndexPaths?.(this, this._draggingIndexPaths, {session})) {
|
|
3272
|
+
const message = this.delegate?.collectionDeleteMessageForIndexPaths?.(this, this._draggingIndexPaths, {session}) ?? 'Remove';
|
|
3273
|
+
this._dragAction = BMDragSessionAction.actionWithKind(BMDragSessionActionKind.Delete, {message});
|
|
3274
|
+
}
|
|
3275
|
+
|
|
3276
|
+
if (this._scrollFrameIdentifier) {
|
|
3277
|
+
this._dragScrollDirectionX = 0;
|
|
3278
|
+
this._dragScrollDirectionY = 0;
|
|
3279
|
+
window.cancelAnimationFrame(this._scrollFrameIdentifier);
|
|
3280
|
+
this._scrollFrameIdentifier = undefined;
|
|
3281
|
+
}
|
|
3282
|
+
},
|
|
3283
|
+
|
|
3284
|
+
dragSessionWillFinish(session) {
|
|
3285
|
+
this.delegate?.collectionViewWillFinishInteractiveMovementForCell?.(this, this._draggingCells[0], {atIndexPath: this._draggingCells[0].indexPath, session});
|
|
3286
|
+
},
|
|
3287
|
+
|
|
3288
|
+
dragSessionPerformMoveForItems(session, items) {
|
|
3289
|
+
const indexPaths = items.map(i => this._cellItemMap.get(i).indexPath).sort((i1, i2) => {
|
|
3290
|
+
return i1.section == i2.section ? i1.row - i2.row : i1.section - i2.section;
|
|
3291
|
+
});
|
|
3292
|
+
|
|
3293
|
+
this.dataSet.removeItemsAtIndexPaths(indexPaths, {session});
|
|
3294
|
+
},
|
|
3295
|
+
|
|
3296
|
+
dragSessionPerformDelete(session) {
|
|
3297
|
+
this.dataSet.removeItemsAtIndexPaths(this._draggingIndexPaths, {session});
|
|
3298
|
+
},
|
|
3299
|
+
|
|
3300
|
+
dragSessionTransferKind(session) {
|
|
3301
|
+
const acceptPolicy = this.delegate?.collectionViewTransferPolicyForItemsAtIndexPaths?.(this, this._draggingIndexPaths, {session});
|
|
3302
|
+
switch (acceptPolicy) {
|
|
3303
|
+
case BMCollectionViewTransferPolicy.Move:
|
|
3304
|
+
return BMDragTransferKind.Move;
|
|
3305
|
+
case BMCollectionViewTransferPolicy.Copy:
|
|
3306
|
+
default:
|
|
3307
|
+
return BMDragTransferKind.Copy;
|
|
3308
|
+
}
|
|
3309
|
+
},
|
|
3310
|
+
|
|
3311
|
+
dragSessionDidFinish(session) {
|
|
3312
|
+
// Remove the dragging class from the cell
|
|
3313
|
+
this._draggingCells.forEach(cell => {
|
|
3314
|
+
cell.node.classList.remove('BMCollectionViewCellDragging');
|
|
3315
|
+
cell.isDragging = NO;
|
|
3316
|
+
|
|
3317
|
+
// Release the cell
|
|
3318
|
+
cell.release();
|
|
3319
|
+
});
|
|
3320
|
+
|
|
3321
|
+
this._draggingCells = undefined;
|
|
3322
|
+
this._cellItemMap = undefined;
|
|
3323
|
+
this._draggingIndexPaths = undefined;
|
|
3324
|
+
|
|
3325
|
+
this.delegate?.collectionViewDidFinishInteractiveMovementForCell?.(this, this._draggingCells[0], {atIndexPath: this._draggingCells[0].indexPath, session});
|
|
3326
|
+
},
|
|
3327
|
+
|
|
3328
|
+
dragSessionRequiresCustomDropAnimationForItems(session, items) {
|
|
3329
|
+
// Collection view only needs to customize the drop animation for partial transfers
|
|
3330
|
+
// where the transfer kind is move
|
|
3331
|
+
if (session.transferKind == BMDragTransferKind.Move && session.action._action == BMDropSessionActionKind.AcceptPartially) {
|
|
3332
|
+
return YES;
|
|
3333
|
+
}
|
|
3334
|
+
return NO;
|
|
3335
|
+
},
|
|
3336
|
+
|
|
3337
|
+
dragSessionAnimateDropWithPreviews(session, previews) {
|
|
3338
|
+
// If this collection view was already waiting for the data set to insert some data from a drop,
|
|
3339
|
+
// play the generic drop animation for those previews
|
|
3340
|
+
if (this._dropPreviews) {
|
|
3341
|
+
for (const preview of this._dropPreviews) {
|
|
3342
|
+
preview.performDrop();
|
|
3343
|
+
}
|
|
3344
|
+
}
|
|
3345
|
+
|
|
3346
|
+
this._dropPreviews = previews.slice();
|
|
3347
|
+
const dropPreviews = this._dropPreviews;
|
|
3348
|
+
|
|
3349
|
+
// After this method returns, the drag session will instruct collection view to perform the move for the
|
|
3350
|
+
// affected items, which should trigger a synchronous data update to use and clear the drag previews
|
|
3351
|
+
queueMicrotask(() => {
|
|
3352
|
+
if (this._dropPreviews == dropPreviews) {
|
|
3353
|
+
this._dropPreviews = undefined;
|
|
3354
|
+
}
|
|
3355
|
+
});
|
|
3356
|
+
},
|
|
3357
|
+
|
|
3358
|
+
/**
|
|
3359
|
+
* The kind of region being tracked during a drop session. `undefined` if a drop session is
|
|
3360
|
+
* not in progress.
|
|
3361
|
+
*/
|
|
3362
|
+
_dropSessionRegionKind: undefined, // <BMCollectionViewAcceptRegion, nullable>
|
|
3363
|
+
|
|
3364
|
+
/**
|
|
3365
|
+
* The current drop action to use based on the current drop session position.
|
|
3366
|
+
*/
|
|
3367
|
+
_dropAction: undefined, // <BMDropSessionAction, nullable>
|
|
3368
|
+
|
|
3369
|
+
/**
|
|
3370
|
+
* The index path associated with the current drop session, if any.
|
|
3371
|
+
*/
|
|
3372
|
+
_dropIndexPath: undefined, // <BMIndexPath, nullable>
|
|
3373
|
+
|
|
3374
|
+
dropSessionCanBegin(session) {
|
|
3375
|
+
this._lastDropIndexPath = undefined;
|
|
3376
|
+
this._dropIndexPath = undefined;
|
|
3377
|
+
this._dropAction = undefined;
|
|
3378
|
+
|
|
3379
|
+
const items = session.items.map(i => i.itemOfType('default'));
|
|
3380
|
+
const canBegin = this.delegate?.collectionViewCanAcceptItems?.(this, items, {session}) ?? NO;
|
|
3381
|
+
|
|
3382
|
+
// The drop session can begin if the response is not `NO` or `.Nowhere`.
|
|
3383
|
+
if (canBegin != NO && canBegin != BMCollectionViewAcceptRegion.Nowhere) {
|
|
3384
|
+
if (canBegin == YES || canBegin == BMCollectionViewAcceptRegion.Anywhere) {
|
|
3385
|
+
// If the drop session can be accepted anywhere, request the drop action from the delegate
|
|
3386
|
+
this._dropAction = this.delegate?.collectionViewDropActionForDropSession?.(this, session);
|
|
3387
|
+
this._dropAction ??= BMDropSessionAction.actionWithKind(BMDropSessionActionKind.Accept);
|
|
3388
|
+
this._dropSessionRegionKind = BMCollectionViewAcceptRegion.Anywhere;
|
|
3389
|
+
}
|
|
3390
|
+
else {
|
|
3391
|
+
this._dropSessionRegionKind = canBegin;
|
|
3392
|
+
}
|
|
3393
|
+
|
|
3394
|
+
return YES;
|
|
3395
|
+
}
|
|
3396
|
+
|
|
3397
|
+
return NO;
|
|
3398
|
+
},
|
|
3399
|
+
|
|
3400
|
+
dropSessionDidEnter(session) {
|
|
3401
|
+
this._dragScrollDirectionX = 0;
|
|
3402
|
+
this._dragScrollDirectionY = 0;
|
|
3403
|
+
this._scrollFrameIdentifier = window.requestAnimationFrame(() => this._dragScroll());
|
|
3404
|
+
},
|
|
3405
|
+
|
|
3406
|
+
dropSessionDidExit(session) {
|
|
3407
|
+
if (this._scrollFrameIdentifier) {
|
|
3408
|
+
this._dragScrollDirectionX = 0;
|
|
3409
|
+
this._dragScrollDirectionY = 0;
|
|
3410
|
+
window.cancelAnimationFrame(this._scrollFrameIdentifier);
|
|
3411
|
+
this._scrollFrameIdentifier = undefined;
|
|
3412
|
+
}
|
|
3413
|
+
},
|
|
3414
|
+
|
|
3415
|
+
/**
|
|
3416
|
+
* Returns the position of the specified drag or drop session relative to the collection view's bounds.
|
|
3417
|
+
* @param session <BMDragSession or BMDropSession> The drag or drop session.
|
|
3418
|
+
* @return <BMPoint> The coordinates relative to the bounds.
|
|
3419
|
+
*/
|
|
3420
|
+
positionOfDragSession(session) {
|
|
3421
|
+
const point = session.position;
|
|
3422
|
+
|
|
3423
|
+
// Determine the index path over which this session currently is
|
|
3424
|
+
const viewportFrame = BMRectMakeWithNodeFrame(this.node);
|
|
3425
|
+
|
|
3426
|
+
// Discover the coordinates of the point that are relative to the collection view's bounds
|
|
3427
|
+
let localPoint = BMPointMake(
|
|
3428
|
+
point.x - viewportFrame.origin.x,
|
|
3429
|
+
point.y - viewportFrame.origin.y,
|
|
3430
|
+
);
|
|
3431
|
+
localPoint.x += this.scrollOffset.x;
|
|
3432
|
+
localPoint.y += this.scrollOffset.y;
|
|
3433
|
+
|
|
3434
|
+
return localPoint;
|
|
3435
|
+
},
|
|
3436
|
+
|
|
3437
|
+
/**
|
|
3438
|
+
* Determines the index path at the specified point whose coordinates are relative to the bounds.
|
|
3439
|
+
* @param point <BMPoint> The point.
|
|
3440
|
+
* @return <BMIndexPath, nullable> The index path, if any cell's frame intersects the point,
|
|
3441
|
+
* or `undefined` otherwise.
|
|
3442
|
+
*/
|
|
3443
|
+
indexPathAtPoint(point) {
|
|
3444
|
+
// Create a rect around this point with a size of 64 by 64 pixels.
|
|
3445
|
+
const rect = BMRectMake(0, 0, 64, 64);
|
|
3446
|
+
rect.center = point;
|
|
3447
|
+
|
|
3448
|
+
// Request the attributes within the given rect
|
|
3449
|
+
const attributes = this.layout.attributesForElementsInRect(rect);
|
|
3450
|
+
|
|
3451
|
+
// Find the index path to which the cell should move
|
|
3452
|
+
let targetIndexPath;
|
|
3453
|
+
attributes.forEach(attribute => {
|
|
3454
|
+
if (attribute.itemType != BMCollectionViewLayoutAttributesType.Cell) {
|
|
3455
|
+
return;
|
|
3456
|
+
}
|
|
3457
|
+
|
|
3458
|
+
if (attribute.frame.containsPoint(point)) {
|
|
3459
|
+
targetIndexPath = attribute.indexPath.copy();
|
|
3460
|
+
}
|
|
3461
|
+
});
|
|
3462
|
+
|
|
3463
|
+
return targetIndexPath;
|
|
3464
|
+
},
|
|
3465
|
+
|
|
3466
|
+
/**
|
|
3467
|
+
* The most recent index path the current drop session has been over.
|
|
3468
|
+
*/
|
|
3469
|
+
_lastDropIndexPath: undefined, // <BMIndexPath>
|
|
3470
|
+
|
|
3471
|
+
dropSessionDidUpdate(session) {
|
|
3472
|
+
const localPoint = this.positionOfDragSession(session);
|
|
3473
|
+
const targetIndexPath = this.indexPathAtPoint(localPoint);
|
|
3474
|
+
|
|
3475
|
+
if (targetIndexPath) {
|
|
3476
|
+
this._lastDropIndexPath = targetIndexPath;
|
|
3477
|
+
}
|
|
3478
|
+
|
|
3479
|
+
if (this._dropSessionRegionKind == BMCollectionViewAcceptRegion.Anywhere) {
|
|
3480
|
+
return this._dropAction;
|
|
3481
|
+
}
|
|
3482
|
+
|
|
3483
|
+
// Determine the scrolling direction
|
|
3484
|
+
const viewportFrame = BMRectMakeWithNodeFrame(this.node);
|
|
3485
|
+
const slope = _BMCollectionViewDragScrollDistance;
|
|
3486
|
+
const multi = _BMCollectionViewDragScrollMultiplier;
|
|
3487
|
+
if (session.position.x - viewportFrame.origin.x < slope) {
|
|
3488
|
+
this._dragScrollDirectionX =
|
|
3489
|
+
(session.position.x - viewportFrame.origin.x - slope) / slope * multi;
|
|
3490
|
+
}
|
|
3491
|
+
else if (viewportFrame.right - session.position.x < slope) {
|
|
3492
|
+
this._dragScrollDirectionX = (slope - viewportFrame.right + session.position.x) / slope * multi;
|
|
3493
|
+
}
|
|
3494
|
+
else {
|
|
3495
|
+
this._dragScrollDirectionX = 0;
|
|
3496
|
+
}
|
|
3497
|
+
|
|
3498
|
+
if (session.position.y - viewportFrame.origin.y < slope) {
|
|
3499
|
+
this._dragScrollDirectionY = (session.position.y - viewportFrame.origin.y - slope) / slope * multi;
|
|
3500
|
+
}
|
|
3501
|
+
else if (viewportFrame.bottom - session.position.y < slope) {
|
|
3502
|
+
this._dragScrollDirectionY = (slope - viewportFrame.bottom + session.position.y) / slope * multi;
|
|
3503
|
+
}
|
|
3504
|
+
else {
|
|
3505
|
+
this._dragScrollDirectionY = 0;
|
|
3506
|
+
}
|
|
3507
|
+
|
|
3508
|
+
// If the index path changes, notify the delegate using the appropriate methods
|
|
3509
|
+
if (!targetIndexPath) {
|
|
3510
|
+
if (this._dropIndexPath) {
|
|
3511
|
+
this._dropIndexPath = undefined;
|
|
3512
|
+
this.delegate?.collectionViewDropSessionDidExitIndexPath?.(this, session, {indexPath: this._dropIndexPath});
|
|
3513
|
+
|
|
3514
|
+
if (this._dropSessionRegionKind == BMCollectionViewAcceptRegion.Cell) {
|
|
3515
|
+
return BMDropSessionAction.actionWithKind(BMDropSessionActionKind.Ignore);
|
|
3516
|
+
}
|
|
3517
|
+
}
|
|
3518
|
+
}
|
|
3519
|
+
else {
|
|
3520
|
+
let isNewIndexPath = NO;
|
|
3521
|
+
if (!this._dropIndexPath) {
|
|
3522
|
+
isNewIndexPath = YES;
|
|
3523
|
+
}
|
|
3524
|
+
else {
|
|
3525
|
+
if (!this._dropIndexPath.isEqualToIndexPath(targetIndexPath, {usingComparator: this.identityComparator})) {
|
|
3526
|
+
isNewIndexPath = YES;
|
|
3527
|
+
this.delegate?.collectionViewDropSessionDidExitIndexPath?.(this, session, {indexPath: this._dropIndexPath});
|
|
3528
|
+
}
|
|
3529
|
+
}
|
|
3530
|
+
|
|
3531
|
+
this._dropIndexPath = targetIndexPath;
|
|
3532
|
+
|
|
3533
|
+
if (isNewIndexPath) {
|
|
3534
|
+
const action = this.delegate?.collectionViewDropSessionDidEnterIndexPath?.(this, session, {indexPath: this._dropIndexPath});
|
|
3535
|
+
|
|
3536
|
+
if (this._dropSessionRegionKind == BMCollectionViewAcceptRegion.Cell) {
|
|
3537
|
+
return action;
|
|
3538
|
+
}
|
|
3539
|
+
}
|
|
3540
|
+
}
|
|
3541
|
+
|
|
3542
|
+
if (this._dropSessionRegionKind == BMCollectionViewAcceptRegion.Position) {
|
|
3543
|
+
const action = this.delegate?.collectionViewDropSessionDidUpdate?.(this, session, {position: localPoint});
|
|
3544
|
+
return action;
|
|
3545
|
+
}
|
|
3546
|
+
},
|
|
3547
|
+
|
|
3548
|
+
dropSessionPreviewForItem(session, item) {
|
|
3549
|
+
const node = this.delegate?.collectionViewPreviewForDropSession?.(this, session, {item});
|
|
3550
|
+
if (node) {
|
|
3551
|
+
return BMDragPreview.dragPreviewWithPreviewNode(node, {forItem: item});
|
|
3552
|
+
}
|
|
3553
|
+
},
|
|
3554
|
+
|
|
3555
|
+
dropSessionWillFinish(session) {
|
|
3556
|
+
this.delegate?.collectionViewDropSessionWillFinish?.(this, session);
|
|
3557
|
+
},
|
|
3558
|
+
|
|
3559
|
+
dropSessionRequiresCustomDropAnimationForItems(session, items) {
|
|
3560
|
+
return YES;
|
|
3561
|
+
},
|
|
3562
|
+
|
|
3563
|
+
dropSessionTransferKind(session) {
|
|
3564
|
+
const acceptPolicy = this.delegate?.collectionViewAcceptPolicyForItems?.(this, session.items.map(i => i.itemOfType('default')), {session});
|
|
3565
|
+
switch (acceptPolicy) {
|
|
3566
|
+
case BMCollectionViewAcceptPolicy.Move:
|
|
3567
|
+
return BMDragTransferKind.Move;
|
|
3568
|
+
case BMCollectionViewAcceptPolicy.Copy:
|
|
3569
|
+
default:
|
|
3570
|
+
return BMDragTransferKind.Copy;
|
|
3571
|
+
}
|
|
3572
|
+
},
|
|
3573
|
+
|
|
3574
|
+
/**
|
|
3575
|
+
* The drop previews that must be animated at the end of a successful drop session. Only set while performing
|
|
3576
|
+
* the data update associated with accepting items via a drop session.
|
|
3577
|
+
*/
|
|
3578
|
+
_dropPreviews: undefined, // <[BMDropPreview], nullable>
|
|
3579
|
+
|
|
3580
|
+
dropSessionPerformDrop(session) {
|
|
3581
|
+
// If this collection view was already waiting for the data set to insert some data from a drop,
|
|
3582
|
+
// play the generic drop animation for those previews
|
|
3583
|
+
if (this._dropPreviews) {
|
|
3584
|
+
for (const preview of this._dropPreviews) {
|
|
3585
|
+
preview.performDrop();
|
|
3586
|
+
}
|
|
3587
|
+
}
|
|
3588
|
+
|
|
3589
|
+
// If there are no items to accept, don't perform any other changes
|
|
3590
|
+
if (!session.dropItems.length) {
|
|
3591
|
+
return;
|
|
3592
|
+
}
|
|
3593
|
+
|
|
3594
|
+
let toIndexPath = this._lastDropIndexPath;
|
|
3595
|
+
if (!toIndexPath) {
|
|
3596
|
+
const sectionCount = this.numberOfSections();
|
|
3597
|
+
const row = this.numberOfObjectsInSectionAtIndex(sectionCount - 1) - 1;
|
|
3598
|
+
const section = sectionCount - 1;
|
|
3599
|
+
toIndexPath = this.indexPathForObjectAtRow(row, {inSectionAtIndex: section}) ?? BMIndexPathMakeWithRow(row, {section});
|
|
3600
|
+
}
|
|
3601
|
+
|
|
3602
|
+
// Instruct the data set to insert the items to the appropriate index path
|
|
3603
|
+
this._dropPreviews = session.dropPreviews.slice();
|
|
3604
|
+
|
|
3605
|
+
const items = session.dropItems.map(i => i.itemOfType('default'));
|
|
3606
|
+
const result = this.dataSet.insertItems(items, {toIndexPath, session});
|
|
3607
|
+
|
|
3608
|
+
if (result) {
|
|
3609
|
+
// If the data set performs the change asynchronously, give it 200ms to trigger the data update, otherwise
|
|
3610
|
+
// play the generic drop animation for the previews
|
|
3611
|
+
const dropPreviews = this._dropPreviews;
|
|
3612
|
+
let resolved = NO;
|
|
3613
|
+
result.then(() => {
|
|
3614
|
+
resolved = YES;
|
|
3615
|
+
|
|
3616
|
+
if (this._dropPreviews == dropPreviews) {
|
|
3617
|
+
this._dropPreviews = undefined;
|
|
3618
|
+
}
|
|
3619
|
+
});
|
|
3620
|
+
|
|
3621
|
+
setTimeout(() => {
|
|
3622
|
+
if (!resolved) {
|
|
3623
|
+
if (this._dropPreviews == dropPreviews) {
|
|
3624
|
+
this._dropPreviews = undefined;
|
|
3625
|
+
}
|
|
3626
|
+
|
|
3627
|
+
for (const preview of dropPreviews) {
|
|
3628
|
+
preview.performDrop();
|
|
3629
|
+
}
|
|
3630
|
+
}
|
|
3631
|
+
}, _BMCollectionViewAsynchronousDropDelay);
|
|
3632
|
+
}
|
|
3633
|
+
else {
|
|
3634
|
+
this._dropPreviews = undefined;
|
|
3635
|
+
}
|
|
3636
|
+
},
|
|
3637
|
+
|
|
2968
3638
|
/**
|
|
2969
3639
|
* Begins a drag gesture from the given event. The drag event will move the cell from which
|
|
2970
3640
|
* the event originates.
|
|
@@ -2975,7 +3645,7 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
2975
3645
|
* of the touch point that will control this drag & drop operation.
|
|
2976
3646
|
* }
|
|
2977
3647
|
*/
|
|
2978
|
-
|
|
3648
|
+
_beginDragWithEvent(event, args) {
|
|
2979
3649
|
if (this.isDragging) return;
|
|
2980
3650
|
// TODO Consider splitting up this giant method
|
|
2981
3651
|
|
|
@@ -3018,7 +3688,7 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
3018
3688
|
}
|
|
3019
3689
|
else {
|
|
3020
3690
|
cells = [cell];
|
|
3021
|
-
cell.
|
|
3691
|
+
cell.isDragging = YES;
|
|
3022
3692
|
cell.retain();
|
|
3023
3693
|
|
|
3024
3694
|
cell.node.classList.add('BMCollectionViewCellDragging');
|
|
@@ -3082,18 +3752,7 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
3082
3752
|
|
|
3083
3753
|
draggingShadows.push(otherDraggingShadow);
|
|
3084
3754
|
let index = draggingShadows.length;
|
|
3085
|
-
|
|
3086
|
-
// __BMVelocityAnimate(otherDraggingShadow, {
|
|
3087
|
-
// rotateZ: ((index) * 60 / cells.length) + 'deg',
|
|
3088
|
-
// left: [draggingShadowTargetPoint.x + 'px', sourceRect.origin.x + 'px'],
|
|
3089
|
-
// top: [draggingShadowTargetPoint.y + 'py', sourceRect.origin.x + 'px']
|
|
3090
|
-
// }, {
|
|
3091
|
-
// easing: 'easeInOutQuad',
|
|
3092
|
-
// duration: 300,
|
|
3093
|
-
// complete() {
|
|
3094
|
-
// areDraggingShadowsAnimating = NO;
|
|
3095
|
-
// }
|
|
3096
|
-
// });
|
|
3755
|
+
|
|
3097
3756
|
(window.Velocity || $.Velocity).animate(otherDraggingShadow, {tween: 1}, {
|
|
3098
3757
|
easing: 'easeInOutQuad',
|
|
3099
3758
|
duration: 300,
|
|
@@ -3123,15 +3782,6 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
3123
3782
|
draggingShadowsToAdd.forEach(shadow => document.body.appendChild(shadow));
|
|
3124
3783
|
document.body.appendChild(draggingIndicator);
|
|
3125
3784
|
|
|
3126
|
-
// (window.Velocity || $.Velocity).animate(draggingIndicator, {
|
|
3127
|
-
// opacity: [1, 0],
|
|
3128
|
-
// scaleX: [1, 0],
|
|
3129
|
-
// scaleY: [1, 0]
|
|
3130
|
-
// }, {
|
|
3131
|
-
// duration: 300,
|
|
3132
|
-
// easing: 'easeOutQuad'
|
|
3133
|
-
// });
|
|
3134
|
-
|
|
3135
3785
|
__BMVelocityAnimate(draggingIndicator, {
|
|
3136
3786
|
opacity: [1, 0],
|
|
3137
3787
|
scaleX: [1, 0],
|
|
@@ -3342,10 +3992,14 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
3342
3992
|
}
|
|
3343
3993
|
|
|
3344
3994
|
// Temporarily suspend these updates while a data update is in progress
|
|
3345
|
-
if (this.isUpdatingData)
|
|
3995
|
+
if (this.isUpdatingData) {
|
|
3996
|
+
event.preventDefault();
|
|
3997
|
+
event.stopPropagation();
|
|
3998
|
+
return;
|
|
3999
|
+
}
|
|
3346
4000
|
|
|
3347
4001
|
|
|
3348
|
-
// 3.
|
|
4002
|
+
// 3. Enable scrolling while close to the collection view's edges.
|
|
3349
4003
|
if (clientX - collectionViewViewportFrame.origin.x < 32) {
|
|
3350
4004
|
scrollDirectionX = (clientX - collectionViewViewportFrame.origin.x - 32) / 32 * 20;
|
|
3351
4005
|
}
|
|
@@ -3773,7 +4427,7 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
3773
4427
|
// Remove the dragging class from the cell
|
|
3774
4428
|
cells.forEach(cell => {
|
|
3775
4429
|
cell.node.classList.remove('BMCollectionViewCellDragging');
|
|
3776
|
-
cell.
|
|
4430
|
+
cell.isDragging = NO;
|
|
3777
4431
|
|
|
3778
4432
|
// Release the cell
|
|
3779
4433
|
cell.release();
|
|
@@ -4381,7 +5035,7 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
4381
5035
|
* Highlights the index path to the specified direction of the currently highlighted index path.
|
|
4382
5036
|
* @param arrow <String> The key code of the keyboard arrow that was pressed.
|
|
4383
5037
|
* {
|
|
4384
|
-
* @param withEvent <KeyboardEvent> The event that
|
|
5038
|
+
* @param withEvent <KeyboardEvent> The event that triggered this action.
|
|
4385
5039
|
* }
|
|
4386
5040
|
*/
|
|
4387
5041
|
keyboardArrowPressed(arrow, args) {
|
|
@@ -5133,6 +5787,49 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
5133
5787
|
get dataUpdated() { // <Promise<void>, nullable>
|
|
5134
5788
|
return this._dataUpdatePromise;
|
|
5135
5789
|
},
|
|
5790
|
+
|
|
5791
|
+
/**
|
|
5792
|
+
* Finds and returns the drop preview associated with the specified layout attributes, if any exists.
|
|
5793
|
+
* @param attributes <BMCollectionViewLayoutAttributes> Tha attributes for which to find the drop preview.
|
|
5794
|
+
* {
|
|
5795
|
+
* @param previewMap <Map<BMIndexPath<T>, BMDropPreview>, nullable>
|
|
5796
|
+
* An optional mapping between index paths and drop items
|
|
5797
|
+
* used to find the drop preview for the item representation
|
|
5798
|
+
* that the data set actually inserted. The default item
|
|
5799
|
+
* representation will be used if this is not provided.
|
|
5800
|
+
* }
|
|
5801
|
+
* @returns <BMDropPreview, nullable> The drop preview if it was found, `undefined` otherwise.
|
|
5802
|
+
*/
|
|
5803
|
+
_dropPreviewForLayoutAttributes: function (attributes, {previewMap}) {
|
|
5804
|
+
if (!this._dropPreviews) {
|
|
5805
|
+
return;
|
|
5806
|
+
}
|
|
5807
|
+
|
|
5808
|
+
let dropPreview;
|
|
5809
|
+
|
|
5810
|
+
if (this._cellItemMap) {
|
|
5811
|
+
for (const [item, cell] of this._cellItemMap.entries()) {
|
|
5812
|
+
if (cell.indexPath.isLooselyEqualToIndexPath(attributes.indexPath, {usingComparator: this.identityComparator})) {
|
|
5813
|
+
return this._dropPreviews.find(p => p.item == item);
|
|
5814
|
+
}
|
|
5815
|
+
}
|
|
5816
|
+
}
|
|
5817
|
+
else if (previewMap) {
|
|
5818
|
+
for (const [indexPath, preview] of previewMap.entries()) {
|
|
5819
|
+
if (indexPath.isEqualToIndexPath(attributes.indexPath, {usingComparator: this.identityComparator})) {
|
|
5820
|
+
dropPreview = preview;
|
|
5821
|
+
break;
|
|
5822
|
+
}
|
|
5823
|
+
}
|
|
5824
|
+
}
|
|
5825
|
+
else {
|
|
5826
|
+
// If the data set did not provide the new index paths, assume that the default representation
|
|
5827
|
+
// was used and instead look for the object
|
|
5828
|
+
dropPreview = this._dropPreviews.find(p => p.item.itemOfType('default') == attributes.indexPath.object);
|
|
5829
|
+
}
|
|
5830
|
+
|
|
5831
|
+
return dropPreview;
|
|
5832
|
+
},
|
|
5136
5833
|
|
|
5137
5834
|
/**
|
|
5138
5835
|
* Should be invoked when the entire data set is updated in bulk.
|
|
@@ -5272,8 +5969,14 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
5272
5969
|
// Disable scrolling and interaction during update
|
|
5273
5970
|
this._container[0].style.pointerEvents = 'none';
|
|
5274
5971
|
var containerScrollOffset = this.scrollOffset;
|
|
5275
|
-
|
|
5276
|
-
if (this.
|
|
5972
|
+
|
|
5973
|
+
if (!this.iScroll) {
|
|
5974
|
+
this._container[0].scrollTo(containerScrollOffset.x, containerScrollOffset.y);
|
|
5975
|
+
}
|
|
5976
|
+
|
|
5977
|
+
if (this.scrollView) {
|
|
5978
|
+
this.scrollView.scrollingEnabled = NO;
|
|
5979
|
+
}
|
|
5277
5980
|
|
|
5278
5981
|
// Get the new content
|
|
5279
5982
|
var attributes = this.layout.attributesForElementsInRect(this._bounds);
|
|
@@ -5284,6 +5987,12 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
5284
5987
|
var deletedCells = [];
|
|
5285
5988
|
var insertedCells = [];
|
|
5286
5989
|
var movingCells = [];
|
|
5990
|
+
|
|
5991
|
+
// Contains cells that are temporarily hidden due to a drop animation
|
|
5992
|
+
const sessionDropCells = [];
|
|
5993
|
+
|
|
5994
|
+
// Contains moving cells that have associated drop previews
|
|
5995
|
+
const dropMovingCells = [];
|
|
5287
5996
|
|
|
5288
5997
|
var supplementaryViewsToInsert = this.layout.supplementaryViewsToInsert();
|
|
5289
5998
|
var supplementaryViewsToDelete = this.layout.supplementaryViewsToDelete();
|
|
@@ -5297,6 +6006,20 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
5297
6006
|
var visibleRect = new BMRect(BMPointMake(this._bounds.origin.x + this._offscreenBufferSize, this._bounds.origin.y + this._offscreenBufferSize), this._frame.size.copy());
|
|
5298
6007
|
var currentVisibleRect = new BMRect(BMPointMake(oldBounds.origin.x + this._offscreenBufferSize, oldBounds.origin.y + this._offscreenBufferSize), this._frame.size.copy());
|
|
5299
6008
|
|
|
6009
|
+
// If this update occurs because of a drag & drop operation, try to obtain the associated index paths from the data set
|
|
6010
|
+
let dropPreviewMap;
|
|
6011
|
+
if (this._dropPreviews && this.dataSet.indexPathForDragItem) {
|
|
6012
|
+
dropPreviewMap = new Map();
|
|
6013
|
+
|
|
6014
|
+
for (const preview of this._dropPreviews) {
|
|
6015
|
+
const indexPath = this.dataSet.indexPathForDragItem(preview.item);
|
|
6016
|
+
|
|
6017
|
+
if (indexPath) {
|
|
6018
|
+
dropPreviewMap.set(indexPath, preview);
|
|
6019
|
+
}
|
|
6020
|
+
}
|
|
6021
|
+
}
|
|
6022
|
+
|
|
5300
6023
|
// Compare the current content to the new content and data set
|
|
5301
6024
|
for (var i = 0; i < oldCells.length; i++) {
|
|
5302
6025
|
var cell = oldCells[i];
|
|
@@ -5314,13 +6037,17 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
5314
6037
|
var attribute = attributes[j];
|
|
5315
6038
|
|
|
5316
6039
|
// Skip cells with different item types
|
|
5317
|
-
if (cell.itemType !== attribute.itemType)
|
|
6040
|
+
if (cell.itemType !== attribute.itemType) {
|
|
6041
|
+
continue;
|
|
6042
|
+
}
|
|
5318
6043
|
|
|
5319
6044
|
// Two cells refer to the same object if they are the same type and their index paths are loosely equal
|
|
5320
6045
|
if (cell.indexPath.isLooselyEqualToIndexPath(attribute.indexPath, {usingComparator: this.identityComparator})) {
|
|
5321
6046
|
|
|
5322
6047
|
// For supplementary views, it is also required that they have the same type identifier
|
|
5323
|
-
if (cell.itemType === BMCollectionViewLayoutAttributesType.SupplementaryView && cell.reuseIdentifier !== attribute.identifier)
|
|
6048
|
+
if (cell.itemType === BMCollectionViewLayoutAttributesType.SupplementaryView && cell.reuseIdentifier !== attribute.identifier) {
|
|
6049
|
+
continue;
|
|
6050
|
+
}
|
|
5324
6051
|
|
|
5325
6052
|
// If they are equal, mark the cell as moving and continue
|
|
5326
6053
|
cell.targetAttributes = attribute;
|
|
@@ -5330,17 +6057,35 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
5330
6057
|
|
|
5331
6058
|
// Instruct the data set to update this cell's content
|
|
5332
6059
|
if (cell.itemType === BMCollectionViewLayoutAttributesType.Cell) {
|
|
5333
|
-
|
|
6060
|
+
|
|
6061
|
+
// If a drop preview exists for this cell, store it so that the drop is performed
|
|
6062
|
+
// at the appropriate position
|
|
6063
|
+
if (this._dropPreviews) {
|
|
6064
|
+
const dropPreview = this._dropPreviewForLayoutAttributes(cell.targetAttributes, {previewMap: dropPreviewMap});
|
|
6065
|
+
|
|
6066
|
+
if (dropPreview) {
|
|
6067
|
+
cell._dropPreview = dropPreview;
|
|
6068
|
+
dropMovingCells.push(cell);
|
|
6069
|
+
}
|
|
6070
|
+
}
|
|
6071
|
+
|
|
6072
|
+
if (this.dataSet.updateCell) {
|
|
6073
|
+
this.dataSet.updateCell(cell, {atIndexPath: attribute.indexPath});
|
|
6074
|
+
}
|
|
5334
6075
|
}
|
|
5335
6076
|
else if (cell.itemType === BMCollectionViewLayoutAttributesType.SupplementaryView) {
|
|
5336
|
-
if (this.dataSet.updateSupplementaryView)
|
|
6077
|
+
if (this.dataSet.updateSupplementaryView) {
|
|
6078
|
+
this.dataSet.updateSupplementaryView(cell, {withIdentifier: cell.reuseIdentifier, atIndexPath: attribute.indexPath});
|
|
6079
|
+
}
|
|
5337
6080
|
}
|
|
5338
6081
|
|
|
5339
6082
|
break;
|
|
5340
6083
|
}
|
|
5341
6084
|
}
|
|
5342
6085
|
|
|
5343
|
-
if (foundCell)
|
|
6086
|
+
if (foundCell) {
|
|
6087
|
+
continue;
|
|
6088
|
+
}
|
|
5344
6089
|
|
|
5345
6090
|
// If the cell wasn't found in the new layout, check to see if its object still exists in the data set
|
|
5346
6091
|
if (cell.itemType === BMCollectionViewLayoutAttributesType.Cell) {
|
|
@@ -5351,9 +6096,22 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
5351
6096
|
var attribute = this.layout.attributesForCellAtIndexPath(indexPath);
|
|
5352
6097
|
cell.targetAttributes = attribute;
|
|
5353
6098
|
movingCells.push(cell);
|
|
6099
|
+
|
|
6100
|
+
// If a drop preview exists for this cell, store it so that the drop is performed
|
|
6101
|
+
// at the appropriate position
|
|
6102
|
+
if (this._dropPreviews) {
|
|
6103
|
+
const dropPreview = this._dropPreviewForLayoutAttributes(cell.targetAttributes, {previewMap: dropPreviewMap});
|
|
6104
|
+
|
|
6105
|
+
if (dropPreview) {
|
|
6106
|
+
cell._dropPreview = dropPreview;
|
|
6107
|
+
dropMovingCells.push(cell);
|
|
6108
|
+
}
|
|
6109
|
+
}
|
|
5354
6110
|
|
|
5355
6111
|
// Instruct the data set to update this cell's content
|
|
5356
|
-
if (this.dataSet.updateCell)
|
|
6112
|
+
if (this.dataSet.updateCell) {
|
|
6113
|
+
this.dataSet.updateCell(cell, {atIndexPath: attribute.indexPath});
|
|
6114
|
+
}
|
|
5357
6115
|
}
|
|
5358
6116
|
else {
|
|
5359
6117
|
// Otherwise the cell was removed from the data set
|
|
@@ -5381,7 +6139,9 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
5381
6139
|
movingCells.push(cell);
|
|
5382
6140
|
|
|
5383
6141
|
// Instruct the data set to update this supplementary view's content
|
|
5384
|
-
if (this.dataSet.updateSupplementaryView)
|
|
6142
|
+
if (this.dataSet.updateSupplementaryView) {
|
|
6143
|
+
this.dataSet.updateSupplementaryView(cell, {withIdentifier: cell.reuseIdentifier, atIndexPath: attribute.indexPath});
|
|
6144
|
+
}
|
|
5385
6145
|
}
|
|
5386
6146
|
else {
|
|
5387
6147
|
// Otherwise find its final attributes
|
|
@@ -5396,12 +6156,6 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
5396
6156
|
|
|
5397
6157
|
// Construct the cells for the new attributes
|
|
5398
6158
|
var newCells = [];
|
|
5399
|
-
|
|
5400
|
-
// If this update occurs because of a drag & drop operation, the collection view's viewport frame will be needed
|
|
5401
|
-
var viewportFrame;
|
|
5402
|
-
if (this._droppedShadows) {
|
|
5403
|
-
viewportFrame = BMRectMakeWithNodeFrame(this._container[0]);
|
|
5404
|
-
}
|
|
5405
6159
|
|
|
5406
6160
|
// Compare the remaining new content to the old data set
|
|
5407
6161
|
for (var i = 0; i < attributes.length; i++) {
|
|
@@ -5424,53 +6178,55 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
5424
6178
|
var oldAttribute = this.layout.initialAttributesForMovingCellFromIndexPath(oldIndexPath, {toIndexPath: attribute.indexPath, withTargetAttributes: attribute});
|
|
5425
6179
|
attribute.initialAttributes = oldAttribute;
|
|
5426
6180
|
//oldAttribute.indexPath = attribute.indexPath;
|
|
6181
|
+
|
|
6182
|
+
// If a drop preview exists for this cell, store it so that the drop is performed
|
|
6183
|
+
// at the appropriate position
|
|
6184
|
+
if (this._dropPreviews) {
|
|
6185
|
+
const dropPreview = this._dropPreviewForLayoutAttributes(cell.targetAttributes, {previewMap: dropPreviewMap});
|
|
6186
|
+
|
|
6187
|
+
if (dropPreview) {
|
|
6188
|
+
cell._dropPreview = dropPreview;
|
|
6189
|
+
dropMovingCells.push(cell);
|
|
6190
|
+
}
|
|
6191
|
+
}
|
|
5427
6192
|
}
|
|
5428
6193
|
else {
|
|
5429
6194
|
// Otherwise this is a new element
|
|
5430
6195
|
|
|
5431
|
-
// Check if there is a drop
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
frame.origin.y += cellTransform.origin.y;
|
|
5461
|
-
|
|
5462
|
-
initialAttributes.frame = frame;
|
|
5463
|
-
initialAttributes.style.rotateZ = droppedShadow.rotation + 'deg';
|
|
5464
|
-
initialAttributes.style.scaleX = cellTransform.size.width;
|
|
5465
|
-
initialAttributes.style.scaleY = cellTransform.size.height;
|
|
5466
|
-
initialAttributes.style.opacity = 0;
|
|
6196
|
+
// Check if there is a drop preview associated with this element and transition from that preview
|
|
6197
|
+
if (this._dropPreviews) {
|
|
6198
|
+
// Find if a newly inserted index path matches this cell's index path
|
|
6199
|
+
const dropPreview = this._dropPreviewForLayoutAttributes(attribute, {previewMap: dropPreviewMap});
|
|
6200
|
+
|
|
6201
|
+
let initialAttributes = attribute;
|
|
6202
|
+
|
|
6203
|
+
// If a preferred scroll offset is provided by the layout, displace the cell initially so that it
|
|
6204
|
+
// starts out at the position it will be in at the end of the scroll animation, relative to the viewport
|
|
6205
|
+
const displacement = BMPointMake(
|
|
6206
|
+
preferredScrollOffset.x - scrollOffset.x,
|
|
6207
|
+
preferredScrollOffset.y - scrollOffset.y
|
|
6208
|
+
);
|
|
6209
|
+
|
|
6210
|
+
if (displacement.x || displacement.y) {
|
|
6211
|
+
initialAttributes = attribute.copy();
|
|
6212
|
+
initialAttributes.frame = initialAttributes.frame.copy();
|
|
6213
|
+
initialAttributes.frame.offset(displacement.x, displacement.y);
|
|
6214
|
+
}
|
|
6215
|
+
|
|
6216
|
+
if (dropPreview) {
|
|
6217
|
+
newCell._dropPreview = dropPreview;
|
|
6218
|
+
attribute.initialAttributes = initialAttributes;
|
|
6219
|
+
insertedCells.push(newCell);
|
|
6220
|
+
}
|
|
6221
|
+
else {
|
|
6222
|
+
const initialAttributes = this.layout.initialAttributesForAppearingCellAtIndexPath(attribute.indexPath, {withTargetAttributes: attribute});
|
|
6223
|
+
attribute.initialAttributes = initialAttributes;
|
|
6224
|
+
}
|
|
5467
6225
|
}
|
|
5468
6226
|
else {
|
|
5469
6227
|
var initialAttributes = this.layout.initialAttributesForAppearingCellAtIndexPath(attribute.indexPath, {withTargetAttributes: attribute});
|
|
6228
|
+
attribute.initialAttributes = initialAttributes;
|
|
5470
6229
|
}
|
|
5471
|
-
|
|
5472
|
-
attribute.initialAttributes = initialAttributes;
|
|
5473
|
-
//initialAttributes.indexPath = attribute.indexPath;
|
|
5474
6230
|
}
|
|
5475
6231
|
|
|
5476
6232
|
newCell.attributes = attribute.initialAttributes;
|
|
@@ -5596,7 +6352,14 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
5596
6352
|
animationCells[i].release();
|
|
5597
6353
|
|
|
5598
6354
|
// Additionally, unmanage hidden cells
|
|
5599
|
-
if (animationCells[i].attributes.isHidden)
|
|
6355
|
+
if (animationCells[i].attributes.isHidden) {
|
|
6356
|
+
animationCells[i]._unmanage();
|
|
6357
|
+
}
|
|
6358
|
+
}
|
|
6359
|
+
|
|
6360
|
+
// Remove the hiding class from inserted cells
|
|
6361
|
+
for (const cell of sessionDropCells) {
|
|
6362
|
+
cell.node.classList.remove('BMCollectionViewCellInserting');
|
|
5600
6363
|
}
|
|
5601
6364
|
|
|
5602
6365
|
// Destroy the deleted cells
|
|
@@ -5629,56 +6392,6 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
5629
6392
|
|
|
5630
6393
|
};
|
|
5631
6394
|
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
// Apply the new scroll offset, if it changed
|
|
5635
|
-
/*if (oldBounds.origin.x != self._bounds.origin.x || oldBounds.origin.y != self._bounds.origin.y) {
|
|
5636
|
-
|
|
5637
|
-
if (self.scrollView) {
|
|
5638
|
-
var currentOffset = self.scrollView.offset.copy();
|
|
5639
|
-
var targetOffset = self._bounds.origin.copy();
|
|
5640
|
-
|
|
5641
|
-
targetOffset.x += self._offscreenBufferSize;
|
|
5642
|
-
targetOffset.y += self._offscreenBufferSize;
|
|
5643
|
-
|
|
5644
|
-
animationOptions.progress = function (elements, fraction) {
|
|
5645
|
-
var offsetX = currentOffset.x + fraction * (targetOffset.x - currentOffset.x);
|
|
5646
|
-
var offsetY = currentOffset.y + fraction * (targetOffset.y - currentOffset.y);
|
|
5647
|
-
|
|
5648
|
-
self.scrollView.offset = BMPointMake(offsetX, offsetY);
|
|
5649
|
-
}
|
|
5650
|
-
}
|
|
5651
|
-
else if (self.iScroll) {
|
|
5652
|
-
var currentOffset = scrollOffset;
|
|
5653
|
-
var targetOffset = self._bounds.origin.copy();
|
|
5654
|
-
|
|
5655
|
-
targetOffset.x += self._offscreenBufferSize;
|
|
5656
|
-
targetOffset.y += self._offscreenBufferSize;
|
|
5657
|
-
|
|
5658
|
-
animationOptions.progress = function (elements, fraction) {
|
|
5659
|
-
var offsetX = currentOffset.x + fraction * (targetOffset.x - currentOffset.x);
|
|
5660
|
-
var offsetY = currentOffset.y + fraction * (targetOffset.y - currentOffset.y);
|
|
5661
|
-
|
|
5662
|
-
self.iScroll._translate(-offsetX, -offsetY);
|
|
5663
|
-
}
|
|
5664
|
-
}
|
|
5665
|
-
else {
|
|
5666
|
-
var currentOffset = scrollOffset;
|
|
5667
|
-
var targetOffset = self._bounds.origin.copy();
|
|
5668
|
-
|
|
5669
|
-
targetOffset.x += self._offscreenBufferSize;
|
|
5670
|
-
targetOffset.y += self._offscreenBufferSize;
|
|
5671
|
-
|
|
5672
|
-
animationOptions.progress = function (elements, fraction) {
|
|
5673
|
-
var offsetX = currentOffset.x + fraction * (targetOffset.x - currentOffset.x);
|
|
5674
|
-
var offsetY = currentOffset.y + fraction * (targetOffset.y - currentOffset.y);
|
|
5675
|
-
|
|
5676
|
-
self._container[0].scrollTo(offsetX, offsetY);
|
|
5677
|
-
}
|
|
5678
|
-
}
|
|
5679
|
-
|
|
5680
|
-
}*/
|
|
5681
|
-
|
|
5682
6395
|
// All cells involved in the animation will be retained for the duration of the animation
|
|
5683
6396
|
// And then released at the end
|
|
5684
6397
|
var animationCells = [];
|
|
@@ -5696,26 +6409,65 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
5696
6409
|
}
|
|
5697
6410
|
|
|
5698
6411
|
// Apply the drop shadow animations if needed
|
|
5699
|
-
if (self.
|
|
5700
|
-
|
|
5701
|
-
|
|
5702
|
-
|
|
5703
|
-
|
|
5704
|
-
|
|
5705
|
-
|
|
5706
|
-
|
|
5707
|
-
controller.registerBuiltInProperty('scaleY', {withValue: shadow.transform.size.height});
|
|
5708
|
-
controller.registerBuiltInProperty('rotateZ', {withValue: '0deg'});
|
|
5709
|
-
controller.registerBuiltInProperty('opacity', {withValue: 0});
|
|
6412
|
+
if (self._dropPreviews) {
|
|
6413
|
+
for (const cell of insertedCells) {
|
|
6414
|
+
cell._dropPreview.performDropToNode(cell.node);
|
|
6415
|
+
|
|
6416
|
+
const index = self._dropPreviews.indexOf(cell._dropPreview);
|
|
6417
|
+
|
|
6418
|
+
if (index != -1) {
|
|
6419
|
+
self._dropPreviews.splice(index, 1);
|
|
5710
6420
|
}
|
|
5711
|
-
|
|
5712
|
-
|
|
5713
|
-
|
|
5714
|
-
|
|
5715
|
-
|
|
5716
|
-
|
|
6421
|
+
}
|
|
6422
|
+
|
|
6423
|
+
if (dropMovingCells.length) {
|
|
6424
|
+
// For the items that move, move them instantly to their final positions start the drop
|
|
6425
|
+
// animations, then move them back for the regular animation to play for them
|
|
6426
|
+
BMAnimationContextBeginStatic();
|
|
6427
|
+
const initialAttributeMap = new Map();
|
|
6428
|
+
for (const cell of dropMovingCells) {
|
|
6429
|
+
// Instantly move each cell to its final attributes
|
|
6430
|
+
initialAttributeMap.set(cell, cell.attributes);
|
|
6431
|
+
cell.attributes = cell.targetAttributes;
|
|
5717
6432
|
}
|
|
5718
|
-
|
|
6433
|
+
BMAnimationApply();
|
|
6434
|
+
|
|
6435
|
+
// Play all drop animations
|
|
6436
|
+
for (const cell of dropMovingCells) {
|
|
6437
|
+
cell._dropPreview.performDropToNode(cell.node);
|
|
6438
|
+
const index = self._dropPreviews.indexOf(cell._dropPreview);
|
|
6439
|
+
|
|
6440
|
+
if (index != -1) {
|
|
6441
|
+
self._dropPreviews.splice(index, 1);
|
|
6442
|
+
}
|
|
6443
|
+
}
|
|
6444
|
+
|
|
6445
|
+
// Revert each cell to its staging attributes
|
|
6446
|
+
BMAnimationContextBeginStatic();
|
|
6447
|
+
for (const [cell, attributes] of initialAttributeMap) {
|
|
6448
|
+
cell.attributes = attributes;
|
|
6449
|
+
}
|
|
6450
|
+
BMAnimationApply();
|
|
6451
|
+
}
|
|
6452
|
+
|
|
6453
|
+
// For remaining drop previews, play an animation to the target cell if available
|
|
6454
|
+
if (self._cellItemMap) {
|
|
6455
|
+
for (let i = 0; i < self._dropPreviews.length; i++) {
|
|
6456
|
+
const item = self._dropPreviews[i];
|
|
6457
|
+
const cell = self._cellItemMap.get(item);
|
|
6458
|
+
|
|
6459
|
+
if (cell) {
|
|
6460
|
+
self._dropPreviews.performDropToNode(cell.node);
|
|
6461
|
+
self._dropPreviews.splice(i, 1);
|
|
6462
|
+
i--;
|
|
6463
|
+
}
|
|
6464
|
+
}
|
|
6465
|
+
}
|
|
6466
|
+
|
|
6467
|
+
// Play a generic animation for all remaining drop previews without associated cells
|
|
6468
|
+
for (const preview of self._dropPreviews) {
|
|
6469
|
+
preview.performDrop();
|
|
6470
|
+
}
|
|
5719
6471
|
}
|
|
5720
6472
|
|
|
5721
6473
|
// Apply the new scroll offset, if it changed
|
|
@@ -5766,7 +6518,15 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
5766
6518
|
var cell = newCells[i];
|
|
5767
6519
|
if (!cell.animatable) continue;
|
|
5768
6520
|
|
|
5769
|
-
cell.
|
|
6521
|
+
if (cell._dropPreview) {
|
|
6522
|
+
cell._dropPreview = undefined;
|
|
6523
|
+
cell.node.classList.add('BMCollectionViewCellInserting');
|
|
6524
|
+
sessionDropCells.push(cell);
|
|
6525
|
+
}
|
|
6526
|
+
else {
|
|
6527
|
+
cell.attributes = cell.targetAttributes;
|
|
6528
|
+
}
|
|
6529
|
+
|
|
5770
6530
|
cell.animatable = NO;
|
|
5771
6531
|
|
|
5772
6532
|
animationCells.push(cell.retain());
|
|
@@ -5803,6 +6563,11 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
5803
6563
|
if (BMAnimationContextGetCurrent()) {
|
|
5804
6564
|
animationBlock();
|
|
5805
6565
|
BMAnimationContextAddCompletionHandler(animationOptions.complete);
|
|
6566
|
+
|
|
6567
|
+
// Clear out all target attributes on all cell after the animation starts
|
|
6568
|
+
for (const cell of this.allCells) {
|
|
6569
|
+
cell.targetAttributes = undefined;
|
|
6570
|
+
}
|
|
5806
6571
|
}
|
|
5807
6572
|
else {
|
|
5808
6573
|
BMAnimateWithBlock(animationBlock, animationOptions);
|
|
@@ -5812,7 +6577,7 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
5812
6577
|
this.oldBounds = undefined;
|
|
5813
6578
|
|
|
5814
6579
|
// If no cells should be changed, immediately run the completion handler
|
|
5815
|
-
if (newCells.length == 0 && oldCells.length == 0) {
|
|
6580
|
+
if (newCells.length == 0 && oldCells.length == 0 && !this._dropPreviews) {
|
|
5816
6581
|
animationOptions.complete();
|
|
5817
6582
|
}
|
|
5818
6583
|
|
|
@@ -5997,9 +6762,16 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
5997
6762
|
// Scroll to the offset point
|
|
5998
6763
|
if (options.animated) {
|
|
5999
6764
|
var self = this;
|
|
6000
|
-
|
|
6001
|
-
|
|
6002
|
-
|
|
6765
|
+
const currentContext = BMAnimationContextGetCurrent();
|
|
6766
|
+
if (!currentContext) {
|
|
6767
|
+
BMAnimationBeginWithDuration(300);
|
|
6768
|
+
}
|
|
6769
|
+
|
|
6770
|
+
self.scrollOffset = offset;
|
|
6771
|
+
|
|
6772
|
+
if (!currentContext) {
|
|
6773
|
+
BMAnimationApply();
|
|
6774
|
+
}
|
|
6003
6775
|
}
|
|
6004
6776
|
else {
|
|
6005
6777
|
// Scrolling is performed differently based on whether iScroll is used or not
|
|
@@ -6282,6 +7054,7 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
6282
7054
|
var self = this;
|
|
6283
7055
|
|
|
6284
7056
|
_BMCollectionViews.delete(this);
|
|
7057
|
+
BMDragSession._dropTargets.delete(this);
|
|
6285
7058
|
|
|
6286
7059
|
// Unbind the scroll event listener
|
|
6287
7060
|
if (this.initialized && !this.iScroll) {
|
|
@@ -6419,8 +7192,8 @@ class BMCollectionViewDataSourceAdapter {
|
|
|
6419
7192
|
return this._dataSet.moveItemsFromIndexPaths(indexPaths, args);
|
|
6420
7193
|
}
|
|
6421
7194
|
|
|
6422
|
-
collectionViewRemoveItemsAtIndexPaths(collectionView, indexPaths) {
|
|
6423
|
-
return this._dataSet.removeItemsAtIndexPaths(indexPaths);
|
|
7195
|
+
collectionViewRemoveItemsAtIndexPaths(collectionView, indexPaths, args) {
|
|
7196
|
+
return this._dataSet.removeItemsAtIndexPaths(indexPaths, args);
|
|
6424
7197
|
}
|
|
6425
7198
|
|
|
6426
7199
|
collectionViewInsertItems(collectionView, items, args) {
|
|
@@ -6436,6 +7209,18 @@ class BMCollectionViewDataSourceAdapter {
|
|
|
6436
7209
|
};
|
|
6437
7210
|
}
|
|
6438
7211
|
|
|
7212
|
+
if (dataSet.dragItemForIndexPath) {
|
|
7213
|
+
adapter.collectionViewDragItemForIndexPath = function (collectionView, indexPath, args) {
|
|
7214
|
+
return dataSet.dragItemForIndexPath(indexPath, args);
|
|
7215
|
+
};
|
|
7216
|
+
}
|
|
7217
|
+
|
|
7218
|
+
if (dataSet.indexPathForDragItem) {
|
|
7219
|
+
adapter.collectionViewIndexPathForDragItem = function (collectionView, item, args) {
|
|
7220
|
+
return dataSet.indexPathForDragItem(item, args);
|
|
7221
|
+
};
|
|
7222
|
+
}
|
|
7223
|
+
|
|
6439
7224
|
return adapter;
|
|
6440
7225
|
}
|
|
6441
7226
|
}
|
|
@@ -6472,30 +7257,14 @@ class BMCollectionViewDataSetAdapter {
|
|
|
6472
7257
|
return this._dataSource.collectionViewIndexPathForObject(this._collectionView, object);
|
|
6473
7258
|
}
|
|
6474
7259
|
|
|
6475
|
-
contentsForCellWithReuseIdentifier(identifier) {
|
|
6476
|
-
throw new Error(`contentsForCellWithReuseIdentifier is unsupported when using data source objects`);
|
|
6477
|
-
}
|
|
6478
|
-
|
|
6479
7260
|
cellForItemAtIndexPath(indexPath) {
|
|
6480
7261
|
return this._dataSource.collectionViewCellForItemAtIndexPath(this._collectionView, indexPath);
|
|
6481
7262
|
}
|
|
6482
7263
|
|
|
6483
|
-
contentsForSupplementaryViewWithIdentifier(identifier) {
|
|
6484
|
-
throw new Error(`contentsForSupplementaryViewWithIdentifier is unsupported when using data source objects`);
|
|
6485
|
-
}
|
|
6486
|
-
|
|
6487
7264
|
cellForSupplementaryViewWithIdentifier(identifier, args) {
|
|
6488
7265
|
return this._dataSource.collectionViewCellForSupplementaryViewWithIdentifier(this._collectionView, identifier, args);
|
|
6489
7266
|
}
|
|
6490
7267
|
|
|
6491
|
-
updateCell(cell, {atIndexPath: indexPath}) {
|
|
6492
|
-
throw new Error(`updateCell is unsupported when using data source objects`);
|
|
6493
|
-
}
|
|
6494
|
-
|
|
6495
|
-
updateSupplementaryView(view, {withIdentifier: identifier, atIndexPath: indexPath}) {
|
|
6496
|
-
throw new Error(`updateSupplementaryView is unsupported when using data source objects`);
|
|
6497
|
-
}
|
|
6498
|
-
|
|
6499
7268
|
useOldData(use) {
|
|
6500
7269
|
return this._dataSource.collectionViewUseOldData(this._collectionView, use);
|
|
6501
7270
|
}
|
|
@@ -6512,8 +7281,8 @@ class BMCollectionViewDataSetAdapter {
|
|
|
6512
7281
|
return this._dataSource.collectionViewMoveItemsFromIndexPaths(this._collectionView, indexPaths, args);
|
|
6513
7282
|
}
|
|
6514
7283
|
|
|
6515
|
-
removeItemsAtIndexPaths(indexPaths) {
|
|
6516
|
-
return this._dataSource.collectionViewRemoveItemsAtIndexPaths(this._collectionView, indexPaths);
|
|
7284
|
+
removeItemsAtIndexPaths(indexPaths, args) {
|
|
7285
|
+
return this._dataSource.collectionViewRemoveItemsAtIndexPaths(this._collectionView, indexPaths, args);
|
|
6517
7286
|
}
|
|
6518
7287
|
|
|
6519
7288
|
insertItems(items, args) {
|
|
@@ -6529,6 +7298,18 @@ class BMCollectionViewDataSetAdapter {
|
|
|
6529
7298
|
};
|
|
6530
7299
|
}
|
|
6531
7300
|
|
|
7301
|
+
if (dataSource.collectionViewDragItemForIndexPath) {
|
|
7302
|
+
adapter.dragItemForIndexPath = function (indexPath, args) {
|
|
7303
|
+
return dataSource.collectionViewDragItemForIndexPath(adapter._collectionView, indexPath, args);
|
|
7304
|
+
};
|
|
7305
|
+
}
|
|
7306
|
+
|
|
7307
|
+
if (dataSource.collectionViewIndexPathForDragItem) {
|
|
7308
|
+
adapter.indexPathForDragItem = function (item, args) {
|
|
7309
|
+
return dataSource.collectionViewIndexPathForDragItem(adapter._collectionView, item, args);
|
|
7310
|
+
};
|
|
7311
|
+
}
|
|
7312
|
+
|
|
6532
7313
|
return adapter;
|
|
6533
7314
|
}
|
|
6534
7315
|
}
|