Merge pull request #13902 from MoonE/type-safe-collection
Improve Collection type-safety
This commit is contained in:
@@ -14,6 +14,10 @@ The `toStringHDMS` function from the `ol/coordinate.js` module now formats longi
|
|||||||
|
|
||||||
The default intervals now align with integer minutes and seconds better suited to the default label formatter. If formatting in decimal degrees you may wish to specify custom intervals suited to that format.
|
The default intervals now align with integer minutes and seconds better suited to the default label formatter. If formatting in decimal degrees you may wish to specify custom intervals suited to that format.
|
||||||
|
|
||||||
|
#### ol/Collection
|
||||||
|
|
||||||
|
Inserting with `setAt` or `insertAt` beyond the current length used to create a sparse Collection with `undefined` inserted for any missing indexes. This will now throw an error instead.
|
||||||
|
|
||||||
### 6.15.0
|
### 6.15.0
|
||||||
|
|
||||||
#### Deprecated `tilePixelRatio` option for data tile sources.
|
#### Deprecated `tilePixelRatio` option for data tile sources.
|
||||||
|
|||||||
+41
-27
@@ -18,37 +18,39 @@ const Property = {
|
|||||||
* @classdesc
|
* @classdesc
|
||||||
* Events emitted by {@link module:ol/Collection~Collection} instances are instances of this
|
* Events emitted by {@link module:ol/Collection~Collection} instances are instances of this
|
||||||
* type.
|
* type.
|
||||||
|
* @template T
|
||||||
*/
|
*/
|
||||||
export class CollectionEvent extends Event {
|
export class CollectionEvent extends Event {
|
||||||
/**
|
/**
|
||||||
* @param {import("./CollectionEventType.js").default} type Type.
|
* @param {import("./CollectionEventType.js").default} type Type.
|
||||||
* @param {*} [opt_element] Element.
|
* @param {T} element Element.
|
||||||
* @param {number} [opt_index] The index of the added or removed element.
|
* @param {number} index The index of the added or removed element.
|
||||||
*/
|
*/
|
||||||
constructor(type, opt_element, opt_index) {
|
constructor(type, element, index) {
|
||||||
super(type);
|
super(type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The element that is added to or removed from the collection.
|
* The element that is added to or removed from the collection.
|
||||||
* @type {*}
|
* @type {T}
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
this.element = opt_element;
|
this.element = element;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The index of the added or removed element.
|
* The index of the added or removed element.
|
||||||
* @type {number}
|
* @type {number}
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
this.index = opt_index;
|
this.index = index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
|
* @template T
|
||||||
* @template Return
|
* @template Return
|
||||||
* @typedef {import("./Observable").OnSignature<import("./Observable").EventTypes, import("./events/Event.js").default, Return> &
|
* @typedef {import("./Observable").OnSignature<import("./Observable").EventTypes, import("./events/Event.js").default, Return> &
|
||||||
* import("./Observable").OnSignature<import("./ObjectEventType").Types|'change:length', import("./Object").ObjectEvent, Return> &
|
* import("./Observable").OnSignature<import("./ObjectEventType").Types|'change:length', import("./Object").ObjectEvent, Return> &
|
||||||
* import("./Observable").OnSignature<'add'|'remove', CollectionEvent, Return> &
|
* import("./Observable").OnSignature<'add'|'remove', CollectionEvent<T>, Return> &
|
||||||
* import("./Observable").CombinedOnSignature<import("./Observable").EventTypes|import("./ObjectEventType").Types|
|
* import("./Observable").CombinedOnSignature<import("./Observable").EventTypes|import("./ObjectEventType").Types|
|
||||||
* 'change:length'|'add'|'remove',Return>} CollectionOnSignature
|
* 'change:length'|'add'|'remove',Return>} CollectionOnSignature
|
||||||
*/
|
*/
|
||||||
@@ -81,17 +83,17 @@ class Collection extends BaseObject {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* @type {CollectionOnSignature<import("./events").EventsKey>}
|
* @type {CollectionOnSignature<T, import("./events").EventsKey>}
|
||||||
*/
|
*/
|
||||||
this.on;
|
this.on;
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* @type {CollectionOnSignature<import("./events").EventsKey>}
|
* @type {CollectionOnSignature<T, import("./events").EventsKey>}
|
||||||
*/
|
*/
|
||||||
this.once;
|
this.once;
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* @type {CollectionOnSignature<void>}
|
* @type {CollectionOnSignature<T, void>}
|
||||||
*/
|
*/
|
||||||
this.un;
|
this.un;
|
||||||
|
|
||||||
@@ -195,6 +197,9 @@ class Collection extends BaseObject {
|
|||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
insertAt(index, elem) {
|
insertAt(index, elem) {
|
||||||
|
if (index < 0 || index > this.getLength()) {
|
||||||
|
throw new Error('Index out of bounds: ' + index);
|
||||||
|
}
|
||||||
if (this.unique_) {
|
if (this.unique_) {
|
||||||
this.assertUnique_(elem);
|
this.assertUnique_(elem);
|
||||||
}
|
}
|
||||||
@@ -254,11 +259,16 @@ class Collection extends BaseObject {
|
|||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
removeAt(index) {
|
removeAt(index) {
|
||||||
|
if (index < 0 || index >= this.getLength()) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
const prev = this.array_[index];
|
const prev = this.array_[index];
|
||||||
this.array_.splice(index, 1);
|
this.array_.splice(index, 1);
|
||||||
this.updateLength_();
|
this.updateLength_();
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new CollectionEvent(CollectionEventType.REMOVE, prev, index)
|
/** @type {CollectionEvent<T>} */ (
|
||||||
|
new CollectionEvent(CollectionEventType.REMOVE, prev, index)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
return prev;
|
return prev;
|
||||||
}
|
}
|
||||||
@@ -271,24 +281,28 @@ class Collection extends BaseObject {
|
|||||||
*/
|
*/
|
||||||
setAt(index, elem) {
|
setAt(index, elem) {
|
||||||
const n = this.getLength();
|
const n = this.getLength();
|
||||||
if (index < n) {
|
if (index >= n) {
|
||||||
if (this.unique_) {
|
|
||||||
this.assertUnique_(elem, index);
|
|
||||||
}
|
|
||||||
const prev = this.array_[index];
|
|
||||||
this.array_[index] = elem;
|
|
||||||
this.dispatchEvent(
|
|
||||||
new CollectionEvent(CollectionEventType.REMOVE, prev, index)
|
|
||||||
);
|
|
||||||
this.dispatchEvent(
|
|
||||||
new CollectionEvent(CollectionEventType.ADD, elem, index)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
for (let j = n; j < index; ++j) {
|
|
||||||
this.insertAt(j, undefined);
|
|
||||||
}
|
|
||||||
this.insertAt(index, elem);
|
this.insertAt(index, elem);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
if (index < 0) {
|
||||||
|
throw new Error('Index out of bounds: ' + index);
|
||||||
|
}
|
||||||
|
if (this.unique_) {
|
||||||
|
this.assertUnique_(elem, index);
|
||||||
|
}
|
||||||
|
const prev = this.array_[index];
|
||||||
|
this.array_[index] = elem;
|
||||||
|
this.dispatchEvent(
|
||||||
|
/** @type {CollectionEvent<T>} */ (
|
||||||
|
new CollectionEvent(CollectionEventType.REMOVE, prev, index)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
this.dispatchEvent(
|
||||||
|
/** @type {CollectionEvent<T>} */ (
|
||||||
|
new CollectionEvent(CollectionEventType.ADD, elem, index)
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+19
-16
@@ -439,7 +439,7 @@ class PluggableMap extends BaseObject {
|
|||||||
this.controls.addEventListener(
|
this.controls.addEventListener(
|
||||||
CollectionEventType.ADD,
|
CollectionEventType.ADD,
|
||||||
/**
|
/**
|
||||||
* @param {import("./Collection.js").CollectionEvent} event CollectionEvent.
|
* @param {import("./Collection.js").CollectionEvent<import("./control/Control.js").default>} event CollectionEvent
|
||||||
*/
|
*/
|
||||||
function (event) {
|
function (event) {
|
||||||
event.element.setMap(this);
|
event.element.setMap(this);
|
||||||
@@ -449,7 +449,7 @@ class PluggableMap extends BaseObject {
|
|||||||
this.controls.addEventListener(
|
this.controls.addEventListener(
|
||||||
CollectionEventType.REMOVE,
|
CollectionEventType.REMOVE,
|
||||||
/**
|
/**
|
||||||
* @param {import("./Collection.js").CollectionEvent} event CollectionEvent.
|
* @param {import("./Collection.js").CollectionEvent<import("./control/Control.js").default>} event CollectionEvent.
|
||||||
*/
|
*/
|
||||||
function (event) {
|
function (event) {
|
||||||
event.element.setMap(null);
|
event.element.setMap(null);
|
||||||
@@ -459,7 +459,7 @@ class PluggableMap extends BaseObject {
|
|||||||
this.interactions.addEventListener(
|
this.interactions.addEventListener(
|
||||||
CollectionEventType.ADD,
|
CollectionEventType.ADD,
|
||||||
/**
|
/**
|
||||||
* @param {import("./Collection.js").CollectionEvent} event CollectionEvent.
|
* @param {import("./Collection.js").CollectionEvent<import("./interaction/Interaction.js").default>} event CollectionEvent.
|
||||||
*/
|
*/
|
||||||
function (event) {
|
function (event) {
|
||||||
event.element.setMap(this);
|
event.element.setMap(this);
|
||||||
@@ -469,7 +469,7 @@ class PluggableMap extends BaseObject {
|
|||||||
this.interactions.addEventListener(
|
this.interactions.addEventListener(
|
||||||
CollectionEventType.REMOVE,
|
CollectionEventType.REMOVE,
|
||||||
/**
|
/**
|
||||||
* @param {import("./Collection.js").CollectionEvent} event CollectionEvent.
|
* @param {import("./Collection.js").CollectionEvent<import("./interaction/Interaction.js").default>} event CollectionEvent.
|
||||||
*/
|
*/
|
||||||
function (event) {
|
function (event) {
|
||||||
event.element.setMap(null);
|
event.element.setMap(null);
|
||||||
@@ -479,25 +479,20 @@ class PluggableMap extends BaseObject {
|
|||||||
this.overlays_.addEventListener(
|
this.overlays_.addEventListener(
|
||||||
CollectionEventType.ADD,
|
CollectionEventType.ADD,
|
||||||
/**
|
/**
|
||||||
* @param {import("./Collection.js").CollectionEvent} event CollectionEvent.
|
* @param {import("./Collection.js").CollectionEvent<import("./Overlay.js").default>} event CollectionEvent.
|
||||||
*/
|
*/
|
||||||
function (event) {
|
function (event) {
|
||||||
this.addOverlayInternal_(
|
this.addOverlayInternal_(event.element);
|
||||||
/** @type {import("./Overlay.js").default} */ (event.element)
|
|
||||||
);
|
|
||||||
}.bind(this)
|
}.bind(this)
|
||||||
);
|
);
|
||||||
|
|
||||||
this.overlays_.addEventListener(
|
this.overlays_.addEventListener(
|
||||||
CollectionEventType.REMOVE,
|
CollectionEventType.REMOVE,
|
||||||
/**
|
/**
|
||||||
* @param {import("./Collection.js").CollectionEvent} event CollectionEvent.
|
* @param {import("./Collection.js").CollectionEvent<import("./Overlay.js").default>} event CollectionEvent.
|
||||||
*/
|
*/
|
||||||
function (event) {
|
function (event) {
|
||||||
const overlay = /** @type {import("./Overlay.js").default} */ (
|
const id = event.element.getId();
|
||||||
event.element
|
|
||||||
);
|
|
||||||
const id = overlay.getId();
|
|
||||||
if (id !== undefined) {
|
if (id !== undefined) {
|
||||||
delete this.overlayIdIndex_[id.toString()];
|
delete this.overlayIdIndex_[id.toString()];
|
||||||
}
|
}
|
||||||
@@ -1709,7 +1704,12 @@ function createOptionsInternal(options) {
|
|||||||
options.layers &&
|
options.layers &&
|
||||||
typeof (/** @type {?} */ (options.layers).getLayers) === 'function'
|
typeof (/** @type {?} */ (options.layers).getLayers) === 'function'
|
||||||
? /** @type {LayerGroup} */ (options.layers)
|
? /** @type {LayerGroup} */ (options.layers)
|
||||||
: new LayerGroup({layers: /** @type {Collection} */ (options.layers)});
|
: new LayerGroup({
|
||||||
|
layers:
|
||||||
|
/** @type {Collection<import("./layer/Base.js").default>|Array<import("./layer/Base.js").default>} */ (
|
||||||
|
options.layers
|
||||||
|
),
|
||||||
|
});
|
||||||
values[MapProperty.LAYERGROUP] = layerGroup;
|
values[MapProperty.LAYERGROUP] = layerGroup;
|
||||||
|
|
||||||
values[MapProperty.TARGET] = options.target;
|
values[MapProperty.TARGET] = options.target;
|
||||||
@@ -1717,6 +1717,7 @@ function createOptionsInternal(options) {
|
|||||||
values[MapProperty.VIEW] =
|
values[MapProperty.VIEW] =
|
||||||
options.view instanceof View ? options.view : new View();
|
options.view instanceof View ? options.view : new View();
|
||||||
|
|
||||||
|
/** @type {Collection<import("./control/Control.js").default>} */
|
||||||
let controls;
|
let controls;
|
||||||
if (options.controls !== undefined) {
|
if (options.controls !== undefined) {
|
||||||
if (Array.isArray(options.controls)) {
|
if (Array.isArray(options.controls)) {
|
||||||
@@ -1726,10 +1727,11 @@ function createOptionsInternal(options) {
|
|||||||
typeof (/** @type {?} */ (options.controls).getArray) === 'function',
|
typeof (/** @type {?} */ (options.controls).getArray) === 'function',
|
||||||
47
|
47
|
||||||
); // Expected `controls` to be an array or an `import("./Collection.js").Collection`
|
); // Expected `controls` to be an array or an `import("./Collection.js").Collection`
|
||||||
controls = /** @type {Collection} */ (options.controls);
|
controls = options.controls;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @type {Collection<import("./interaction/Interaction").default>} */
|
||||||
let interactions;
|
let interactions;
|
||||||
if (options.interactions !== undefined) {
|
if (options.interactions !== undefined) {
|
||||||
if (Array.isArray(options.interactions)) {
|
if (Array.isArray(options.interactions)) {
|
||||||
@@ -1740,10 +1742,11 @@ function createOptionsInternal(options) {
|
|||||||
'function',
|
'function',
|
||||||
48
|
48
|
||||||
); // Expected `interactions` to be an array or an `import("./Collection.js").Collection`
|
); // Expected `interactions` to be an array or an `import("./Collection.js").Collection`
|
||||||
interactions = /** @type {Collection} */ (options.interactions);
|
interactions = options.interactions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @type {Collection<import("./Overlay.js").default>} */
|
||||||
let overlays;
|
let overlays;
|
||||||
if (options.overlays !== undefined) {
|
if (options.overlays !== undefined) {
|
||||||
if (Array.isArray(options.overlays)) {
|
if (Array.isArray(options.overlays)) {
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ export {default as ZoomToExtent} from './control/ZoomToExtent.js';
|
|||||||
export function defaults(opt_options) {
|
export function defaults(opt_options) {
|
||||||
const options = opt_options ? opt_options : {};
|
const options = opt_options ? opt_options : {};
|
||||||
|
|
||||||
|
/** @type {Collection<import("./control/Control.js").default>} */
|
||||||
const controls = new Collection();
|
const controls = new Collection();
|
||||||
|
|
||||||
const zoomControl = options.zoom !== undefined ? options.zoom : true;
|
const zoomControl = options.zoom !== undefined ? options.zoom : true;
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ export {default as Translate} from './interaction/Translate.js';
|
|||||||
export function defaults(opt_options) {
|
export function defaults(opt_options) {
|
||||||
const options = opt_options ? opt_options : {};
|
const options = opt_options ? opt_options : {};
|
||||||
|
|
||||||
|
/** @type {Collection<import("./interaction/Interaction.js").default>} */
|
||||||
const interactions = new Collection();
|
const interactions = new Collection();
|
||||||
|
|
||||||
const kinetic = new Kinetic(-0.005, 0.05, 100);
|
const kinetic = new Kinetic(-0.005, 0.05, 100);
|
||||||
|
|||||||
@@ -361,6 +361,7 @@ class Modify extends PointerInteraction {
|
|||||||
*/
|
*/
|
||||||
this.hitDetection_ = null;
|
this.hitDetection_ = null;
|
||||||
|
|
||||||
|
/** @type {Collection<Feature>} */
|
||||||
let features;
|
let features;
|
||||||
if (options.features) {
|
if (options.features) {
|
||||||
features = options.features;
|
features = options.features;
|
||||||
@@ -574,11 +575,11 @@ class Modify extends PointerInteraction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("../Collection.js").CollectionEvent} evt Event.
|
* @param {import("../Collection.js").CollectionEvent<Feature>} evt Event.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
handleFeatureAdd_(evt) {
|
handleFeatureAdd_(evt) {
|
||||||
this.addFeature_(/** @type {Feature} */ (evt.element));
|
this.addFeature_(evt.element);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -594,12 +595,11 @@ class Modify extends PointerInteraction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("../Collection.js").CollectionEvent} evt Event.
|
* @param {import("../Collection.js").CollectionEvent<Feature>} evt Event.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
handleFeatureRemove_(evt) {
|
handleFeatureRemove_(evt) {
|
||||||
const feature = /** @type {Feature} */ (evt.element);
|
this.removeFeature_(evt.element);
|
||||||
this.removeFeature_(feature);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ const SelectEventType = {
|
|||||||
* @property {boolean} [multi=false] A boolean that determines if the default
|
* @property {boolean} [multi=false] A boolean that determines if the default
|
||||||
* behaviour should select only single features or all (overlapping) features at
|
* behaviour should select only single features or all (overlapping) features at
|
||||||
* the clicked map position. The default of `false` means single select.
|
* the clicked map position. The default of `false` means single select.
|
||||||
* @property {import("../Collection.js").default<import("../Feature.js").default>} [features]
|
* @property {Collection<Feature>} [features]
|
||||||
* Collection where the interaction will place selected features. Optional. If
|
* Collection where the interaction will place selected features. Optional. If
|
||||||
* not set the interaction will create a collection. In any case the collection
|
* not set the interaction will create a collection. In any case the collection
|
||||||
* used by the interaction is returned by
|
* used by the interaction is returned by
|
||||||
@@ -245,7 +245,7 @@ class Select extends Interaction {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @type {import("../Collection.js").default}
|
* @type {Collection<Feature>}
|
||||||
*/
|
*/
|
||||||
this.features_ = options.features || new Collection();
|
this.features_ = options.features || new Collection();
|
||||||
|
|
||||||
@@ -290,7 +290,7 @@ class Select extends Interaction {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the selected features.
|
* Get the selected features.
|
||||||
* @return {import("../Collection.js").default<import("../Feature.js").default>} Features collection.
|
* @return {Collection<Feature>} Features collection.
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
getFeatures() {
|
getFeatures() {
|
||||||
@@ -367,7 +367,7 @@ class Select extends Interaction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("../Collection.js").CollectionEvent} evt Event.
|
* @param {import("../Collection.js").CollectionEvent<Feature>} evt Event.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
addFeature_(evt) {
|
addFeature_(evt) {
|
||||||
@@ -396,13 +396,12 @@ class Select extends Interaction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("../Collection.js").CollectionEvent} evt Event.
|
* @param {import("../Collection.js").CollectionEvent<Feature>} evt Event.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
removeFeature_(evt) {
|
removeFeature_(evt) {
|
||||||
const feature = evt.element;
|
|
||||||
if (this.style_) {
|
if (this.style_) {
|
||||||
this.restorePreviousStyle_(feature);
|
this.restorePreviousStyle_(evt.element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,7 +413,7 @@ class Select extends Interaction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("../Feature.js").default} feature Feature
|
* @param {Feature} feature Feature
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
applySelectedStyle_(feature) {
|
applySelectedStyle_(feature) {
|
||||||
@@ -426,7 +425,7 @@ class Select extends Interaction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("../Feature.js").default} feature Feature
|
* @param {Feature} feature Feature
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
restorePreviousStyle_(feature) {
|
restorePreviousStyle_(feature) {
|
||||||
@@ -450,7 +449,7 @@ class Select extends Interaction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("../Feature.js").default} feature Feature.
|
* @param {Feature} feature Feature.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
removeFeatureLayerAssociation_(feature) {
|
removeFeatureLayerAssociation_(feature) {
|
||||||
@@ -476,12 +475,12 @@ class Select extends Interaction {
|
|||||||
const features = this.getFeatures();
|
const features = this.getFeatures();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {Array<import("../Feature.js").default>}
|
* @type {Array<Feature>}
|
||||||
*/
|
*/
|
||||||
const deselected = [];
|
const deselected = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {Array<import("../Feature.js").default>}
|
* @type {Array<Feature>}
|
||||||
*/
|
*/
|
||||||
const selected = [];
|
const selected = [];
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ import {listen, unlistenByKey} from '../events.js';
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("../source/Vector.js").VectorSourceEvent|import("../Collection.js").CollectionEvent} evt Event.
|
* @param {import("../source/Vector.js").VectorSourceEvent|import("../Collection.js").CollectionEvent<import("../Feature.js").default>} evt Event.
|
||||||
* @return {import("../Feature.js").default} Feature.
|
* @return {import("../Feature.js").default} Feature.
|
||||||
*/
|
*/
|
||||||
function getFeatureFromEvent(evt) {
|
function getFeatureFromEvent(evt) {
|
||||||
@@ -55,11 +55,13 @@ function getFeatureFromEvent(evt) {
|
|||||||
return /** @type {import("../source/Vector.js").VectorSourceEvent} */ (evt)
|
return /** @type {import("../source/Vector.js").VectorSourceEvent} */ (evt)
|
||||||
.feature;
|
.feature;
|
||||||
} else if (
|
} else if (
|
||||||
/** @type {import("../Collection.js").CollectionEvent} */ (evt).element
|
/** @type {import("../Collection.js").CollectionEvent<import("../Feature.js").default>} */ (
|
||||||
|
evt
|
||||||
|
).element
|
||||||
) {
|
) {
|
||||||
return /** @type {import("../Feature.js").default} */ (
|
return /** @type {import("../Collection.js").CollectionEvent<import("../Feature.js").default>} */ (
|
||||||
/** @type {import("../Collection.js").CollectionEvent} */ (evt).element
|
evt
|
||||||
);
|
).element;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,6 +263,7 @@ class Snap extends PointerInteraction {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
getFeatures_() {
|
getFeatures_() {
|
||||||
|
/** @type {import("../Collection.js").default<import("../Feature.js").default>|Array<import("../Feature.js").default>} */
|
||||||
let features;
|
let features;
|
||||||
if (this.features_) {
|
if (this.features_) {
|
||||||
features = this.features_;
|
features = this.features_;
|
||||||
@@ -284,7 +287,7 @@ class Snap extends PointerInteraction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("../source/Vector.js").VectorSourceEvent|import("../Collection.js").CollectionEvent} evt Event.
|
* @param {import("../source/Vector.js").VectorSourceEvent|import("../Collection.js").CollectionEvent<import("../Feature.js").default>} evt Event.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
handleFeatureAdd_(evt) {
|
handleFeatureAdd_(evt) {
|
||||||
@@ -293,7 +296,7 @@ class Snap extends PointerInteraction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("../source/Vector.js").VectorSourceEvent|import("../Collection.js").CollectionEvent} evt Event.
|
* @param {import("../source/Vector.js").VectorSourceEvent|import("../Collection.js").CollectionEvent<import("../Feature.js").default>} evt Event.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
handleFeatureRemove_(evt) {
|
handleFeatureRemove_(evt) {
|
||||||
|
|||||||
+8
-12
@@ -66,7 +66,7 @@ export class GroupEvent extends Event {
|
|||||||
* visible.
|
* visible.
|
||||||
* @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will
|
* @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will
|
||||||
* be visible.
|
* be visible.
|
||||||
* @property {Array<import("./Base.js").default>|import("../Collection.js").default<import("./Base.js").default>} [layers] Child layers.
|
* @property {Array<import("./Base.js").default>|Collection<import("./Base.js").default>} [layers] Child layers.
|
||||||
* @property {Object<string, *>} [properties] Arbitrary observable properties. Can be accessed with `#get()` and `#set()`.
|
* @property {Object<string, *>} [properties] Arbitrary observable properties. Can be accessed with `#get()` and `#set()`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -214,26 +214,22 @@ class LayerGroup extends BaseLayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("../Collection.js").CollectionEvent} collectionEvent CollectionEvent.
|
* @param {import("../Collection.js").CollectionEvent<import("./Base.js").default>} collectionEvent CollectionEvent.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
handleLayersAdd_(collectionEvent) {
|
handleLayersAdd_(collectionEvent) {
|
||||||
const layer = /** @type {import("./Base.js").default} */ (
|
const layer = collectionEvent.element;
|
||||||
collectionEvent.element
|
|
||||||
);
|
|
||||||
this.registerLayerListeners_(layer);
|
this.registerLayerListeners_(layer);
|
||||||
this.dispatchEvent(new GroupEvent('addlayer', layer));
|
this.dispatchEvent(new GroupEvent('addlayer', layer));
|
||||||
this.changed();
|
this.changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("../Collection.js").CollectionEvent} collectionEvent CollectionEvent.
|
* @param {import("../Collection.js").CollectionEvent<import("./Base.js").default>} collectionEvent CollectionEvent.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
handleLayersRemove_(collectionEvent) {
|
handleLayersRemove_(collectionEvent) {
|
||||||
const layer = /** @type {import("./Base.js").default} */ (
|
const layer = collectionEvent.element;
|
||||||
collectionEvent.element
|
|
||||||
);
|
|
||||||
const key = getUid(layer);
|
const key = getUid(layer);
|
||||||
this.listenerKeys_[key].forEach(unlistenByKey);
|
this.listenerKeys_[key].forEach(unlistenByKey);
|
||||||
delete this.listenerKeys_[key];
|
delete this.listenerKeys_[key];
|
||||||
@@ -244,13 +240,13 @@ class LayerGroup extends BaseLayer {
|
|||||||
/**
|
/**
|
||||||
* Returns the {@link module:ol/Collection~Collection collection} of {@link module:ol/layer/Layer~Layer layers}
|
* Returns the {@link module:ol/Collection~Collection collection} of {@link module:ol/layer/Layer~Layer layers}
|
||||||
* in this group.
|
* in this group.
|
||||||
* @return {!import("../Collection.js").default<import("./Base.js").default>} Collection of
|
* @return {!Collection<import("./Base.js").default>} Collection of
|
||||||
* {@link module:ol/layer/Base~BaseLayer layers} that are part of this group.
|
* {@link module:ol/layer/Base~BaseLayer layers} that are part of this group.
|
||||||
* @observable
|
* @observable
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
getLayers() {
|
getLayers() {
|
||||||
return /** @type {!import("../Collection.js").default<import("./Base.js").default>} */ (
|
return /** @type {!Collection<import("./Base.js").default>} */ (
|
||||||
this.get(Property.LAYERS)
|
this.get(Property.LAYERS)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -258,7 +254,7 @@ class LayerGroup extends BaseLayer {
|
|||||||
/**
|
/**
|
||||||
* Set the {@link module:ol/Collection~Collection collection} of {@link module:ol/layer/Layer~Layer layers}
|
* Set the {@link module:ol/Collection~Collection collection} of {@link module:ol/layer/Layer~Layer layers}
|
||||||
* in this group.
|
* in this group.
|
||||||
* @param {!import("../Collection.js").default<import("./Base.js").default>} layers Collection of
|
* @param {!Collection<import("./Base.js").default>} layers Collection of
|
||||||
* {@link module:ol/layer/Base~BaseLayer layers} that are part of this group.
|
* {@link module:ol/layer/Base~BaseLayer layers} that are part of this group.
|
||||||
* @observable
|
* @observable
|
||||||
* @api
|
* @api
|
||||||
|
|||||||
+13
-23
@@ -72,7 +72,7 @@ export class VectorSourceEvent extends Event {
|
|||||||
/**
|
/**
|
||||||
* @typedef {Object} Options
|
* @typedef {Object} Options
|
||||||
* @property {import("./Source.js").AttributionLike} [attributions] Attributions.
|
* @property {import("./Source.js").AttributionLike} [attributions] Attributions.
|
||||||
* @property {Array<import("../Feature.js").default>|Collection<import("../Feature.js").default>} [features]
|
* @property {Array<import("../Feature.js").default<Geometry>>|Collection<import("../Feature.js").default<Geometry>>} [features]
|
||||||
* Features. If provided as {@link module:ol/Collection~Collection}, the features in the source
|
* Features. If provided as {@link module:ol/Collection~Collection}, the features in the source
|
||||||
* and the collection will stay in sync.
|
* and the collection will stay in sync.
|
||||||
* @property {import("../format/Feature.js").default} [format] The feature format used by the XHR
|
* @property {import("../format/Feature.js").default} [format] The feature format used by the XHR
|
||||||
@@ -159,6 +159,7 @@ export class VectorSourceEvent extends Event {
|
|||||||
* @property {boolean} [wrapX=true] Wrap the world horizontally. For vector editing across the
|
* @property {boolean} [wrapX=true] Wrap the world horizontally. For vector editing across the
|
||||||
* -180° and 180° meridians to work properly, this should be set to `false`. The
|
* -180° and 180° meridians to work properly, this should be set to `false`. The
|
||||||
* resulting geometry coordinates will then exceed the world bounds.
|
* resulting geometry coordinates will then exceed the world bounds.
|
||||||
|
* @template {import("../geom/Geometry.js").default} [Geometry=import("../geom/Geometry.js").default]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -173,7 +174,7 @@ export class VectorSourceEvent extends Event {
|
|||||||
*/
|
*/
|
||||||
class VectorSource extends Source {
|
class VectorSource extends Source {
|
||||||
/**
|
/**
|
||||||
* @param {Options} [opt_options] Vector source options.
|
* @param {Options<Geometry>} [opt_options] Vector source options.
|
||||||
*/
|
*/
|
||||||
constructor(opt_options) {
|
constructor(opt_options) {
|
||||||
const options = opt_options || {};
|
const options = opt_options || {};
|
||||||
@@ -296,17 +297,14 @@ class VectorSource extends Source {
|
|||||||
*/
|
*/
|
||||||
this.featuresCollection_ = null;
|
this.featuresCollection_ = null;
|
||||||
|
|
||||||
let collection, features;
|
/** @type {Collection<import("../Feature.js").default<Geometry>>} */
|
||||||
|
let collection;
|
||||||
|
/** @type {Array<import("../Feature.js").default<Geometry>>} */
|
||||||
|
let features;
|
||||||
if (Array.isArray(options.features)) {
|
if (Array.isArray(options.features)) {
|
||||||
features =
|
features = options.features;
|
||||||
/** @type {Array<import("../Feature.js").default<Geometry>>} */ (
|
|
||||||
options.features
|
|
||||||
);
|
|
||||||
} else if (options.features) {
|
} else if (options.features) {
|
||||||
collection =
|
collection = options.features;
|
||||||
/** @type {Collection<import("../Feature.js").default<Geometry>>} */ (
|
|
||||||
options.features
|
|
||||||
);
|
|
||||||
features = collection.getArray();
|
features = collection.getArray();
|
||||||
}
|
}
|
||||||
if (!useSpatialIndex && collection === undefined) {
|
if (!useSpatialIndex && collection === undefined) {
|
||||||
@@ -500,16 +498,12 @@ class VectorSource extends Source {
|
|||||||
collection.addEventListener(
|
collection.addEventListener(
|
||||||
CollectionEventType.ADD,
|
CollectionEventType.ADD,
|
||||||
/**
|
/**
|
||||||
* @param {import("../Collection.js").CollectionEvent} evt The collection event
|
* @param {import("../Collection.js").CollectionEvent<import("../Feature.js").default<Geometry>>} evt The collection event
|
||||||
*/
|
*/
|
||||||
function (evt) {
|
function (evt) {
|
||||||
if (!modifyingCollection) {
|
if (!modifyingCollection) {
|
||||||
modifyingCollection = true;
|
modifyingCollection = true;
|
||||||
this.addFeature(
|
this.addFeature(evt.element);
|
||||||
/** @type {import("../Feature.js").default<Geometry>} */ (
|
|
||||||
evt.element
|
|
||||||
)
|
|
||||||
);
|
|
||||||
modifyingCollection = false;
|
modifyingCollection = false;
|
||||||
}
|
}
|
||||||
}.bind(this)
|
}.bind(this)
|
||||||
@@ -517,16 +511,12 @@ class VectorSource extends Source {
|
|||||||
collection.addEventListener(
|
collection.addEventListener(
|
||||||
CollectionEventType.REMOVE,
|
CollectionEventType.REMOVE,
|
||||||
/**
|
/**
|
||||||
* @param {import("../Collection.js").CollectionEvent} evt The collection event
|
* @param {import("../Collection.js").CollectionEvent<import("../Feature.js").default<Geometry>>} evt The collection event
|
||||||
*/
|
*/
|
||||||
function (evt) {
|
function (evt) {
|
||||||
if (!modifyingCollection) {
|
if (!modifyingCollection) {
|
||||||
modifyingCollection = true;
|
modifyingCollection = true;
|
||||||
this.removeFeature(
|
this.removeFeature(evt.element);
|
||||||
/** @type {import("../Feature.js").default<Geometry>} */ (
|
|
||||||
evt.element
|
|
||||||
)
|
|
||||||
);
|
|
||||||
modifyingCollection = false;
|
modifyingCollection = false;
|
||||||
}
|
}
|
||||||
}.bind(this)
|
}.bind(this)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import sinon from 'sinon';
|
|||||||
import {listen} from '../../../src/ol/events.js';
|
import {listen} from '../../../src/ol/events.js';
|
||||||
|
|
||||||
describe('ol/Collection.js', function () {
|
describe('ol/Collection.js', function () {
|
||||||
|
/** @type {Collection} */
|
||||||
let collection;
|
let collection;
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
@@ -72,10 +73,15 @@ describe('ol/Collection.js', function () {
|
|||||||
|
|
||||||
describe('setAt', function () {
|
describe('setAt', function () {
|
||||||
it('sets at the correct location', function () {
|
it('sets at the correct location', function () {
|
||||||
collection.setAt(1, 1);
|
collection.setAt(0, 1);
|
||||||
expect(collection.getLength()).to.eql(2);
|
collection.setAt(1, 2);
|
||||||
expect(collection.item(0)).to.be(undefined);
|
expect(collection.getLength()).to.be(2);
|
||||||
expect(collection.item(1)).to.eql(1);
|
expect(collection.item(0)).to.be(1);
|
||||||
|
expect(collection.item(1)).to.be(2);
|
||||||
|
|
||||||
|
collection.setAt(0, 3);
|
||||||
|
expect(collection.getLength()).to.be(2);
|
||||||
|
expect(collection.item(0)).to.be(3);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -86,6 +92,13 @@ describe('ol/Collection.js', function () {
|
|||||||
expect(collection.item(0)).to.eql(0);
|
expect(collection.item(0)).to.eql(0);
|
||||||
expect(collection.item(1)).to.eql(2);
|
expect(collection.item(1)).to.eql(2);
|
||||||
});
|
});
|
||||||
|
it('does not fire event for invalid index', function () {
|
||||||
|
const collection = new Collection([0, 1, 2]);
|
||||||
|
collection.on('remove', function () {
|
||||||
|
throw new Error('Should not fire event for invalid index');
|
||||||
|
});
|
||||||
|
expect(collection.removeAt(3)).to.be(undefined);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('forEach', function () {
|
describe('forEach', function () {
|
||||||
@@ -187,23 +200,32 @@ describe('ol/Collection.js', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('setAt beyond end', function () {
|
describe('setAt beyond end', function () {
|
||||||
|
it('does not allow setting invalid index', function () {
|
||||||
|
try {
|
||||||
|
collection.setAt(1, 1);
|
||||||
|
} catch (e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new Error('Collection should throw');
|
||||||
|
});
|
||||||
it('triggers events properly', function () {
|
it('triggers events properly', function () {
|
||||||
const added = [],
|
const added = [];
|
||||||
addedIndexes = [];
|
const addedIndexes = [];
|
||||||
listen(collection, CollectionEventType.ADD, function (e) {
|
listen(collection, CollectionEventType.ADD, function (e) {
|
||||||
added.push(e.element);
|
added.push(e.element);
|
||||||
addedIndexes.push(e.index);
|
addedIndexes.push(e.index);
|
||||||
});
|
});
|
||||||
collection.setAt(2, 0);
|
collection.setAt(0, 0);
|
||||||
expect(collection.getLength()).to.eql(3);
|
collection.setAt(1, 1);
|
||||||
expect(collection.item(0)).to.be(undefined);
|
collection.setAt(0, 2);
|
||||||
expect(collection.item(1)).to.be(undefined);
|
expect(collection.getLength()).to.be(2);
|
||||||
expect(collection.item(2)).to.eql(0);
|
expect(collection.item(0)).to.be(2);
|
||||||
expect(added.length).to.eql(3);
|
expect(collection.item(1)).to.be(1);
|
||||||
expect(added[0]).to.eql(undefined);
|
expect(added.length).to.be(3);
|
||||||
expect(added[1]).to.eql(undefined);
|
expect(added[0]).to.be(0);
|
||||||
expect(added[2]).to.eql(0);
|
expect(added[1]).to.be(1);
|
||||||
expect(addedIndexes).to.eql([0, 1, 2]);
|
expect(added[2]).to.be(2);
|
||||||
|
expect(addedIndexes).to.eql([0, 1, 0]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user