PropertyBinding.js 15.9 KB
Newer Older
1 2
/**
 *
3 4 5
 * A reference to a real property in the scene graph.
 *
 *
6 7
 * @author Ben Houston / http://clara.io/
 * @author David Sarno / http://lighthaus.us/
8
 * @author tschw
9 10
 */

11 12 13
// Characters [].:/ are reserved for track binding syntax.
var RESERVED_CHARS_RE = '\\[\\]\\.:\\/';

M
Mr.doob 已提交
14
function Composite( targetGroup, path, optionalParsedPath ) {
15

16
	var parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path );
17

18 19
	this._targetGroup = targetGroup;
	this._bindings = targetGroup.subscribe_( path, parsedPath );
20

M
Mr.doob 已提交
21
}
22

23
Object.assign( Composite.prototype, {
24

M
Mr.doob 已提交
25
	getValue: function ( array, offset ) {
26

27
		this.bind(); // bind all binding
28

29 30
		var firstValidIndex = this._targetGroup.nCachedObjects_,
			binding = this._bindings[ firstValidIndex ];
B
Ben Houston 已提交
31

32 33
		// and only call .getValue on the first
		if ( binding !== undefined ) binding.getValue( array, offset );
34

35
	},
B
Ben Houston 已提交
36

M
Mr.doob 已提交
37
	setValue: function ( array, offset ) {
38

39
		var bindings = this._bindings;
40

41 42
		for ( var i = this._targetGroup.nCachedObjects_,
				  n = bindings.length; i !== n; ++ i ) {
T
tschw 已提交
43

44
			bindings[ i ].setValue( array, offset );
T
tschw 已提交
45

46
		}
47

48
	},
T
tschw 已提交
49

M
Mr.doob 已提交
50
	bind: function () {
T
tschw 已提交
51

52
		var bindings = this._bindings;
53

54 55
		for ( var i = this._targetGroup.nCachedObjects_,
				  n = bindings.length; i !== n; ++ i ) {
56

57
			bindings[ i ].bind();
T
tschw 已提交
58

59
		}
T
tschw 已提交
60

61
	},
T
tschw 已提交
62

M
Mr.doob 已提交
63
	unbind: function () {
T
tschw 已提交
64

65
		var bindings = this._bindings;
T
tschw 已提交
66

67 68
		for ( var i = this._targetGroup.nCachedObjects_,
				  n = bindings.length; i !== n; ++ i ) {
T
tschw 已提交
69

70
			bindings[ i ].unbind();
T
tschw 已提交
71

72
		}
T
tschw 已提交
73

74
	}
T
tschw 已提交
75

76
} );
T
tschw 已提交
77 78


79
function PropertyBinding( rootNode, path, parsedPath ) {
T
tschw 已提交
80

81 82
	this.path = path;
	this.parsedPath = parsedPath || PropertyBinding.parseTrackName( path );
T
tschw 已提交
83

84
	this.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName ) || rootNode;
T
tschw 已提交
85

86
	this.rootNode = rootNode;
T
tschw 已提交
87

88
}
T
tschw 已提交
89

