@aura3d/animation 4.7.12 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AnimationAction.d.ts +80 -1
- package/dist/AnimationAction.d.ts.map +1 -1
- package/dist/AnimationAction.js +450 -80
- package/dist/AnimationAction.js.map +1 -1
- package/dist/AnimationClip.d.ts.map +1 -1
- package/dist/AnimationClip.js.map +1 -1
- package/dist/AnimationClipEvents.d.ts.map +1 -1
- package/dist/AnimationClipEvents.js.map +1 -1
- package/dist/AnimationClipRegistry.d.ts.map +1 -1
- package/dist/AnimationClipRegistry.js.map +1 -1
- package/dist/AnimationController.d.ts.map +1 -1
- package/dist/AnimationController.js.map +1 -1
- package/dist/AnimationEvents.d.ts +23 -0
- package/dist/AnimationEvents.d.ts.map +1 -1
- package/dist/AnimationEvents.js +145 -36
- package/dist/AnimationEvents.js.map +1 -1
- package/dist/AnimationLayer.d.ts.map +1 -1
- package/dist/AnimationLayer.js.map +1 -1
- package/dist/AnimationMixer.d.ts +58 -3
- package/dist/AnimationMixer.d.ts.map +1 -1
- package/dist/AnimationMixer.js +366 -12
- package/dist/AnimationMixer.js.map +1 -1
- package/dist/AnimationObjectGroup.d.ts +36 -12
- package/dist/AnimationObjectGroup.d.ts.map +1 -1
- package/dist/AnimationObjectGroup.js +219 -208
- package/dist/AnimationObjectGroup.js.map +1 -1
- package/dist/AnimationStateGraph.d.ts.map +1 -1
- package/dist/AnimationStateGraph.js.map +1 -1
- package/dist/AnimationStateMachine.d.ts.map +1 -1
- package/dist/AnimationStateMachine.js.map +1 -1
- package/dist/AnimationTrack.d.ts +7 -1
- package/dist/AnimationTrack.d.ts.map +1 -1
- package/dist/AnimationTrack.js +87 -10
- package/dist/AnimationTrack.js.map +1 -1
- package/dist/AnimationUtils.d.ts +16 -14
- package/dist/AnimationUtils.d.ts.map +1 -1
- package/dist/AnimationUtils.js +148 -109
- package/dist/AnimationUtils.js.map +1 -1
- package/dist/BlendTree.d.ts.map +1 -1
- package/dist/BlendTree.js.map +1 -1
- package/dist/Bone.d.ts.map +1 -1
- package/dist/Bone.js.map +1 -1
- package/dist/ECSAnimationBridge.d.ts.map +1 -1
- package/dist/ECSAnimationBridge.js.map +1 -1
- package/dist/FighterAnimationAdapter.d.ts.map +1 -1
- package/dist/FighterAnimationAdapter.js.map +1 -1
- package/dist/FootIk.d.ts.map +1 -1
- package/dist/FootIk.js.map +1 -1
- package/dist/HumanoidBoneInference.d.ts.map +1 -1
- package/dist/HumanoidBoneInference.js.map +1 -1
- package/dist/HumanoidRetargeting.d.ts.map +1 -1
- package/dist/HumanoidRetargeting.js.map +1 -1
- package/dist/IK.d.ts.map +1 -1
- package/dist/IK.js.map +1 -1
- package/dist/Inertialization.d.ts.map +1 -1
- package/dist/Inertialization.js.map +1 -1
- package/dist/Keyframe.d.ts +15 -1
- package/dist/Keyframe.d.ts.map +1 -1
- package/dist/Keyframe.js +34 -1
- package/dist/Keyframe.js.map +1 -1
- package/dist/LocomotionController.d.ts.map +1 -1
- package/dist/LocomotionController.js.map +1 -1
- package/dist/LocomotionEvidence.d.ts.map +1 -1
- package/dist/LocomotionEvidence.js.map +1 -1
- package/dist/LocomotionKit.d.ts.map +1 -1
- package/dist/LocomotionKit.js.map +1 -1
- package/dist/MotionQuality.d.ts.map +1 -1
- package/dist/MotionQuality.js.map +1 -1
- package/dist/PropertyBinding.d.ts +42 -22
- package/dist/PropertyBinding.d.ts.map +1 -1
- package/dist/PropertyBinding.js +390 -293
- package/dist/PropertyBinding.js.map +1 -1
- package/dist/RigQuality.d.ts.map +1 -1
- package/dist/RigQuality.js.map +1 -1
- package/dist/RootMotion.d.ts.map +1 -1
- package/dist/RootMotion.js.map +1 -1
- package/dist/SceneAnimationBridge.d.ts +7 -0
- package/dist/SceneAnimationBridge.d.ts.map +1 -1
- package/dist/SceneAnimationBridge.js +48 -3
- package/dist/SceneAnimationBridge.js.map +1 -1
- package/dist/Skeleton.d.ts.map +1 -1
- package/dist/Skeleton.js.map +1 -1
- package/dist/Skinning.d.ts.map +1 -1
- package/dist/Skinning.js.map +1 -1
- package/dist/SpringBones.d.ts.map +1 -1
- package/dist/SpringBones.js.map +1 -1
- package/dist/browser-index.d.ts +1 -1
- package/dist/browser-index.d.ts.map +1 -1
- package/dist/browser-index.js +1 -1
- package/dist/browser-index.js.map +1 -1
- package/dist/contracts/index.d.ts.map +1 -1
- package/dist/contracts/index.js.map +1 -1
- package/dist/contracts/pose.d.ts.map +1 -1
- package/dist/contracts/pose.js.map +1 -1
- package/dist/experimental/CrowdAnimation.d.ts.map +1 -1
- package/dist/experimental/CrowdAnimation.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lanes/index.d.ts.map +1 -1
- package/dist/lanes/index.js.map +1 -1
- package/dist/lanes/prd01.d.ts.map +1 -1
- package/dist/lanes/prd01.js.map +1 -1
- package/dist/lanes/prd02.d.ts.map +1 -1
- package/dist/lanes/prd02.js.map +1 -1
- package/dist/lanes/prd03.d.ts.map +1 -1
- package/dist/lanes/prd03.js.map +1 -1
- package/dist/lanes/prd04.d.ts.map +1 -1
- package/dist/lanes/prd04.js.map +1 -1
- package/dist/lanes/prd05.d.ts.map +1 -1
- package/dist/lanes/prd05.js.map +1 -1
- package/dist/lanes/prd06.d.ts.map +1 -1
- package/dist/lanes/prd06.js.map +1 -1
- package/dist/lanes/prd07.d.ts.map +1 -1
- package/dist/lanes/prd07.js.map +1 -1
- package/dist/lanes/prd08.d.ts.map +1 -1
- package/dist/lanes/prd08.js.map +1 -1
- package/dist/lanes/prd09.d.ts.map +1 -1
- package/dist/lanes/prd09.js.map +1 -1
- package/dist/lanes/prd10.d.ts.map +1 -1
- package/dist/lanes/prd10.js.map +1 -1
- package/dist/lanes/prd11.d.ts.map +1 -1
- package/dist/lanes/prd11.js.map +1 -1
- package/dist/lanes/prd12.d.ts.map +1 -1
- package/dist/lanes/prd12.js.map +1 -1
- package/dist/lanes/prd13.d.ts.map +1 -1
- package/dist/lanes/prd13.js.map +1 -1
- package/dist/lanes/prd14.d.ts.map +1 -1
- package/dist/lanes/prd14.js.map +1 -1
- package/dist/lanes/prd15.d.ts.map +1 -1
- package/dist/lanes/prd15.js.map +1 -1
- package/dist/library/performanceStateGraph.d.ts.map +1 -1
- package/dist/library/performanceStateGraph.js.map +1 -1
- package/dist/library/standardHumanoidClips.d.ts.map +1 -1
- package/dist/library/standardHumanoidClips.js.map +1 -1
- package/dist/pose/BoneMask.d.ts.map +1 -1
- package/dist/pose/BoneMask.js.map +1 -1
- package/dist/pose/CcdIkConstraint.d.ts.map +1 -1
- package/dist/pose/CcdIkConstraint.js.map +1 -1
- package/dist/pose/CompiledClip.d.ts +15 -8
- package/dist/pose/CompiledClip.d.ts.map +1 -1
- package/dist/pose/CompiledClip.js +82 -50
- package/dist/pose/CompiledClip.js.map +1 -1
- package/dist/pose/LookAtConstraint.d.ts.map +1 -1
- package/dist/pose/LookAtConstraint.js.map +1 -1
- package/dist/pose/MotionMetrics.d.ts.map +1 -1
- package/dist/pose/MotionMetrics.js.map +1 -1
- package/dist/pose/PoseBuffer.d.ts.map +1 -1
- package/dist/pose/PoseBuffer.js.map +1 -1
- package/dist/pose/PoseInertializer.d.ts.map +1 -1
- package/dist/pose/PoseInertializer.js.map +1 -1
- package/dist/pose/PoseMixer.d.ts +196 -19
- package/dist/pose/PoseMixer.d.ts.map +1 -1
- package/dist/pose/PoseMixer.js +1209 -188
- package/dist/pose/PoseMixer.js.map +1 -1
- package/dist/pose/Retarget.d.ts +4 -3
- package/dist/pose/Retarget.d.ts.map +1 -1
- package/dist/pose/Retarget.js +32 -15
- package/dist/pose/Retarget.js.map +1 -1
- package/dist/pose/RetargetCache.d.ts +12 -6
- package/dist/pose/RetargetCache.d.ts.map +1 -1
- package/dist/pose/RetargetCache.js +253 -29
- package/dist/pose/RetargetCache.js.map +1 -1
- package/dist/pose/RetargetWorker.d.ts.map +1 -1
- package/dist/pose/RetargetWorker.js +5 -0
- package/dist/pose/RetargetWorker.js.map +1 -1
- package/dist/pose/SkeletonBinding.d.ts.map +1 -1
- package/dist/pose/SkeletonBinding.js.map +1 -1
- package/dist/pose/blendKernels.d.ts.map +1 -1
- package/dist/pose/blendKernels.js.map +1 -1
- package/dist/pose/makeClipAdditive.d.ts +7 -14
- package/dist/pose/makeClipAdditive.d.ts.map +1 -1
- package/dist/pose/makeClipAdditive.js +53 -85
- package/dist/pose/makeClipAdditive.js.map +1 -1
- package/dist/pose/poseMixerFlags.d.ts.map +1 -1
- package/dist/pose/poseMixerFlags.js.map +1 -1
- package/dist/pose/quatFlat.d.ts.map +1 -1
- package/dist/pose/quatFlat.js.map +1 -1
- package/dist/pose/retarget.worker.d.ts.map +1 -1
- package/dist/pose/retarget.worker.js.map +1 -1
- package/dist/threejs-compatibility/AnimationAction.d.ts.map +1 -1
- package/dist/threejs-compatibility/AnimationAction.js.map +1 -1
- package/dist/threejs-compatibility/AnimationClip.d.ts.map +1 -1
- package/dist/threejs-compatibility/AnimationClip.js.map +1 -1
- package/dist/threejs-compatibility/AnimationDiagnostics.d.ts.map +1 -1
- package/dist/threejs-compatibility/AnimationDiagnostics.js.map +1 -1
- package/dist/threejs-compatibility/AnimationMixer.d.ts.map +1 -1
- package/dist/threejs-compatibility/AnimationMixer.js.map +1 -1
- package/dist/threejs-compatibility/MorphTargetMixer.d.ts.map +1 -1
- package/dist/threejs-compatibility/MorphTargetMixer.js.map +1 -1
- package/dist/threejs-compatibility/Skeleton.d.ts.map +1 -1
- package/dist/threejs-compatibility/Skeleton.js.map +1 -1
- package/dist/threejs-compatibility/SkinnedMesh.d.ts.map +1 -1
- package/dist/threejs-compatibility/SkinnedMesh.js.map +1 -1
- package/dist/threejs-compatibility/index.d.ts.map +1 -1
- package/dist/threejs-compatibility/index.js.map +1 -1
- package/package.json +2 -2
package/dist/PropertyBinding.js
CHANGED
|
@@ -1,129 +1,240 @@
|
|
|
1
|
+
const OBJECT_SEGMENTS = new Set(["material", "materials", "bones", "map"]);
|
|
2
|
+
const UNSAFE_KEYS = new Set(["__proto__", "prototype", "constructor"]);
|
|
1
3
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* `nodeName.property[index]`, `.morphTargetInfluences[name]`,
|
|
8
|
-
* `uuid.materials[0].opacity`, `parent/child.position`, and
|
|
9
|
-
* `.bones[Armature.DEF_cog].position` resolve exactly as they do upstream.
|
|
4
|
+
* Parses `node.property[index]` and `node.object[index].property` paths.
|
|
5
|
+
* Unescaped `.` separates selectors; `/` and `:` delimit a hierarchy prefix.
|
|
6
|
+
* Escape any delimiter, bracket, quote or backslash with `\\`. Accessors may
|
|
7
|
+
* also be quoted, e.g. `.weights["smile.right"]`. Names are Unicode strings.
|
|
8
|
+
* The prefix is retained for callers; legacy lookup uses its leaf node name.
|
|
10
9
|
*/
|
|
11
|
-
// Characters `[].:/` are reserved for track binding syntax.
|
|
12
|
-
const RESERVED_CHARS_RE = "\\[\\]\\.:\\/";
|
|
13
|
-
const RESERVED_RE = new RegExp("[" + RESERVED_CHARS_RE + "]", "g");
|
|
14
|
-
// Attempts to allow node names from any language: match everything except the
|
|
15
|
-
// reserved characters (three deliberately avoids `\w`).
|
|
16
|
-
const WORD_CHAR = "[^" + RESERVED_CHARS_RE + "]";
|
|
17
|
-
const WORD_CHAR_OR_DOT = "[^" + RESERVED_CHARS_RE.replace("\\.", "") + "]";
|
|
18
|
-
// Parent directories, delimited by '/' or ':'. Currently unused, but must be
|
|
19
|
-
// matched to parse the rest of the track name.
|
|
20
|
-
const DIRECTORY_RE = /((?:WC+[\/:])*)/.source.replace(/WC/g, WORD_CHAR);
|
|
21
|
-
// Target node. May contain word characters and '.' (e.g. 'foo.bar.baz').
|
|
22
|
-
const NODE_RE = /(WCOD+)?/.source.replace(/WCOD/g, WORD_CHAR_OR_DOT);
|
|
23
|
-
// Object on target node, and accessor (`materials[0]`).
|
|
24
|
-
const OBJECT_RE = /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace(/WC/g, WORD_CHAR);
|
|
25
|
-
// Property and accessor (`morphTargetInfluences[run]`, `position[x]`).
|
|
26
|
-
const PROPERTY_RE = /\.(WC+)(?:\[(.+)\])?/.source.replace(/WC/g, WORD_CHAR);
|
|
27
|
-
const TRACK_RE = new RegExp("^" + DIRECTORY_RE + NODE_RE + OBJECT_RE + PROPERTY_RE + "$");
|
|
28
|
-
const SUPPORTED_OBJECT_NAMES = ["material", "materials", "bones", "map"];
|
|
29
10
|
export function parseTrackName(trackName) {
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
11
|
+
const { dots, directories } = scanPath(trackName);
|
|
12
|
+
const directoryEnd = directories.length ? directories[directories.length - 1] + 1 : 0;
|
|
13
|
+
const propertyDot = dots[dots.length - 1];
|
|
14
|
+
if (propertyDot === undefined || propertyDot < directoryEnd)
|
|
15
|
+
throw invalidPath(trackName);
|
|
16
|
+
const property = parseSegment(trackName.slice(propertyDot + 1), trackName);
|
|
17
|
+
const prefix = trackName.slice(directoryEnd, propertyDot);
|
|
18
|
+
const precedingDot = dots.filter((position) => position >= directoryEnd && position < propertyDot).pop();
|
|
19
|
+
let node = prefix;
|
|
20
|
+
let object;
|
|
21
|
+
if (precedingDot !== undefined) {
|
|
22
|
+
const candidate = parseSegment(trackName.slice(precedingDot + 1, propertyDot), trackName);
|
|
23
|
+
if (candidate.index !== undefined || OBJECT_SEGMENTS.has(candidate.name)) {
|
|
24
|
+
object = candidate;
|
|
25
|
+
node = trackName.slice(directoryEnd, precedingDot);
|
|
26
|
+
}
|
|
33
27
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
28
|
+
// No brackets may appear in the remaining node selector; literal brackets
|
|
29
|
+
// in a name must be escaped so a malformed object selector cannot be ignored.
|
|
30
|
+
if (hasUnescapedBracket(node))
|
|
31
|
+
throw invalidPath(trackName);
|
|
32
|
+
const result = {
|
|
33
|
+
directoryName: decodeEscapes(trackName.slice(0, directoryEnd), trackName),
|
|
34
|
+
nodeName: node ? decodeEscapes(node, trackName) : undefined,
|
|
35
|
+
objectName: object?.name,
|
|
36
|
+
objectIndex: object?.index,
|
|
37
|
+
propertyName: property.name,
|
|
38
|
+
propertyIndex: property.index
|
|
41
39
|
};
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
40
|
+
assertSafePath(result, trackName);
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
function invalidPath(path) {
|
|
44
|
+
return new Error(`PropertyBinding: Cannot parse trackName: ${path}`);
|
|
45
|
+
}
|
|
46
|
+
function scanPath(path) {
|
|
47
|
+
if (!path)
|
|
48
|
+
throw invalidPath(path);
|
|
49
|
+
const dots = [];
|
|
50
|
+
const directories = [];
|
|
51
|
+
let bracket = -1;
|
|
52
|
+
let quote;
|
|
53
|
+
let quoteClosed = false;
|
|
54
|
+
let afterBracket = false;
|
|
55
|
+
for (let i = 0; i < path.length; i++) {
|
|
56
|
+
const char = path[i];
|
|
57
|
+
if (afterBracket && char !== ".")
|
|
58
|
+
throw invalidPath(path);
|
|
59
|
+
if (char === "\\") {
|
|
60
|
+
if (++i >= path.length)
|
|
61
|
+
throw invalidPath(path);
|
|
62
|
+
continue;
|
|
51
63
|
}
|
|
64
|
+
if (bracket >= 0) {
|
|
65
|
+
if (quote) {
|
|
66
|
+
if (char === quote) {
|
|
67
|
+
quote = undefined;
|
|
68
|
+
quoteClosed = true;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else if (i === bracket + 1 && (char === '"' || char === "'")) {
|
|
72
|
+
quote = char;
|
|
73
|
+
}
|
|
74
|
+
else if (char === "]") {
|
|
75
|
+
bracket = -1;
|
|
76
|
+
quoteClosed = false;
|
|
77
|
+
afterBracket = true;
|
|
78
|
+
}
|
|
79
|
+
else if (char === "[" || quoteClosed) {
|
|
80
|
+
throw invalidPath(path);
|
|
81
|
+
}
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (char === "[")
|
|
85
|
+
bracket = i;
|
|
86
|
+
else if (char === "]")
|
|
87
|
+
throw invalidPath(path);
|
|
88
|
+
else if (char === ".") {
|
|
89
|
+
dots.push(i);
|
|
90
|
+
afterBracket = false;
|
|
91
|
+
}
|
|
92
|
+
else if (char === "/" || char === ":")
|
|
93
|
+
directories.push(i);
|
|
52
94
|
}
|
|
53
|
-
if (
|
|
54
|
-
throw
|
|
55
|
-
}
|
|
56
|
-
return results;
|
|
95
|
+
if (bracket >= 0 || quote)
|
|
96
|
+
throw invalidPath(path);
|
|
97
|
+
return { dots, directories };
|
|
57
98
|
}
|
|
58
|
-
|
|
59
|
-
|
|
99
|
+
function decodeEscapes(text, path) {
|
|
100
|
+
let result = "";
|
|
101
|
+
for (let i = 0; i < text.length; i++) {
|
|
102
|
+
if (text[i] === "\\") {
|
|
103
|
+
if (++i >= text.length)
|
|
104
|
+
throw invalidPath(path);
|
|
105
|
+
}
|
|
106
|
+
result += text[i];
|
|
107
|
+
}
|
|
108
|
+
return result;
|
|
60
109
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
110
|
+
function hasUnescapedBracket(text) {
|
|
111
|
+
for (let i = 0; i < text.length; i++) {
|
|
112
|
+
if (text[i] === "\\") {
|
|
113
|
+
i++;
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
if (text[i] === "[" || text[i] === "]")
|
|
117
|
+
return true;
|
|
64
118
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
function parseSegment(raw, path) {
|
|
122
|
+
if (!raw)
|
|
123
|
+
throw invalidPath(path);
|
|
124
|
+
let open = -1;
|
|
125
|
+
for (let i = 0; i < raw.length; i++) {
|
|
126
|
+
if (raw[i] === "\\") {
|
|
127
|
+
i++;
|
|
128
|
+
continue;
|
|
70
129
|
}
|
|
71
|
-
if (
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
return named;
|
|
75
|
-
}
|
|
130
|
+
if (raw[i] === "[") {
|
|
131
|
+
open = i;
|
|
132
|
+
break;
|
|
76
133
|
}
|
|
77
134
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
135
|
+
if (open < 0)
|
|
136
|
+
return { name: decodeEscapes(raw, path) };
|
|
137
|
+
if (open === 0 || raw[raw.length - 1] !== "]")
|
|
138
|
+
throw invalidPath(path);
|
|
139
|
+
const name = decodeEscapes(raw.slice(0, open), path);
|
|
140
|
+
let index = raw.slice(open + 1, -1);
|
|
141
|
+
if (!index)
|
|
142
|
+
throw invalidPath(path);
|
|
143
|
+
if (index[0] === '"' || index[0] === "'") {
|
|
144
|
+
if (index.length < 2 || index[index.length - 1] !== index[0])
|
|
145
|
+
throw invalidPath(path);
|
|
146
|
+
index = index.slice(1, -1);
|
|
147
|
+
}
|
|
148
|
+
index = decodeEscapes(index, path);
|
|
149
|
+
if (!index)
|
|
150
|
+
throw invalidPath(path);
|
|
151
|
+
return { name, index };
|
|
152
|
+
}
|
|
153
|
+
function assertSafePath(path, source) {
|
|
154
|
+
const keys = [path.objectName, path.objectIndex, path.propertyName, path.propertyIndex];
|
|
155
|
+
if (!path.propertyName || keys.some((key) => key !== undefined && UNSAFE_KEYS.has(String(key)))) {
|
|
156
|
+
throw new Error(`PropertyBinding: Unsafe property path: ${source}`);
|
|
84
157
|
}
|
|
85
|
-
return null;
|
|
86
158
|
}
|
|
87
|
-
function
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
159
|
+
export function sanitizeNodeName(name) {
|
|
160
|
+
return name.replace(/\s/g, "_").replace(/[\[\].:/]/g, "").replace(/\\/g, "");
|
|
161
|
+
}
|
|
162
|
+
/** UUIDs take precedence; duplicate names resolve in depth-first child order. */
|
|
163
|
+
export function findNode(root, nodeName) {
|
|
164
|
+
if (nodeName === undefined || nodeName === "" || nodeName === "." || nodeName === -1 || nodeName === root.uuid)
|
|
165
|
+
return root;
|
|
166
|
+
const bones = root.skeleton?.bones ?? [];
|
|
167
|
+
const nodes = [];
|
|
168
|
+
const pending = [...(root.children ?? [])].reverse();
|
|
169
|
+
const visited = new Set([root]);
|
|
170
|
+
while (pending.length) {
|
|
171
|
+
const candidate = pending.pop();
|
|
172
|
+
if (visited.has(candidate))
|
|
173
|
+
continue;
|
|
174
|
+
visited.add(candidate);
|
|
175
|
+
nodes.push(candidate);
|
|
176
|
+
if (candidate.children) {
|
|
177
|
+
for (let i = candidate.children.length - 1; i >= 0; i--)
|
|
178
|
+
pending.push(candidate.children[i]);
|
|
91
179
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
180
|
+
}
|
|
181
|
+
const byUuid = [...bones, ...nodes].find((candidate) => candidate.uuid === nodeName);
|
|
182
|
+
if (byUuid)
|
|
183
|
+
return byUuid;
|
|
184
|
+
if (nodeName === root.name)
|
|
185
|
+
return root;
|
|
186
|
+
const bone = root.skeleton?.getBoneByName?.(String(nodeName));
|
|
187
|
+
return bone ?? bones.find((candidate) => candidate.name === nodeName)
|
|
188
|
+
?? nodes.find((candidate) => candidate.name === nodeName) ?? null;
|
|
189
|
+
}
|
|
190
|
+
function isObject(value) {
|
|
191
|
+
return value !== null && (typeof value === "object" || typeof value === "function");
|
|
192
|
+
}
|
|
193
|
+
/** Own properties and declared class accessors are permitted; prototype data is not. */
|
|
194
|
+
function lookup(object, key) {
|
|
195
|
+
if (!isObject(object) || UNSAFE_KEYS.has(String(key)))
|
|
196
|
+
return { found: false };
|
|
197
|
+
const own = Object.getOwnPropertyDescriptor(object, key);
|
|
198
|
+
if (own)
|
|
199
|
+
return { found: true, value: Reflect.get(object, key) };
|
|
200
|
+
let prototype = Object.getPrototypeOf(object);
|
|
201
|
+
while (prototype && prototype !== Object.prototype && prototype !== Array.prototype) {
|
|
202
|
+
const descriptor = Object.getOwnPropertyDescriptor(prototype, key);
|
|
203
|
+
if (descriptor) {
|
|
204
|
+
const constructor = Object.getOwnPropertyDescriptor(prototype, "constructor")?.value;
|
|
205
|
+
return (descriptor.get || descriptor.set) && typeof constructor === "function" && constructor.prototype === prototype
|
|
206
|
+
? { found: true, value: Reflect.get(object, key) }
|
|
207
|
+
: { found: false };
|
|
97
208
|
}
|
|
209
|
+
prototype = Object.getPrototypeOf(prototype);
|
|
98
210
|
}
|
|
99
|
-
return
|
|
211
|
+
return { found: false };
|
|
100
212
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
(
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
213
|
+
function numericIndex(key) {
|
|
214
|
+
if (!/^(0|[1-9]\d*)$/.test(key))
|
|
215
|
+
return undefined;
|
|
216
|
+
const value = Number(key);
|
|
217
|
+
return Number.isSafeInteger(value) ? value : undefined;
|
|
218
|
+
}
|
|
219
|
+
function isNumericArray(value) {
|
|
220
|
+
return Array.isArray(value) || (ArrayBuffer.isView(value) && !(value instanceof DataView)
|
|
221
|
+
&& !(value instanceof BigInt64Array) && !(value instanceof BigUint64Array));
|
|
222
|
+
}
|
|
223
|
+
function isArrayConvertible(value) {
|
|
224
|
+
const candidate = value;
|
|
225
|
+
return typeof candidate?.fromArray === "function" && typeof candidate?.toArray === "function";
|
|
226
|
+
}
|
|
227
|
+
// The group can revalidate membership after a lazy bind invokes a user getter.
|
|
228
|
+
// These operations stay internal to the module; the public binding methods
|
|
229
|
+
// retain their original signatures.
|
|
230
|
+
const readForGroup = Symbol("readForGroup");
|
|
231
|
+
const writeForGroup = Symbol("writeForGroup");
|
|
232
|
+
/** Resolves a track to an existing property; missing paths remain unbound. */
|
|
119
233
|
export class PropertyBinding {
|
|
120
234
|
static parseTrackName = parseTrackName;
|
|
121
235
|
static sanitizeNodeName = sanitizeNodeName;
|
|
122
236
|
static findNode = findNode;
|
|
123
|
-
|
|
124
|
-
static get Composite() {
|
|
125
|
-
return PropertyBindingComposite;
|
|
126
|
-
}
|
|
237
|
+
static get Composite() { return PropertyBindingComposite; }
|
|
127
238
|
path;
|
|
128
239
|
parsedPath;
|
|
129
240
|
rootNode;
|
|
@@ -132,262 +243,248 @@ export class PropertyBinding {
|
|
|
132
243
|
resolvedProperty;
|
|
133
244
|
propertyName;
|
|
134
245
|
propertyIndex;
|
|
246
|
+
kind = "direct";
|
|
135
247
|
bound = false;
|
|
136
248
|
constructor(rootNode, path, parsedPath) {
|
|
137
249
|
this.path = path;
|
|
138
|
-
|
|
250
|
+
// Copy caller-owned descriptors so later mutation cannot redirect a binding.
|
|
251
|
+
this.parsedPath = parsedPath ? { ...parsedPath } : parseTrackName(path);
|
|
252
|
+
assertSafePath(this.parsedPath, path);
|
|
139
253
|
this.rootNode = rootNode;
|
|
140
254
|
this.node = findNode(rootNode, this.parsedPath.nodeName);
|
|
141
255
|
}
|
|
142
|
-
/**
|
|
143
|
-
* Factory matching three's `PropertyBinding.create`: a root marked
|
|
144
|
-
* `isAnimationObjectGroup` produces a composite binding shared across the
|
|
145
|
-
* group's objects.
|
|
146
|
-
*/
|
|
147
256
|
static create(root, path, parsedPath) {
|
|
148
|
-
if (
|
|
149
|
-
return new
|
|
150
|
-
|
|
151
|
-
return new PropertyBindingComposite(root, path, parsedPath);
|
|
257
|
+
if ("isAnimationObjectGroup" in root && root.isAnimationObjectGroup)
|
|
258
|
+
return new PropertyBindingComposite(root, path, parsedPath);
|
|
259
|
+
return new PropertyBinding(root, path, parsedPath);
|
|
152
260
|
}
|
|
153
261
|
bind() {
|
|
154
|
-
let targetObject = this.node;
|
|
155
|
-
const parsedPath = this.parsedPath;
|
|
156
|
-
const objectName = parsedPath.objectName;
|
|
157
|
-
const propertyName = parsedPath.propertyName;
|
|
158
|
-
let propertyIndex = parsedPath.propertyIndex;
|
|
159
|
-
if (!targetObject) {
|
|
160
|
-
targetObject = findNode(this.rootNode, parsedPath.nodeName);
|
|
161
|
-
this.node = targetObject;
|
|
162
|
-
}
|
|
163
262
|
this.bound = false;
|
|
164
|
-
|
|
165
|
-
|
|
263
|
+
this.targetObject = undefined;
|
|
264
|
+
this.resolvedProperty = undefined;
|
|
265
|
+
this.propertyName = undefined;
|
|
266
|
+
this.propertyIndex = undefined;
|
|
267
|
+
assertSafePath(this.parsedPath, this.path);
|
|
268
|
+
const node = this.node ?? findNode(this.rootNode, this.parsedPath.nodeName);
|
|
269
|
+
this.node = node;
|
|
270
|
+
if (!node)
|
|
166
271
|
return;
|
|
167
|
-
|
|
272
|
+
let target = node;
|
|
273
|
+
const { objectName, propertyName } = this.parsedPath;
|
|
274
|
+
let objectIndex = this.parsedPath.objectIndex;
|
|
275
|
+
let propertyIndex = this.parsedPath.propertyIndex;
|
|
168
276
|
if (objectName) {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
case "bones": {
|
|
185
|
-
if (!targetObject.skeleton) {
|
|
186
|
-
console.error("PropertyBinding: Can not bind to bones as node does not have a skeleton.", this);
|
|
187
|
-
return;
|
|
188
|
-
}
|
|
189
|
-
const bones = (targetObject.skeleton.bones ?? []);
|
|
190
|
-
targetObject = bones;
|
|
191
|
-
// support resolving bone names into indices.
|
|
192
|
-
for (let i = 0; i < bones.length; i++) {
|
|
193
|
-
if (bones[i].name === objectIndex) {
|
|
194
|
-
objectIndex = i;
|
|
195
|
-
break;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
break;
|
|
199
|
-
}
|
|
200
|
-
case "map": {
|
|
201
|
-
if ("map" in targetObject) {
|
|
202
|
-
targetObject = targetObject.map;
|
|
203
|
-
break;
|
|
204
|
-
}
|
|
205
|
-
const material = targetObject.material;
|
|
206
|
-
if (!material) {
|
|
207
|
-
console.error("PropertyBinding: Can not bind to material as node does not have a material.", this);
|
|
208
|
-
return;
|
|
209
|
-
}
|
|
210
|
-
if (!material.map) {
|
|
211
|
-
console.error("PropertyBinding: Can not bind to material.map as node.material does not have a map.", this);
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
targetObject = material.map;
|
|
215
|
-
break;
|
|
216
|
-
}
|
|
217
|
-
default: {
|
|
218
|
-
if (targetObject[objectName] === undefined) {
|
|
219
|
-
console.error("PropertyBinding: Can not bind to objectName of node undefined.", this);
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
222
|
-
targetObject = targetObject[objectName];
|
|
277
|
+
if (objectName === "materials") {
|
|
278
|
+
const material = lookup(node, "material");
|
|
279
|
+
const materials = material.found ? lookup(material.value, "materials") : { found: false };
|
|
280
|
+
target = material.found && Array.isArray(material.value) ? material.value : materials.found ? materials.value : undefined;
|
|
281
|
+
}
|
|
282
|
+
else if (objectName === "bones") {
|
|
283
|
+
const skeleton = lookup(node, "skeleton");
|
|
284
|
+
const bones = skeleton.found ? lookup(skeleton.value, "bones") : { found: false };
|
|
285
|
+
target = bones.found ? bones.value : undefined;
|
|
286
|
+
if (Array.isArray(target) && objectIndex !== undefined) {
|
|
287
|
+
let index = target.findIndex((bone) => bone?.uuid === objectIndex);
|
|
288
|
+
if (index < 0)
|
|
289
|
+
index = target.findIndex((bone) => bone?.name === objectIndex);
|
|
290
|
+
if (index >= 0)
|
|
291
|
+
objectIndex = String(index);
|
|
223
292
|
}
|
|
224
293
|
}
|
|
294
|
+
else if (objectName === "map") {
|
|
295
|
+
const direct = lookup(node, "map");
|
|
296
|
+
const material = lookup(node, "material");
|
|
297
|
+
const fallback = material.found ? lookup(material.value, "map") : { found: false };
|
|
298
|
+
target = direct.found && direct.value !== undefined ? direct.value : fallback.found ? fallback.value : undefined;
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
const object = lookup(node, objectName);
|
|
302
|
+
target = object.found ? object.value : undefined;
|
|
303
|
+
}
|
|
225
304
|
if (objectIndex !== undefined) {
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
console.error("PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.", this, targetObject);
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
targetObject = indexed;
|
|
305
|
+
const entry = lookup(target, objectIndex);
|
|
306
|
+
target = entry.found ? entry.value : undefined;
|
|
232
307
|
}
|
|
233
308
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
309
|
+
if (!isObject(target))
|
|
310
|
+
return;
|
|
311
|
+
const property = lookup(target, propertyName);
|
|
312
|
+
if (!property.found || property.value === undefined)
|
|
238
313
|
return;
|
|
239
|
-
}
|
|
240
|
-
this.targetObject = targetObject;
|
|
241
314
|
if (propertyIndex !== undefined) {
|
|
242
|
-
// access a sub element of the property array (only primitives are supported right now)
|
|
243
315
|
if (propertyName === "morphTargetInfluences") {
|
|
244
|
-
//
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
}
|
|
252
|
-
if (dictionary[propertyIndex] !== undefined) {
|
|
253
|
-
propertyIndex = dictionary[propertyIndex];
|
|
254
|
-
}
|
|
255
|
-
else if (!Number.isInteger(Number(propertyIndex))) {
|
|
256
|
-
console.error(`PropertyBinding: Can not bind to morphTargetInfluences[${String(propertyIndex)}] because it is not a known morph target.`, this);
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
316
|
+
// This is a fixed API hook, not a user-selected property path; class
|
|
317
|
+
// implementations may provide it as a prototype method.
|
|
318
|
+
const dictionarySource = target.morphTargetDictionary;
|
|
319
|
+
const dictionary = typeof dictionarySource === "function" ? dictionarySource.call(target) : dictionarySource;
|
|
320
|
+
const named = lookup(dictionary, propertyIndex);
|
|
321
|
+
if (named.found && typeof named.value === "number" && Number.isSafeInteger(named.value) && named.value >= 0)
|
|
322
|
+
propertyIndex = named.value;
|
|
259
323
|
else {
|
|
260
|
-
|
|
324
|
+
const index = numericIndex(propertyIndex);
|
|
325
|
+
if (index === undefined)
|
|
326
|
+
return;
|
|
327
|
+
propertyIndex = index;
|
|
261
328
|
}
|
|
262
329
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
330
|
+
else if (typeof propertyIndex === "string" && isNumericArray(property.value)) {
|
|
331
|
+
const components = { x: 0, y: 1, z: 2, w: 3 };
|
|
332
|
+
const index = Object.hasOwn(components, propertyIndex) ? components[propertyIndex] : numericIndex(propertyIndex);
|
|
333
|
+
if (index === undefined)
|
|
334
|
+
return;
|
|
335
|
+
propertyIndex = index;
|
|
336
|
+
}
|
|
337
|
+
const entry = lookup(property.value, propertyIndex);
|
|
338
|
+
if (!entry.found || entry.value === undefined)
|
|
339
|
+
return;
|
|
340
|
+
this.kind = "element";
|
|
341
|
+
this.resolvedProperty = property.value;
|
|
266
342
|
this.propertyIndex = propertyIndex;
|
|
267
|
-
this.bindingType = BindingType.ArrayElement;
|
|
268
343
|
}
|
|
269
|
-
else if (
|
|
270
|
-
this.
|
|
271
|
-
this.
|
|
272
|
-
this.propertyName = undefined;
|
|
344
|
+
else if (isArrayConvertible(property.value)) {
|
|
345
|
+
this.kind = "convertible";
|
|
346
|
+
this.resolvedProperty = property.value;
|
|
273
347
|
}
|
|
274
|
-
else if (
|
|
275
|
-
this.
|
|
276
|
-
this.
|
|
277
|
-
this.propertyName = undefined;
|
|
348
|
+
else if (isNumericArray(property.value)) {
|
|
349
|
+
this.kind = "array";
|
|
350
|
+
this.resolvedProperty = property.value;
|
|
278
351
|
}
|
|
279
352
|
else {
|
|
353
|
+
this.kind = "direct";
|
|
280
354
|
this.propertyName = propertyName;
|
|
281
|
-
this.bindingType = BindingType.Direct;
|
|
282
355
|
}
|
|
283
|
-
this.
|
|
284
|
-
? Versioning.NeedsUpdate
|
|
285
|
-
: targetObject.isObject3D === true
|
|
286
|
-
? Versioning.MatrixWorldNeedsUpdate
|
|
287
|
-
: Versioning.None;
|
|
356
|
+
this.targetObject = target;
|
|
288
357
|
this.bound = true;
|
|
289
358
|
}
|
|
290
359
|
unbind() {
|
|
291
360
|
this.node = null;
|
|
361
|
+
this.targetObject = undefined;
|
|
362
|
+
this.resolvedProperty = undefined;
|
|
363
|
+
this.propertyName = undefined;
|
|
364
|
+
this.propertyIndex = undefined;
|
|
292
365
|
this.bound = false;
|
|
293
366
|
}
|
|
294
367
|
getValue() {
|
|
295
|
-
|
|
368
|
+
return this[readForGroup]();
|
|
369
|
+
}
|
|
370
|
+
[readForGroup](isActive) {
|
|
371
|
+
if (!this.bound)
|
|
296
372
|
this.bind();
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
return [...this.resolvedProperty];
|
|
307
|
-
case BindingType.HasFromToArray: {
|
|
308
|
-
const source = this.resolvedProperty.toArray();
|
|
309
|
-
return Array.from(source);
|
|
310
|
-
}
|
|
311
|
-
default:
|
|
312
|
-
return target[this.propertyName];
|
|
313
|
-
}
|
|
373
|
+
if (!this.bound || (isActive && !isActive()))
|
|
374
|
+
return undefined;
|
|
375
|
+
if (this.kind === "element")
|
|
376
|
+
return this.resolvedProperty[this.propertyIndex];
|
|
377
|
+
if (this.kind === "array")
|
|
378
|
+
return Array.from(this.resolvedProperty);
|
|
379
|
+
if (this.kind === "convertible")
|
|
380
|
+
return Array.from(this.resolvedProperty.toArray());
|
|
381
|
+
return this.targetObject[this.propertyName];
|
|
314
382
|
}
|
|
315
383
|
setValue(value) {
|
|
316
|
-
|
|
384
|
+
this[writeForGroup](value);
|
|
385
|
+
}
|
|
386
|
+
[writeForGroup](value, isActive) {
|
|
387
|
+
if (!this.bound)
|
|
317
388
|
this.bind();
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
389
|
+
if (!this.bound || (isActive && !isActive()))
|
|
390
|
+
return;
|
|
391
|
+
// A setter can uncache or dispose its own group, which unbinds this
|
|
392
|
+
// binding while the assignment is in progress. Keep the actual target
|
|
393
|
+
// that received the write so invalidation remains safe and accurate.
|
|
322
394
|
const target = this.targetObject;
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
dest[i] = source[i];
|
|
332
|
-
}
|
|
333
|
-
break;
|
|
334
|
-
}
|
|
335
|
-
case BindingType.HasFromToArray:
|
|
336
|
-
this.resolvedProperty.fromArray(value);
|
|
337
|
-
break;
|
|
338
|
-
default:
|
|
339
|
-
target[this.propertyName] = value;
|
|
395
|
+
if (this.kind === "element")
|
|
396
|
+
this.resolvedProperty[this.propertyIndex] = value;
|
|
397
|
+
else if (this.kind === "array") {
|
|
398
|
+
if (!Array.isArray(value))
|
|
399
|
+
throw new Error(`PropertyBinding: Expected an array for ${this.path}.`);
|
|
400
|
+
const destination = this.resolvedProperty;
|
|
401
|
+
for (let i = 0; i < Math.min(destination.length, value.length); i++)
|
|
402
|
+
destination[i] = value[i];
|
|
340
403
|
}
|
|
341
|
-
if (this.
|
|
342
|
-
|
|
404
|
+
else if (this.kind === "convertible") {
|
|
405
|
+
if (!Array.isArray(value))
|
|
406
|
+
throw new Error(`PropertyBinding: Expected an array for ${this.path}.`);
|
|
407
|
+
this.resolvedProperty.fromArray(value);
|
|
343
408
|
}
|
|
344
|
-
else
|
|
409
|
+
else
|
|
410
|
+
target[this.propertyName] = value;
|
|
411
|
+
if (target.isMaterial === true)
|
|
412
|
+
target.needsUpdate = true;
|
|
413
|
+
else if (target.isObject3D === true) {
|
|
345
414
|
target.matrixWorldNeedsUpdate = true;
|
|
415
|
+
// Aura3D scene nodes cache transforms separately from their object fields.
|
|
416
|
+
// Updating a vector in place must invalidate that cache as well.
|
|
417
|
+
const transform = target.transform;
|
|
418
|
+
transform?.markDirty?.();
|
|
346
419
|
}
|
|
347
420
|
}
|
|
348
|
-
bindingType = BindingType.Direct;
|
|
349
|
-
versioning = Versioning.None;
|
|
350
|
-
}
|
|
351
|
-
function isFromToArrayCapable(value) {
|
|
352
|
-
const candidate = value;
|
|
353
|
-
return typeof candidate?.fromArray === "function" && typeof candidate?.toArray === "function";
|
|
354
421
|
}
|
|
422
|
+
// Capture the original dispatch methods once so a consumer's later prototype
|
|
423
|
+
// override continues to receive composite calls through its public method.
|
|
424
|
+
const defaultGetValue = PropertyBinding.prototype.getValue;
|
|
425
|
+
const defaultSetValue = PropertyBinding.prototype.setValue;
|
|
355
426
|
/**
|
|
356
|
-
*
|
|
357
|
-
*
|
|
358
|
-
*
|
|
427
|
+
* Fans a path out over active group members. Each operation snapshots the
|
|
428
|
+
* active binding identities at its start. New members wait for the next
|
|
429
|
+
* operation; members removed, uncached, unsubscribed or disposed before their
|
|
430
|
+
* turn are skipped. A member removed and reactivated before its turn remains
|
|
431
|
+
* eligible if it still has the same binding. Nested calls take new snapshots.
|
|
359
432
|
*/
|
|
360
433
|
export class PropertyBindingComposite {
|
|
361
434
|
targetGroup;
|
|
362
435
|
bindings;
|
|
436
|
+
path;
|
|
363
437
|
constructor(targetGroup, path, optionalParsedPath) {
|
|
364
438
|
const parsedPath = optionalParsedPath ?? parseTrackName(path);
|
|
439
|
+
assertSafePath(parsedPath, path);
|
|
365
440
|
this.targetGroup = targetGroup;
|
|
441
|
+
this.path = path;
|
|
366
442
|
this.bindings = targetGroup.subscribe_(path, parsedPath);
|
|
367
443
|
}
|
|
444
|
+
activeSnapshot() {
|
|
445
|
+
return [...new Set(this.bindings.slice(this.targetGroup.nCachedObjects_).filter((binding) => binding != null))];
|
|
446
|
+
}
|
|
447
|
+
isActive(binding) {
|
|
448
|
+
const check = this.targetGroup.isBindingActive_;
|
|
449
|
+
if (typeof check === "function")
|
|
450
|
+
return check.call(this.targetGroup, this.path, binding);
|
|
451
|
+
// Support custom group-like implementations that predate the optional
|
|
452
|
+
// membership method, using their live array and cached boundary.
|
|
453
|
+
return this.bindings.indexOf(binding, this.targetGroup.nCachedObjects_) !== -1;
|
|
454
|
+
}
|
|
368
455
|
getValue() {
|
|
369
|
-
this.
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
456
|
+
for (const binding of this.activeSnapshot()) {
|
|
457
|
+
if (!this.isActive(binding))
|
|
458
|
+
continue;
|
|
459
|
+
const value = binding instanceof PropertyBinding && binding.getValue === defaultGetValue
|
|
460
|
+
? binding[readForGroup](() => this.isActive(binding))
|
|
461
|
+
: binding.getValue();
|
|
462
|
+
if (value !== undefined && this.isActive(binding))
|
|
463
|
+
return value;
|
|
464
|
+
}
|
|
465
|
+
return undefined;
|
|
373
466
|
}
|
|
374
467
|
setValue(value) {
|
|
375
|
-
const
|
|
376
|
-
|
|
377
|
-
|
|
468
|
+
for (const binding of this.activeSnapshot()) {
|
|
469
|
+
if (!this.isActive(binding))
|
|
470
|
+
continue;
|
|
471
|
+
if (binding instanceof PropertyBinding && binding.setValue === defaultSetValue) {
|
|
472
|
+
binding[writeForGroup](value, () => this.isActive(binding));
|
|
473
|
+
}
|
|
474
|
+
else {
|
|
475
|
+
binding.setValue(value);
|
|
476
|
+
}
|
|
378
477
|
}
|
|
379
478
|
}
|
|
380
479
|
bind() {
|
|
381
|
-
const
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
}
|
|
480
|
+
for (const binding of this.activeSnapshot())
|
|
481
|
+
if (this.isActive(binding))
|
|
482
|
+
binding.bind();
|
|
385
483
|
}
|
|
386
484
|
unbind() {
|
|
387
|
-
const
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
}
|
|
485
|
+
for (const binding of this.activeSnapshot())
|
|
486
|
+
if (this.isActive(binding))
|
|
487
|
+
binding.unbind();
|
|
391
488
|
}
|
|
392
489
|
}
|
|
393
490
|
//# sourceMappingURL=PropertyBinding.js.map
|