bm-core-ui 2.7.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.
- package/CHANGELOG.md +1624 -0
- package/LICENSE +21 -0
- package/README.md +145 -0
- package/build/@types/index.d.ts +14078 -0
- package/build/BMCodeEditor/BMCodeEditor.js +707 -0
- package/build/BMCollectionView/BMCollectionView.js +5861 -0
- package/build/BMCollectionView/BMCollectionViewCell.js +688 -0
- package/build/BMCollectionView/BMCollectionViewFlowLayout.js +4467 -0
- package/build/BMCollectionView/BMCollectionViewLayout.js +830 -0
- package/build/BMCollectionView/BMCollectionViewLayoutAttributes.js +673 -0
- package/build/BMCollectionView/BMCollectionViewMasonryLayout.js +491 -0
- package/build/BMCollectionView/BMCollectionViewStackLayout.js +634 -0
- package/build/BMCollectionView/BMCollectionViewTileLayout.js +1121 -0
- package/build/BMCoreUI.css +2833 -0
- package/build/BMView/BMAttributedLabelView.js +310 -0
- package/build/BMView/BMLayoutConstraint_v2.5.js +1813 -0
- package/build/BMView/BMLayoutGuide.js +192 -0
- package/build/BMView/BMLayoutSizeClass.js +466 -0
- package/build/BMView/BMMenu.js +574 -0
- package/build/BMView/BMScrollView.js +247 -0
- package/build/BMView/BMTextField.js +512 -0
- package/build/BMView/BMTextFieldDelegate.js +71 -0
- package/build/BMView/BMView_v2.5.js +3572 -0
- package/build/BMView/BMViewport.js +221 -0
- package/build/BMViewLayoutEditor/BMLayoutEditor.js +6117 -0
- package/build/BMViewLayoutEditor/BMLayoutEditorConstraintSettings.js +417 -0
- package/build/BMViewLayoutEditor/BMLayoutEditorDelegate.js +59 -0
- package/build/BMViewLayoutEditor/BMLayoutEditorSettingCells.js +1653 -0
- package/build/BMViewLayoutEditor/BMLayoutEditorSettings.js +1480 -0
- package/build/BMViewLayoutEditor/BMLayoutEditorSettingsComplexCells.js +431 -0
- package/build/BMViewLayoutEditor/BMLayoutEditorSettingsDelegate.js +46 -0
- package/build/BMViewLayoutEditor/BMLayoutEditorVariablesController.js +460 -0
- package/build/BMViewLayoutEditor/BMLayoutEditorViewGroupSettings.js +293 -0
- package/build/BMViewLayoutEditor/BMLayoutEditorViewSettings.js +382 -0
- package/build/BMViewLayoutEditor/BMLayoutVariableProvider.js +202 -0
- package/build/BMWindow/BMConfirmationPopup.js +477 -0
- package/build/BMWindow/BMKeyboardShortcut.js +151 -0
- package/build/BMWindow/BMPopover/BMPopover.js +492 -0
- package/build/BMWindow/BMToolWindow.js +71 -0
- package/build/BMWindow/BMWindow.js +2000 -0
- package/build/Core/BMAnimationContext.js +1181 -0
- package/build/Core/BMColor.js +991 -0
- package/build/Core/BMCoreUI.js +470 -0
- package/build/Core/BMFunctionCollection.js +110 -0
- package/build/Core/BMIndexPath.js +165 -0
- package/build/Core/BMInset.js +138 -0
- package/build/Core/BMKeyPath.js +100 -0
- package/build/Core/BMPoint.js +291 -0
- package/build/Core/BMRect.js +556 -0
- package/build/Core/BMSize.js +137 -0
- package/build/iScroll/LICENSE +22 -0
- package/build/iScroll/iscroll-probe.js +2154 -0
- 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 +40 -0
- package/lib/@types/BMCoreUI.min.d.ts +14078 -0
- package/lib/BMCoreUI.min.js +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1,1121 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import {YES, NO, BMExtend, BMCopyProperties} from '../Core/BMCoreUI'
|
|
4
|
+
import {BMInsetMake, BMInset} from '../Core/BMInset'
|
|
5
|
+
import {BMPointMakeWithX} from '../Core/BMPoint'
|
|
6
|
+
import {BMSizeMake} from '../Core/BMSize'
|
|
7
|
+
import {BMRectMake, BMRectMakeWithX, BMRectMakeWithOrigin} from '../Core/BMRect'
|
|
8
|
+
import {BMIndexPathMakeWithIndexes} from '../Core/BMIndexPath'
|
|
9
|
+
import {BMCollectionViewLayoutAttributesMakeForCellAtIndexPath, BMCollectionViewLayoutAttributesMakeForSupplementaryViewWithIdentifier} from './BMCollectionViewLayoutAttributes'
|
|
10
|
+
import {BMCollectionViewFlowLayoutSupplementaryView, BMCollectionViewTableLayoutSupplementaryView} from './BMCollectionViewFlowLayout'
|
|
11
|
+
import {BMCollectionViewLayout} from './BMCollectionViewLayout'
|
|
12
|
+
|
|
13
|
+
// @type BMCollectionViewTileLayoutOrientation
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* An enum containing the possible orientations that the tile layout can use.
|
|
17
|
+
*/
|
|
18
|
+
export var BMCollectionViewTileLayoutOrientation = Object.freeze({
|
|
19
|
+
/**
|
|
20
|
+
* Indicates that the tile layout will arrange cells primarily along the horizontal axis.
|
|
21
|
+
* When the orientation is set to this value the tile layout will scroll horizontally and cells
|
|
22
|
+
* will be primarily placed into the leftmost available positions.
|
|
23
|
+
*/
|
|
24
|
+
Horizontal: {},
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Indicates that the tile layout will arrange cells primarily along the vertical axis.
|
|
28
|
+
* When the orientation is set to this value the tile layout will scroll vertically and cells
|
|
29
|
+
* will be primarily placed into the topmost available positions.
|
|
30
|
+
*/
|
|
31
|
+
Vertical: {}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// @endtype
|
|
35
|
+
|
|
36
|
+
// @type BMCollectionViewTileLayout extends BMCollectionViewLayout
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* TBD.
|
|
40
|
+
*
|
|
41
|
+
* Collection views using the tile layout must have a delegate object that conforms to the <code>BMCollectionViewDelegateTileLayout</code> protocol.
|
|
42
|
+
*/
|
|
43
|
+
export function BMCollectionViewTileLayout() {}; // <constructor>
|
|
44
|
+
|
|
45
|
+
BMCollectionViewTileLayout.prototype = BMExtend({}, BMCollectionViewLayout.prototype, {
|
|
46
|
+
|
|
47
|
+
// @override - BMCollectionViewLayout
|
|
48
|
+
get supportsCopying() {
|
|
49
|
+
return YES;
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* An optional number which represents the grid size to which all sizes will be constrained.
|
|
54
|
+
* If this property is set to a positive number, all size dimensions will be constrained to the closest number
|
|
55
|
+
* that is a multiple of this property.
|
|
56
|
+
*/
|
|
57
|
+
_gridSize: 0, // <Number>
|
|
58
|
+
get gridSize() {
|
|
59
|
+
return this._gridSize;
|
|
60
|
+
},
|
|
61
|
+
set gridSize(gridSize) {
|
|
62
|
+
this._gridSize = gridSize || 0;
|
|
63
|
+
this.invalidateLayout();
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* When set to a positive number, this represents the spacing to use between cells.
|
|
68
|
+
*/
|
|
69
|
+
_spacing: 0, // <Number>
|
|
70
|
+
get spacing() {
|
|
71
|
+
return this._spacing;
|
|
72
|
+
},
|
|
73
|
+
set spacing(spacing) {
|
|
74
|
+
this._spacing = spacing || 0;
|
|
75
|
+
this.invalidateLayout();
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Determines whether or not the tile layout should generate header supplementary views or not.
|
|
80
|
+
*/
|
|
81
|
+
_showsHeaders: NO, // <Boolean>
|
|
82
|
+
|
|
83
|
+
get showsHeaders() { return this._showsHeaders; },
|
|
84
|
+
set showsHeaders(showsHeaders) {
|
|
85
|
+
this._showsHeaders = showsHeaders;
|
|
86
|
+
this.invalidateLayout();
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* The height to use for headers. Does not have any effect if showsHeaders is set to NO.
|
|
91
|
+
* This attribute is always 0 if showsHeader is set to NO.
|
|
92
|
+
*/
|
|
93
|
+
_headerHeight: 22, // <Number>
|
|
94
|
+
|
|
95
|
+
get headerHeight() {
|
|
96
|
+
return this._showsHeaders ? this._headerHeight : 0;
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
set headerHeight(headerHeight) {
|
|
100
|
+
this._headerHeight = headerHeight;
|
|
101
|
+
if (this._showsHeader) this.invalidateLayout();
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Determines whether or not the tile layout should generate footer supplementary views or not.
|
|
106
|
+
*/
|
|
107
|
+
_showsFooters: NO, // <Boolean>
|
|
108
|
+
|
|
109
|
+
get showsFooters() { return this._showsFooters; },
|
|
110
|
+
set showsFooters(showsFooters) {
|
|
111
|
+
this._showsFooters = showsFooters;
|
|
112
|
+
this.invalidateLayout();
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* The height to use for footers. Does not have any effect if showsFooters is set to NO.
|
|
117
|
+
* This attribute is always 0 if showsFooters is set to NO.
|
|
118
|
+
*/
|
|
119
|
+
_footerHeight: 22, // <Number>
|
|
120
|
+
|
|
121
|
+
get footerHeight() {
|
|
122
|
+
return this._showsFooters? this._footerHeight : 0;
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
set footerHeight(footerHeight) {
|
|
126
|
+
this._footerHeight = footerHeight;
|
|
127
|
+
if (this._showsFooters) this.invalidateLayout();
|
|
128
|
+
},
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* The insets to apply to each section which control their distance from the collection view edges and from other sections.
|
|
132
|
+
*/
|
|
133
|
+
_sectionInsets: BMInsetMake(), // <BMInset, nullResettable>
|
|
134
|
+
|
|
135
|
+
get sectionInsets() { return this._sectionInsets; },
|
|
136
|
+
set sectionInsets(insets) {
|
|
137
|
+
this._sectionInsets = insets || BMInsetMake();
|
|
138
|
+
this.invalidateLayout();
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* The padding from the top edge to the first item.
|
|
143
|
+
*/
|
|
144
|
+
_topPadding: 0, // <Number>
|
|
145
|
+
get topPadding() { return this._topPadding; },
|
|
146
|
+
set topPadding(padding) {
|
|
147
|
+
this._topPadding = padding;
|
|
148
|
+
|
|
149
|
+
this.invalidateLayout();
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* The padding from the bottom edge to the last item.
|
|
154
|
+
*/
|
|
155
|
+
_bottomPadding: 0, // <Number>
|
|
156
|
+
get bottomPadding() { return this._bottomPadding; },
|
|
157
|
+
set bottomPadding(padding) {
|
|
158
|
+
this._bottomPadding = padding;
|
|
159
|
+
|
|
160
|
+
this.invalidateLayout();
|
|
161
|
+
},
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* When set to YES, the tile layout will stick the header supplementary views to the top edge of the collection view while scrolling.
|
|
165
|
+
* Otherwise, the header supplementary views will scroll with the rest of the content.
|
|
166
|
+
*/
|
|
167
|
+
_pinsHeadersToContentEdge: NO, // <Boolean>
|
|
168
|
+
|
|
169
|
+
get pinsHeadersToContentEdge() { return this._pinsHeadersToContentEdge; },
|
|
170
|
+
set pinsHeadersToContentEdge(pins) {
|
|
171
|
+
this._pinsHeadersToContentEdge = pins;
|
|
172
|
+
this.invalidateLayout();
|
|
173
|
+
},
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* When set to YES, the tile layout will stick the footer supplementary views to the bottom edge of the collection view while scrolling.
|
|
177
|
+
* Otherwise, the footer supplementary views will scroll with the rest of the content.
|
|
178
|
+
*/
|
|
179
|
+
_pinsFootersToContentEdge: NO, // <Boolean>
|
|
180
|
+
|
|
181
|
+
get pinsFootersToContentEdge() { return this._pinsFootersToContentEdge; },
|
|
182
|
+
set pinsFootersToContentEdge(pins) {
|
|
183
|
+
this._pinsFootersToContentEdge = pins;
|
|
184
|
+
this.invalidateLayout();
|
|
185
|
+
},
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* The tile layout's orientation.
|
|
189
|
+
* For more information about the possible values, refer to the
|
|
190
|
+
* documentation for the <code>BMCollectionViewTileLayoutOrientation</code> enum.
|
|
191
|
+
*/
|
|
192
|
+
_orientation: BMCollectionViewTileLayoutOrientation.Vertical, // <BMCollectionViewTileLayoutOrientation>
|
|
193
|
+
get orientation() { return this._orientation; },
|
|
194
|
+
set orientation(orientation) {
|
|
195
|
+
this._orientation = orientation;
|
|
196
|
+
this.invalidateLayout();
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
// @override - BMCollectionViewLayout
|
|
200
|
+
copy() {
|
|
201
|
+
let copy = new BMCollectionViewTileLayout();
|
|
202
|
+
|
|
203
|
+
copy._gridSize = this._gridSize;
|
|
204
|
+
copy._spacing = this._spacing;
|
|
205
|
+
copy._showsHeaders = this._showsHeaders;
|
|
206
|
+
copy._headerHeight = this._headerHeight;
|
|
207
|
+
copy._showsFooters = this._showsFooters;
|
|
208
|
+
copy._footerHeight = this._footerHeight;
|
|
209
|
+
copy._sectionInsets = this._sectionInsets.copy();
|
|
210
|
+
copy._topPadding = this._topPadding;
|
|
211
|
+
copy._bottomPadding = this._bottomPadding;
|
|
212
|
+
copy._pinsFootersToContentEdge = this._pinsFootersToContentEdge;
|
|
213
|
+
copy._pinsHeadersToContentEdge = this._pinsHeadersToContentEdge;
|
|
214
|
+
copy._orientation = this._orientation;
|
|
215
|
+
|
|
216
|
+
return copy;
|
|
217
|
+
},
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Set to YES while the collection view is performing a layout invalidation
|
|
221
|
+
* in response to a bounds change.
|
|
222
|
+
*/
|
|
223
|
+
_isChangingBounds: NO, // <Boolean>
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Returns a size that represents the given size, constrained to this layout's grid size and maximum available space.
|
|
227
|
+
* This does not modify the original size.
|
|
228
|
+
* @param size <BMSize> A size.
|
|
229
|
+
* @return <BMSize> The constrained size.
|
|
230
|
+
*/
|
|
231
|
+
constrainedSizeWithSize: function (size) {
|
|
232
|
+
return BMSizeMake(
|
|
233
|
+
Math.min(this.constrainedValueWithValue(size.width), this.collectionView.frame.size.width - this._sectionInsets.left - this._sectionInsets.right),
|
|
234
|
+
this.constrainedValueWithValue(size.height)
|
|
235
|
+
);
|
|
236
|
+
},
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Returns a value that represents the multiple of this layout's grid size that is closest to the given value.
|
|
240
|
+
* @param value <Number> A value.
|
|
241
|
+
* @return <Number> The constrained value.
|
|
242
|
+
*/
|
|
243
|
+
constrainedValueWithValue: function (value) {
|
|
244
|
+
if (this._gridSize > 1) {
|
|
245
|
+
var gridSize = this._gridSize;
|
|
246
|
+
var spacing = this._spacing;
|
|
247
|
+
var multiple = (value / (gridSize + spacing)) | 0;
|
|
248
|
+
if (multiple == 0) multiple = 1;
|
|
249
|
+
var constrainedValue = multiple * gridSize + (multiple - 1) * spacing;
|
|
250
|
+
if (value - constrainedValue > constrainedValue + gridSize + spacing - value) {
|
|
251
|
+
return constrainedValue + gridSize + spacing;
|
|
252
|
+
}
|
|
253
|
+
return constrainedValue;
|
|
254
|
+
}
|
|
255
|
+
return value;
|
|
256
|
+
},
|
|
257
|
+
|
|
258
|
+
// @override
|
|
259
|
+
collectionViewWillStartUpdates: function (updates) {
|
|
260
|
+
this.previousLayoutCache = this.layoutCache;
|
|
261
|
+
this.prepareLayout();
|
|
262
|
+
},
|
|
263
|
+
|
|
264
|
+
// @override
|
|
265
|
+
collectionViewDidStartUpdates: function (updates) {
|
|
266
|
+
this.previousLayoutCache = undefined;
|
|
267
|
+
},
|
|
268
|
+
|
|
269
|
+
// @override - BMCollectionViewLayout
|
|
270
|
+
prepareLayout: function () {
|
|
271
|
+
return this._prepareLayoutWithScrollbarOffset(NO);
|
|
272
|
+
},
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Prepares the layout, optionally taking the scrollbar size into account.
|
|
276
|
+
*/
|
|
277
|
+
_prepareLayoutWithScrollbarOffset: function (useOffset) {
|
|
278
|
+
|
|
279
|
+
if (this._isChangingBounds) {
|
|
280
|
+
// If the layout is invalidated because of scrolling, it is not required to recalculate the caches, so this request should be ignored.
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
var availableWidth = this.collectionView.frame.size.width - this._sectionInsets.left - this._sectionInsets.right;
|
|
285
|
+
|
|
286
|
+
// TODO: headers, footers
|
|
287
|
+
var layoutCache = {};
|
|
288
|
+
var sectionCount = this.collectionView.numberOfSections();
|
|
289
|
+
|
|
290
|
+
this.layoutCache = layoutCache;
|
|
291
|
+
|
|
292
|
+
layoutCache.sections = new Array(sectionCount);
|
|
293
|
+
layoutCache.size = BMSizeMake(this.collectionView.frame.size.width, 0);
|
|
294
|
+
|
|
295
|
+
var top = this._topPadding;
|
|
296
|
+
|
|
297
|
+
for (var i = 0; i < sectionCount; i++) {
|
|
298
|
+
var sectionCache = {attributes: []};
|
|
299
|
+
layoutCache.sections[i] = sectionCache;
|
|
300
|
+
|
|
301
|
+
top += this._sectionInsets.top;
|
|
302
|
+
|
|
303
|
+
sectionCache.outerFrame = BMRectMake(this._sectionInsets.left, top, availableWidth, 0);
|
|
304
|
+
|
|
305
|
+
if (this._showsHeaders) {
|
|
306
|
+
sectionCache.outerFrame.size.height += this._headerHeight + this._spacing;
|
|
307
|
+
top += this._headerHeight + this._spacing;
|
|
308
|
+
var headerAttributes = BMCollectionViewLayoutAttributesMakeForSupplementaryViewWithIdentifier(BMCollectionViewFlowLayoutSupplementaryView.Header, {atIndexPath: BMIndexPathMakeWithIndexes([i])});
|
|
309
|
+
headerAttributes.frame = sectionCache.outerFrame.copy();
|
|
310
|
+
headerAttributes.frame.size.height = this._headerHeight;
|
|
311
|
+
sectionCache.headerAttributes = headerAttributes;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
sectionCache.frame = BMRectMake(this._sectionInsets.left, top, availableWidth, 0);
|
|
315
|
+
|
|
316
|
+
this._prepareLayoutForSection(i, {intoCache: sectionCache});
|
|
317
|
+
sectionCache.outerFrame.size.height += sectionCache.frame.size.height;
|
|
318
|
+
top = sectionCache.outerFrame.bottom;
|
|
319
|
+
|
|
320
|
+
if (this._showsFooters) {
|
|
321
|
+
var footerAttributes = BMCollectionViewLayoutAttributesMakeForSupplementaryViewWithIdentifier(BMCollectionViewFlowLayoutSupplementaryView.Footer, {atIndexPath: BMIndexPathMakeWithIndexes([i])});
|
|
322
|
+
footerAttributes.frame = sectionCache.outerFrame.copy();
|
|
323
|
+
footerAttributes.frame.size.height = this._footerHeight;
|
|
324
|
+
footerAttributes.frame.origin.y = top + this._spacing;
|
|
325
|
+
|
|
326
|
+
sectionCache.footerAttributes = footerAttributes;
|
|
327
|
+
|
|
328
|
+
sectionCache.outerFrame.size.height += this._footerHeight + this._spacing;
|
|
329
|
+
top += this._footerHeight + this._spacing;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
sectionCache.outerFrame.size.height += this._sectionInsets.bottom;
|
|
333
|
+
|
|
334
|
+
top = sectionCache.outerFrame.bottom;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
layoutCache.size.height = top + this._bottomPadding;
|
|
338
|
+
|
|
339
|
+
},
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Prepares the layout for a single section, optionally taking the scrollbar size into account.
|
|
343
|
+
* @param section <Number> The index of the section for which to prepare the layout.
|
|
344
|
+
* {
|
|
345
|
+
* @param intoCache <Object> The layout cache into which the layout will be prepared.
|
|
346
|
+
* }
|
|
347
|
+
*/
|
|
348
|
+
_prepareLayoutForSection: function (section, args) {
|
|
349
|
+
var count = this.collectionView.numberOfObjectsInSectionAtIndex(section);
|
|
350
|
+
var cache = args.intoCache;
|
|
351
|
+
|
|
352
|
+
// Represents the bottommost extent of this section's content
|
|
353
|
+
var bottom = cache.frame.origin.y;
|
|
354
|
+
// Represents the rightmost extent of this section's content
|
|
355
|
+
var right = cache.frame.origin.x;
|
|
356
|
+
|
|
357
|
+
// The extents are the zones in which content may be placed
|
|
358
|
+
// The extents start out with a single rect encompassing the entire available collection view area
|
|
359
|
+
// This rect then gets split up into several rects as content is added into the collection view.
|
|
360
|
+
var extents = [BMRectMakeWithX(cache.frame.origin.x, {y: cache.frame.origin.y, width: cache.frame.size.width, height: Number.MAX_SAFE_INTEGER})];
|
|
361
|
+
|
|
362
|
+
for (var i = 0; i < count; i++) {
|
|
363
|
+
if (this.DEBUG) debugger;
|
|
364
|
+
var indexPath = this.collectionView.indexPathForObjectAtRow(i, {inSectionAtIndex: section});
|
|
365
|
+
var size = this.collectionView.delegate.collectionViewSizeForCellAtIndexPath(this.collectionView, indexPath);
|
|
366
|
+
size = this.constrainedSizeWithSize(size);
|
|
367
|
+
|
|
368
|
+
// After obtaining the size for each element, enumerate the available extents, selecting the topmost one
|
|
369
|
+
// If there are several extents with the same y origin, the leftmost one will be used
|
|
370
|
+
var topLeftMostExtent = undefined;
|
|
371
|
+
|
|
372
|
+
for (var j = 0; j < extents.length; j++) {
|
|
373
|
+
var extent = extents[j];
|
|
374
|
+
|
|
375
|
+
// Exclude extents that cannot accomodate the size of this cell
|
|
376
|
+
// NOTE: because the extents have 'infinite' height/width and the sizes are always constrained
|
|
377
|
+
// there will always be at least one extent that will fit this size
|
|
378
|
+
if (extent.size.width < size.width || extent.size.height < size.height) {
|
|
379
|
+
continue;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// Because the extents are always sorted so that the top-leftmost ones are the first,
|
|
383
|
+
// finding the first extent is sufficient and the iteration can stop
|
|
384
|
+
if (!topLeftMostExtent) {
|
|
385
|
+
topLeftMostExtent = extent;
|
|
386
|
+
break;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// Once the extent has been found, create the attributes and slice up the extents intersecting the newly created frame
|
|
391
|
+
var frame = BMRectMakeWithOrigin(BMPointMakeWithX(topLeftMostExtent.origin.x, {y: topLeftMostExtent.origin.y}), {size: size});
|
|
392
|
+
|
|
393
|
+
var attributes = BMCollectionViewLayoutAttributesMakeForCellAtIndexPath(indexPath);
|
|
394
|
+
attributes.frame = frame;
|
|
395
|
+
|
|
396
|
+
cache.attributes.push(attributes);
|
|
397
|
+
|
|
398
|
+
if (this.DEBUG) {
|
|
399
|
+
var aDiv = document.createElement('div');
|
|
400
|
+
BMCopyProperties(aDiv.style, {position: 'absolute', boxSizing: 'border-box',
|
|
401
|
+
top: frame.origin.y + 'px',
|
|
402
|
+
left: frame.origin.x + 'px',
|
|
403
|
+
width: frame.size.width + 'px',
|
|
404
|
+
height: frame.size.height + 'px',
|
|
405
|
+
boxShadow: '0px 0px 1px 1px blue'
|
|
406
|
+
});
|
|
407
|
+
((this.collectionView._contentWrapper && this.collectionView._contentWrapper[0]) || this.collectionView._container[0]).appendChild(aDiv);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// Adjust the section extents as needed
|
|
411
|
+
if (bottom < frame.bottom) bottom = frame.bottom;
|
|
412
|
+
if (right < frame.right) right = frame.right;
|
|
413
|
+
|
|
414
|
+
if (this.DEBUG) debugger;
|
|
415
|
+
|
|
416
|
+
// The trimming frame is the cell's frame, expanded in all dimensions by the spacing.
|
|
417
|
+
// This rect is then used to trim all available extents
|
|
418
|
+
var trimmingFrame = frame.rectWithInset(BMInset.insetWithEqualInsets(-this._spacing));
|
|
419
|
+
|
|
420
|
+
// Slice up the extents that intersect this frame
|
|
421
|
+
for (var j = 0; j < extents.length; j++) {
|
|
422
|
+
var extent = extents[j];
|
|
423
|
+
|
|
424
|
+
// For frames that are identical to their extents, or extents that are fully contained within the rect, remove the extents entirely
|
|
425
|
+
if (extent.isEqualToRect(trimmingFrame) || trimmingFrame.containsRect(extent)) {
|
|
426
|
+
extents.splice(j, 1);
|
|
427
|
+
if (extent.div) extent.div.remove();
|
|
428
|
+
j--;
|
|
429
|
+
continue;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// For all others, slice the extents up
|
|
433
|
+
if (trimmingFrame.intersectsContentOfRect(extent)) {
|
|
434
|
+
var extentSlices = this.rectsWithDifferenceOfExtent(extent, {fromRect: trimmingFrame, spacing: this._spacing});
|
|
435
|
+
|
|
436
|
+
// Remove the extent that was just sliced up
|
|
437
|
+
extents.splice(j, 1);
|
|
438
|
+
// In debugging-mode also remove the slice's outline
|
|
439
|
+
if (extent.div) extent.div.remove();
|
|
440
|
+
|
|
441
|
+
var currentExtentSliceIndex = 0;
|
|
442
|
+
var currentExtentSlice = extentSlices[0];
|
|
443
|
+
// Remove duplicate extents to prevent an exponentially growing list of possible extents
|
|
444
|
+
// and add the extent slices to the appropriate positions
|
|
445
|
+
if (currentExtentSlice) for (var k = j; k < extents.length; k++) {
|
|
446
|
+
var currentExtent = extents[k];
|
|
447
|
+
|
|
448
|
+
// Remove the slice if it is a duplicate of an already existing slice
|
|
449
|
+
if (currentExtent.isEqualToRect(currentExtentSlice)) {
|
|
450
|
+
currentExtentSliceIndex++;
|
|
451
|
+
currentExtentSlice.isInvalid = YES;
|
|
452
|
+
currentExtentSlice = extentSlices[currentExtentSliceIndex];
|
|
453
|
+
if (!currentExtentSlice) break;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// When the current extent in the iteration is in a lower position than the
|
|
457
|
+
// current sliced extent, insert the sliced extent in the place of the current iteration extent
|
|
458
|
+
if (currentExtent.origin.y > currentExtentSlice.origin.y) {
|
|
459
|
+
extents.splice(k, 0, currentExtentSlice);
|
|
460
|
+
k++;
|
|
461
|
+
|
|
462
|
+
currentExtentSliceIndex++;
|
|
463
|
+
currentExtentSlice = extentSlices[currentExtentSliceIndex];
|
|
464
|
+
if (!currentExtentSlice) break;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// If the current iteration extent is in the same top position as the current sliced extent
|
|
468
|
+
// but its horizontal position is more towards the right than the sliced extent, insert the
|
|
469
|
+
// sliced extent in place of the current iteration extent
|
|
470
|
+
if (currentExtent.origin.y == currentExtentSlice.origin.y && currentExtent.origin.x > currentExtentSlice.origin.x) {
|
|
471
|
+
extents.splice(k, 0, currentExtentSlice);
|
|
472
|
+
k++;
|
|
473
|
+
|
|
474
|
+
currentExtentSliceIndex++;
|
|
475
|
+
currentExtentSlice = extentSlices[currentExtentSliceIndex];
|
|
476
|
+
if (!currentExtentSlice) break;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// Add the remaining extents to the end of the extents array, if there are still any extent slices after the iteration,
|
|
481
|
+
// then they are lower and more to the right than any of the other extents
|
|
482
|
+
if (currentExtentSlice) {
|
|
483
|
+
for (; currentExtentSliceIndex < extentSlices.length; currentExtentSliceIndex++) {
|
|
484
|
+
extents.push(extentSlices[currentExtentSliceIndex]);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// Restart the iteration from the beginning
|
|
489
|
+
j = -1;
|
|
490
|
+
|
|
491
|
+
if (this.DEBUG) for (var k = 0; k < extentSlices.length; k++) {
|
|
492
|
+
var div = document.createElement('div');
|
|
493
|
+
var dExtent = extentSlices[k];
|
|
494
|
+
if (dExtent.isInvalid) continue;
|
|
495
|
+
BMCopyProperties(div.style, {position: 'absolute', boxSizing: 'border-box',
|
|
496
|
+
top: dExtent.origin.y + 'px',
|
|
497
|
+
left: dExtent.origin.x + 'px',
|
|
498
|
+
width: dExtent.size.width + 'px',
|
|
499
|
+
height: dExtent.size.height + 'px',
|
|
500
|
+
boxShadow: '0px 0px 1px 1px red'
|
|
501
|
+
});
|
|
502
|
+
dExtent.div = div;
|
|
503
|
+
|
|
504
|
+
((this.collectionView._contentWrapper && this.collectionView._contentWrapper[0]) || this.collectionView._container[0]).appendChild(div);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
bottom += this._spacing + this._sectionInsets.bottom;
|
|
512
|
+
|
|
513
|
+
var offset = (cache.frame.right - right) / 2 | 0;
|
|
514
|
+
if (offset) {
|
|
515
|
+
cache.attributes = cache.attributes.map(function (attribute) { attribute.frame.origin.x += offset; return attribute });
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// Update the section's frame according to the extents
|
|
519
|
+
cache.frame.size.width = right - cache.frame.origin.x;
|
|
520
|
+
cache.frame.size.height = bottom - cache.frame.origin.y;
|
|
521
|
+
|
|
522
|
+
},
|
|
523
|
+
|
|
524
|
+
// @override - BMCollectionViewLayout
|
|
525
|
+
attributesForElementsInRect: function (rect) {
|
|
526
|
+
|
|
527
|
+
// When there are no sections in the collection view, this method will always return a single instance of attributes
|
|
528
|
+
// for the empty supplementary view
|
|
529
|
+
if (this.collectionView.numberOfSections() == 0) {
|
|
530
|
+
var attribute = BMCollectionViewLayoutAttributesMakeForSupplementaryViewWithIdentifier(
|
|
531
|
+
BMCollectionViewTableLayoutSupplementaryView.Empty,
|
|
532
|
+
{atIndexPath: BMIndexPathMakeWithIndexes([0])}
|
|
533
|
+
);
|
|
534
|
+
|
|
535
|
+
attribute.frame = BMRectMake(0, 0, this.collectionView.frame.size.width, this.collectionView.frame.size.height);
|
|
536
|
+
return [attribute];
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
var sectionCount = this.layoutCache.sections.length;
|
|
541
|
+
|
|
542
|
+
var attributes = [];
|
|
543
|
+
|
|
544
|
+
// foundSections is set to NO until the first section whose outer frame intersects the visible rect is found
|
|
545
|
+
var foundSections = NO;
|
|
546
|
+
var lastSection, lastFooterAttributes;
|
|
547
|
+
|
|
548
|
+
var pinnedHeaderAttributes, lastCreatedFooterAttributes;
|
|
549
|
+
|
|
550
|
+
for (var i = 0; i < sectionCount; i++) {
|
|
551
|
+
var section = this.layoutCache.sections[i];
|
|
552
|
+
|
|
553
|
+
if (rect.intersectsRect(section.outerFrame)) {
|
|
554
|
+
|
|
555
|
+
var lastSection = section;
|
|
556
|
+
|
|
557
|
+
var headerAttributes;
|
|
558
|
+
// If the section's header frame intersects the visible rect, add it to the attributes array and retain a reference to it
|
|
559
|
+
// This reference will be used later if the tile layout pins headers to content edges where its position will be adjusted to fit the content edges
|
|
560
|
+
if (section.headerAttributes && rect.intersectsRect(section.headerAttributes.frame)) {
|
|
561
|
+
attributes.push(headerAttributes = section.headerAttributes.copy());
|
|
562
|
+
|
|
563
|
+
// If an incoming header intersects the pinned header attributes, displace pinned header so it doesn't cover the incoming header
|
|
564
|
+
if (pinnedHeaderAttributes && headerAttributes.frame.intersectsRect(pinnedHeaderAttributes.frame)) {
|
|
565
|
+
if (this.orientation == BMCollectionViewTileLayoutOrientation.Horizontal) {
|
|
566
|
+
pinnedHeaderAttributes.frame.origin.x = headerAttributes.frame.origin.x - pinnedHeaderAttributes.frame.size.width;
|
|
567
|
+
}
|
|
568
|
+
if (this.orientation == BMCollectionViewTileLayoutOrientation.Vertical) {
|
|
569
|
+
pinnedHeaderAttributes.frame.origin.y = headerAttributes.frame.origin.y - pinnedHeaderAttributes.frame.size.height;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
if (!foundSections) {
|
|
575
|
+
foundSections = YES;
|
|
576
|
+
if (this.pinsHeadersToContentEdge && section.headerAttributes) {
|
|
577
|
+
// If the header attributes did not intersect the visible rect, add them to the attributes array now
|
|
578
|
+
if (!headerAttributes) {
|
|
579
|
+
attributes.push(headerAttributes = section.headerAttributes.copy());
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
pinnedHeaderAttributes = headerAttributes;
|
|
583
|
+
pinnedHeaderAttributes.style.zIndex = 1;
|
|
584
|
+
|
|
585
|
+
// Adjust the position so it appears at the edge of the collection view
|
|
586
|
+
headerAttributes.frame.origin.y = Math.max(this.collectionView.scrollOffset.y, headerAttributes.frame.origin.y);
|
|
587
|
+
headerAttributes.frame.origin.x = Math.max(this.collectionView.scrollOffset.x, headerAttributes.frame.origin.x);
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
var attributesLength = section.attributes.length;
|
|
592
|
+
for (var j = 0; j < attributesLength; j++) {
|
|
593
|
+
if (rect.intersectsRect(section.attributes[j].frame)) {
|
|
594
|
+
attributes.push(section.attributes[j]);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
if (section.footerAttributes && rect.intersectsRect(section.footerAttributes.frame)) {
|
|
599
|
+
attributes.push(lastFooterAttributes = section.footerAttributes.copy());
|
|
600
|
+
lastCreatedFooterAttributes = lastFooterAttributes;
|
|
601
|
+
}
|
|
602
|
+
else {
|
|
603
|
+
// If this section's footer attributes do not intersect the visible rect, reset the
|
|
604
|
+
// lastFooterAttributes reference so that tile layout will know to add the footer attributes for this section if it is the last one
|
|
605
|
+
lastFooterAttributes = undefined;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
}
|
|
609
|
+
else if (foundSections) {
|
|
610
|
+
// Break after sections no longer intersect the visible rect because sections are ordered by position in the cache
|
|
611
|
+
break;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
if (lastSection && this.pinsFootersToContentEdge && lastSection.footerAttributes) {
|
|
616
|
+
// If the footer attributes did not intersect the visible rect, add them to the attributes array now
|
|
617
|
+
if (!lastFooterAttributes) {
|
|
618
|
+
attributes.push(lastFooterAttributes = lastSection.footerAttributes.copy());
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
lastFooterAttributes.style.zIndex = 1;
|
|
622
|
+
|
|
623
|
+
// Adjust the position so it appears at the edge of the collection view
|
|
624
|
+
lastFooterAttributes.frame.origin.y = Math.min(this.collectionView.scrollOffset.y + this.collectionView.frame.size.height - lastFooterAttributes.frame.size.height, lastFooterAttributes.frame.origin.y);
|
|
625
|
+
lastFooterAttributes.frame.origin.x = Math.min(this.collectionView.scrollOffset.x + this.collectionView.frame.size.width - lastFooterAttributes.frame.size.width, lastFooterAttributes.frame.origin.x);
|
|
626
|
+
|
|
627
|
+
// If an outgoing footer intersects the pinned footer's frame, adjust the pinned footer's position so it appears below the outgoing footer
|
|
628
|
+
if (lastCreatedFooterAttributes && lastFooterAttributes.frame.intersectsRect(lastCreatedFooterAttributes.frame)) {
|
|
629
|
+
if (this.orientation == BMCollectionViewTileLayoutOrientation.Horizontal) {
|
|
630
|
+
lastFooterAttributes.frame.origin.x = lastCreatedFooterAttributes.frame.origin.x - lastFooterAttributes.frame.size.width;
|
|
631
|
+
}
|
|
632
|
+
if (this.orientation == BMCollectionViewTileLayoutOrientation.Vertical) {
|
|
633
|
+
lastFooterAttributes.frame.origin.y = lastCreatedFooterAttributes.frame.origin.y - lastFooterAttributes.frame.size.height;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
return attributes;
|
|
639
|
+
},
|
|
640
|
+
|
|
641
|
+
// @override - BMCollectionViewLayout
|
|
642
|
+
shouldInvalidateLayoutForBoundsChange: function () {
|
|
643
|
+
var shouldInvalidate = this._pinsHeadersToContentEdge || this._pinsFootersToContentEdge;
|
|
644
|
+
if (shouldInvalidate) {
|
|
645
|
+
this._isChangingBounds = YES;
|
|
646
|
+
}
|
|
647
|
+
return shouldInvalidate;
|
|
648
|
+
},
|
|
649
|
+
|
|
650
|
+
// @override - BMCollectionViewLayout
|
|
651
|
+
didInvalidateLayoutForBoundsChange: function () {
|
|
652
|
+
this._isChangingBounds = NO;
|
|
653
|
+
},
|
|
654
|
+
|
|
655
|
+
// @override - BMCollectionViewLayout
|
|
656
|
+
attributesForCellAtIndexPath: function (indexPath) {
|
|
657
|
+
return this.cachedAttributesForCellAtIndexPath(indexPath, {withCache: this.layoutCache});
|
|
658
|
+
},
|
|
659
|
+
|
|
660
|
+
cachedAttributesForCellAtIndexPath: function (indexPath, args) {
|
|
661
|
+
return args.withCache.sections[indexPath.section].attributes[indexPath.row];
|
|
662
|
+
},
|
|
663
|
+
|
|
664
|
+
initialAttributesForMovingCellFromIndexPath: function (indexPath) {
|
|
665
|
+
return this.cachedAttributesForCellAtIndexPath(indexPath, {withCache: this.previousLayoutCache});
|
|
666
|
+
},
|
|
667
|
+
|
|
668
|
+
// @override - BMCollectionViewLayout
|
|
669
|
+
attributesForSupplementaryViewWithIdentifier: function (identifier, args) {
|
|
670
|
+
|
|
671
|
+
// The empty supplementary view will always ever have one instance with a preset index path
|
|
672
|
+
if (identifier === BMCollectionViewTableLayoutSupplementaryView.Empty) {
|
|
673
|
+
var attribute = BMCollectionViewLayoutAttributesMakeForSupplementaryViewWithIdentifier(
|
|
674
|
+
BMCollectionViewTableLayoutSupplementaryView.Empty,
|
|
675
|
+
{atIndexPath: BMIndexPathMakeWithIndexes([0])}
|
|
676
|
+
);
|
|
677
|
+
|
|
678
|
+
attribute.frame = BMRectMake(0, 0, this.collectionView.frame.size.width, this.collectionView.frame.size.height);
|
|
679
|
+
return attribute;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
var indexPath = args.atIndexPath;
|
|
683
|
+
if (identifier == BMCollectionViewFlowLayoutSupplementaryView.Footer) {
|
|
684
|
+
return this.layoutCache.sections[indexPath.section].footerAttributes;
|
|
685
|
+
}
|
|
686
|
+
else if (identifier == BMCollectionViewFlowLayoutSupplementaryView.Header) {
|
|
687
|
+
return this.layoutCache.sections[indexPath.section].headerAttributes;
|
|
688
|
+
}
|
|
689
|
+
},
|
|
690
|
+
|
|
691
|
+
// @override - BMCollectionViewLayout
|
|
692
|
+
contentSize: function () {
|
|
693
|
+
let size = this.layoutCache.size;
|
|
694
|
+
|
|
695
|
+
size.height = Math.max(size.height, this.collectionView.frame.size.height);
|
|
696
|
+
|
|
697
|
+
return size;
|
|
698
|
+
},
|
|
699
|
+
|
|
700
|
+
initialAttributesForPresentedCellAtIndexPath: function (indexPath, args) {
|
|
701
|
+
var attributes = args.withTargetAttributes.copy();
|
|
702
|
+
|
|
703
|
+
var frame = attributes.frame;
|
|
704
|
+
|
|
705
|
+
var slope = this.collectionView.bounds.center.slopeAngleToPoint(frame.center);
|
|
706
|
+
var distance = this.collectionView.bounds.center.distanceToPoint(frame.center);
|
|
707
|
+
|
|
708
|
+
frame.offset(distance * 4 * Math.cos(slope), distance * 4 * Math.sin(slope));
|
|
709
|
+
attributes.style.scaleX = 2;
|
|
710
|
+
attributes.style.scaleY = 2;
|
|
711
|
+
attributes.style.opacity = 0;
|
|
712
|
+
|
|
713
|
+
return attributes;
|
|
714
|
+
},
|
|
715
|
+
|
|
716
|
+
// @override - BMCollectionViewLayout
|
|
717
|
+
supplementaryViewsToInsert: function () {
|
|
718
|
+
var count = this.collectionView.numberOfSections();
|
|
719
|
+
var oldCount;
|
|
720
|
+
var self = this;
|
|
721
|
+
|
|
722
|
+
this.collectionView.usingOldDataSet(function () {
|
|
723
|
+
oldCount = self.collectionView.numberOfSections();
|
|
724
|
+
});
|
|
725
|
+
|
|
726
|
+
var views = [];
|
|
727
|
+
|
|
728
|
+
for (var i = oldCount; i < count; i++) {
|
|
729
|
+
if (this.showsHeaders) {
|
|
730
|
+
views.push(BMCollectionViewLayoutAttributesMakeForSupplementaryViewWithIdentifier(
|
|
731
|
+
BMCollectionViewFlowLayoutSupplementaryView.Header,
|
|
732
|
+
{atIndexPath: BMIndexPathMakeWithIndexes([i])}
|
|
733
|
+
));
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
if (this.showsFooters) {
|
|
737
|
+
views.push(BMCollectionViewLayoutAttributesMakeForSupplementaryViewWithIdentifier(
|
|
738
|
+
BMCollectionViewFlowLayoutSupplementaryView.Footer,
|
|
739
|
+
{atIndexPath: BMIndexPathMakeWithIndexes([i])}
|
|
740
|
+
));
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
if (oldCount > 0 && count == 0) {
|
|
745
|
+
views.push(BMCollectionViewLayoutAttributesMakeForSupplementaryViewWithIdentifier(
|
|
746
|
+
BMCollectionViewTableLayoutSupplementaryView.Empty,
|
|
747
|
+
{atIndexPath: BMIndexPathMakeWithIndexes([0])}
|
|
748
|
+
));
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
return views;
|
|
752
|
+
},
|
|
753
|
+
|
|
754
|
+
// @override - BMCollectionViewLayout
|
|
755
|
+
supplementaryViewsToDelete: function () {
|
|
756
|
+
var count = this.collectionView.numberOfSections();
|
|
757
|
+
var oldCount;
|
|
758
|
+
var self = this;
|
|
759
|
+
|
|
760
|
+
this.collectionView.usingOldDataSet(function () {
|
|
761
|
+
oldCount = self.collectionView.numberOfSections();
|
|
762
|
+
});
|
|
763
|
+
|
|
764
|
+
var views = [];
|
|
765
|
+
|
|
766
|
+
for (var i = count; i < oldCount; i++) {
|
|
767
|
+
if (this.showsHeaders) {
|
|
768
|
+
views.push(BMCollectionViewLayoutAttributesMakeForSupplementaryViewWithIdentifier(
|
|
769
|
+
BMCollectionViewFlowLayoutSupplementaryView.Header,
|
|
770
|
+
{atIndexPath: BMIndexPathMakeWithIndexes([i])}
|
|
771
|
+
));
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
if (this.showsFooters) {
|
|
775
|
+
views.push(BMCollectionViewLayoutAttributesMakeForSupplementaryViewWithIdentifier(
|
|
776
|
+
BMCollectionViewFlowLayoutSupplementaryView.Footer,
|
|
777
|
+
{atIndexPath: BMIndexPathMakeWithIndexes([i])}
|
|
778
|
+
));
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
if (oldCount == 0 && count > 0) {
|
|
783
|
+
views.push(BMCollectionViewLayoutAttributesMakeForSupplementaryViewWithIdentifier(
|
|
784
|
+
BMCollectionViewTableLayoutSupplementaryView.Empty,
|
|
785
|
+
{atIndexPath: BMIndexPathMakeWithIndexes([0])}
|
|
786
|
+
));
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
return views;
|
|
790
|
+
},
|
|
791
|
+
|
|
792
|
+
/**
|
|
793
|
+
* Returns the extent resulting by trimming the entire left side of the given extent
|
|
794
|
+
* by the given rect.
|
|
795
|
+
* The given rect must intersect the extent from the top, left or bottom, otherwise the resulting
|
|
796
|
+
* extent will not be valid.
|
|
797
|
+
* @param extent <BMRect> The extent to trim.
|
|
798
|
+
* {
|
|
799
|
+
* @param withIntersectingRect <BMRect> The rect intersecting the extent.
|
|
800
|
+
* }
|
|
801
|
+
* @return <BMRect> The resulting extent.
|
|
802
|
+
*/
|
|
803
|
+
rightExtentByTrimmingLeftSideOfExtent: function (extent, args) {
|
|
804
|
+
var rect = args.withIntersectingRect;
|
|
805
|
+
|
|
806
|
+
// The right trim of the extent will start at the rect's right side,
|
|
807
|
+
// run up to the extent's right edge and retain its vertical size and position
|
|
808
|
+
return BMRectMakeWithX(rect.right, {y: extent.origin.y, width: extent.right - rect.right, height: extent.height});
|
|
809
|
+
},
|
|
810
|
+
|
|
811
|
+
/**
|
|
812
|
+
* Returns the extent resulting by trimming the entire right side of the given extent
|
|
813
|
+
* by the given rect.
|
|
814
|
+
* The given rect must intersect the extent from the top, right or bottom, otherwise the resulting
|
|
815
|
+
* extent will not be valid.
|
|
816
|
+
* @param extent <BMRect> The extent to trim.
|
|
817
|
+
* {
|
|
818
|
+
* @param withIntersectingRect <BMRect> The rect intersecting the extent.
|
|
819
|
+
* }
|
|
820
|
+
* @return <BMRect> The resulting extent.
|
|
821
|
+
*/
|
|
822
|
+
leftExtentByTrimmingRightSideOfExtent: function (extent, args) {
|
|
823
|
+
var rect = args.withIntersectingRect;
|
|
824
|
+
|
|
825
|
+
// The left trim of the extent will start at the extent's left side,
|
|
826
|
+
// run up to the extent's left edge and retain its vertical size and position
|
|
827
|
+
return BMRectMakeWithX(extent.origin.x, {y: extent.origin.y, width: rect.origin.x - extent.origin.x, height: extent.height});
|
|
828
|
+
},
|
|
829
|
+
|
|
830
|
+
/**
|
|
831
|
+
* Returns the extent resulting by trimming the entire bottom side of the given extent
|
|
832
|
+
* by the given rect.
|
|
833
|
+
* The given rect must intersect the extent from the top, right or left, otherwise the resulting
|
|
834
|
+
* extent will not be valid.
|
|
835
|
+
* @param extent <BMRect> The extent to trim.
|
|
836
|
+
* {
|
|
837
|
+
* @param withIntersectingRect <BMRect> The rect intersecting the extent.
|
|
838
|
+
* }
|
|
839
|
+
* @return <BMRect> The resulting extent.
|
|
840
|
+
*/
|
|
841
|
+
topExtentByTrimmingBottomSideOfExtent: function (extent, args) {
|
|
842
|
+
var rect = args.withIntersectingRect;
|
|
843
|
+
|
|
844
|
+
// The top trim of the extent will start at the extent's top edge,
|
|
845
|
+
// run up to the rect's top edge and retain its horizontal size and position
|
|
846
|
+
return BMRectMakeWithX(extent.origin.x, {y: extent.origin.y, width: extent.size.width, height: rect.origin.y - extent.origin.y});
|
|
847
|
+
},
|
|
848
|
+
|
|
849
|
+
/**
|
|
850
|
+
* Returns the extent resulting by trimming the entire top side of the given extent
|
|
851
|
+
* by the given rect.
|
|
852
|
+
* The given rect must intersect the extent from the bottom, right or left, otherwise the resulting
|
|
853
|
+
* extent will not be valid.
|
|
854
|
+
* @param extent <BMRect> The extent to trim.
|
|
855
|
+
* {
|
|
856
|
+
* @param withIntersectingRect <BMRect> The rect intersecting the extent.
|
|
857
|
+
* }
|
|
858
|
+
* @return <BMRect> The resulting extent.
|
|
859
|
+
*/
|
|
860
|
+
bottomExtentByTrimmingTopSideOfExtent: function (extent, args) {
|
|
861
|
+
var rect = args.withIntersectingRect;
|
|
862
|
+
|
|
863
|
+
// The top trim of the extent will start at the extent's top edge,
|
|
864
|
+
// run up to the rect's top edge and retain its horizontal size and position
|
|
865
|
+
return BMRectMakeWithX(extent.origin.x, {y: rect.bottom, width: extent.size.width, height: extent.bottom - rect.bottom});
|
|
866
|
+
},
|
|
867
|
+
|
|
868
|
+
/**
|
|
869
|
+
* Returns an array of extent rects that represent the possible extents created after the given rect is placed within an extent.
|
|
870
|
+
* This will slice up the given extent and return the remaining extents. These extents will contain intersecting regions.
|
|
871
|
+
* The given rect must intersect the extent from the top, otherwise this function's result will not be well-defined.
|
|
872
|
+
* @param extent <BMRect> The extent intersected by the rect.
|
|
873
|
+
* {
|
|
874
|
+
* @param fromRect <BMRect> The rect interescting the extent.
|
|
875
|
+
* @param spacing <Number, nullable> Defaults to 0. Additional spacing to maintain between the rect and the extents.
|
|
876
|
+
* }
|
|
877
|
+
* @return <[BMRect]> The resulting extents.
|
|
878
|
+
*/
|
|
879
|
+
rectsWithDifferenceOfExtent: function (extent, args) {
|
|
880
|
+
var spacing = args.spacing || 0;
|
|
881
|
+
var gridSize = this._gridSize;
|
|
882
|
+
|
|
883
|
+
var rect = args.fromRect;
|
|
884
|
+
|
|
885
|
+
// The are several cases handled by this method
|
|
886
|
+
// In all cases, it is assumed that the rect lies partially on the left, top, bottom or right edge of the extent
|
|
887
|
+
// or any combination of at most three edges
|
|
888
|
+
|
|
889
|
+
// Up to three extents will be generated in each case by trimming the base extent with the given rect
|
|
890
|
+
// If the rect intersects more than one edge of the extent, some of the resulting trimmed
|
|
891
|
+
// extents will be invalid, in which case they will not be included in the result
|
|
892
|
+
|
|
893
|
+
// Additionally, the resulting extents will be ordered so that the topmost and leftmost extents appear before other extents
|
|
894
|
+
|
|
895
|
+
// The case where the rect intersects the top edge of the extent
|
|
896
|
+
if (rect.bottom >= extent.origin.y && rect.top <= extent.origin.y) {
|
|
897
|
+
var resultingExtents = [];
|
|
898
|
+
|
|
899
|
+
var leftExtent = this.leftExtentByTrimmingRightSideOfExtent(extent, {withIntersectingRect: rect});
|
|
900
|
+
(leftExtent.width >= gridSize) && resultingExtents.push(leftExtent);
|
|
901
|
+
|
|
902
|
+
var rightExtent = this.rightExtentByTrimmingLeftSideOfExtent(extent, {withIntersectingRect: rect});
|
|
903
|
+
(rightExtent.width >= gridSize) && resultingExtents.push(rightExtent);
|
|
904
|
+
|
|
905
|
+
var bottomExtent = this.bottomExtentByTrimmingTopSideOfExtent(extent, {withIntersectingRect: rect});
|
|
906
|
+
(bottomExtent.height >= gridSize) && resultingExtents.push(bottomExtent);
|
|
907
|
+
|
|
908
|
+
return resultingExtents;
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
// The final case where the rect intersects the left edge of the extent
|
|
912
|
+
if (rect.right >= extent.origin.x && rect.origin.x <= extent.origin.x) {
|
|
913
|
+
var resultingExtents = [];
|
|
914
|
+
|
|
915
|
+
var topExtent = this.topExtentByTrimmingBottomSideOfExtent(extent, {withIntersectingRect: rect});
|
|
916
|
+
(topExtent.height >= gridSize) && resultingExtents.push(topExtent);
|
|
917
|
+
|
|
918
|
+
var rightExtent = this.rightExtentByTrimmingLeftSideOfExtent(extent, {withIntersectingRect: rect});
|
|
919
|
+
(rightExtent.width >= gridSize) && resultingExtents.push(rightExtent);
|
|
920
|
+
|
|
921
|
+
var bottomExtent = this.bottomExtentByTrimmingTopSideOfExtent(extent, {withIntersectingRect: rect});
|
|
922
|
+
(bottomExtent.height >= gridSize) && resultingExtents.push(bottomExtent);
|
|
923
|
+
|
|
924
|
+
return resultingExtents;
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
// The final case where the rect intersects the right edge of the extent
|
|
928
|
+
if (rect.origin.x <= extent.right && rect.right >= extent.right) {
|
|
929
|
+
var resultingExtents = [];
|
|
930
|
+
|
|
931
|
+
var topExtent = this.topExtentByTrimmingBottomSideOfExtent(extent, {withIntersectingRect: rect});
|
|
932
|
+
(topExtent.height >= gridSize) && resultingExtents.push(topExtent);
|
|
933
|
+
|
|
934
|
+
var leftExtent = this.leftExtentByTrimmingRightSideOfExtent(extent, {withIntersectingRect: rect});
|
|
935
|
+
(leftExtent.width >= gridSize) && resultingExtents.push(leftExtent);
|
|
936
|
+
|
|
937
|
+
var bottomExtent = this.bottomExtentByTrimmingTopSideOfExtent(extent, {withIntersectingRect: rect});
|
|
938
|
+
(bottomExtent.height >= gridSize) && resultingExtents.push(bottomExtent);
|
|
939
|
+
|
|
940
|
+
return resultingExtents;
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
// The case where the rect intersects the bottom edge of the extent
|
|
944
|
+
if (rect.origin.y <= extent.bottom && rect.bottom >= extent.bottom) {
|
|
945
|
+
var resultingExtents = [];
|
|
946
|
+
|
|
947
|
+
var leftExtent = this.leftExtentByTrimmingRightSideOfExtent(extent, {withIntersectingRect: rect});
|
|
948
|
+
(leftExtent.width >= gridSize) && resultingExtents.push(leftExtent);
|
|
949
|
+
|
|
950
|
+
var topExtent = this.topExtentByTrimmingBottomSideOfExtent(extent, {withIntersectingRect: rect});
|
|
951
|
+
(bottomExtent.height >= gridSize) && resultingExtents.push(bottomExtent);
|
|
952
|
+
|
|
953
|
+
var rightExtent = this.rightExtentByTrimmingLeftSideOfExtent(extent, {withIntersectingRect: rect});
|
|
954
|
+
(rightExtent.width >= gridSize) && resultingExtents.push(rightExtent);
|
|
955
|
+
|
|
956
|
+
return resultingExtents;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
// Code below this point is deprecated
|
|
960
|
+
// Control shouldn't reach this point
|
|
961
|
+
debugger;
|
|
962
|
+
|
|
963
|
+
// First case is when the rect intersects the top-left corner of the extent
|
|
964
|
+
if (rect.intersectsPoint(extent.origin)) {
|
|
965
|
+
var resultingExtents = [];
|
|
966
|
+
|
|
967
|
+
// In this case there are two extents
|
|
968
|
+
// The first one runs alongside the rect's right edge
|
|
969
|
+
var rightExtent = BMRectMakeWithX(rect.right, {y: extent.origin.y, width: extent.right - rect.right, height: extent.height});
|
|
970
|
+
// This extent will have negative or zero width if the rect is as wide or wider than the extent, in that case it will be discarded
|
|
971
|
+
(rightExtent.width >= gridSize) && resultingExtents.push(rightExtent);
|
|
972
|
+
|
|
973
|
+
// The second one runs below the rect's bottom edge
|
|
974
|
+
var bottomExtent = BMRectMakeWithX(extent.origin.x, {y: rect.bottom, width: extent.width, height: extent.bottom - rect.bottom});
|
|
975
|
+
// This extent will have negative or zero height if the rect is as tall or taller than the extent, in that case it will be discarded
|
|
976
|
+
(bottomExtent.height >= gridSize) && resultingExtents.push(bottomExtent);
|
|
977
|
+
|
|
978
|
+
return resultingExtents;
|
|
979
|
+
}
|
|
980
|
+
else {
|
|
981
|
+
// The other cases handle intersection with a single edge and none of the corners
|
|
982
|
+
// Rarely, however, in certain configurations it is possible that the rect will intersect the top-right edge of the extent
|
|
983
|
+
if (rect.intersectsPoint({x: extent.right, y: extent.origin.y})) {
|
|
984
|
+
// This case is similar to the first one, except that the first extent will run alongside the rect's left edge instead of the right
|
|
985
|
+
var resultingExtents = [];
|
|
986
|
+
|
|
987
|
+
// In this case there are two extents
|
|
988
|
+
// The first one runs alongside the rect's left edge
|
|
989
|
+
var leftExtent = BMRectMakeWithX(extent.origin.x, {y: extent.origin.y, width: rect.origin.x - extent.origin.x, height: extent.height});
|
|
990
|
+
// This extent will have negative or zero width if the rect is as wide or wider than the extent, in that case it will be discarded
|
|
991
|
+
(leftExtent.width >= gridSize) && resultingExtents.push(leftExtent);
|
|
992
|
+
|
|
993
|
+
// The second one runs below the rect's bottom edge
|
|
994
|
+
var bottomExtent = BMRectMakeWithX(extent.origin.x, {y: rect.bottom, width: extent.width, height: extent.bottom - rect.bottom});
|
|
995
|
+
// This extent will have negative or zero height if the rect is as tall or taller than the extent, in that case it will be discarded
|
|
996
|
+
(bottomExtent.height >= gridSize) && resultingExtents.push(bottomExtent);
|
|
997
|
+
|
|
998
|
+
return resultingExtents;
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
if (rect.intersectsPoint({x: extent.left, y: extent.bottom})) {
|
|
1002
|
+
// This case is similar to the first one, except that the first extent will run alongside the rect's left edge instead of the right
|
|
1003
|
+
var resultingExtents = [];
|
|
1004
|
+
|
|
1005
|
+
// The first one will run above the rect's top edge
|
|
1006
|
+
var topExtent = BMRectMakeWithX(extent.origin.x, {y: extent.origin.y, width: extent.size.width, height: rect.origin.y - extent.origin.y});
|
|
1007
|
+
// This extent will have negative or zero height if the rect is as tall or taller than the extent, in that case it will be discarded
|
|
1008
|
+
(topExtent.height >= gridSize) && resultingExtents.push(topExtent);
|
|
1009
|
+
|
|
1010
|
+
// In this case there are two extents
|
|
1011
|
+
// The first one runs alongside the rect's right edge
|
|
1012
|
+
var rightExtent = BMRectMakeWithX(rect.right, {y: extent.origin.y, width: extent.right - rect.right, height: extent.height});
|
|
1013
|
+
// This extent will have negative or zero width if the rect is as wide or wider than the extent, in that case it will be discarded
|
|
1014
|
+
(rightExtent.width >= gridSize) && resultingExtents.push(rightExtent);
|
|
1015
|
+
|
|
1016
|
+
return resultingExtents;
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
if (rect.intersectsPoint({x: extent.right, y: extent.bottom})) {
|
|
1020
|
+
// This case is similar to the first one, except that the first extent will run alongside the rect's left edge instead of the right
|
|
1021
|
+
var resultingExtents = [];
|
|
1022
|
+
|
|
1023
|
+
// The first one will run above the rect's top edge
|
|
1024
|
+
var topExtent = BMRectMakeWithX(extent.origin.x, {y: extent.origin.y, width: extent.size.width, height: rect.origin.y - extent.origin.y});
|
|
1025
|
+
// This extent will have negative or zero height if the rect is as tall or taller than the extent, in that case it will be discarded
|
|
1026
|
+
(topExtent.height >= gridSize) && resultingExtents.push(topExtent);
|
|
1027
|
+
|
|
1028
|
+
// In this case there are two extents
|
|
1029
|
+
// The first one runs alongside the rect's left edge
|
|
1030
|
+
var leftExtent = BMRectMakeWithX(extent.origin.x, {y: extent.origin.y, width: rect.origin.x - extent.origin.x, height: extent.height});
|
|
1031
|
+
// This extent will have negative or zero width if the rect is as wide or wider than the extent, in that case it will be discarded
|
|
1032
|
+
(leftExtent.width >= gridSize) && resultingExtents.push(leftExtent);
|
|
1033
|
+
|
|
1034
|
+
return resultingExtents;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
// The case where the rect intersects the top edge of the extent
|
|
1038
|
+
if (rect.bottom >= extent.origin.y && rect.top <= extent.origin.y) {
|
|
1039
|
+
// Three extents will be generated in this case
|
|
1040
|
+
var resultingExtents = [];
|
|
1041
|
+
|
|
1042
|
+
// The first one will run up to the rect's left edge
|
|
1043
|
+
var leftExtent = BMRectMakeWithX(extent.origin.x, {y: extent.origin.y, width: rect.origin.x - extent.origin.x, height: extent.height});
|
|
1044
|
+
// This extent will have negative or zero width if the rect is as wide or wider than the extent, in that case it will be discarded
|
|
1045
|
+
(leftExtent.width >= gridSize) && resultingExtents.push(leftExtent);
|
|
1046
|
+
|
|
1047
|
+
// The second one will start at the rect's right edge
|
|
1048
|
+
var rightExtent = BMRectMakeWithX(rect.right, {y: extent.origin.y, width: extent.right - rect.right, height: extent.height});
|
|
1049
|
+
// This extent will have negative or zero width if the rect is as wide or wider than the extent, in that case it will be discarded
|
|
1050
|
+
(rightExtent.width >= gridSize) && resultingExtents.push(rightExtent);
|
|
1051
|
+
|
|
1052
|
+
// The last one runs below the rect's bottom edge
|
|
1053
|
+
var bottomExtent = BMRectMakeWithX(extent.origin.x, {y: rect.bottom, width: extent.width, height: extent.bottom - rect.bottom});
|
|
1054
|
+
// This extent will have negative or zero height if the rect is as tall or taller than the extent, in that case it will be discarded
|
|
1055
|
+
(bottomExtent.height >= gridSize) && resultingExtents.push(bottomExtent);
|
|
1056
|
+
|
|
1057
|
+
return resultingExtents;
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
// The final case where the rect intersects the left edge of the extent
|
|
1061
|
+
if (rect.right >= extent.origin.x && rect.origin.x <= extent.origin.x) {
|
|
1062
|
+
// Three extents will be generated in this case
|
|
1063
|
+
var resultingExtents = [];
|
|
1064
|
+
|
|
1065
|
+
// The first one will run above the rect's top edge
|
|
1066
|
+
var topExtent = BMRectMakeWithX(extent.origin.x, {y: extent.origin.y, width: extent.size.width, height: rect.origin.y - extent.origin.y});
|
|
1067
|
+
// This extent will have negative or zero height if the rect is as tall or taller than the extent, in that case it will be discarded
|
|
1068
|
+
(topExtent.height >= gridSize) && resultingExtents.push(topExtent);
|
|
1069
|
+
|
|
1070
|
+
// The second one will start at the rect's right edge
|
|
1071
|
+
var rightExtent = BMRectMakeWithX(rect.right, {y: extent.origin.y, width: extent.right - rect.right, height: extent.height});
|
|
1072
|
+
// This extent will have negative or zero width if the rect is as wide or wider than the extent, in that case it will be discarded
|
|
1073
|
+
(rightExtent.width >= gridSize) && resultingExtents.push(rightExtent);
|
|
1074
|
+
|
|
1075
|
+
// The last one runs below the rect's bottom edge
|
|
1076
|
+
var bottomExtent = BMRectMakeWithX(extent.origin.x, {y: rect.bottom, width: extent.width, height: extent.bottom - rect.bottom});
|
|
1077
|
+
// This extent will have negative or zero height if the rect is as tall or taller than the extent, in that case it will be discarded
|
|
1078
|
+
(bottomExtent.height >= gridSize) && resultingExtents.push(bottomExtent);
|
|
1079
|
+
|
|
1080
|
+
return resultingExtents;
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
// The final case where the rect intersects the right edge of the extent
|
|
1084
|
+
if (rect.origin.x <= extent.right && rect.right >= extent.right) {
|
|
1085
|
+
// Three extents will be generated in this case
|
|
1086
|
+
var resultingExtents = [];
|
|
1087
|
+
|
|
1088
|
+
// The first one will run above the rect's top edge
|
|
1089
|
+
var topExtent = BMRectMakeWithX(extent.origin.x, {y: extent.origin.y, width: extent.size.width, height: rect.origin.y - extent.origin.y});
|
|
1090
|
+
// This extent will have negative or zero height if the rect is as tall or taller than the extent, in that case it will be discarded
|
|
1091
|
+
(topExtent.height >= gridSize) && resultingExtents.push(topExtent);
|
|
1092
|
+
|
|
1093
|
+
// The second one will start at the rect's left edge
|
|
1094
|
+
var leftExtent = BMRectMakeWithX(extent.right, {y: extent.origin.y, width: rect.right - extent.right, height: extent.height});
|
|
1095
|
+
// This extent will have negative or zero width if the rect is as wide or wider than the extent, in that case it will be discarded
|
|
1096
|
+
(leftExtent.width >= gridSize) && resultingExtents.push(leftExtent);
|
|
1097
|
+
|
|
1098
|
+
// The last one runs below the rect's bottom edge
|
|
1099
|
+
var bottomExtent = BMRectMakeWithX(extent.origin.x, {y: rect.bottom, width: extent.width, height: extent.bottom - rect.bottom});
|
|
1100
|
+
// This extent will have negative or zero height if the rect is as tall or taller than the extent, in that case it will be discarded
|
|
1101
|
+
(bottomExtent.height >= gridSize) && resultingExtents.push(bottomExtent);
|
|
1102
|
+
|
|
1103
|
+
return resultingExtents;
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
// Control shouldn't reach this point
|
|
1108
|
+
debugger;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
});
|
|
1112
|
+
|
|
1113
|
+
/**
|
|
1114
|
+
* Constructs and returns a new tile layout.
|
|
1115
|
+
* @return <BMCollectionViewTileLayout> A tile layout.
|
|
1116
|
+
*/
|
|
1117
|
+
BMCollectionViewTileLayout.tileLayout = function () {
|
|
1118
|
+
return new BMCollectionViewTileLayout();
|
|
1119
|
+
};
|
|
1120
|
+
|
|
1121
|
+
// @endtype
|