90
Object.assign( PropertyBinding, {
T
tschw 已提交
91

92
	Composite: Composite,
T
tschw 已提交
93

M
Mr.doob 已提交
94
	create: function ( root, path, parsedPath ) {
T
tschw 已提交
95

96
		if ( ! ( root && root.isAnimationObjectGroup ) ) {
T
tschw 已提交
97

98
			return new PropertyBinding( root, path, parsedPath );
T
tschw 已提交
99

100
		} else {
T
tschw 已提交
101

102
			return new PropertyBinding.Composite( root, path, parsedPath );
103

104
		}
T
tschw 已提交
105

106
	},
T
tschw 已提交
107

D
Don McCurdy 已提交
108 109 110 111 112 113 114
	/**
	 * 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}
	 */
115
	sanitizeNodeName: ( function () {
D
Don McCurdy 已提交
116

117 118
		var reservedRe = new RegExp( '[' + RESERVED_CHARS_RE + ']', 'g' );

119
		return function sanitizeNodeName ( name ) {
D
Don McCurdy 已提交
120

121 122 123 124 125
			return name.replace( /\s/g, '_' ).replace( reservedRe, '' );

		};

	}() ),
D
Don McCurdy 已提交
126

127
	parseTrackName: function () {
T
tschw 已提交
128

129 130 131 132 133 134
		// 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( '\\.', '' ) + ']';

135 136
		// Parent directories, delimited by '/' or ':'. Currently unused, but must
		// be matched to parse the rest of the track name.
137
		var directoryRe = /((?:WC+[\/:])*)/.source.replace( 'WC', wordChar );
T
tschw 已提交
138

139
		// Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'.
140
		var nodeRe = /(WCOD+)?/.source.replace( 'WCOD', wordCharOrDot );
141

142
		// Object on target node, and accessor. May not contain reserved
D
Don McCurdy 已提交
143
		// characters. Accessor may contain any character except closing bracket.
144
		var objectRe = /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace( 'WC', wordChar );
T
tschw 已提交
145

146
		// Property and accessor. May not contain reserved characters. Accessor may
147
		// contain any non-bracket characters.
148
		var propertyRe = /\.(WC+)(?:\[(.+)\])?/.source.replace( 'WC', wordChar );
149

M
Mugen87 已提交
150
		var trackRe = new RegExp( ''
151
			+ '^'
152 153 154 155
			+ directoryRe
			+ nodeRe
			+ objectRe
			+ propertyRe
156 157
			+ '$'
		);
158

159
		var supportedObjectNames = [ 'material', 'materials', 'bones' ];
T
tschw 已提交
160

T
Takahiro 已提交
161
		return function parseTrackName( trackName ) {
T
tschw 已提交
162

M
Mugen87 已提交
163
			var matches = trackRe.exec( trackName );
T
tschw 已提交
164

M
Mugen87 已提交
165
			if ( ! matches ) {
166

M
Mugen87 已提交
167
				throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName );
168

M
Mugen87 已提交
169
			}
170

M
Mugen87 已提交
171 172 173 174 175 176 177 178
			var results = {
				// directoryName: matches[ 1 ], // (tschw) currently unused
				nodeName: matches[ 2 ],
				objectName: matches[ 3 ],
				objectIndex: matches[ 4 ],
				propertyName: matches[ 5 ], // required
				propertyIndex: matches[ 6 ]
			};
179

M
Mugen87 已提交
180
			var lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' );
181

M
Mugen87 已提交
182
			if ( lastDot !== undefined && lastDot !== - 1 ) {
183

M
Mugen87 已提交
184
				var objectName = results.nodeName.substring( lastDot + 1 );
185

M
Mugen87 已提交
186 187 188 189 190
				// 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 ) {
191

M
Mugen87 已提交
192 193
					results.nodeName = results.nodeName.substring( 0, lastDot );
					results.objectName = objectName;
194 195 196

				}

M
Mugen87 已提交
197
			}
198

M
Mugen87 已提交
199
			if ( results.propertyName === null || results.propertyName.length === 0 ) {
200

M
Mugen87 已提交
201
				throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName );
202

M
Mugen87 已提交
203
			}
204

M
Mugen87 已提交
205 206 207
			return results;

		};
208 209

	}(),
210

M
Mr.doob 已提交
211
	findNode: function ( root, nodeName ) {
212

M
Mr.doob 已提交
213
		if ( ! nodeName || nodeName === "" || nodeName === "root" || nodeName === "." || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid ) {
214

215
			return root;
216 217 218

		}

219 220
		// search into skeleton bones.
		if ( root.skeleton ) {
T
tschw 已提交
221

T
Takahiro 已提交
222
			var bone = root.skeleton.findBoneByName( nodeName );
T
tschw 已提交
223

224
			if ( bone ) {
T
tschw 已提交
225

226
				return bone;
T
tschw 已提交
227

228
			}
M
Mr.doob 已提交
229

230
		}
231

232 233
		// search into node subtree.
		if ( root.children ) {
234

M
Mr.doob 已提交
235
			var searchNodeSubtree = function ( children ) {
236

M
Mr.doob 已提交
237
				for ( var i = 0; i < children.length; i ++ ) {
238

239
					var childNode = children[ i ];
240

241
					if ( childNode.name === nodeName || childNode.uuid === nodeName ) {
242

243
						return childNode;
T
tschw 已提交
244

245
					}
T
tschw 已提交
246

247
					var result = searchNodeSubtree( childNode.children );
T
tschw 已提交
248

249
					if ( result ) return result;
250

251
				}
252

253
				return null;
254

255
			};
256

257
			var subTreeNode = searchNodeSubtree( root.children );
258

259
			if ( subTreeNode ) {
260

261
				return subTreeNode;
262

263 264 265 266 267
			}

		}

		return null;
268

T
tschw 已提交
269
	}
