PropertyBinding.js 16.1 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

M
Mr.doob 已提交
222
			var searchSkeleton = function ( skeleton ) {
223

M
Mr.doob 已提交
224
				for ( var i = 0; i < skeleton.bones.length; i ++ ) {
T
tschw 已提交
225

226
					var bone = skeleton.bones[ i ];
T
tschw 已提交
227

228
					if ( bone.name === nodeName ) {
T
tschw 已提交
229

230
						return bone;
T
tschw 已提交
231

232
					}
M
Mr.doob 已提交
233

234
				}
235

236
				return null;
T
tschw 已提交
237

238
			};
T
tschw 已提交
239

240
			var bone = searchSkeleton( root.skeleton );
T
tschw 已提交
241

242
			if ( bone ) {
T
tschw 已提交
243

244
				return bone;
T
tschw 已提交
245

246
			}
M
Mr.doob 已提交
247

248
		}
249

250 251
		// search into node subtree.
		if ( root.children ) {
252

M
Mr.doob 已提交
253
			var searchNodeSubtree = function ( children ) {
254

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

257
					var childNode = children[ i ];
258

259
					if ( childNode.name === nodeName || childNode.uuid === nodeName ) {
260

261
						return childNode;
T
tschw 已提交
262

263
					}
T
tschw 已提交
264

265
					var result = searchNodeSubtree( childNode.children );
T
tschw 已提交
266

267
					if ( result ) return result;
268

269
				}
270

271
				return null;
272

273
			};
274

275
			var subTreeNode = searchNodeSubtree( root.children );
276

277
			if ( subTreeNode ) {
278

279
				return subTreeNode;
280

281 282 283 284 285
			}

		}

		return null;
286

T
tschw 已提交
287
	}
288

289
} );
290

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

T
tschw 已提交
293
	// these are used to "bind" a nonexistent property
M
Mr.doob 已提交
294 295
	_getValue_unavailable: function () {},
	_setValue_unavailable: function () {},
296

T
tschw 已提交
297 298
	BindingType: {
		Direct: 0,
T
tschw 已提交
299 300 301
		EntireArray: 1,
		ArrayElement: 2,
		HasFromToArray: 3
T
tschw 已提交
302
	},
303

T
tschw 已提交
304 305 306 307 308
	Versioning: {
		None: 0,
		NeedsUpdate: 1,
		MatrixWorldNeedsUpdate: 2
	},
309

T
tschw 已提交
310
	GetterByBindingType: [
311

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

T
tschw 已提交
314
			buffer[ offset ] = this.node[ this.propertyName ];
315

T
tschw 已提交
316
		},
317

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

320
			var source = this.resolvedProperty;
T
tschw 已提交
321 322 323 324 325 326 327 328 329

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

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

			}

		},

T
tschw 已提交
330
		function getValue_arrayElement( buffer, offset ) {
331

T
tschw 已提交
332
			buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ];
333

T
tschw 已提交
334
		},
335

T
tschw 已提交
336
		function getValue_toArray( buffer, offset ) {
337

T
tschw 已提交
338
			this.resolvedProperty.toArray( buffer, offset );
339

T
tschw 已提交
340
		}
341

T
tschw 已提交
342
	],
343

T
tschw 已提交
344
	SetterByBindingTypeAndVersioning: [
345

T
tschw 已提交
346 347
		[
			// Direct
348

T
tschw 已提交
349
			function setValue_direct( buffer, offset ) {
350

351
				this.targetObject[ this.propertyName ] = buffer[ offset ];
352

T
tschw 已提交
353
			},
354

T
tschw 已提交
355
			function setValue_direct_setNeedsUpdate( buffer, offset ) {
356

357
				this.targetObject[ this.propertyName ] = buffer[ offset ];
T
tschw 已提交
358 359 360 361 362 363
				this.targetObject.needsUpdate = true;

			},

			function setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) {

364
				this.targetObject[ this.propertyName ] = buffer[ offset ];
T
tschw 已提交
365
				this.targetObject.matrixWorldNeedsUpdate = true;
T
tschw 已提交
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 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409

			}

		], [

			// 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;
410 411 412

			}

T
tschw 已提交
413
		], [
414

T
tschw 已提交
415
			// ArrayElement
416

T
tschw 已提交
417
			function setValue_arrayElement( buffer, offset ) {
418

T
tschw 已提交
419
				this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
420

T
tschw 已提交
421
			},
422

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

T
tschw 已提交
425 426
				this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
				this.targetObject.needsUpdate = true;
427

T
tschw 已提交
428
			},
429

T
tschw 已提交
430
			function setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) {
431

T
tschw 已提交
432 433
				this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
				this.targetObject.matrixWorldNeedsUpdate = true;
434

T
tschw 已提交
435
			}
B
Ben Houston 已提交
436

T
tschw 已提交
437
		], [
438

T
tschw 已提交
439
			// HasToFromArray
440

T
tschw 已提交
441
			function setValue_fromArray( buffer, offset ) {
442

T
tschw 已提交
443
				this.resolvedProperty.fromArray( buffer, offset );
444

T
tschw 已提交
445
			},
446

T
tschw 已提交
447
			function setValue_fromArray_setNeedsUpdate( buffer, offset ) {
448

T
tschw 已提交
449 450
				this.resolvedProperty.fromArray( buffer, offset );
				this.targetObject.needsUpdate = true;
451

T
tschw 已提交
452
			},
453

T
tschw 已提交
454 455 456 457
			function setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) {

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

459
			}
B
Ben Houston 已提交
460

