727 lines
16 KiB
JavaScript
727 lines
16 KiB
JavaScript
|
/**
|
||
|
*
|
||
|
* A reference to a real property in the scene graph.
|
||
|
*
|
||
|
*
|
||
|
* @author Ben Houston / http://clara.io/
|
||
|
* @author David Sarno / http://lighthaus.us/
|
||
|
* @author tschw
|
||
|
*/
|
||
|
|
||
|
// Characters [].:/ are reserved for track binding syntax.
|
||
|
var RESERVED_CHARS_RE = '\\[\\]\\.:\\/';
|
||
|
|
||
|
function Composite( targetGroup, path, optionalParsedPath ) {
|
||
|
|
||
|
var parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path );
|
||
|
|
||
|
this._targetGroup = targetGroup;
|
||
|
this._bindings = targetGroup.subscribe_( path, parsedPath );
|
||
|
|
||
|
}
|
||
|
|
||
|
Object.assign( Composite.prototype, {
|
||
|
|
||
|
getValue: function ( array, offset ) {
|
||
|
|
||
|
this.bind(); // bind all binding
|
||
|
|
||
|
var firstValidIndex = this._targetGroup.nCachedObjects_,
|
||
|
binding = this._bindings[ firstValidIndex ];
|
||
|
|
||
|
// and only call .getValue on the first
|
||
|
if ( binding !== undefined ) binding.getValue( array, offset );
|
||
|
|
||
|
},
|
||
|
|
||
|
setValue: function ( array, offset ) {
|
||
|
|
||
|
var bindings = this._bindings;
|
||
|
|
||
|
for ( var i = this._targetGroup.nCachedObjects_,
|
||
|
n = bindings.length; i !== n; ++ i ) {
|
||
|
|
||
|
bindings[ i ].setValue( array, offset );
|
||
|
|
||
|
}
|
||
|
|
||
|
},
|
||
|
|
||
|
bind: function () {
|
||
|
|
||
|
var bindings = this._bindings;
|
||
|
|
||
|
for ( var i = this._targetGroup.nCachedObjects_,
|
||
|
n = bindings.length; i !== n; ++ i ) {
|
||
|
|
||
|
bindings[ i ].bind();
|
||
|
|
||
|
}
|
||
|
|
||
|
},
|
||
|
|
||
|
unbind: function () {
|
||
|
|
||
|
var bindings = this._bindings;
|
||
|
|
||
|
for ( var i = this._targetGroup.nCachedObjects_,
|
||
|
n = bindings.length; i !== n; ++ i ) {
|
||
|
|
||
|
bindings[ i ].unbind();
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
} );
|
||
|
|
||
|
|
||
|
function PropertyBinding( rootNode, path, parsedPath ) {
|
||
|
|
||
|
this.path = path;
|
||
|
this.parsedPath = parsedPath || PropertyBinding.parseTrackName( path );
|
||
|
|
||
|
this.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName ) || rootNode;
|
||
|
|
||
|
this.rootNode = rootNode;
|
||
|
|
||
|
}
|
||
|
|
||
|
Object.assign( PropertyBinding, {
|
||
|
|
||
|
Composite: Composite,
|
||
|
|
||
|
create: function ( root, path, parsedPath ) {
|
||
|
|
||
|
if ( ! ( root && root.isAnimationObjectGroup ) ) {
|
||
|
|
||
|
return new PropertyBinding( root, path, parsedPath );
|
||
|
|
||
|
} else {
|
||
|
|
||
|
return new PropertyBinding.Composite( root, path, parsedPath );
|
||
|
|
||
|
}
|
||
|
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Replaces spaces with underscores and removes unsupported characters from
|
||
|
* node names, to ensure compatibility with parseTrackName().
|
||
|
*
|
||
|
* @param {string} name Node name to be sanitized.
|
||
|
* @return {string}
|
||
|
*/
|
||
|
sanitizeNodeName: ( function () {
|
||
|
|
||
|
var reservedRe = new RegExp( '[' + RESERVED_CHARS_RE + ']', 'g' );
|
||
|
|
||
|
return function sanitizeNodeName( name ) {
|
||
|
|
||
|
return name.replace( /\s/g, '_' ).replace( reservedRe, '' );
|
||
|
|
||
|
};
|
||
|
|
||
|
}() ),
|
||
|
|
||
|
parseTrackName: function () {
|
||
|
|
||
|
// Attempts to allow node names from any language. ES5's `\w` regexp matches
|
||
|
// only latin characters, and the unicode \p{L} is not yet supported. So
|
||
|
// instead, we exclude reserved characters and match everything else.
|
||
|
var wordChar = '[^' + RESERVED_CHARS_RE + ']';
|
||
|
var wordCharOrDot = '[^' + RESERVED_CHARS_RE.replace( '\\.', '' ) + ']';
|
||
|
|
||
|
// Parent directories, delimited by '/' or ':'. Currently unused, but must
|
||
|
// be matched to parse the rest of the track name.
|
||
|
var directoryRe = /((?:WC+[\/:])*)/.source.replace( 'WC', wordChar );
|
||
|
|
||
|
// Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'.
|
||
|
var nodeRe = /(WCOD+)?/.source.replace( 'WCOD', wordCharOrDot );
|
||
|
|
||
|
// Object on target node, and accessor. May not contain reserved
|
||
|
// characters. Accessor may contain any character except closing bracket.
|
||
|
var objectRe = /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace( 'WC', wordChar );
|
||
|
|
||
|
// Property and accessor. May not contain reserved characters. Accessor may
|
||
|
// contain any non-bracket characters.
|
||
|
var propertyRe = /\.(WC+)(?:\[(.+)\])?/.source.replace( 'WC', wordChar );
|
||
|
|
||
|
var trackRe = new RegExp( ''
|
||
|
+ '^'
|
||
|
+ directoryRe
|
||
|
+ nodeRe
|
||
|
+ objectRe
|
||
|
+ propertyRe
|
||
|
+ '$'
|
||
|
);
|
||
|
|
||
|
var supportedObjectNames = [ 'material', 'materials', 'bones' ];
|
||
|
|
||
|
return function parseTrackName( trackName ) {
|
||
|
|
||
|
var matches = trackRe.exec( trackName );
|
||
|
|
||
|
if ( ! matches ) {
|
||
|
|
||
|
throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName );
|
||
|
|
||
|
}
|
||
|
|
||
|
var results = {
|
||
|
// directoryName: matches[ 1 ], // (tschw) currently unused
|
||
|
nodeName: matches[ 2 ],
|
||
|
objectName: matches[ 3 ],
|
||
|
objectIndex: matches[ 4 ],
|
||
|
propertyName: matches[ 5 ], // required
|
||
|
propertyIndex: matches[ 6 ]
|
||
|
};
|
||
|
|
||
|
var lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' );
|
||
|
|
||
|
if ( lastDot !== undefined && lastDot !== - 1 ) {
|
||
|
|
||
|
var objectName = results.nodeName.substring( lastDot + 1 );
|
||
|
|
||
|
// Object names must be checked against a whitelist. Otherwise, there
|
||
|
// is no way to parse 'foo.bar.baz': 'baz' must be a property, but
|
||
|
// 'bar' could be the objectName, or part of a nodeName (which can
|
||
|
// include '.' characters).
|
||
|
if ( supportedObjectNames.indexOf( objectName ) !== - 1 ) {
|
||
|
|
||
|
results.nodeName = results.nodeName.substring( 0, lastDot );
|
||
|
results.objectName = objectName;
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
if ( results.propertyName === null || results.propertyName.length === 0 ) {
|
||
|
|
||
|
throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName );
|
||
|
|
||
|
}
|
||
|
|
||
|
return results;
|
||
|
|
||
|
};
|
||
|
|
||
|
}(),
|
||
|
|
||
|
findNode: function ( root, nodeName ) {
|
||
|
|
||
|
if ( ! nodeName || nodeName === "" || nodeName === "root" || nodeName === "." || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid ) {
|
||
|
|
||
|
return root;
|
||
|
|
||
|
}
|
||
|
|
||
|
// search into skeleton bones.
|
||
|
if ( root.skeleton ) {
|
||
|
|
||
|
var bone = root.skeleton.getBoneByName( nodeName );
|
||
|
|
||
|
if ( bone !== undefined ) {
|
||
|
|
||
|
return bone;
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// search into node subtree.
|
||
|
if ( root.children ) {
|
||
|
|
||
|
var searchNodeSubtree = function ( children ) {
|
||
|
|
||
|
for ( var i = 0; i < children.length; i ++ ) {
|
||
|
|
||
|
var childNode = children[ i ];
|
||
|
|
||
|
if ( childNode.name === nodeName || childNode.uuid === nodeName ) {
|
||
|
|
||
|
return childNode;
|
||
|
|
||
|
}
|
||
|
|
||
|
var result = searchNodeSubtree( childNode.children );
|
||
|
|
||
|
if ( result ) return result;
|
||
|
|
||
|
}
|
||
|
|
||
|
return null;
|
||
|
|
||
|
};
|
||
|
|
||
|
var subTreeNode = searchNodeSubtree( root.children );
|
||
|
|
||
|
if ( subTreeNode ) {
|
||
|
|
||
|
return subTreeNode;
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return null;
|
||
|
|
||
|
}
|
||
|
|
||
|
} );
|
||
|
|
||
|
Object.assign( PropertyBinding.prototype, { // prototype, continued
|
||
|
|
||
|
// these are used to "bind" a nonexistent property
|
||
|
_getValue_unavailable: function () {},
|
||
|
_setValue_unavailable: function () {},
|
||
|
|
||
|
BindingType: {
|
||
|
Direct: 0,
|
||
|
EntireArray: 1,
|
||
|
ArrayElement: 2,
|
||
|
HasFromToArray: 3
|
||
|
},
|
||
|
|
||
|
Versioning: {
|
||
|
None: 0,
|
||
|
NeedsUpdate: 1,
|
||
|
MatrixWorldNeedsUpdate: 2
|
||
|
},
|
||
|
|
||
|
GetterByBindingType: [
|
||
|
|
||
|
function getValue_direct( buffer, offset ) {
|
||
|
|
||
|
buffer[ offset ] = this.node[ this.propertyName ];
|
||
|
|
||
|
},
|
||
|
|
||
|
function getValue_array( buffer, offset ) {
|
||
|
|
||
|
var source = this.resolvedProperty;
|
||
|
|
||
|
for ( var i = 0, n = source.length; i !== n; ++ i ) {
|
||
|
|
||
|
buffer[ offset ++ ] = source[ i ];
|
||
|
|
||
|
}
|
||
|
|
||
|
},
|
||
|
|
||
|
function getValue_arrayElement( buffer, offset ) {
|
||
|
|
||
|
buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ];
|
||
|
|
||
|
},
|
||
|
|
||
|
function getValue_toArray( buffer, offset ) {
|
||
|
|
||
|
this.resolvedProperty.toArray( buffer, offset );
|
||
|
|
||
|
}
|
||
|
|
||
|
],
|
||
|
|
||
|
SetterByBindingTypeAndVersioning: [
|
||
|
|
||
|
[
|
||
|
// Direct
|
||
|
|
||
|
function setValue_direct( buffer, offset ) {
|
||
|
|
||
|
this.targetObject[ this.propertyName ] = buffer[ offset ];
|
||
|
|
||
|
},
|
||
|
|
||
|
function setValue_direct_setNeedsUpdate( buffer, offset ) {
|
||
|
|
||
|
this.targetObject[ this.propertyName ] = buffer[ offset ];
|
||
|
this.targetObject.needsUpdate = true;
|
||
|
|
||
|
},
|
||
|
|
||
|
function setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) {
|
||
|
|
||
|
this.targetObject[ this.propertyName ] = buffer[ offset ];
|
||
|
this.targetObject.matrixWorldNeedsUpdate = true;
|
||
|
|
||
|
}
|
||
|
|
||
|
], [
|
||
|
|
||
|
// EntireArray
|
||
|
|
||
|
function setValue_array( buffer, offset ) {
|
||
|
|
||
|
var dest = this.resolvedProperty;
|
||
|
|
||
|
for ( var i = 0, n = dest.length; i !== n; ++ i ) {
|
||
|
|
||
|
dest[ i ] = buffer[ offset ++ ];
|
||
|
|
||
|
}
|
||
|
|
||
|
},
|
||
|
|
||
|
function setValue_array_setNeedsUpdate( buffer, offset ) {
|
||
|
|
||
|
var dest = this.resolvedProperty;
|
||
|
|
||
|
for ( var i = 0, n = dest.length; i !== n; ++ i ) {
|
||
|
|
||
|
dest[ i ] = buffer[ offset ++ ];
|
||
|
|
||
|
}
|
||
|
|
||
|
this.targetObject.needsUpdate = true;
|
||
|
|
||
|
},
|
||
|
|
||
|
function setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) {
|
||
|
|
||
|
var dest = this.resolvedProperty;
|
||
|
|
||
|
for ( var i = 0, n = dest.length; i !== n; ++ i ) {
|
||
|
|
||
|
dest[ i ] = buffer[ offset ++ ];
|
||
|
|
||
|
}
|
||
|
|
||
|
this.targetObject.matrixWorldNeedsUpdate = true;
|
||
|
|
||
|
}
|
||
|
|
||
|
], [
|
||
|
|
||
|
// ArrayElement
|
||
|
|
||
|
function setValue_arrayElement( buffer, offset ) {
|
||
|
|
||
|
this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
|
||
|
|
||
|
},
|
||
|
|
||
|
function setValue_arrayElement_setNeedsUpdate( buffer, offset ) {
|
||
|
|
||
|
this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
|
||
|
this.targetObject.needsUpdate = true;
|
||
|
|
||
|
},
|
||
|
|
||
|
function setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) {
|
||
|
|
||
|
this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
|
||
|
this.targetObject.matrixWorldNeedsUpdate = true;
|
||
|
|
||
|
}
|
||
|
|
||
|
], [
|
||
|
|
||
|
// HasToFromArray
|
||
|
|
||
|
function setValue_fromArray( buffer, offset ) {
|
||
|
|
||
|
this.resolvedProperty.fromArray( buffer, offset );
|
||
|
|
||
|
},
|
||
|
|
||
|
function setValue_fromArray_setNeedsUpdate( buffer, offset ) {
|
||
|
|
||
|
this.resolvedProperty.fromArray( buffer, offset );
|
||
|
this.targetObject.needsUpdate = true;
|
||
|
|
||
|
},
|
||
|
|
||
|
function setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) {
|
||
|
|
||
|
this.resolvedProperty.fromArray( buffer, offset );
|
||
|
this.targetObject.matrixWorldNeedsUpdate = true;
|
||
|
|
||
|
}
|
||
|
|
||
|
]
|
||
|
|
||
|
],
|
||
|
|
||
|
getValue: function getValue_unbound( targetArray, offset ) {
|
||
|
|
||
|
this.bind();
|
||
|
this.getValue( targetArray, offset );
|
||
|
|
||
|
// Note: This class uses a State pattern on a per-method basis:
|
||
|
// 'bind' sets 'this.getValue' / 'setValue' and shadows the
|
||
|
// prototype version of these methods with one that represents
|
||
|
// the bound state. When the property is not found, the methods
|
||
|
// become no-ops.
|
||
|
|
||
|
},
|
||
|
|
||
|
setValue: function getValue_unbound( sourceArray, offset ) {
|
||
|
|
||
|
this.bind();
|
||
|
this.setValue( sourceArray, offset );
|
||
|
|
||
|
},
|
||
|
|
||
|
// create getter / setter pair for a property in the scene graph
|
||
|
bind: function () {
|
||
|
|
||
|
var targetObject = this.node,
|
||
|
parsedPath = this.parsedPath,
|
||
|
|
||
|
objectName = parsedPath.objectName,
|
||
|
propertyName = parsedPath.propertyName,
|
||
|
propertyIndex = parsedPath.propertyIndex;
|
||
|
|
||
|
if ( ! targetObject ) {
|
||
|
|
||
|
targetObject = PropertyBinding.findNode( this.rootNode, parsedPath.nodeName ) || this.rootNode;
|
||
|
|
||
|
this.node = targetObject;
|
||
|
|
||
|
}
|
||
|
|
||
|
// set fail state so we can just 'return' on error
|
||
|
this.getValue = this._getValue_unavailable;
|
||
|
this.setValue = this._setValue_unavailable;
|
||
|
|
||
|
// ensure there is a value node
|
||
|
if ( ! targetObject ) {
|
||
|
|
||
|
console.error( 'THREE.PropertyBinding: Trying to update node for track: ' + this.path + ' but it wasn\'t found.' );
|
||
|
return;
|
||
|
|
||
|
}
|
||
|
|
||
|
if ( objectName ) {
|
||
|
|
||
|
var objectIndex = parsedPath.objectIndex;
|
||
|
|
||
|
// special cases were we need to reach deeper into the hierarchy to get the face materials....
|
||
|
switch ( objectName ) {
|
||
|
|
||
|
case 'materials':
|
||
|
|
||
|
if ( ! targetObject.material ) {
|
||
|
|
||
|
console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this );
|
||
|
return;
|
||
|
|
||
|
}
|
||
|
|
||
|
if ( ! targetObject.material.materials ) {
|
||
|
|
||
|
console.error( 'THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this );
|
||
|
return;
|
||
|
|
||
|
}
|
||
|
|
||
|
targetObject = targetObject.material.materials;
|
||
|
|
||
|
break;
|
||
|
|
||
|
case 'bones':
|
||
|
|
||
|
if ( ! targetObject.skeleton ) {
|
||
|
|
||
|
console.error( 'THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this );
|
||
|
return;
|
||
|
|
||
|
}
|
||
|
|
||
|
// potential future optimization: skip this if propertyIndex is already an integer
|
||
|
// and convert the integer string to a true integer.
|
||
|
|
||
|
targetObject = targetObject.skeleton.bones;
|
||
|
|
||
|
// support resolving morphTarget names into indices.
|
||
|
for ( var i = 0; i < targetObject.length; i ++ ) {
|
||
|
|
||
|
if ( targetObject[ i ].name === objectIndex ) {
|
||
|
|
||
|
objectIndex = i;
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
|
||
|
if ( targetObject[ objectName ] === undefined ) {
|
||
|
|
||
|
console.error( 'THREE.PropertyBinding: Can not bind to objectName of node undefined.', this );
|
||
|
return;
|
||
|
|
||
|
}
|
||
|
|
||
|
targetObject = targetObject[ objectName ];
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
if ( objectIndex !== undefined ) {
|
||
|
|
||
|
if ( targetObject[ objectIndex ] === undefined ) {
|
||
|
|
||
|
console.error( 'THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject );
|
||
|
return;
|
||
|
|
||
|
}
|
||
|
|
||
|
targetObject = targetObject[ objectIndex ];
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// resolve property
|
||
|
var nodeProperty = targetObject[ propertyName ];
|
||
|
|
||
|
if ( nodeProperty === undefined ) {
|
||
|
|
||
|
var nodeName = parsedPath.nodeName;
|
||
|
|
||
|
console.error( 'THREE.PropertyBinding: Trying to update property for track: ' + nodeName +
|
||
|
'.' + propertyName + ' but it wasn\'t found.', targetObject );
|
||
|
return;
|
||
|
|
||
|
}
|
||
|
|
||
|
// determine versioning scheme
|
||
|
var versioning = this.Versioning.None;
|
||
|
|
||
|
this.targetObject = targetObject;
|
||
|
|
||
|
if ( targetObject.needsUpdate !== undefined ) { // material
|
||
|
|
||
|
versioning = this.Versioning.NeedsUpdate;
|
||
|
|
||
|
} else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform
|
||
|
|
||
|
versioning = this.Versioning.MatrixWorldNeedsUpdate;
|
||
|
|
||
|
}
|
||
|
|
||
|
// determine how the property gets bound
|
||
|
var bindingType = this.BindingType.Direct;
|
||
|
|
||
|
if ( propertyIndex !== undefined ) {
|
||
|
|
||
|
// access a sub element of the property array (only primitives are supported right now)
|
||
|
|
||
|
if ( propertyName === "morphTargetInfluences" ) {
|
||
|
|
||
|
// potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer.
|
||
|
|
||
|
// support resolving morphTarget names into indices.
|
||
|
if ( ! targetObject.geometry ) {
|
||
|
|
||
|
console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this );
|
||
|
return;
|
||
|
|
||
|
}
|
||
|
|
||
|
if ( targetObject.geometry.isBufferGeometry ) {
|
||
|
|
||
|
if ( ! targetObject.geometry.morphAttributes ) {
|
||
|
|
||
|
console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this );
|
||
|
return;
|
||
|
|
||
|
}
|
||
|
|
||
|
for ( var i = 0; i < this.node.geometry.morphAttributes.position.length; i ++ ) {
|
||
|
|
||
|
if ( targetObject.geometry.morphAttributes.position[ i ].name === propertyIndex ) {
|
||
|
|
||
|
propertyIndex = i;
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
} else {
|
||
|
|
||
|
if ( ! targetObject.geometry.morphTargets ) {
|
||
|
|
||
|
console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphTargets.', this );
|
||
|
return;
|
||
|
|
||
|
}
|
||
|
|
||
|
for ( var i = 0; i < this.node.geometry.morphTargets.length; i ++ ) {
|
||
|
|
||
|
if ( targetObject.geometry.morphTargets[ i ].name === propertyIndex ) {
|
||
|
|
||
|
propertyIndex = i;
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
bindingType = this.BindingType.ArrayElement;
|
||
|
|
||
|
this.resolvedProperty = nodeProperty;
|
||
|
this.propertyIndex = propertyIndex;
|
||
|
|
||
|
} else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) {
|
||
|
|
||
|
// must use copy for Object3D.Euler/Quaternion
|
||
|
|
||
|
bindingType = this.BindingType.HasFromToArray;
|
||
|
|
||
|
this.resolvedProperty = nodeProperty;
|
||
|
|
||
|
} else if ( Array.isArray( nodeProperty ) ) {
|
||
|
|
||
|
bindingType = this.BindingType.EntireArray;
|
||
|
|
||
|
this.resolvedProperty = nodeProperty;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
this.propertyName = propertyName;
|
||
|
|
||
|
}
|
||
|
|
||
|
// select getter / setter
|
||
|
this.getValue = this.GetterByBindingType[ bindingType ];
|
||
|
this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ];
|
||
|
|
||
|
},
|
||
|
|
||
|
unbind: function () {
|
||
|
|
||
|
this.node = null;
|
||
|
|
||
|
// back to the prototype version of getValue / setValue
|
||
|
// note: avoiding to mutate the shape of 'this' via 'delete'
|
||
|
this.getValue = this._getValue_unbound;
|
||
|
this.setValue = this._setValue_unbound;
|
||
|
|
||
|
}
|
||
|
|
||
|
} );
|
||
|
|
||
|
//!\ DECLARE ALIAS AFTER assign prototype !
|
||
|
Object.assign( PropertyBinding.prototype, {
|
||
|
|
||
|
// initial state of these methods that calls 'bind'
|
||
|
_getValue_unbound: PropertyBinding.prototype.getValue,
|
||
|
_setValue_unbound: PropertyBinding.prototype.setValue,
|
||
|
|
||
|
} );
|
||
|
|
||
|
export { PropertyBinding };
|