270

271
} );
272

R
Rich Harris 已提交
273
Object.assign( PropertyBinding.prototype, { // prototype, continued
274

T
tschw 已提交
275
	// these are used to "bind" a nonexistent property
M
Mr.doob 已提交
276 277
	_getValue_unavailable: function () {},
	_setValue_unavailable: function () {},
278

T
tschw 已提交
279 280
	BindingType: {
		Direct: 0,
T
tschw 已提交
281 282 283
		EntireArray: 1,
		ArrayElement: 2,
		HasFromToArray: 3
T
tschw 已提交
284
	},
285

T
tschw 已提交
286 287 288 289 290
	Versioning: {
		None: 0,
		NeedsUpdate: 1,
		MatrixWorldNeedsUpdate: 2
	},
291

T
tschw 已提交
292
	GetterByBindingType: [
293

T
tschw 已提交
294
		function getValue_direct( buffer, offset ) {
295

T
tschw 已提交
296
			buffer[ offset ] = this.node[ this.propertyName ];
297

T
tschw 已提交
298
		},
299

T
tschw 已提交
300 301
		function getValue_array( buffer, offset ) {

302
			var source = this.resolvedProperty;
T
tschw 已提交
303 304 305 306 307 308 309 310 311

			for ( var i = 0, n = source.length; i !== n; ++ i ) {

				buffer[ offset ++ ] = source[ i ];

			}

		},

T
tschw 已提交
312
		function getValue_arrayElement( buffer, offset ) {
313

T
tschw 已提交
314
			buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ];
315

T
tschw 已提交
316
		},
317

T
tschw 已提交
318
		function getValue_toArray( buffer, offset ) {
319

T
tschw 已提交
320
			this.resolvedProperty.toArray( buffer, offset );
321

T
tschw 已提交
322
		}
323

T
tschw 已提交
324
	],
325

T
tschw 已提交
326
	SetterByBindingTypeAndVersioning: [
327

T
tschw 已提交
328 329
		[
			// Direct
330

T
tschw 已提交
331
			function setValue_direct( buffer, offset ) {
332

333
				this.targetObject[ this.propertyName ] = buffer[ offset ];
334

T
tschw 已提交
335
			},
336

T
tschw 已提交
337
			function setValue_direct_setNeedsUpdate( buffer, offset ) {
338

339
				this.targetObject[ this.propertyName ] = buffer[ offset ];
T
tschw 已提交
340 341 342 343 344 345
				this.targetObject.needsUpdate = true;

			},

			function setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) {

346
				this.targetObject[ this.propertyName ] = buffer[ offset ];
T
tschw 已提交
347
				this.targetObject.matrixWorldNeedsUpdate = true;
T
tschw 已提交
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391

			}

		], [

			// 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;
392 393 394

			}

T
tschw 已提交
395
		], [
396

T
tschw 已提交
397
			// ArrayElement
398

T
tschw 已提交
399
			function setValue_arrayElement( buffer, offset ) {
400

T
tschw 已提交
401
				this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
402

T
tschw 已提交
403
			},
404

T
tschw 已提交
405
			function setValue_arrayElement_setNeedsUpdate( buffer, offset ) {
406

T
tschw 已提交
407 408
				this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
				this.targetObject.needsUpdate = true;
409

T
tschw 已提交
410
			},
411

T
tschw 已提交
412
			function setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) {
413

T
tschw 已提交
414 415
				this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
				this.targetObject.matrixWorldNeedsUpdate = true;
416

T
tschw 已提交
417
			}
B
Ben Houston 已提交
418