T
tschw 已提交
461 462
		]

463
	],
T
tschw 已提交
464

465
	getValue: function getValue_unbound( targetArray, offset ) {
T
tschw 已提交
466

467 468
		this.bind();
		this.getValue( targetArray, offset );
T
tschw 已提交
469

470 471 472 473 474
		// 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 已提交
475

476
	},
T
tschw 已提交
477

478
	setValue: function getValue_unbound( sourceArray, offset ) {
T
tschw 已提交
479

480 481
		this.bind();
		this.setValue( sourceArray, offset );
T
tschw 已提交
482

483
	},
T
tschw 已提交
484

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

488 489
		var targetObject = this.node,
			parsedPath = this.parsedPath,
T
tschw 已提交
490

491 492 493
			objectName = parsedPath.objectName,
			propertyName = parsedPath.propertyName,
			propertyIndex = parsedPath.propertyIndex;
T
tschw 已提交
494

495
		if ( ! targetObject ) {
T
tschw 已提交
496

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

499
			this.node = targetObject;
T
tschw 已提交
500

501
		}
T
tschw 已提交
502

503 504 505
		// set fail state so we can just 'return' on error
		this.getValue = this._getValue_unavailable;
		this.setValue = this._setValue_unavailable;
T
tschw 已提交
506

507 508
		// ensure there is a value node
		if ( ! targetObject ) {
T
tschw 已提交
509

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

513
		}
T
tschw 已提交
514

515
		if ( objectName ) {
T
tschw 已提交
516

517
			var objectIndex = parsedPath.objectIndex;
T
tschw 已提交
518

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

522
				case 'materials':
T
tschw 已提交
523

524
					if ( ! targetObject.material ) {
525

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

529
					}
530

531
					if ( ! targetObject.material.materials ) {
532

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

536
					}
T
tschw 已提交
537

538
					targetObject = targetObject.material.materials;
539

540
					break;
541

542
				case 'bones':
543

544
					if ( ! targetObject.skeleton ) {
545

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

549
					}
550

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

554
					targetObject = targetObject.skeleton.bones;
T
tschw 已提交
555

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

559
						if ( targetObject[ i ].name === objectIndex ) {
560

561 562
							objectIndex = i;
							break;
563

564
						}
565

566
					}
567

568
					break;
569

570
				default:
571

572
					if ( targetObject[ objectName ] === undefined ) {
573

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

577
					}
578

579
					targetObject = targetObject[ objectName ];
580

581
			}
582

583

584
			if ( objectIndex !== undefined ) {
585

586
				if ( targetObject[ objectIndex ] === undefined ) {
587

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

591
				}
592

593
				targetObject = targetObject[ objectIndex ];
594

595
			}
596

597
		}
598

599 600
		// resolve property
		var nodeProperty = targetObject[ propertyName ];
601

602
		if ( nodeProperty === undefined ) {
603

604
			var nodeName = parsedPath.nodeName;
605

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

610
		}
611

612 613
		// determine versioning scheme
		var versioning = this.Versioning.None;
614

615
		if ( targetObject.needsUpdate !== undefined ) { // material
616

617 618
			versioning = this.Versioning.NeedsUpdate;
			this.targetObject = targetObject;
619

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

622 623
			versioning = this.Versioning.MatrixWorldNeedsUpdate;
			this.targetObject = targetObject;
624 625 626

		}

627 628 629 630
		// determine how the property gets bound
		var bindingType = this.BindingType.Direct;

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

632 633 634
			// access a sub element of the property array (only primitives are supported right now)

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

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

638 639
				// support resolving morphTarget names into indices.
				if ( ! targetObject.geometry ) {
640

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

644
				}
645

646
				if ( targetObject.geometry.isBufferGeometry ) {
647

648
					if ( ! targetObject.geometry.morphAttributes ) {
649

M
Mugen87 已提交
650
						console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this );
651 652 653 654 655
						return;

					}

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

657 658 659 660 661 662 663 664
						if ( targetObject.geometry.morphAttributes.position[ i ].name === propertyIndex ) {

							propertyIndex = i;
							break;

						}

					}
665 666


667 668 669 670
				} else {

					if ( ! targetObject.geometry.morphTargets ) {

M
Mugen87 已提交
671
						console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphTargets.', this );
672 673 674 675 676 677 678 679 680 681 682 683
						return;

					}

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

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

							propertyIndex = i;
							break;

						}
684 685

					}
686

687
				}
688

T
tschw 已提交
689
			}
690

691
			bindingType = this.BindingType.ArrayElement;
692

693 694 695 696
			this.resolvedProperty = nodeProperty;
			this.propertyIndex = propertyIndex;

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

698 699 700 701 702
			// must use copy for Object3D.Euler/Quaternion

			bindingType = this.BindingType.HasFromToArray;

			this.resolvedProperty = nodeProperty;
703

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

706
			bindingType = this.BindingType.EntireArray;
707

708 709 710
			this.resolvedProperty = nodeProperty;

		} else {
711

712
			this.propertyName = propertyName;
713 714 715

		}

716 717 718 719 720 721
		// select getter / setter
		this.getValue = this.GetterByBindingType[ bindingType ];
		this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ];

	},

M
Mr.doob 已提交
722
	unbind: function () {
723 724 725 726 727 728 729

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

731
	}
T
tschw 已提交
732

733
} );
R
Rich Harris 已提交
734

T
Tristan VALCKE 已提交
735 736 737 738 739 740 741 742
//!\ 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 已提交
743

744
export { PropertyBinding };