mirror of
https://gitee.com/openharmony/arkui_ace_engine
synced 2024-12-02 20:44:41 +00:00
add makeobserved
Signed-off-by: liwenzhen <liwenzhen3@huawei.com>
This commit is contained in:
parent
e5cab0e8e9
commit
f49ca87d6b
@ -178,6 +178,21 @@ class UIUtils {
|
||||
static getTarget(source) {
|
||||
return UIUtils.uiUtilsImpl_.getTarget(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make non-observed data into observed data.
|
||||
* Support non-observed class, JSON.parse, and collection.Set, collection.Map, collection.Array.
|
||||
*
|
||||
* @param { T } source input source object data.
|
||||
* @returns { T } proxy object from the source object data.
|
||||
* @syscap SystemCapability.ArkUI.ArkUI.Full
|
||||
* @crossplatform
|
||||
* @atomicservice
|
||||
* @since 12
|
||||
*/
|
||||
static makeObserved(source) {
|
||||
return UIUtils.uiUtilsImpl_.makeObserved(source);
|
||||
}
|
||||
}
|
||||
|
||||
UIUtils.uiUtilsImpl_ = UIUtilsImpl.instance();
|
||||
|
@ -2349,6 +2349,7 @@ class SubscribableHandler {
|
||||
break;
|
||||
case ObserveV2.SYMBOL_REFS:
|
||||
case ObserveV2.V2_DECO_META:
|
||||
case ObserveV2.SYMBOL_MAKE_OBSERVED:
|
||||
// return result unmonitored
|
||||
return Reflect.get(target, property, receiver);
|
||||
break;
|
||||
@ -4455,6 +4456,37 @@ PUV2ViewBase.compareNumber = (a, b) => {
|
||||
// when paused, getCurrentlyRenderedElmtId() will return UINodeRegisterProxy.notRecordingDependencies
|
||||
PUV2ViewBase.renderingPaused = false;
|
||||
PUV2ViewBase.arkThemeScopeManager = undefined;
|
||||
/*
|
||||
* Copyright (c) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
;
|
||||
;
|
||||
;
|
||||
class SendableType {
|
||||
static isArray(o) {
|
||||
return o instanceof SendableArray;
|
||||
}
|
||||
static isSet(o) {
|
||||
return o instanceof SendableSet;
|
||||
}
|
||||
static isMap(o) {
|
||||
return o instanceof SendableMap;
|
||||
}
|
||||
static isContainer(o) {
|
||||
return o instanceof SendableMap || o instanceof SendableSet || o instanceof SendableArray;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -4862,15 +4894,15 @@ class ObservedPropertyAbstractPU extends ObservedPropertyAbstract {
|
||||
FIXME this expects the Map, Set patch to go in
|
||||
*/
|
||||
checkIsSupportedValue(value) {
|
||||
let res = ((typeof value === 'object' && typeof value !== 'function' && !ObserveV2.IsObservedObjectV2(value)) ||
|
||||
typeof value === 'number' || typeof value === 'string' || typeof value === 'boolean' ||
|
||||
value === undefined || value === null);
|
||||
let res = ((typeof value === 'object' && typeof value !== 'function' && !ObserveV2.IsObservedObjectV2(value) &&
|
||||
!ObserveV2.IsMakeObserved(value)) || typeof value === 'number' || typeof value === 'string' ||
|
||||
typeof value === 'boolean' || value === undefined || value === null);
|
||||
if (!res) {
|
||||
errorReport.varValueCheckFailed({
|
||||
customComponent: this.debugInfoOwningView(),
|
||||
variableDeco: this.debugInfoDecorator(),
|
||||
variableName: this.info(),
|
||||
expectedType: `undefined, null, number, boolean, string, or Object but not function, not V3 @observed / @track class`,
|
||||
expectedType: `undefined, null, number, boolean, string, or Object but not function, not V2 @ObservedV2 / @Trace class, and makeObserved return value either`,
|
||||
value: value
|
||||
});
|
||||
}
|
||||
@ -7385,6 +7417,10 @@ class ObserveV2 {
|
||||
static IsObservedObjectV2(value) {
|
||||
return (value && typeof (value) === 'object' && value[ObserveV2.V2_DECO_META]);
|
||||
}
|
||||
// return true given value is the return value of makeObserved
|
||||
static IsMakeObserved(value) {
|
||||
return (value && typeof (value) === 'object' && value[ObserveV2.SYMBOL_MAKE_OBSERVED]);
|
||||
}
|
||||
static getCurrentRecordedId() {
|
||||
const bound = ObserveV2.getObserve().stackOfRenderedComponents_.top();
|
||||
return bound ? bound[0] : -1;
|
||||
@ -7869,10 +7905,22 @@ class ObserveV2 {
|
||||
}
|
||||
// If the return value is an Array, Set, Map
|
||||
if (!(val instanceof Date)) {
|
||||
ObserveV2.getObserve().addRef(val, ObserveV2.OB_LENGTH);
|
||||
ObserveV2.getObserve().addRef(ObserveV2.IsMakeObserved(val) ? RefInfo.get(UIUtilsImpl.instance().getTarget(val)) :
|
||||
val, ObserveV2.OB_LENGTH);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
static commonHandlerSet(target, key, value) {
|
||||
if (typeof key === 'symbol') {
|
||||
return true;
|
||||
}
|
||||
if (target[key] === value) {
|
||||
return true;
|
||||
}
|
||||
target[key] = value;
|
||||
ObserveV2.getObserve().fireChange(RefInfo.get(target), key.toString());
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Helper function to add meta data about decorator to ViewPU or ViewV2
|
||||
* @param proto prototype object of application class derived from ViewPU or ViewV2
|
||||
@ -7927,6 +7975,7 @@ ObserveV2.ID_REFS = Symbol('__id_refs__');
|
||||
ObserveV2.MONITOR_REFS = Symbol('___monitor_refs_');
|
||||
ObserveV2.COMPUTED_REFS = Symbol('___computed_refs_');
|
||||
ObserveV2.SYMBOL_PROXY_GET_TARGET = Symbol('__proxy_get_target');
|
||||
ObserveV2.SYMBOL_MAKE_OBSERVED = Symbol('___make_observed__');
|
||||
ObserveV2.OB_PREFIX = '__ob_'; // OB_PREFIX + attrName => backing store attribute name
|
||||
ObserveV2.OB_PREFIX_LEN = 5;
|
||||
// used by array Handler to create dependency on artificial 'length'
|
||||
@ -7934,11 +7983,265 @@ ObserveV2.OB_PREFIX_LEN = 5;
|
||||
ObserveV2.OB_LENGTH = '___obj_length';
|
||||
ObserveV2.OB_MAP_SET_ANY_PROPERTY = '___ob_map_set';
|
||||
ObserveV2.OB_DATE = '__date__';
|
||||
ObserveV2.arrayLengthChangingFunctions = new Set(['push', 'pop', 'shift', 'splice', 'unshift']);
|
||||
// shrinkTo and extendTo is collection.Array api.
|
||||
ObserveV2.arrayLengthChangingFunctions = new Set(['push', 'pop', 'shift', 'splice', 'unshift', 'shrinkTo', 'extendTo']);
|
||||
ObserveV2.arrayMutatingFunctions = new Set(['copyWithin', 'fill', 'reverse', 'sort']);
|
||||
ObserveV2.dateSetFunctions = new Set(['setFullYear', 'setMonth', 'setDate', 'setHours', 'setMinutes',
|
||||
'setSeconds', 'setMilliseconds', 'setTime', 'setUTCFullYear', 'setUTCMonth', 'setUTCDate', 'setUTCHours',
|
||||
'setUTCMinutes', 'setUTCSeconds', 'setUTCMilliseconds']);
|
||||
ObserveV2.normalObjectHandlerDeepObserved = {
|
||||
get(target, property, receiver) {
|
||||
if (typeof property === 'symbol') {
|
||||
if (property === ObserveV2.SYMBOL_PROXY_GET_TARGET) {
|
||||
return target;
|
||||
}
|
||||
if (property === ObserveV2.SYMBOL_MAKE_OBSERVED) {
|
||||
return true;
|
||||
}
|
||||
return target[property];
|
||||
}
|
||||
let prop = property;
|
||||
ObserveV2.getObserve().addRef(RefInfo.get(target), prop);
|
||||
let ret = target[prop];
|
||||
let type = typeof (ret);
|
||||
return type === "function"
|
||||
? ret.bind(receiver)
|
||||
: (type === "object"
|
||||
? RefInfo.get(ret).proxy
|
||||
: ret);
|
||||
},
|
||||
set(target, prop, value, receiver) {
|
||||
if (target[prop] === value) {
|
||||
return true;
|
||||
}
|
||||
target[prop] = value;
|
||||
ObserveV2.getObserve().fireChange(RefInfo.get(target), prop);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
ObserveV2.arrayHandlerDeepObserved = {
|
||||
get(target, key, receiver) {
|
||||
if (typeof key === 'symbol') {
|
||||
if (key === Symbol.iterator) {
|
||||
let refInfo = RefInfo.get(target);
|
||||
ObserveV2.getObserve().fireChange(refInfo, ObserveV2.OB_MAP_SET_ANY_PROPERTY);
|
||||
ObserveV2.getObserve().addRef(refInfo, ObserveV2.OB_LENGTH);
|
||||
return (...args) => target[key](...args);
|
||||
}
|
||||
if (key === ObserveV2.SYMBOL_PROXY_GET_TARGET) {
|
||||
return target;
|
||||
}
|
||||
if (key === ObserveV2.SYMBOL_MAKE_OBSERVED) {
|
||||
return true;
|
||||
}
|
||||
return target[key];
|
||||
}
|
||||
let refInfo = RefInfo.get(target);
|
||||
if (key === 'size') {
|
||||
ObserveV2.getObserve().addRef(refInfo, ObserveV2.OB_LENGTH);
|
||||
return target.size;
|
||||
}
|
||||
let ret = target[key];
|
||||
if (typeof (ret) !== 'function') {
|
||||
if (typeof (ret) === "object") {
|
||||
let wrapper = RefInfo.get(ret);
|
||||
ObserveV2.getObserve().addRef(refInfo, key);
|
||||
return wrapper.proxy;
|
||||
}
|
||||
if (key === 'length') {
|
||||
ObserveV2.getObserve().addRef(refInfo, ObserveV2.OB_LENGTH);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
if (ObserveV2.arrayMutatingFunctions.has(key)) {
|
||||
return function (...args) {
|
||||
ret.call(target, ...args);
|
||||
ObserveV2.getObserve().fireChange(refInfo, ObserveV2.OB_LENGTH);
|
||||
// returning the 'receiver(proxied object)' ensures that when chain calls also 2nd function call
|
||||
// operates on the proxied object.
|
||||
return receiver;
|
||||
};
|
||||
}
|
||||
else if (ObserveV2.arrayLengthChangingFunctions.has(key)) {
|
||||
return function (...args) {
|
||||
const result = ret.call(target, ...args);
|
||||
ObserveV2.getObserve().fireChange(refInfo, ObserveV2.OB_LENGTH);
|
||||
return result;
|
||||
};
|
||||
}
|
||||
else if (key === 'forEach') {
|
||||
// to make ForEach Component and its Item can addref
|
||||
ObserveV2.getObserve().addRef(refInfo, ObserveV2.OB_LENGTH);
|
||||
return function (callbackFn) {
|
||||
const result = ret.call(target, (value, index, array) => {
|
||||
callbackFn(typeof value == "object" ? RefInfo.get(value).proxy : value, index, receiver);
|
||||
});
|
||||
return result;
|
||||
};
|
||||
}
|
||||
else {
|
||||
return ret.bind(target);
|
||||
}
|
||||
},
|
||||
set(target, key, value) {
|
||||
return ObserveV2.commonHandlerSet(target, key, value);
|
||||
}
|
||||
};
|
||||
ObserveV2.setMapHandlerDeepObserved = {
|
||||
get(target, key, receiver) {
|
||||
if (typeof key === 'symbol') {
|
||||
if (key === Symbol.iterator) {
|
||||
let refInfo = RefInfo.get(target);
|
||||
ObserveV2.getObserve().fireChange(refInfo, ObserveV2.OB_MAP_SET_ANY_PROPERTY);
|
||||
ObserveV2.getObserve().addRef(refInfo, ObserveV2.OB_LENGTH);
|
||||
return (...args) => target[key](...args);
|
||||
}
|
||||
if (key === ObserveV2.SYMBOL_PROXY_GET_TARGET) {
|
||||
return target;
|
||||
}
|
||||
if (key === ObserveV2.SYMBOL_MAKE_OBSERVED) {
|
||||
return true;
|
||||
}
|
||||
return target[key];
|
||||
}
|
||||
let refInfo = RefInfo.get(target);
|
||||
if (key === 'size') {
|
||||
ObserveV2.getObserve().addRef(refInfo, ObserveV2.OB_LENGTH);
|
||||
return target.size;
|
||||
}
|
||||
let ret = target[key];
|
||||
if (typeof (ret) !== 'function') {
|
||||
if (typeof (ret) === "object") {
|
||||
let wrapper = RefInfo.get(ret);
|
||||
ObserveV2.getObserve().addRef(refInfo, key);
|
||||
return wrapper.proxy;
|
||||
}
|
||||
if (key === 'length') {
|
||||
ObserveV2.getObserve().addRef(refInfo, ObserveV2.OB_LENGTH);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
if (key === 'has') {
|
||||
return (prop) => {
|
||||
const ret = target.has(prop);
|
||||
if (ret) {
|
||||
ObserveV2.getObserve().addRef(refInfo, prop);
|
||||
}
|
||||
else {
|
||||
ObserveV2.getObserve().addRef(refInfo, ObserveV2.OB_LENGTH);
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
}
|
||||
if (key === 'delete') {
|
||||
return (prop) => {
|
||||
if (target.has(prop)) {
|
||||
ObserveV2.getObserve().fireChange(refInfo, prop);
|
||||
ObserveV2.getObserve().fireChange(refInfo, ObserveV2.OB_LENGTH);
|
||||
return target.delete(prop);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
if (key === 'clear') {
|
||||
return () => {
|
||||
if (target.size > 0) {
|
||||
target.forEach((_, prop) => {
|
||||
ObserveV2.getObserve().fireChange(refInfo, prop.toString());
|
||||
});
|
||||
ObserveV2.getObserve().fireChange(refInfo, ObserveV2.OB_LENGTH);
|
||||
ObserveV2.getObserve().addRef(refInfo, ObserveV2.OB_MAP_SET_ANY_PROPERTY);
|
||||
target.clear();
|
||||
}
|
||||
};
|
||||
}
|
||||
if (key === 'keys' || key === 'values' || key === 'entries') {
|
||||
return () => {
|
||||
ObserveV2.getObserve().addRef(refInfo, ObserveV2.OB_MAP_SET_ANY_PROPERTY);
|
||||
ObserveV2.getObserve().addRef(refInfo, ObserveV2.OB_LENGTH);
|
||||
return target[key]();
|
||||
};
|
||||
}
|
||||
if (target instanceof Set || SendableType.isSet(target)) {
|
||||
return key === 'add' ?
|
||||
(val) => {
|
||||
ObserveV2.getObserve().fireChange(refInfo, val.toString());
|
||||
ObserveV2.getObserve().fireChange(refInfo, ObserveV2.OB_MAP_SET_ANY_PROPERTY);
|
||||
if (!target.has(val)) {
|
||||
ObserveV2.getObserve().fireChange(refInfo, ObserveV2.OB_LENGTH);
|
||||
target.add(val);
|
||||
}
|
||||
// return proxied This
|
||||
return receiver;
|
||||
} : (typeof ret === 'function')
|
||||
? ret.bind(target) : ret;
|
||||
}
|
||||
if (target instanceof Map || SendableType.isMap(target)) {
|
||||
if (key === 'get') { // for Map
|
||||
return (prop) => {
|
||||
if (target.has(prop)) {
|
||||
ObserveV2.getObserve().addRef(refInfo, prop);
|
||||
}
|
||||
else {
|
||||
ObserveV2.getObserve().addRef(refInfo, ObserveV2.OB_LENGTH);
|
||||
}
|
||||
let ret = target.get(prop);
|
||||
return typeof ret === 'object' ? RefInfo.get(ret).proxy : ret;
|
||||
};
|
||||
}
|
||||
if (key === 'set') { // for Map
|
||||
return (prop, val) => {
|
||||
if (!target.has(prop)) {
|
||||
ObserveV2.getObserve().fireChange(refInfo, ObserveV2.OB_LENGTH);
|
||||
}
|
||||
else if (target.get(prop) !== val) {
|
||||
ObserveV2.getObserve().fireChange(refInfo, prop);
|
||||
}
|
||||
ObserveV2.getObserve().fireChange(refInfo, ObserveV2.OB_MAP_SET_ANY_PROPERTY);
|
||||
target.set(prop, val);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
}
|
||||
return (typeof ret === 'function') ? ret.bind(target) : ret;
|
||||
},
|
||||
set(target, key, value) {
|
||||
return ObserveV2.commonHandlerSet(target, key, value);
|
||||
}
|
||||
};
|
||||
ObserveV2.dateHandlerDeepObserved = {
|
||||
get(target, key, receiver) {
|
||||
if (typeof key === 'symbol') {
|
||||
if (key === ObserveV2.SYMBOL_PROXY_GET_TARGET) {
|
||||
return target;
|
||||
}
|
||||
if (key === ObserveV2.SYMBOL_MAKE_OBSERVED) {
|
||||
return true;
|
||||
}
|
||||
return target[key];
|
||||
}
|
||||
let ret = target[key];
|
||||
let refInfo = RefInfo.get(target);
|
||||
if (ObserveV2.dateSetFunctions.has(key)) {
|
||||
return function (...args) {
|
||||
// execute original function with given arguments
|
||||
let result = ret.call(this, ...args);
|
||||
ObserveV2.getObserve().fireChange(refInfo, ObserveV2.OB_DATE);
|
||||
return result;
|
||||
// bind 'this' to target inside the function
|
||||
}.bind(target);
|
||||
}
|
||||
else {
|
||||
ObserveV2.getObserve().addRef(refInfo, ObserveV2.OB_DATE);
|
||||
}
|
||||
return ret.bind(target);
|
||||
},
|
||||
set(target, key, value) {
|
||||
return ObserveV2.commonHandlerSet(target, key, value);
|
||||
}
|
||||
};
|
||||
ObserveV2.arraySetMapProxy = {
|
||||
get(target, key, receiver) {
|
||||
if (typeof key === 'symbol') {
|
||||
@ -9630,6 +9933,50 @@ class JSONCoder {
|
||||
return target;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
class RefInfo {
|
||||
static get(target) {
|
||||
if (typeof (target) !== "object") {
|
||||
throw new Error("target must be a object");
|
||||
}
|
||||
// makeObserved does not support @Observed and @ObservedV2/@Trace class, will return target directly
|
||||
if (ObservedObject.IsObservedObject(target) || ObserveV2.IsObservedObjectV2(target)) {
|
||||
stateMgmtConsole.warn(`${target.constructor.name} is Observed ${ObservedObject.IsObservedObject(target)}, IsObservedV2 ${ObserveV2.IsObservedObjectV2(target)}. makeObserved will stop work`);
|
||||
return { proxy: target };
|
||||
}
|
||||
let ret = RefInfo.obj2ref.get(target);
|
||||
if (!ret) {
|
||||
if (Array.isArray(target) || SendableType.isArray(target)) {
|
||||
ret = { proxy: new Proxy(target, ObserveV2.arrayHandlerDeepObserved) };
|
||||
}
|
||||
else if (target instanceof Set || SendableType.isSet(target) || target instanceof Map || SendableType.isMap(target)) {
|
||||
ret = { proxy: new Proxy(target, ObserveV2.setMapHandlerDeepObserved) };
|
||||
}
|
||||
else if (target instanceof Date) {
|
||||
ret = { proxy: new Proxy(target, ObserveV2.dateHandlerDeepObserved) };
|
||||
}
|
||||
else {
|
||||
ret = { proxy: new Proxy(target, ObserveV2.normalObjectHandlerDeepObserved) };
|
||||
}
|
||||
RefInfo.obj2ref.set(target, ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
RefInfo.obj2ref = new WeakMap();
|
||||
/*
|
||||
* Copyright (c) 2023-2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -10678,6 +11025,11 @@ class UIUtilsImpl {
|
||||
return source;
|
||||
}
|
||||
}
|
||||
makeObserved(target) {
|
||||
// mark makeObserved using V2 feature
|
||||
ConfigureStateMgmt.instance.usingV2ObservedTrack('makeObserved', 'use');
|
||||
return RefInfo.get(target).proxy;
|
||||
}
|
||||
static instance() {
|
||||
if (UIUtilsImpl.instance_) {
|
||||
return UIUtilsImpl.instance_;
|
||||
|
@ -204,6 +204,7 @@ class SubscribableHandler {
|
||||
break;
|
||||
case ObserveV2.SYMBOL_REFS:
|
||||
case ObserveV2.V2_DECO_META:
|
||||
case ObserveV2.SYMBOL_MAKE_OBSERVED:
|
||||
// return result unmonitored
|
||||
return Reflect.get(target, property, receiver);
|
||||
break;
|
||||
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
declare class SendableMap {};
|
||||
declare class SendableSet {};
|
||||
declare class SendableArray {};
|
||||
|
||||
|
||||
class SendableType {
|
||||
public static isArray<T extends object>(o: T): boolean {
|
||||
return o instanceof SendableArray;
|
||||
}
|
||||
public static isSet<T extends object>(o: T): boolean {
|
||||
return o instanceof SendableSet;
|
||||
}
|
||||
|
||||
public static isMap<T extends object>(o: T): boolean {
|
||||
return o instanceof SendableMap;
|
||||
}
|
||||
|
||||
public static isContainer<T extends object>(o: T): boolean {
|
||||
return o instanceof SendableMap || o instanceof SendableSet || o instanceof SendableArray;
|
||||
}
|
||||
}
|
@ -357,17 +357,17 @@ implements ISinglePropertyChangeSubscriber<T>, IMultiPropertiesChangeSubscriber,
|
||||
*/
|
||||
|
||||
protected checkIsSupportedValue(value: T): boolean {
|
||||
let res = ((typeof value === 'object' && typeof value !== 'function' && !ObserveV2.IsObservedObjectV2(value)) ||
|
||||
typeof value === 'number' || typeof value === 'string' || typeof value === 'boolean' ||
|
||||
value === undefined || value === null);
|
||||
let res = ((typeof value === 'object' && typeof value !== 'function' && !ObserveV2.IsObservedObjectV2(value) &&
|
||||
!ObserveV2.IsMakeObserved(value)) || typeof value === 'number' || typeof value === 'string' ||
|
||||
typeof value === 'boolean' || value === undefined || value === null);
|
||||
if (!res) {
|
||||
errorReport.varValueCheckFailed({
|
||||
customComponent: this.debugInfoOwningView(),
|
||||
variableDeco: this.debugInfoDecorator(),
|
||||
variableName: this.info(),
|
||||
expectedType: `undefined, null, number, boolean, string, or Object but not function, not V3 @observed / @track class`,
|
||||
value: value
|
||||
});
|
||||
customComponent: this.debugInfoOwningView(),
|
||||
variableDeco: this.debugInfoDecorator(),
|
||||
variableName: this.info(),
|
||||
expectedType: `undefined, null, number, boolean, string, or Object but not function, not V2 @ObservedV2 / @Trace class, and makeObserved return value either`,
|
||||
value: value
|
||||
});
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -32,6 +32,12 @@ class UIUtilsImpl {
|
||||
}
|
||||
}
|
||||
|
||||
public makeObserved<T extends object>(target: T): T {
|
||||
// mark makeObserved using V2 feature
|
||||
ConfigureStateMgmt.instance.usingV2ObservedTrack('makeObserved', 'use')
|
||||
return RefInfo.get(target).proxy as T
|
||||
}
|
||||
|
||||
public static instance(): UIUtilsImpl {
|
||||
if (UIUtilsImpl.instance_) {
|
||||
return UIUtilsImpl.instance_;
|
||||
|
@ -71,6 +71,8 @@ class ObserveV2 {
|
||||
|
||||
public static readonly SYMBOL_PROXY_GET_TARGET = Symbol('__proxy_get_target');
|
||||
|
||||
public static readonly SYMBOL_MAKE_OBSERVED = Symbol('___make_observed__');
|
||||
|
||||
public static readonly OB_PREFIX = '__ob_'; // OB_PREFIX + attrName => backing store attribute name
|
||||
public static readonly OB_PREFIX_LEN = 5;
|
||||
|
||||
@ -125,6 +127,11 @@ class ObserveV2 {
|
||||
return (value && typeof (value) === 'object' && value[ObserveV2.V2_DECO_META]);
|
||||
}
|
||||
|
||||
// return true given value is the return value of makeObserved
|
||||
public static IsMakeObserved(value: any): boolean {
|
||||
return (value && typeof (value) === 'object' && value[ObserveV2.SYMBOL_MAKE_OBSERVED]);
|
||||
}
|
||||
|
||||
public static getCurrentRecordedId(): number {
|
||||
const bound = ObserveV2.getObserve().stackOfRenderedComponents_.top();
|
||||
return bound ? bound[0] : -1;
|
||||
@ -638,18 +645,299 @@ class ObserveV2 {
|
||||
|
||||
// If the return value is an Array, Set, Map
|
||||
if (!(val instanceof Date)) {
|
||||
ObserveV2.getObserve().addRef(val, ObserveV2.OB_LENGTH);
|
||||
ObserveV2.getObserve().addRef(ObserveV2.IsMakeObserved(val) ? RefInfo.get(UIUtilsImpl.instance().getTarget(val)) :
|
||||
val, ObserveV2.OB_LENGTH);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
private static readonly arrayLengthChangingFunctions = new Set(['push', 'pop', 'shift', 'splice', 'unshift']);
|
||||
// shrinkTo and extendTo is collection.Array api.
|
||||
private static readonly arrayLengthChangingFunctions = new Set(['push', 'pop', 'shift', 'splice', 'unshift', 'shrinkTo', 'extendTo']);
|
||||
private static readonly arrayMutatingFunctions = new Set(['copyWithin', 'fill', 'reverse', 'sort']);
|
||||
private static readonly dateSetFunctions = new Set(['setFullYear', 'setMonth', 'setDate', 'setHours', 'setMinutes',
|
||||
'setSeconds', 'setMilliseconds', 'setTime', 'setUTCFullYear', 'setUTCMonth', 'setUTCDate', 'setUTCHours',
|
||||
'setUTCMinutes', 'setUTCSeconds', 'setUTCMilliseconds']);
|
||||
|
||||
public static readonly normalObjectHandlerDeepObserved = {
|
||||
get(target: object, property: string | Symbol, receiver: any) {
|
||||
if (typeof property === 'symbol') {
|
||||
if (property === ObserveV2.SYMBOL_PROXY_GET_TARGET) {
|
||||
return target;
|
||||
}
|
||||
if (property === ObserveV2.SYMBOL_MAKE_OBSERVED) {
|
||||
return true;
|
||||
}
|
||||
return target[property];
|
||||
}
|
||||
|
||||
let prop = property as string;
|
||||
ObserveV2.getObserve().addRef(RefInfo.get(target), prop);
|
||||
let ret = target[prop];
|
||||
let type = typeof (ret);
|
||||
|
||||
return type === "function"
|
||||
? ret.bind(receiver)
|
||||
: (type === "object"
|
||||
? RefInfo.get(ret).proxy
|
||||
: ret);
|
||||
},
|
||||
set(target: object, prop: string, value: any, receiver: any) {
|
||||
if (target[prop] === value) {
|
||||
return true;
|
||||
}
|
||||
target[prop] = value;
|
||||
ObserveV2.getObserve().fireChange(RefInfo.get(target), prop);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static commonHandlerSet(target: any, key: string | symbol, value: any): boolean {
|
||||
if (typeof key === 'symbol') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (target[key] === value) {
|
||||
return true;
|
||||
}
|
||||
target[key] = value;
|
||||
ObserveV2.getObserve().fireChange(RefInfo.get(target), key.toString());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public static readonly arrayHandlerDeepObserved = {
|
||||
get(target: any, key: string | symbol, receiver: any): any {
|
||||
if (typeof key === 'symbol') {
|
||||
if (key === Symbol.iterator) {
|
||||
let refInfo = RefInfo.get(target);
|
||||
ObserveV2.getObserve().fireChange(refInfo, ObserveV2.OB_MAP_SET_ANY_PROPERTY);
|
||||
ObserveV2.getObserve().addRef(refInfo, ObserveV2.OB_LENGTH);
|
||||
return (...args): any => target[key](...args);
|
||||
}
|
||||
if (key === ObserveV2.SYMBOL_PROXY_GET_TARGET) {
|
||||
return target;
|
||||
}
|
||||
if (key === ObserveV2.SYMBOL_MAKE_OBSERVED) {
|
||||
return true;
|
||||
}
|
||||
return target[key];
|
||||
}
|
||||
|
||||
let refInfo = RefInfo.get(target);
|
||||
if (key === 'size') {
|
||||
ObserveV2.getObserve().addRef(refInfo, ObserveV2.OB_LENGTH);
|
||||
return target.size;
|
||||
}
|
||||
|
||||
let ret = target[key];
|
||||
if (typeof (ret) !== 'function') {
|
||||
if (typeof (ret) === "object") {
|
||||
let wrapper = RefInfo.get(ret);
|
||||
ObserveV2.getObserve().addRef(refInfo, key);
|
||||
return wrapper.proxy;
|
||||
}
|
||||
if (key === 'length') {
|
||||
ObserveV2.getObserve().addRef(refInfo, ObserveV2.OB_LENGTH);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ObserveV2.arrayMutatingFunctions.has(key as string)) {
|
||||
return function (...args): any {
|
||||
ret.call(target, ...args);
|
||||
ObserveV2.getObserve().fireChange(refInfo, ObserveV2.OB_LENGTH);
|
||||
// returning the 'receiver(proxied object)' ensures that when chain calls also 2nd function call
|
||||
// operates on the proxied object.
|
||||
return receiver;
|
||||
};
|
||||
} else if (ObserveV2.arrayLengthChangingFunctions.has(key as string)) {
|
||||
return function (...args): any {
|
||||
const result = ret.call(target, ...args);
|
||||
ObserveV2.getObserve().fireChange(refInfo, ObserveV2.OB_LENGTH);
|
||||
return result;
|
||||
};
|
||||
} else if (key === 'forEach') {
|
||||
// to make ForEach Component and its Item can addref
|
||||
ObserveV2.getObserve().addRef(refInfo, ObserveV2.OB_LENGTH)
|
||||
return function (callbackFn: (value: any, index: number, array: Array<any>) => void): any {
|
||||
const result = ret.call(target, (value: any, index: number, array: Array<any>) => {
|
||||
callbackFn(typeof value == "object" ? RefInfo.get(value).proxy : value, index, receiver);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
return ret.bind(target);
|
||||
}
|
||||
|
||||
},
|
||||
set(target: any, key: string | symbol, value: any): boolean {
|
||||
return ObserveV2.commonHandlerSet(target, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly setMapHandlerDeepObserved = {
|
||||
get(target: any, key: string | symbol, receiver: any): any {
|
||||
if (typeof key === 'symbol') {
|
||||
if (key === Symbol.iterator) {
|
||||
let refInfo = RefInfo.get(target);
|
||||
ObserveV2.getObserve().fireChange(refInfo, ObserveV2.OB_MAP_SET_ANY_PROPERTY);
|
||||
ObserveV2.getObserve().addRef(refInfo, ObserveV2.OB_LENGTH);
|
||||
return (...args): any => target[key](...args);
|
||||
}
|
||||
if (key === ObserveV2.SYMBOL_PROXY_GET_TARGET) {
|
||||
return target;
|
||||
}
|
||||
if (key === ObserveV2.SYMBOL_MAKE_OBSERVED) {
|
||||
return true;
|
||||
}
|
||||
return target[key];
|
||||
}
|
||||
|
||||
let refInfo = RefInfo.get(target);
|
||||
if (key === 'size') {
|
||||
ObserveV2.getObserve().addRef(refInfo, ObserveV2.OB_LENGTH);
|
||||
return target.size;
|
||||
}
|
||||
|
||||
let ret = target[key];
|
||||
if (typeof (ret) !== 'function') {
|
||||
if (typeof (ret) === "object") {
|
||||
let wrapper = RefInfo.get(ret);
|
||||
ObserveV2.getObserve().addRef(refInfo, key);
|
||||
return wrapper.proxy;
|
||||
}
|
||||
if (key === 'length') {
|
||||
ObserveV2.getObserve().addRef(refInfo, ObserveV2.OB_LENGTH);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (key === 'has') {
|
||||
return (prop): boolean => {
|
||||
const ret = target.has(prop);
|
||||
if (ret) {
|
||||
ObserveV2.getObserve().addRef(refInfo, prop);
|
||||
} else {
|
||||
ObserveV2.getObserve().addRef(refInfo, ObserveV2.OB_LENGTH);
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
}
|
||||
if (key === 'delete') {
|
||||
return (prop): boolean => {
|
||||
if (target.has(prop)) {
|
||||
ObserveV2.getObserve().fireChange(refInfo, prop);
|
||||
ObserveV2.getObserve().fireChange(refInfo, ObserveV2.OB_LENGTH);
|
||||
return target.delete(prop);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
if (key === 'clear') {
|
||||
return (): void => {
|
||||
if (target.size > 0) {
|
||||
target.forEach((_, prop) => {
|
||||
ObserveV2.getObserve().fireChange(refInfo, prop.toString());
|
||||
});
|
||||
ObserveV2.getObserve().fireChange(refInfo, ObserveV2.OB_LENGTH);
|
||||
ObserveV2.getObserve().addRef(refInfo, ObserveV2.OB_MAP_SET_ANY_PROPERTY);
|
||||
target.clear();
|
||||
}
|
||||
};
|
||||
}
|
||||
if (key === 'keys' || key === 'values' || key === 'entries') {
|
||||
return (): any => {
|
||||
ObserveV2.getObserve().addRef(refInfo, ObserveV2.OB_MAP_SET_ANY_PROPERTY);
|
||||
ObserveV2.getObserve().addRef(refInfo, ObserveV2.OB_LENGTH);
|
||||
return target[key]();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
if (target instanceof Set || SendableType.isSet(target)) {
|
||||
return key === 'add' ?
|
||||
(val): any => {
|
||||
ObserveV2.getObserve().fireChange(refInfo, val.toString());
|
||||
ObserveV2.getObserve().fireChange(refInfo, ObserveV2.OB_MAP_SET_ANY_PROPERTY);
|
||||
if (!target.has(val)) {
|
||||
ObserveV2.getObserve().fireChange(refInfo, ObserveV2.OB_LENGTH);
|
||||
target.add(val);
|
||||
}
|
||||
// return proxied This
|
||||
return receiver;
|
||||
} : (typeof ret === 'function')
|
||||
? ret.bind(target) : ret;
|
||||
}
|
||||
|
||||
if (target instanceof Map || SendableType.isMap(target)) {
|
||||
if (key === 'get') { // for Map
|
||||
return (prop): any => {
|
||||
if (target.has(prop)) {
|
||||
ObserveV2.getObserve().addRef(refInfo, prop);
|
||||
} else {
|
||||
ObserveV2.getObserve().addRef(refInfo, ObserveV2.OB_LENGTH);
|
||||
}
|
||||
let ret = target.get(prop);
|
||||
|
||||
return typeof ret === 'object' ? RefInfo.get(ret).proxy : ret;
|
||||
};
|
||||
}
|
||||
if (key === 'set') { // for Map
|
||||
return (prop, val): any => {
|
||||
if (!target.has(prop)) {
|
||||
ObserveV2.getObserve().fireChange(refInfo, ObserveV2.OB_LENGTH);
|
||||
} else if (target.get(prop) !== val) {
|
||||
ObserveV2.getObserve().fireChange(refInfo, prop);
|
||||
}
|
||||
ObserveV2.getObserve().fireChange(refInfo, ObserveV2.OB_MAP_SET_ANY_PROPERTY);
|
||||
target.set(prop, val);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
}
|
||||
return (typeof ret === 'function') ? ret.bind(target) : ret;
|
||||
},
|
||||
set(target: any, key: string | symbol, value: any): boolean {
|
||||
return ObserveV2.commonHandlerSet(target, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly dateHandlerDeepObserved = {
|
||||
get(target: any, key: string | symbol, receiver: any): any {
|
||||
if (typeof key === 'symbol') {
|
||||
if (key === ObserveV2.SYMBOL_PROXY_GET_TARGET) {
|
||||
return target;
|
||||
}
|
||||
if (key === ObserveV2.SYMBOL_MAKE_OBSERVED) {
|
||||
return true;
|
||||
}
|
||||
return target[key];
|
||||
}
|
||||
|
||||
let ret = target[key];
|
||||
let refInfo = RefInfo.get(target);
|
||||
if (ObserveV2.dateSetFunctions.has(key)) {
|
||||
return function (...args): any {
|
||||
// execute original function with given arguments
|
||||
let result = ret.call(this, ...args);
|
||||
ObserveV2.getObserve().fireChange(refInfo, ObserveV2.OB_DATE);
|
||||
return result;
|
||||
// bind 'this' to target inside the function
|
||||
}.bind(target);
|
||||
} else {
|
||||
ObserveV2.getObserve().addRef(refInfo, ObserveV2.OB_DATE);
|
||||
}
|
||||
return ret.bind(target);
|
||||
},
|
||||
|
||||
set(target: any, key: string | symbol, value: any): boolean {
|
||||
return ObserveV2.commonHandlerSet(target, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly arraySetMapProxy = {
|
||||
get(
|
||||
target: any,
|
||||
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class RefInfo {
|
||||
private static obj2ref: WeakMap<object, object> = new WeakMap();
|
||||
|
||||
static get(target: Object): any {
|
||||
if (typeof (target) !== "object") {
|
||||
throw new Error("target must be a object");
|
||||
}
|
||||
// makeObserved does not support @Observed and @ObservedV2/@Trace class, will return target directly
|
||||
if (ObservedObject.IsObservedObject(target) || ObserveV2.IsObservedObjectV2(target)) {
|
||||
stateMgmtConsole.warn(`${target.constructor.name} is Observed ${ObservedObject.IsObservedObject(target)}, IsObservedV2 ${ObserveV2.IsObservedObjectV2(target)}. makeObserved will stop work`)
|
||||
return { proxy: target };
|
||||
}
|
||||
let ret = RefInfo.obj2ref.get(target);
|
||||
if (!ret) {
|
||||
if (Array.isArray(target) || SendableType.isArray(target)) {
|
||||
ret = { proxy: new Proxy(target, ObserveV2.arrayHandlerDeepObserved) };
|
||||
} else if (target instanceof Set || SendableType.isSet(target) || target instanceof Map || SendableType.isMap(target)) {
|
||||
ret = { proxy: new Proxy(target, ObserveV2.setMapHandlerDeepObserved) };
|
||||
} else if (target instanceof Date) {
|
||||
ret = { proxy: new Proxy(target, ObserveV2.dateHandlerDeepObserved) };
|
||||
} else {
|
||||
ret = { proxy: new Proxy(target, ObserveV2.normalObjectHandlerDeepObserved) };
|
||||
}
|
||||
RefInfo.obj2ref.set(target, ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
@ -85,6 +85,8 @@
|
||||
"src/lib/v2/v2_view.ts",
|
||||
"src/lib/v2/v2_decorators.ts",
|
||||
"src/lib/v2/v2_json_coder.ts",
|
||||
"src/lib/v2/v2_make_observed.ts",
|
||||
"src/lib/common/sendable_type.ts",
|
||||
|
||||
// partial_update specific
|
||||
"src/lib/partial_update/pu_repeat.ts",
|
||||
|
@ -87,6 +87,8 @@
|
||||
"src/lib/v2/v2_view.ts",
|
||||
"src/lib/v2/v2_decorators.ts",
|
||||
"src/lib/v2/v2_json_coder.ts",
|
||||
"src/lib/v2/v2_make_observed_core.ts",
|
||||
"src/lib/common/sendable_type.ts",
|
||||
|
||||
// partial_update specific
|
||||
"src/lib/partial_update/pu_repeat.ts",
|
||||
|
@ -62,6 +62,7 @@
|
||||
"src/lib/puv2_common/puv2_updatefunc.ts",
|
||||
"src/lib/puv2_common/puv2_view_native_base.d.ts",
|
||||
"src/lib/puv2_common/puv2_view_base.ts",
|
||||
"src/lib/common/sendable_type.ts",
|
||||
|
||||
// partial_update specific
|
||||
"src/lib/partial_update/pu_types_events.ts",
|
||||
@ -85,6 +86,9 @@
|
||||
"src/lib/v2/v2_view.ts",
|
||||
"src/lib/v2/v2_decorators.ts",
|
||||
"src/lib/v2/v2_json_coder.ts",
|
||||
"src/lib/v2/v2_make_observed.ts",
|
||||
"src/lib/common/sendable_type.ts",
|
||||
|
||||
|
||||
// partial_update specific
|
||||
"src/lib/partial_update/pu_repeat.ts",
|
||||
|
@ -73,6 +73,9 @@
|
||||
"src/lib/v2/v2_view.ts",
|
||||
"src/lib/v2/v2_decorators.ts",
|
||||
"src/lib/v2/v2_json_coder.ts",
|
||||
"src/lib/v2/v2_make_observed.ts",
|
||||
"src/lib/common/sendable_type.ts",
|
||||
|
||||
|
||||
// partial_update specific
|
||||
"src/lib/partial_update/pu_repeat.ts",
|
||||
|
Loading…
Reference in New Issue
Block a user