T
tschw 已提交
419
		], [
420

T
tschw 已提交
421
			// HasToFromArray
422

T
tschw 已提交
423
			function setValue_fromArray( buffer, offset ) {
424

T
tschw 已提交
425
				this.resolvedProperty.fromArray( buffer, offset );
426

T
tschw 已提交
427
			},
428

T
tschw 已提交
429
			function setValue_fromArray_setNeedsUpdate( buffer, offset ) {
430

T
tschw 已提交
431 432
				this.resolvedProperty.fromArray( buffer, offset );
				this.targetObject.needsUpdate = true;
433

T
tschw 已提交
434
			},
435

T
tschw 已提交
436 437 438 439
			function setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) {

				this.resolvedProperty.fromArray( buffer, offset );
				this.targetObject.matrixWorldNeedsUpdate = true;
440

441
			}
B
Ben Houston 已提交
442

T
tschw 已提交
443 444
		]

445
	],
T
tschw 已提交
446

447
	getValue: function getValue_unbound( targetArray, offset ) {
T
tschw 已提交
448

449 450
		this.bind();
		this.getValue( targetArray, offset );
T
tschw 已提交
451

452 453 454 455 456
		// 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.
T
tschw 已提交
457

458
	},
T
tschw 已提交
459

460
	setValue: function getValue_unbound( sourceArray, offset ) {
T
tschw 已提交
461

462 463
		this.bind();
		this.setValue( sourceArray, offset );
T
tschw 已提交
464

465
	},
T
tschw 已提交
466

467
	// create getter / setter pair for a property in the scene graph
