bm-core-ui 2.7.0 → 2.8.3
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 +147 -0
- package/build/@types/index.d.ts +672 -92
- package/build/BMCodeEditor/BMCodeEditor.js +24 -27
- package/build/BMCollectionView/BMCollectionView.js +404 -55
- package/build/BMCollectionView/BMCollectionViewFlowLayout.js +423 -33
- package/build/BMCollectionView/BMCollectionViewLayout.js +158 -0
- package/build/BMCollectionView/BMCollectionViewMasonryLayout.js +145 -5
- package/build/BMCollectionView/BMCollectionViewTileLayout.js +147 -2
- package/build/BMCoreUI.css +60 -10
- package/build/BMView/BMMenu.js +155 -8
- package/build/BMView/BMTextField.js +25 -14
- package/build/BMView/BMView_v2.5.js +205 -3
- package/build/BMViewLayoutEditor/BMLayoutEditor.js +188 -168
- package/build/BMViewLayoutEditor/BMLayoutEditorSettingCells.js +2 -2
- package/build/BMWindow/BMConfirmationPopup.js +15 -0
- package/build/BMWindow/BMKeyboardShortcut.js +122 -3
- package/build/BMWindow/BMWindow.js +25 -90
- package/build/Core/BMAnimationContext.js +0 -4
- package/build/Core/BMCoreUI.js +9 -1
- package/lib/@types/BMCoreUI.min.d.ts +672 -92
- package/lib/BMCoreUI.min.js +1 -1
- package/package.json +1 -1
|
@@ -15,6 +15,7 @@ import {_BMCollectionViewTransitionLayout} from './BMCollectionViewLayout'
|
|
|
15
15
|
import {IScroll} from '../iScroll/iscroll-probe'
|
|
16
16
|
import { BMLayoutAttribute } from '../BMView/BMLayoutConstraint_v2.5'
|
|
17
17
|
import { BMMenuSourceNodeCSSClass } from '../BMView/BMMenu'
|
|
18
|
+
import { BMKeyboardShortcut, BMKeyboardShortcutModifier } from '../BMWindow/BMKeyboardShortcut'
|
|
18
19
|
|
|
19
20
|
// When set to YES, this will cause collection view to use static animation contexts when setting up animations
|
|
20
21
|
const BM_COLLECTION_VIEW_USE_STATIC_CONTEXT = YES;
|
|
@@ -515,6 +516,13 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
515
516
|
*/
|
|
516
517
|
_bounds: undefined, // <BMRect>
|
|
517
518
|
get bounds() { return this._bounds; },
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* A rect that represents the part of the bounds that are visible on screen.
|
|
522
|
+
*/
|
|
523
|
+
get visibleBounds() { // <BMRect>
|
|
524
|
+
return new BMRect(BMPointMake(this._bounds.origin.x + this._offscreenBufferSize, this._bounds.origin.y + this._offscreenBufferSize), this._frame.size.copy());
|
|
525
|
+
},
|
|
518
526
|
|
|
519
527
|
/**
|
|
520
528
|
* The number of pixels by which to extend the bounds to preload layout attributes and render off-screen elements.
|
|
@@ -682,6 +690,30 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
682
690
|
*/
|
|
683
691
|
assignsReuseIdentifierAsClass: YES, // <Boolean>
|
|
684
692
|
|
|
693
|
+
/**
|
|
694
|
+
* Defaults to `YES`. When set to `NO`, keyboard navigation is disabled.
|
|
695
|
+
*/
|
|
696
|
+
_supportsKeyboardNavigation: NO, // <Boolean>
|
|
697
|
+
|
|
698
|
+
get supportsKeyboardNavigation() {
|
|
699
|
+
return this._supportsKeyboardNavigation;
|
|
700
|
+
},
|
|
701
|
+
|
|
702
|
+
set supportsKeyboardNavigation(supports) {
|
|
703
|
+
if (supports != this._supportsKeyboardNavigation) {
|
|
704
|
+
this._supportsKeyboardNavigation = supports;
|
|
705
|
+
|
|
706
|
+
if (this.initialized) {
|
|
707
|
+
if (supports) {
|
|
708
|
+
this.configureKeyboardShortcuts();
|
|
709
|
+
}
|
|
710
|
+
else {
|
|
711
|
+
this.disableKeyboardShortcuts();
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
},
|
|
716
|
+
|
|
685
717
|
/**
|
|
686
718
|
* Registers a class to be used when creating cells with the given reuse identifier.
|
|
687
719
|
* This does not affect already existing cells, but newly created cells with the given identifier will be created
|
|
@@ -962,6 +994,10 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
962
994
|
delay: 0
|
|
963
995
|
}, delegateOptions));
|
|
964
996
|
}
|
|
997
|
+
|
|
998
|
+
if (this._supportsKeyboardNavigation) {
|
|
999
|
+
this.configureKeyboardShortcuts();
|
|
1000
|
+
}
|
|
965
1001
|
|
|
966
1002
|
this.initialized = YES;
|
|
967
1003
|
|
|
@@ -2223,8 +2259,8 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
2223
2259
|
else {
|
|
2224
2260
|
// Otherwise use the cell's own CSS size for this purpose
|
|
2225
2261
|
size = BMSizeMake(
|
|
2226
|
-
cell._variables[BMLayoutAttribute.Width].value()
|
|
2227
|
-
cell._variables[BMLayoutAttribute.Height].value()
|
|
2262
|
+
cell._variables[BMLayoutAttribute.Width].value() || cell.node.offsetWidth,
|
|
2263
|
+
cell._variables[BMLayoutAttribute.Height].value() || cell.node.offsetHeight
|
|
2228
2264
|
);
|
|
2229
2265
|
}
|
|
2230
2266
|
|
|
@@ -2376,7 +2412,7 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
2376
2412
|
node.style.cssText = "position: absolute; left: 0px; top: 0px; visibility: hidden; overflow: visible;";
|
|
2377
2413
|
|
|
2378
2414
|
var cell = Object.create(cellClass.prototype).initWithCollectionView(this, {reuseIdentifier: identifier, node: node, kind: BMCollectionViewLayoutAttributesType.Cell});
|
|
2379
|
-
cell.
|
|
2415
|
+
cell.layoutQueue = this._cellLayoutQueue;
|
|
2380
2416
|
//BMCollectionViewCellMakeForCollectionView(this, {withReuseIdentifier: identifier});
|
|
2381
2417
|
|
|
2382
2418
|
|
|
@@ -2413,6 +2449,28 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
2413
2449
|
var useCapture = NO;
|
|
2414
2450
|
|
|
2415
2451
|
var canDrag = NO;
|
|
2452
|
+
|
|
2453
|
+
// Stops processing the current event sequence
|
|
2454
|
+
const cancelProcessing = () => {
|
|
2455
|
+
cellEventIsMouseDown = NO;
|
|
2456
|
+
cellEventCanTouchDrag = NO;
|
|
2457
|
+
cellEventTrackedTouch = undefined;
|
|
2458
|
+
|
|
2459
|
+
window.removeEventListener('mousemove', cell.mousemoveHandler, YES);
|
|
2460
|
+
window.removeEventListener('mouseup', cell.mouseupHandler, YES);
|
|
2461
|
+
|
|
2462
|
+
cellEventClicks = 0;
|
|
2463
|
+
|
|
2464
|
+
if (cellEventLongClickTimeout) {
|
|
2465
|
+
window.clearTimeout(cellEventLongClickTimeout);
|
|
2466
|
+
cellEventLongClickTimeout = undefined;
|
|
2467
|
+
}
|
|
2468
|
+
|
|
2469
|
+
if (cellEventDoubleClickTimeout) {
|
|
2470
|
+
window.clearTimeout(cellEventDoubleClickTimeout);
|
|
2471
|
+
cellEventDoubleClickTimeout = undefined;
|
|
2472
|
+
}
|
|
2473
|
+
}
|
|
2416
2474
|
|
|
2417
2475
|
// Click, double click, long click, tap, double tap and long tap handlers
|
|
2418
2476
|
cell.mousedownHandler = function (event) {
|
|
@@ -2428,6 +2486,7 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
2428
2486
|
event.target.parentNode.nodeName == 'BUTTON' || event.target.parentNode.nodeName == 'INPUT' || event.target.parentNode.nodeName == 'LABEL' ||
|
|
2429
2487
|
event.target.classList.contains('BMCollectionViewCellEventHandler') || event.target.parentNode.classList.contains('BMCollectionViewCellEventHandler') ||
|
|
2430
2488
|
event.target.classList.contains('widget-foldingpanel-header') ||
|
|
2489
|
+
event.target.hasAttribute('contenteditable') ||
|
|
2431
2490
|
// This a specific Thingworx workaround that depends on jQuery
|
|
2432
2491
|
(window.$ ? window.$(event.target).parents('.widget-dhxdropdown').length : false)) {
|
|
2433
2492
|
return;
|
|
@@ -2472,6 +2531,14 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
2472
2531
|
// TODO: Consider if mouse events should also trigger drag & drop in this case
|
|
2473
2532
|
|
|
2474
2533
|
if (canDrag) {
|
|
2534
|
+
// If a different collection view already handled this event, stop processing this sequence
|
|
2535
|
+
if (event.BM_Handled) {
|
|
2536
|
+
cancelProcessing();
|
|
2537
|
+
return;
|
|
2538
|
+
}
|
|
2539
|
+
|
|
2540
|
+
event.BM_Handled = YES;
|
|
2541
|
+
|
|
2475
2542
|
// These events will be processed by the interactive movement handlers from this point on
|
|
2476
2543
|
// So the global mousemove and mouseup handlers should be unregistered
|
|
2477
2544
|
window.removeEventListener('mousemove', cell.mousemoveHandler, YES);
|
|
@@ -2524,6 +2591,12 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
2524
2591
|
// to fire even after the touch point has moved outside of the element
|
|
2525
2592
|
// Because of this, mousemove is attached to window for the duration of a click and then released at the end
|
|
2526
2593
|
cell.mousemoveHandler = function (event) {
|
|
2594
|
+
// If this event was already handled, stop processing
|
|
2595
|
+
if (event.BM_Handled) {
|
|
2596
|
+
cancelProcessing();
|
|
2597
|
+
return;
|
|
2598
|
+
}
|
|
2599
|
+
|
|
2527
2600
|
if (_BMCoreUIIsDragging) return void (event.preventDefault(), event.stopPropagation());
|
|
2528
2601
|
if (canDrag) event.preventDefault();
|
|
2529
2602
|
event.originalEvent = event;
|
|
@@ -2576,6 +2649,10 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
2576
2649
|
}*/
|
|
2577
2650
|
|
|
2578
2651
|
if (canDrag) {
|
|
2652
|
+
// Mark this event as handled, so that when it bubbles up to other collection views they don't also trigger
|
|
2653
|
+
// drag & drop
|
|
2654
|
+
event.BM_Handled = YES;
|
|
2655
|
+
|
|
2579
2656
|
if (self.delegate && self.delegate.collectionViewWillBeginInteractiveMovementForCell) {
|
|
2580
2657
|
self.delegate.collectionViewWillBeginInteractiveMovementForCell(self, cell, {atIndexPath: cell.indexPath});
|
|
2581
2658
|
}
|
|
@@ -3622,7 +3699,7 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
3622
3699
|
// Otherwise construct a new one
|
|
3623
3700
|
var cellClass = this._supplementaryViewClasses[identifier] || this._cellClass;
|
|
3624
3701
|
var cell = Object.create(cellClass.prototype).initWithCollectionView(this, {reuseIdentifier: identifier, node: node, kind: BMCollectionViewLayoutAttributesType.SupplementaryView});
|
|
3625
|
-
cell.
|
|
3702
|
+
cell.layoutQueue = this._cellLayoutQueue;
|
|
3626
3703
|
|
|
3627
3704
|
// When using custom classes, it is no longer the data set object's responsibility to provide the contents for the cell
|
|
3628
3705
|
if (cellClass == BMCollectionViewCell) cell.element.append(this._dataSet.contentsForSupplementaryViewWithIdentifier(identifier));
|
|
@@ -3910,6 +3987,11 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
3910
3987
|
cellWasClicked: function (cell, options) {
|
|
3911
3988
|
if (options && options.withEvent) options.withEvent._BMOriginalTarget = cell.node;
|
|
3912
3989
|
|
|
3990
|
+
// Acquire focus if not already owned
|
|
3991
|
+
if (document.activeElement != this.node && this._supportsKeyboardNavigation) {
|
|
3992
|
+
this.node.focus();
|
|
3993
|
+
}
|
|
3994
|
+
|
|
3913
3995
|
// Forward this event to the delegate, giving it a chance to handle the event
|
|
3914
3996
|
var eventHandled = NO;
|
|
3915
3997
|
if (this.delegate && this.delegate.collectionViewCellWasClicked) {
|
|
@@ -3918,15 +4000,26 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
3918
4000
|
|
|
3919
4001
|
// If the delegate did handle this event, do not invoke the default behavior
|
|
3920
4002
|
if (eventHandled) return;
|
|
3921
|
-
|
|
3922
|
-
|
|
4003
|
+
|
|
4004
|
+
// The default behaviour when clicking cells is to highlight them
|
|
4005
|
+
if (this._highlightedIndexPath && !this._highlightedIndexPath.isLooselyEqualToIndexPath(cell.indexPath, {usingComparator: this.identityComparator})) {
|
|
4006
|
+
let canHighlight = YES;
|
|
4007
|
+
if (this.delegate && this.delegate.collectionViewCanHighlightCellAtIndexPath) {
|
|
4008
|
+
canHighlight = this.delegate.collectionViewCanHighlightCellAtIndexPath(this, cell.indexPath, {withEvent: options.withEvent});
|
|
4009
|
+
}
|
|
4010
|
+
|
|
4011
|
+
if (canHighlight) {
|
|
4012
|
+
this._highlightIndexPath(cell.indexPath, {withEvent: options.withEvent});
|
|
4013
|
+
}
|
|
4014
|
+
}
|
|
4015
|
+
|
|
4016
|
+
// The previous default click behavior is to toggle cells' selection state
|
|
3923
4017
|
// Ask the delegate if the cell is selectable or deselectable,
|
|
3924
4018
|
// depending on whether the cell is currently selected or not.
|
|
3925
4019
|
var selectable = YES;
|
|
3926
|
-
|
|
3927
|
-
|
|
4020
|
+
const selected = this.isCellAtIndexPathSelected(cell.indexPath);
|
|
3928
4021
|
|
|
3929
|
-
if (selected
|
|
4022
|
+
if (selected) {
|
|
3930
4023
|
if (this.delegate && typeof this.delegate.collectionViewCanDeselectCellAtIndexPath === 'function') {
|
|
3931
4024
|
selectable = this.delegate.collectionViewCanDeselectCellAtIndexPath(this, cell.indexPath);
|
|
3932
4025
|
}
|
|
@@ -3959,6 +4052,11 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
3959
4052
|
cellWasDoubleClicked: function (cell, options) {
|
|
3960
4053
|
if (options && options.withEvent) options.withEvent._BMOriginalTarget = cell.node;
|
|
3961
4054
|
|
|
4055
|
+
// Acquire focus if not already owned
|
|
4056
|
+
if (document.activeElement != this.node && this._supportsKeyboardNavigation) {
|
|
4057
|
+
this.node.focus();
|
|
4058
|
+
}
|
|
4059
|
+
|
|
3962
4060
|
// Forward this event to the delegate, giving it a chance to handle the event
|
|
3963
4061
|
var eventHandled = NO;
|
|
3964
4062
|
if (this.delegate && this.delegate.collectionViewCellWasDoubleClicked) {
|
|
@@ -3975,6 +4073,11 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
3975
4073
|
*/
|
|
3976
4074
|
cellWasLongClicked: function (cell, options) {
|
|
3977
4075
|
if (options && options.withEvent) options.withEvent._BMOriginalTarget = cell.node;
|
|
4076
|
+
|
|
4077
|
+
// Acquire focus if not already owned
|
|
4078
|
+
if (document.activeElement != this.node && this._supportsKeyboardNavigation) {
|
|
4079
|
+
this.node.focus();
|
|
4080
|
+
}
|
|
3978
4081
|
|
|
3979
4082
|
// Forward this event to the delegate, giving it a chance to handle the event
|
|
3980
4083
|
var eventHandled = NO;
|
|
@@ -4005,6 +4108,223 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
4005
4108
|
return eventHandled;
|
|
4006
4109
|
},
|
|
4007
4110
|
|
|
4111
|
+
|
|
4112
|
+
/************************************* HIGHLIGHT HANDLERS ********************************/
|
|
4113
|
+
|
|
4114
|
+
/**
|
|
4115
|
+
* An array that contains the registered keyboard navigation shortcuts.
|
|
4116
|
+
*/
|
|
4117
|
+
_keyboardNavigationShortcuts: undefined, // <[BMKeyboardShortcut]>
|
|
4118
|
+
|
|
4119
|
+
/**
|
|
4120
|
+
* @protected
|
|
4121
|
+
* Configures the keyboard shortcuts used by the collection view for highlighting.
|
|
4122
|
+
* Subclasses overriding this may invoke the superclass implementation to retain the default keyboard
|
|
4123
|
+
* shortcuts.
|
|
4124
|
+
*/
|
|
4125
|
+
configureKeyboardShortcuts() {
|
|
4126
|
+
// If the shortcuts have already been registered, do nothing
|
|
4127
|
+
if (this._keyboardNavigationShortcuts) return;
|
|
4128
|
+
|
|
4129
|
+
this._keyboardNavigationShortcuts = [];
|
|
4130
|
+
|
|
4131
|
+
// Register the arrow keys, which are used for highlighting
|
|
4132
|
+
this._keyboardNavigationShortcuts.push(BMKeyboardShortcut.keyboardShortcutWithKeyCode('ArrowLeft', {target: this, action: '_keyboardArrowPressedWithEvent'}));
|
|
4133
|
+
this._keyboardNavigationShortcuts.push(BMKeyboardShortcut.keyboardShortcutWithKeyCode('ArrowRight', {target: this, action: '_keyboardArrowPressedWithEvent'}));
|
|
4134
|
+
this._keyboardNavigationShortcuts.push(BMKeyboardShortcut.keyboardShortcutWithKeyCode('ArrowUp', {target: this, action: '_keyboardArrowPressedWithEvent'}));
|
|
4135
|
+
this._keyboardNavigationShortcuts.push(BMKeyboardShortcut.keyboardShortcutWithKeyCode('ArrowDown', {target: this, action: '_keyboardArrowPressedWithEvent'}));
|
|
4136
|
+
|
|
4137
|
+
// Register the shift + arrow keys, which are used for block selection
|
|
4138
|
+
this._keyboardNavigationShortcuts.push(BMKeyboardShortcut.keyboardShortcutWithKeyCode('ArrowLeft', {target: this, action: '_keyboardArrowPressedWithEvent', modifiers: [BMKeyboardShortcutModifier.Shift]}));
|
|
4139
|
+
this._keyboardNavigationShortcuts.push(BMKeyboardShortcut.keyboardShortcutWithKeyCode('ArrowRight', {target: this, action: '_keyboardArrowPressedWithEvent', modifiers: [BMKeyboardShortcutModifier.Shift]}));
|
|
4140
|
+
this._keyboardNavigationShortcuts.push(BMKeyboardShortcut.keyboardShortcutWithKeyCode('ArrowUp', {target: this, action: '_keyboardArrowPressedWithEvent', modifiers: [BMKeyboardShortcutModifier.Shift]}));
|
|
4141
|
+
this._keyboardNavigationShortcuts.push(BMKeyboardShortcut.keyboardShortcutWithKeyCode('ArrowDown', {target: this, action: '_keyboardArrowPressedWithEvent', modifiers: [BMKeyboardShortcutModifier.Shift]}));
|
|
4142
|
+
|
|
4143
|
+
this._keyboardNavigationShortcuts.forEach(k => this.registerKeyboardShortcut(k));
|
|
4144
|
+
},
|
|
4145
|
+
|
|
4146
|
+
/**
|
|
4147
|
+
* @protected
|
|
4148
|
+
* Removes the keyboard shortcuts used by the collection view for highlighting.
|
|
4149
|
+
* Subclasses overriding this should invoke the superclass implementation to remove the default keyboard
|
|
4150
|
+
* shortcuts.
|
|
4151
|
+
*/
|
|
4152
|
+
disableKeyboardShortcuts() {
|
|
4153
|
+
// If the shortcuts have already been removed, do nothing
|
|
4154
|
+
if (!this._keyboardNavigationShortcuts) return;
|
|
4155
|
+
|
|
4156
|
+
this._keyboardNavigationShortcuts.forEach(k => this.unregisterKeyboardShortcut(k));
|
|
4157
|
+
this._keyboardNavigationShortcuts = undefined;
|
|
4158
|
+
},
|
|
4159
|
+
|
|
4160
|
+
/**
|
|
4161
|
+
* Invoked when an arrow key is pressed on the keyboard while this collection view has keyboard focus.
|
|
4162
|
+
* @param event <KeyboardEvent> The keyboard event that triggered this action.
|
|
4163
|
+
*/
|
|
4164
|
+
_keyboardArrowPressedWithEvent(event) {
|
|
4165
|
+
switch (event.code) {
|
|
4166
|
+
case 'ArrowLeft':
|
|
4167
|
+
case 'ArrowUp':
|
|
4168
|
+
case 'ArrowRight':
|
|
4169
|
+
case 'ArrowDown':
|
|
4170
|
+
this.keyboardArrowPressed(event.code, {withEvent: event});
|
|
4171
|
+
break;
|
|
4172
|
+
}
|
|
4173
|
+
},
|
|
4174
|
+
|
|
4175
|
+
/**
|
|
4176
|
+
* The index path, if any, of the cell that is currently receiving keyboard focus.
|
|
4177
|
+
*
|
|
4178
|
+
* Setting this property to a valid index path will cause the relevant cell to become highlighted.
|
|
4179
|
+
* Additionally, setting this property to `undefined` will clear the highlighted cell.
|
|
4180
|
+
*/
|
|
4181
|
+
_highlightedIndexPath: undefined, // <BMIndexPath<T>, nullable>
|
|
4182
|
+
|
|
4183
|
+
get highlightedIndexPath() {
|
|
4184
|
+
return this._highlightedIndexPath;
|
|
4185
|
+
},
|
|
4186
|
+
|
|
4187
|
+
set highlightedIndexPath(indexPath) {
|
|
4188
|
+
this._highlightIndexPath(indexPath);
|
|
4189
|
+
},
|
|
4190
|
+
|
|
4191
|
+
/**
|
|
4192
|
+
* Highlights the given index path.
|
|
4193
|
+
* @param indexPath <BMIndexPath> The index path to highlight.
|
|
4194
|
+
* {
|
|
4195
|
+
* @param withEvent <UIEvent, nullable> The event that triggered this action, if any.
|
|
4196
|
+
* }
|
|
4197
|
+
*/
|
|
4198
|
+
_highlightIndexPath(indexPath, {withEvent: event} = {withEvent: undefined}) {
|
|
4199
|
+
const currentHighlight = this._highlightedIndexPath;
|
|
4200
|
+
|
|
4201
|
+
this._highlightedIndexPath = indexPath;
|
|
4202
|
+
|
|
4203
|
+
// Let the delegate know that the previous cell was dehilighted if any cell was highlighted
|
|
4204
|
+
if (currentHighlight) {
|
|
4205
|
+
if (this.delegate && this.delegate.collectionViewDidDehighlightCellAtIndexPath) {
|
|
4206
|
+
this.delegate.collectionViewDidDehighlightCellAtIndexPath(this, currentHighlight);
|
|
4207
|
+
}
|
|
4208
|
+
}
|
|
4209
|
+
|
|
4210
|
+
if (indexPath) {
|
|
4211
|
+
const cell = this.cellAtIndexPath(indexPath);
|
|
4212
|
+
|
|
4213
|
+
// If the newly highlighted index path isn't visible on screen, attempt to scroll to it
|
|
4214
|
+
if (!cell || !cell._attributes.frame.intersectsRect(this.visibleBounds)) {
|
|
4215
|
+
let shouldScroll = YES;
|
|
4216
|
+
|
|
4217
|
+
if (this.delegate && this.delegate.collectionViewShouldScrollToHighlightedCellAtIndexPath) {
|
|
4218
|
+
shouldScroll = this.delegate.collectionViewShouldScrollToHighlightedCellAtIndexPath(this, indexPath);
|
|
4219
|
+
}
|
|
4220
|
+
|
|
4221
|
+
if (shouldScroll) {
|
|
4222
|
+
this.scrollToCellAtIndexPath(indexPath, {animated: YES});
|
|
4223
|
+
}
|
|
4224
|
+
}
|
|
4225
|
+
|
|
4226
|
+
// If the cell was highlighted, prevent the default action for keyboard events
|
|
4227
|
+
if (event && event instanceof KeyboardEvent) {
|
|
4228
|
+
event.preventDefault();
|
|
4229
|
+
}
|
|
4230
|
+
}
|
|
4231
|
+
|
|
4232
|
+
if (this.delegate && this.delegate.collectionViewDidHighlightCellAtIndexPath) {
|
|
4233
|
+
this.delegate.collectionViewDidHighlightCellAtIndexPath(this, indexPath, {withEvent: event});
|
|
4234
|
+
}
|
|
4235
|
+
},
|
|
4236
|
+
|
|
4237
|
+
/**
|
|
4238
|
+
* Checks if the cell at the specified index path is highlighted.
|
|
4239
|
+
* @param indexPath <BMIndexPath<T>> The index path. This will be loosely compared to the highlighted index path.
|
|
4240
|
+
* @return <Boolean> YES if the cell is highlighted, NO otherwise.
|
|
4241
|
+
*/
|
|
4242
|
+
isCellAtIndexPathHighlighted(indexPath) {
|
|
4243
|
+
if (!this._highlightedIndexPath) return NO;
|
|
4244
|
+
|
|
4245
|
+
return this._highlightedIndexPath.isLooselyEqualToIndexPath(indexPath, {usingComparator: this.identityComparator});
|
|
4246
|
+
},
|
|
4247
|
+
|
|
4248
|
+
/**
|
|
4249
|
+
* Invoked when an arrow is pressed while this collection view has keyboard focus.
|
|
4250
|
+
* Highlights the index path to the specified direction of the currently highlighted index path.
|
|
4251
|
+
* @param arrow <String> The key code of the keyboard arrow that was pressed.
|
|
4252
|
+
* {
|
|
4253
|
+
* @param withEvent <KeyboardEvent> The event that triggerred this action.
|
|
4254
|
+
* }
|
|
4255
|
+
*/
|
|
4256
|
+
keyboardArrowPressed(arrow, args) {
|
|
4257
|
+
let nextIndexPath = this._highlightedIndexPath;
|
|
4258
|
+
const event = args && args.withEvent;
|
|
4259
|
+
|
|
4260
|
+
if (event) {
|
|
4261
|
+
// If this triggered by an event, ask the delegate if collection view should process this event
|
|
4262
|
+
let canProcess = YES;
|
|
4263
|
+
|
|
4264
|
+
if (this.delegate && this.delegate.collectionViewShouldHighlightCellForArrowKey) {
|
|
4265
|
+
canProcess = this.delegate.collectionViewShouldHighlightCellForArrowKey(this, arrow, {withEvent: event});
|
|
4266
|
+
}
|
|
4267
|
+
|
|
4268
|
+
// If the delegate disallows processing this event, stop
|
|
4269
|
+
if (!canProcess) {
|
|
4270
|
+
return;
|
|
4271
|
+
}
|
|
4272
|
+
}
|
|
4273
|
+
|
|
4274
|
+
do {
|
|
4275
|
+
const startingIndexPath = nextIndexPath;
|
|
4276
|
+
|
|
4277
|
+
if (!nextIndexPath) {
|
|
4278
|
+
// If no index path is currently highlighted, highlight the first index path in the data set.
|
|
4279
|
+
nextIndexPath = this.layout.firstIndexPath();
|
|
4280
|
+
}
|
|
4281
|
+
else {
|
|
4282
|
+
// Otherwise highlight the next appropriate index path.
|
|
4283
|
+
switch (arrow) {
|
|
4284
|
+
case 'ArrowLeft':
|
|
4285
|
+
nextIndexPath = this.layout.indexPathToTheLeftOfIndexPath(nextIndexPath);
|
|
4286
|
+
break;
|
|
4287
|
+
case 'ArrowUp':
|
|
4288
|
+
nextIndexPath = this.layout.indexPathAboveIndexPath(nextIndexPath);
|
|
4289
|
+
break;
|
|
4290
|
+
case 'ArrowRight':
|
|
4291
|
+
nextIndexPath = this.layout.indexPathToTheRightOfIndexPath(nextIndexPath);
|
|
4292
|
+
break;
|
|
4293
|
+
case 'ArrowDown':
|
|
4294
|
+
nextIndexPath = this.layout.indexPathBelowIndexPath(nextIndexPath);
|
|
4295
|
+
break;
|
|
4296
|
+
}
|
|
4297
|
+
}
|
|
4298
|
+
|
|
4299
|
+
// If no index path could be found, don't take any action
|
|
4300
|
+
if (!nextIndexPath) return;
|
|
4301
|
+
|
|
4302
|
+
// Check if this index path can be highlighted
|
|
4303
|
+
let canHighlight = YES;
|
|
4304
|
+
if (this.delegate && this.delegate.collectionViewCanHighlightCellAtIndexPath) {
|
|
4305
|
+
canHighlight = this.delegate.collectionViewCanHighlightCellAtIndexPath(this, nextIndexPath, {withEvent: event});
|
|
4306
|
+
}
|
|
4307
|
+
|
|
4308
|
+
if (canHighlight) {
|
|
4309
|
+
// If the index path can be highlighted continue
|
|
4310
|
+
break;
|
|
4311
|
+
}
|
|
4312
|
+
else {
|
|
4313
|
+
// If the index path can't be highlighted and no appropriate next index path exists don't take any action
|
|
4314
|
+
if (startingIndexPath.isEqualToIndexPath(nextIndexPath, {usingComparator: this.identityComparator})) {
|
|
4315
|
+
return;
|
|
4316
|
+
}
|
|
4317
|
+
}
|
|
4318
|
+
|
|
4319
|
+
// Otherwise look for the next index path
|
|
4320
|
+
} while (nextIndexPath);
|
|
4321
|
+
|
|
4322
|
+
// If this keyboard arrow would highlight the same index path, don't take any action
|
|
4323
|
+
if (nextIndexPath.isEqualToIndexPath(this._highlightedIndexPath, {usingComparator: this.identityComparator})) return;
|
|
4324
|
+
|
|
4325
|
+
// Highlight the index path
|
|
4326
|
+
this._highlightIndexPath(nextIndexPath, {withEvent: event});
|
|
4327
|
+
},
|
|
4008
4328
|
|
|
4009
4329
|
|
|
4010
4330
|
/************************************* SELECTION HANDLERS ********************************/
|
|
@@ -4061,7 +4381,7 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
4061
4381
|
},
|
|
4062
4382
|
|
|
4063
4383
|
/**
|
|
4064
|
-
* Invoked by the collection view during an update to refresh the index paths of the selected cells.
|
|
4384
|
+
* Invoked by the collection view during an update to refresh the index paths of the selected and highlighted cells.
|
|
4065
4385
|
* Index paths that are no longer in the data set will be removed and all other index paths will be updated
|
|
4066
4386
|
* to the correct section and row indexes.
|
|
4067
4387
|
*/
|
|
@@ -4075,6 +4395,10 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
4075
4395
|
|
|
4076
4396
|
if (indexPath) this._selectedIndexPaths.push(indexPath);
|
|
4077
4397
|
}
|
|
4398
|
+
|
|
4399
|
+
if (this._highlightedIndexPath) {
|
|
4400
|
+
this._highlightedIndexPath = this.dataSet.indexPathForObject(this._highlightedIndexPath.object);
|
|
4401
|
+
}
|
|
4078
4402
|
},
|
|
4079
4403
|
|
|
4080
4404
|
/**
|
|
@@ -5330,10 +5654,10 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
5330
5654
|
* Optionally, this scrolling may be animated.
|
|
5331
5655
|
* @param indexPath <BMIndexPath<T>> The index path of the cell to scroll to.
|
|
5332
5656
|
* {
|
|
5333
|
-
* @param withVerticalGravity <BMCollectionViewScrollingGravityVertical, nullable> Defaults to
|
|
5657
|
+
* @param withVerticalGravity <BMCollectionViewScrollingGravityVertical, nullable> Defaults to a value depending on where the cell is positioned. The scroll gravity to use,
|
|
5334
5658
|
* which controls where on the screen the cell should appear after the scrolling operation
|
|
5335
5659
|
* completes.
|
|
5336
|
-
* @param horizontalGravity <BMCollectionViewScrollingGravityHorizontal, nullable> Defaults to
|
|
5660
|
+
* @param horizontalGravity <BMCollectionViewScrollingGravityHorizontal, nullable> Defaults to a value depending on where the cell is positioned. The scroll gravity to use,
|
|
5337
5661
|
* which controls where on the screen the cell should appear after the scrolling operation
|
|
5338
5662
|
* completes.
|
|
5339
5663
|
* @param animated <Boolean, nullable> Defaults to `NO`. If set to `YES`, the scroll will be animated, otherwise it will be
|
|
@@ -5343,10 +5667,40 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
5343
5667
|
*/
|
|
5344
5668
|
scrollToCellAtIndexPath: function (indexPath, options) {
|
|
5345
5669
|
var rect = this._layout.rectWithScrollingPositionOfCellAtIndexPath(indexPath);
|
|
5670
|
+
let visibleBounds;
|
|
5346
5671
|
|
|
5347
5672
|
if (rect) {
|
|
5348
|
-
var verticalGravity = (options && options.withVerticalGravity)
|
|
5349
|
-
var horizontalGravity = (options && options.horizontalGravity)
|
|
5673
|
+
var verticalGravity = (options && options.withVerticalGravity);
|
|
5674
|
+
var horizontalGravity = (options && options.horizontalGravity);
|
|
5675
|
+
|
|
5676
|
+
if (!verticalGravity) {
|
|
5677
|
+
visibleBounds = this.visibleBounds;
|
|
5678
|
+
|
|
5679
|
+
if (rect.origin.y > visibleBounds.bottom) {
|
|
5680
|
+
verticalGravity = BMCollectionViewScrollingGravityVertical.Bottom;
|
|
5681
|
+
}
|
|
5682
|
+
else if (rect.bottom < visibleBounds.origin.y) {
|
|
5683
|
+
verticalGravity = BMCollectionViewScrollingGravityVertical.Top;
|
|
5684
|
+
}
|
|
5685
|
+
else {
|
|
5686
|
+
verticalGravity = BMCollectionViewScrollingGravityVertical.Center;
|
|
5687
|
+
}
|
|
5688
|
+
}
|
|
5689
|
+
|
|
5690
|
+
if (!horizontalGravity) {
|
|
5691
|
+
visibleBounds = visibleBounds || this.visibleBounds;
|
|
5692
|
+
|
|
5693
|
+
if (rect.origin.x > visibleBounds.right) {
|
|
5694
|
+
horizontalGravity = BMCollectionViewScrollingGravityHorizontal.Right;
|
|
5695
|
+
}
|
|
5696
|
+
else if (rect.right < visibleBounds.origin.x) {
|
|
5697
|
+
horizontalGravity = BMCollectionViewScrollingGravityHorizontal.Left;
|
|
5698
|
+
}
|
|
5699
|
+
else {
|
|
5700
|
+
horizontalGravity = BMCollectionViewScrollingGravityHorizontal.Center;
|
|
5701
|
+
}
|
|
5702
|
+
}
|
|
5703
|
+
|
|
5350
5704
|
var animated = options && options.animated;
|
|
5351
5705
|
return this.scrollToRect(rect, {withVerticalGravity: verticalGravity, horizontalGravity: horizontalGravity, animated: animated});
|
|
5352
5706
|
}
|
|
@@ -5360,10 +5714,10 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
5360
5714
|
* @param identifier <String> The supplementary view's type identifier.
|
|
5361
5715
|
* {
|
|
5362
5716
|
* @param atIndexPath <BMIndexPath<T>> The index path of the supplementary view to scroll to.
|
|
5363
|
-
* @param verticalGravity <BMCollectionViewScrollingGravityVertical, nullable> Defaults to
|
|
5717
|
+
* @param verticalGravity <BMCollectionViewScrollingGravityVertical, nullable> Defaults to a value depending on where the cell is positioned. The scroll gravity to use,
|
|
5364
5718
|
* which controls where on the screen the cell should appear after the scrolling operation
|
|
5365
5719
|
* completes.
|
|
5366
|
-
* @param horizontalGravity <BMCollectionViewScrollingGravityHorizontal, nullable> Defaults to
|
|
5720
|
+
* @param horizontalGravity <BMCollectionViewScrollingGravityHorizontal, nullable> Defaults to a value depending on where the cell is positioned. The scroll gravity to use,
|
|
5367
5721
|
* which controls where on the screen the cell should appear after the scrolling operation
|
|
5368
5722
|
* completes.
|
|
5369
5723
|
* @param animated <Boolean, nullable> Defaults to NO. If set to YES, the scroll will be animated, otherwise it will be
|
|
@@ -5373,10 +5727,40 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
5373
5727
|
*/
|
|
5374
5728
|
scrollToSupplementaryViewWithIdentifier: function (identifier, options) {
|
|
5375
5729
|
var rect = this._layout.rectWithScrollingPositionOfSupplementaryViewWithIdentifier(identifier, {atIndexPath: options.atIndexPath});
|
|
5730
|
+
let visibleBounds;
|
|
5376
5731
|
|
|
5377
5732
|
if (rect) {
|
|
5378
|
-
var verticalGravity = options.verticalGravity
|
|
5379
|
-
var horizontalGravity = options.horizontalGravity
|
|
5733
|
+
var verticalGravity = options.verticalGravity;
|
|
5734
|
+
var horizontalGravity = options.horizontalGravity;
|
|
5735
|
+
|
|
5736
|
+
if (!verticalGravity) {
|
|
5737
|
+
visibleBounds = this.visibleBounds;
|
|
5738
|
+
|
|
5739
|
+
if (rect.origin.y > visibleBounds.bottom) {
|
|
5740
|
+
verticalGravity = BMCollectionViewScrollingGravityVertical.Bottom;
|
|
5741
|
+
}
|
|
5742
|
+
else if (rect.bottom < visibleBounds.origin.y) {
|
|
5743
|
+
verticalGravity = BMCollectionViewScrollingGravityVertical.Top;
|
|
5744
|
+
}
|
|
5745
|
+
else {
|
|
5746
|
+
verticalGravity = BMCollectionViewScrollingGravityVertical.Center;
|
|
5747
|
+
}
|
|
5748
|
+
}
|
|
5749
|
+
|
|
5750
|
+
if (!horizontalGravity) {
|
|
5751
|
+
visibleBounds = visibleBounds || this.visibleBounds;
|
|
5752
|
+
|
|
5753
|
+
if (rect.origin.x > visibleBounds.right) {
|
|
5754
|
+
horizontalGravity = BMCollectionViewScrollingGravityHorizontal.Right;
|
|
5755
|
+
}
|
|
5756
|
+
else if (rect.right < visibleBounds.origin.x) {
|
|
5757
|
+
horizontalGravity = BMCollectionViewScrollingGravityHorizontal.Left;
|
|
5758
|
+
}
|
|
5759
|
+
else {
|
|
5760
|
+
horizontalGravity = BMCollectionViewScrollingGravityHorizontal.Center;
|
|
5761
|
+
}
|
|
5762
|
+
}
|
|
5763
|
+
|
|
5380
5764
|
var animated = options.animated;
|
|
5381
5765
|
return this.scrollToRect(rect, {withVerticalGravity: verticalGravity, horizontalGravity: horizontalGravity, animated: animated});
|
|
5382
5766
|
}
|
|
@@ -5408,7 +5792,7 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
5408
5792
|
offset.y = rect.origin.y + rect.size.height / 2 - this.frame.size.height / 2;
|
|
5409
5793
|
}
|
|
5410
5794
|
else if (options.withVerticalGravity == BMCollectionViewScrollingGravityVertical.Bottom) {
|
|
5411
|
-
offset.y = rect.origin.y + rect.size.height - this.frame.size.height
|
|
5795
|
+
offset.y = rect.origin.y + rect.size.height - this.frame.size.height;
|
|
5412
5796
|
}
|
|
5413
5797
|
|
|
5414
5798
|
// Then the horizontal X offset
|
|
@@ -5419,7 +5803,7 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
5419
5803
|
offset.x = rect.origin.x + rect.size.width / 2 - this.frame.size.width / 2;
|
|
5420
5804
|
}
|
|
5421
5805
|
else if (options.withVerticalGravity == BMCollectionViewScrollingGravityHorizontal.Right) {
|
|
5422
|
-
offset.x = rect.origin.x + rect.size.width - this.frame.size.width
|
|
5806
|
+
offset.x = rect.origin.x + rect.size.width - this.frame.size.width;
|
|
5423
5807
|
}
|
|
5424
5808
|
|
|
5425
5809
|
// Scroll to the offset point
|
|
@@ -5428,41 +5812,6 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
|
|
|
5428
5812
|
return BMAnimateWithBlock(_ => {
|
|
5429
5813
|
self.scrollOffset = offset;
|
|
5430
5814
|
}, {duration: 300});
|
|
5431
|
-
|
|
5432
|
-
/*
|
|
5433
|
-
// Scrolling is performed differently based on whether iScroll is used or not
|
|
5434
|
-
if (this.iScroll) {
|
|
5435
|
-
this.iScroll.scrollTo(-(offset.x | 0), -(offset.y | 0), 300, IScroll.utils.ease.quadratic);
|
|
5436
|
-
|
|
5437
|
-
// For iScroll, the layout should be refreshed after the animation
|
|
5438
|
-
var self = this;
|
|
5439
|
-
window.setTimeout(function () {
|
|
5440
|
-
self._handleNewScrollFromEvent({x: offset.x, y: offset.y});
|
|
5441
|
-
}, 316);
|
|
5442
|
-
}
|
|
5443
|
-
else {
|
|
5444
|
-
// For native scrolling, jQuery animations are used instead
|
|
5445
|
-
var startingPoint = this.scrollOffset.copy();
|
|
5446
|
-
var targetPoint = offset;
|
|
5447
|
-
var self = this;
|
|
5448
|
-
this._container.velocity({
|
|
5449
|
-
tween: 1
|
|
5450
|
-
}, {
|
|
5451
|
-
duration: 300,
|
|
5452
|
-
queue: NO,
|
|
5453
|
-
progress: function (elements, completion) {
|
|
5454
|
-
self._container[0].scrollLeft = ((targetPoint.x - startingPoint.x) * completion + startingPoint.x) | 0;
|
|
5455
|
-
self._container[0].scrollTop = ((targetPoint.y - startingPoint.y) * completion + startingPoint.y) | 0;
|
|
5456
|
-
|
|
5457
|
-
self._handleNewScrollFromEvent(null);
|
|
5458
|
-
},
|
|
5459
|
-
complete: function () {
|
|
5460
|
-
|
|
5461
|
-
self._handleNewScrollFromEvent(null);
|
|
5462
|
-
}
|
|
5463
|
-
});
|
|
5464
|
-
}
|
|
5465
|
-
*/
|
|
5466
5815
|
}
|
|
5467
5816
|
else {
|
|
5468
5817
|
// Scrolling is performed differently based on whether iScroll is used or not
|