Merge pull request #11188 from michalzielanski/late-obj-init

Late object initialization
This commit is contained in:
Andreas Hocevar
2020-06-24 10:21:43 +02:00
committed by GitHub
9 changed files with 143 additions and 93 deletions

View File

@@ -128,7 +128,9 @@ class Feature extends BaseObject {
* @api
*/
clone() {
const clone = new Feature(this.getProperties());
const clone = new Feature(
this.hasProperties() ? this.getProperties() : null
);
clone.setGeometryName(this.getGeometryName());
const geometry = this.getGeometry();
if (geometry) {

View File

@@ -4,7 +4,7 @@
import Event from './events/Event.js';
import ObjectEventType from './ObjectEventType.js';
import Observable from './Observable.js';
import {assign} from './obj.js';
import {assign, isEmpty} from './obj.js';
import {getUid} from './util.js';
/**
@@ -95,9 +95,9 @@ class BaseObject extends Observable {
/**
* @private
* @type {!Object<string, *>}
* @type {Object<string, *>}
*/
this.values_ = {};
this.values_ = null;
if (opt_values !== undefined) {
this.setProperties(opt_values);
@@ -112,7 +112,7 @@ class BaseObject extends Observable {
*/
get(key) {
let value;
if (this.values_.hasOwnProperty(key)) {
if (this.values_ && this.values_.hasOwnProperty(key)) {
value = this.values_[key];
}
return value;
@@ -124,7 +124,7 @@ class BaseObject extends Observable {
* @api
*/
getKeys() {
return Object.keys(this.values_);
return (this.values_ && Object.keys(this.values_)) || [];
}
/**
@@ -133,7 +133,14 @@ class BaseObject extends Observable {
* @api
*/
getProperties() {
return assign({}, this.values_);
return (this.values_ && assign({}, this.values_)) || {};
}
/**
* @return {boolean} The object has properties.
*/
hasProperties() {
return !!this.values_;
}
/**
@@ -156,11 +163,12 @@ class BaseObject extends Observable {
* @api
*/
set(key, value, opt_silent) {
const values = this.values_ || (this.values_ = {});
if (opt_silent) {
this.values_[key] = value;
values[key] = value;
} else {
const oldValue = this.values_[key];
this.values_[key] = value;
const oldValue = values[key];
values[key] = value;
if (oldValue !== value) {
this.notify(key, oldValue);
}
@@ -187,9 +195,12 @@ class BaseObject extends Observable {
* @api
*/
unset(key, opt_silent) {
if (key in this.values_) {
if (this.values_ && key in this.values_) {
const oldValue = this.values_[key];
delete this.values_[key];
if (isEmpty(this.values_)) {
this.values_ = null;
}
if (!opt_silent) {
this.notify(key, oldValue);
}

View File

@@ -40,21 +40,21 @@ class Target extends Disposable {
/**
* @private
* @type {!Object<string, number>}
* @type {Object<string, number>}
*/
this.pendingRemovals_ = {};
this.pendingRemovals_ = null;
/**
* @private
* @type {!Object<string, number>}
* @type {Object<string, number>}
*/
this.dispatching_ = {};
this.dispatching_ = null;
/**
* @private
* @type {!Object<string, Array<import("../events.js").Listener>>}
* @type {Object<string, Array<import("../events.js").Listener>>}
*/
this.listeners_ = {};
this.listeners_ = null;
}
/**
@@ -65,13 +65,10 @@ class Target extends Disposable {
if (!type || !listener) {
return;
}
let listeners = this.listeners_[type];
if (!listeners) {
listeners = [];
this.listeners_[type] = listeners;
}
if (listeners.indexOf(listener) === -1) {
listeners.push(listener);
const listeners = this.listeners_ || (this.listeners_ = {});
const listenersForType = listeners[type] || (listeners[type] = []);
if (listenersForType.indexOf(listener) === -1) {
listenersForType.push(listener);
}
}
@@ -92,14 +89,17 @@ class Target extends Disposable {
if (!evt.target) {
evt.target = this.eventTarget_ || this;
}
const listeners = this.listeners_[type];
const listeners = this.listeners_ && this.listeners_[type];
let propagate;
if (listeners) {
if (!(type in this.dispatching_)) {
this.dispatching_[type] = 0;
this.pendingRemovals_[type] = 0;
const dispatching = this.dispatching_ || (this.dispatching_ = {});
const pendingRemovals =
this.pendingRemovals_ || (this.pendingRemovals_ = {});
if (!(type in dispatching)) {
dispatching[type] = 0;
pendingRemovals[type] = 0;
}
++this.dispatching_[type];
++dispatching[type];
for (let i = 0, ii = listeners.length; i < ii; ++i) {
if ('handleEvent' in listeners[i]) {
propagate = /** @type {import("../events.js").ListenerObject} */ (listeners[
@@ -115,14 +115,14 @@ class Target extends Disposable {
break;
}
}
--this.dispatching_[type];
if (this.dispatching_[type] === 0) {
let pendingRemovals = this.pendingRemovals_[type];
delete this.pendingRemovals_[type];
while (pendingRemovals--) {
--dispatching[type];
if (dispatching[type] === 0) {
let pr = pendingRemovals[type];
delete pendingRemovals[type];
while (pr--) {
this.removeEventListener(type, VOID);
}
delete this.dispatching_[type];
delete dispatching[type];
}
return propagate;
}
@@ -132,7 +132,7 @@ class Target extends Disposable {
* Clean up.
*/
disposeInternal() {
clear(this.listeners_);
this.listeners_ && clear(this.listeners_);
}
/**
@@ -140,10 +140,10 @@ class Target extends Disposable {
* order that they will be called in.
*
* @param {string} type Type.
* @return {Array<import("../events.js").Listener>} Listeners.
* @return {Array<import("../events.js").Listener>|undefined} Listeners.
*/
getListeners(type) {
return this.listeners_[type];
return (this.listeners_ && this.listeners_[type]) || undefined;
}
/**
@@ -152,6 +152,9 @@ class Target extends Disposable {
* @return {boolean} Has listeners.
*/
hasListener(opt_type) {
if (!this.listeners_) {
return false;
}
return opt_type
? opt_type in this.listeners_
: Object.keys(this.listeners_).length > 0;
@@ -162,11 +165,11 @@ class Target extends Disposable {
* @param {import("../events.js").Listener} listener Listener.
*/
removeEventListener(type, listener) {
const listeners = this.listeners_[type];
const listeners = this.listeners_ && this.listeners_[type];
if (listeners) {
const index = listeners.indexOf(listener);
if (index !== -1) {
if (type in this.pendingRemovals_) {
if (this.pendingRemovals_ && type in this.pendingRemovals_) {
// make listener a no-op, and remove later in #dispatchEvent()
listeners[index] = VOID;
++this.pendingRemovals_[type];

View File

@@ -199,6 +199,11 @@ class EsriJSON extends JSONFeature {
writeFeatureObject(feature, opt_options) {
opt_options = this.adaptOptions(opt_options);
const object = {};
if (!feature.hasProperties()) {
object['attributes'] = {};
return object;
}
const properties = feature.getProperties();
const geometry = feature.getGeometry();
if (geometry) {
object['geometry'] = writeGeometry(geometry, opt_options);
@@ -214,9 +219,8 @@ class EsriJSON extends JSONFeature {
),
});
}
delete properties[feature.getGeometryName()];
}
const properties = feature.getProperties();
delete properties[feature.getGeometryName()];
if (!isEmpty(properties)) {
object['attributes'] = properties;
} else {

View File

@@ -212,29 +212,32 @@ class GML2 extends GMLBase {
context.serializers = {};
context.serializers[featureNS] = {};
}
const properties = feature.getProperties();
const keys = [];
const values = [];
for (const key in properties) {
const value = properties[key];
if (value !== null) {
keys.push(key);
values.push(value);
if (
key == geometryName ||
typeof (/** @type {?} */ (value).getSimplifiedGeometry) === 'function'
) {
if (!(key in context.serializers[featureNS])) {
context.serializers[featureNS][key] = makeChildAppender(
this.writeGeometryElement,
this
);
}
} else {
if (!(key in context.serializers[featureNS])) {
context.serializers[featureNS][key] = makeChildAppender(
writeStringTextNode
);
if (feature.hasProperties()) {
const properties = feature.getProperties();
for (const key in properties) {
const value = properties[key];
if (value !== null) {
keys.push(key);
values.push(value);
if (
key == geometryName ||
typeof (/** @type {?} */ (value).getSimplifiedGeometry) ===
'function'
) {
if (!(key in context.serializers[featureNS])) {
context.serializers[featureNS][key] = makeChildAppender(
this.writeGeometryElement,
this
);
}
} else {
if (!(key in context.serializers[featureNS])) {
context.serializers[featureNS][key] = makeChildAppender(
writeStringTextNode
);
}
}
}
}

View File

@@ -843,29 +843,32 @@ class GML3 extends GMLBase {
context.serializers = {};
context.serializers[featureNS] = {};
}
const properties = feature.getProperties();
const keys = [];
const values = [];
for (const key in properties) {
const value = properties[key];
if (value !== null) {
keys.push(key);
values.push(value);
if (
key == geometryName ||
typeof (/** @type {?} */ (value).getSimplifiedGeometry) === 'function'
) {
if (!(key in context.serializers[featureNS])) {
context.serializers[featureNS][key] = makeChildAppender(
this.writeGeometryElement,
this
);
}
} else {
if (!(key in context.serializers[featureNS])) {
context.serializers[featureNS][key] = makeChildAppender(
writeStringTextNode
);
if (feature.hasProperties()) {
const properties = feature.getProperties();
for (const key in properties) {
const value = properties[key];
if (value !== null) {
keys.push(key);
values.push(value);
if (
key == geometryName ||
typeof (/** @type {?} */ (value).getSimplifiedGeometry) ===
'function'
) {
if (!(key in context.serializers[featureNS])) {
context.serializers[featureNS][key] = makeChildAppender(
this.writeGeometryElement,
this
);
}
} else {
if (!(key in context.serializers[featureNS])) {
context.serializers[featureNS][key] = makeChildAppender(
writeStringTextNode
);
}
}
}
}

View File

@@ -207,16 +207,22 @@ class GeoJSON extends JSONFeature {
object.id = id;
}
const geometry = feature.getGeometry();
if (geometry) {
object.geometry = writeGeometry(geometry, opt_options);
if (!feature.hasProperties()) {
return object;
}
const properties = feature.getProperties();
delete properties[feature.getGeometryName()];
const geometry = feature.getGeometry();
if (geometry) {
object.geometry = writeGeometry(geometry, opt_options);
delete properties[feature.getGeometryName()];
}
if (!isEmpty(properties)) {
object.properties = properties;
}
return object;
}