M
Mr.doob 已提交
468
	bind: function () {
T
tschw 已提交
469

470 471
		var targetObject = this.node,
			parsedPath = this.parsedPath,
T
tschw 已提交
472

473 474 475
			objectName = parsedPath.objectName,
			propertyName = parsedPath.propertyName,
			propertyIndex = parsedPath.propertyIndex;
T
tschw 已提交
476

477
		if ( ! targetObject ) {
T
tschw 已提交
478

M
Mugen87 已提交
479
			targetObject = PropertyBinding.findNode( this.rootNode, parsedPath.nodeName ) || this.rootNode;
T
tschw 已提交
480

481
			this.node = targetObject;
T
tschw 已提交
482

483
		}
T
tschw 已提交
484

485 486 487
		// set fail state so we can just 'return' on error
		this.getValue = this._getValue_unavailable;
		this.setValue = this._setValue_unavailable;
T
tschw 已提交
488

489 490
		// ensure there is a value node
		if ( ! targetObject ) {
T
tschw 已提交
491

M
Mugen87 已提交
492
			console.error( 'THREE.PropertyBinding: Trying to update node for track: ' + this.path + ' but it wasn\'t found.' );
493
			return;
T
tschw 已提交
494

495
		}
T
tschw 已提交
496

497
		if ( objectName ) {
T
tschw 已提交
498

499
			var objectIndex = parsedPath.objectIndex;
T
tschw 已提交
500

501 502
			// special cases were we need to reach deeper into the hierarchy to get the face materials....
			switch ( objectName ) {
T
tschw 已提交
503

504
				case 'materials':
T
tschw 已提交
505

506
					if ( ! targetObject.material ) {
507

M
Mugen87 已提交
508
						console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this );
509
						return;
510

511
					}
512

513
					if ( ! targetObject.material.materials ) {
514

M
Mugen87 已提交
515
						console.error( 'THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this );
516
						return;
T
tschw 已提交
517

518
					}
T
tschw 已提交
519

520
					targetObject = targetObject.material.materials;
521

522
					break;
523

524
				case 'bones':
525

526
					if ( ! targetObject.skeleton ) {
527

M
Mugen87 已提交
528
						console.error( 'THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this );
529
						return;
530

531
					}
532

533 534
					// potential future optimization: skip this if propertyIndex is already an integer
					// and convert the integer string to a true integer.
T
tschw 已提交
535

536
					targetObject = targetObject.skeleton.bones;
T
tschw 已提交
537

538 539
					// support resolving morphTarget names into indices.
					for ( var i = 0; i < targetObject.length; i ++ ) {
T
tschw 已提交
540

541
						if ( targetObject[ i ].name === objectIndex ) {
542

543 544
							objectIndex = i;
							break;
545

546
						}
547

548
					}
549

550
					break;
551

552
				default:
553

554
					if ( targetObject[ objectName ] === undefined ) {
555

M
Mugen87 已提交
556
						console.error( 'THREE.PropertyBinding: Can not bind to objectName of node undefined.', this );
557
						return;
558

559
					}
560

561
					targetObject = targetObject[ objectName ];
562

563
			}
564

565

566
			if ( objectIndex !== undefined ) {
567

568
				if ( targetObject[ objectIndex ] === undefined ) {
569

M
Mugen87 已提交
570
					console.error( 'THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject );
571
					return;
572

573
				}
574

575
				targetObject = targetObject[ objectIndex ];
576

577
			}
578

579
		}
580

581 582
		// resolve property
		var nodeProperty = targetObject[ propertyName ];
583

584
		if ( nodeProperty === undefined ) {
585

586
			var nodeName = parsedPath.nodeName;
587

M
Mugen87 已提交
588 589
			console.error( 'THREE.PropertyBinding: Trying to update property for track: ' + nodeName +
				'.' + propertyName + ' but it wasn\'t found.', targetObject );
590
			return;
591

592
		}
593

594 595
		// determine versioning scheme
		var versioning = this.Versioning.None;
596

597
		if ( targetObject.needsUpdate !== undefined ) { // material
598

599 600
			versioning = this.Versioning.NeedsUpdate;
			this.targetObject = targetObject;
601

602
		} else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform
M
Mr.doob 已提交
603

604 605
			versioning = this.Versioning.MatrixWorldNeedsUpdate;
			this.targetObject = targetObject;
606 607 608

		}

609 610 611 612
		// determine how the property gets bound
		var bindingType = this.BindingType.Direct;

		if ( propertyIndex !== undefined ) {
M
Mr.doob 已提交
613

614 615 616
			// access a sub element of the property array (only primitives are supported right now)

			if ( propertyName === "morphTargetInfluences" ) {
M
Mr.doob 已提交
617

618
				// potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer.
619

620 621
				// support resolving morphTarget names into indices.
				if ( ! targetObject.geometry ) {
622

M
Mugen87 已提交
623
					console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this );
624
					return;
625

626
				}
627

628
				if ( targetObject.geometry.isBufferGeometry ) {
629

630
					if ( ! targetObject.geometry.morphAttributes ) {
631

M
Mugen87 已提交
632
						console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this );
633 634 635 636 637
						return;

					}

					for ( var i = 0; i < this.node.geometry.morphAttributes.position.length; i ++ ) {
638

639 640 641 642 643 644 645 646
						if ( targetObject.geometry.morphAttributes.position[ i ].name === propertyIndex ) {

							propertyIndex = i;
							break;

						}

					}
647 648


649 650 651 652
				} else {

					if ( ! targetObject.geometry.morphTargets ) {

M
Mugen87 已提交
653
						console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphTargets.', this );
654 655 656 657 658 659 660 661 662 663 664 665
						return;

					}

					for ( var i = 0; i < this.node.geometry.morphTargets.length; i ++ ) {

						if ( targetObject.geometry.morphTargets[ i ].name === propertyIndex ) {

							propertyIndex = i;
							break;

						}
666 667

					}
668

669
				}
670

T
tschw 已提交
671
			}
672

673
			bindingType = this.BindingType.ArrayElement;
674

675 676 677 678
			this.resolvedProperty = nodeProperty;
			this.propertyIndex = propertyIndex;

		} else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) {
M
Mr.doob 已提交
679

680 681 682 683 684
			// must use copy for Object3D.Euler/Quaternion

			bindingType = this.BindingType.HasFromToArray;

			this.resolvedProperty = nodeProperty;
685

686
		} else if ( Array.isArray( nodeProperty ) ) {
M
Mr.doob 已提交
687

688
			bindingType = this.BindingType.EntireArray;
689

690 691 692
			this.resolvedProperty = nodeProperty;

		} else {
693

694
			this.propertyName = propertyName;
695 696 697

		}

698 699 700 701 702 703
		// select getter / setter
		this.getValue = this.GetterByBindingType[ bindingType ];
		this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ];

	},

M
Mr.doob 已提交
704
	unbind: function () {
705 706 707 708 709 710 711

		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;
712

713
	}
T
tschw 已提交
714

715
} );
R
Rich Harris 已提交
716

T
Tristan VALCKE 已提交
717 718 719 720 721 722 723 724
//!\ 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,

} );
R
Rich Harris 已提交
725

726
export { PropertyBinding };