@microsoft/fast-element 2.0.0-beta.6 → 2.0.0-beta.7

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.
Files changed (64) hide show
  1. package/CHANGELOG.json +57 -0
  2. package/CHANGELOG.md +16 -1
  3. package/dist/dts/components/attributes.d.ts +10 -0
  4. package/dist/dts/components/{controller.d.ts → element-controller.d.ts} +24 -25
  5. package/dist/dts/components/fast-definitions.d.ts +28 -3
  6. package/dist/dts/components/fast-element.d.ts +2 -2
  7. package/dist/dts/di/di.d.ts +41 -0
  8. package/dist/dts/index.d.ts +2 -2
  9. package/dist/dts/observation/observable.d.ts +86 -47
  10. package/dist/dts/pending-task.d.ts +20 -0
  11. package/dist/dts/platform.d.ts +6 -0
  12. package/dist/dts/styles/css-directive.d.ts +2 -2
  13. package/dist/dts/styles/element-styles.d.ts +3 -3
  14. package/dist/dts/styles/host.d.ts +68 -0
  15. package/dist/dts/templating/binding-signal.d.ts +2 -2
  16. package/dist/dts/templating/binding-two-way.d.ts +11 -3
  17. package/dist/dts/templating/binding.d.ts +21 -119
  18. package/dist/dts/templating/children.d.ts +1 -1
  19. package/dist/dts/templating/html-directive.d.ts +69 -39
  20. package/dist/dts/templating/node-observation.d.ts +4 -5
  21. package/dist/dts/templating/ref.d.ts +5 -13
  22. package/dist/dts/templating/render.d.ts +15 -20
  23. package/dist/dts/templating/repeat.d.ts +11 -16
  24. package/dist/dts/templating/slotted.d.ts +1 -1
  25. package/dist/dts/templating/template.d.ts +4 -4
  26. package/dist/dts/templating/view.d.ts +68 -9
  27. package/dist/dts/templating/when.d.ts +1 -1
  28. package/dist/dts/testing/exports.d.ts +1 -0
  29. package/dist/dts/testing/fakes.d.ts +4 -0
  30. package/dist/dts/testing/fixture.d.ts +0 -6
  31. package/dist/esm/components/attributes.js +13 -4
  32. package/dist/esm/components/{controller.js → element-controller.js} +95 -105
  33. package/dist/esm/components/fast-definitions.js +3 -1
  34. package/dist/esm/components/fast-element.js +4 -4
  35. package/dist/esm/di/di.js +87 -3
  36. package/dist/esm/index.js +2 -1
  37. package/dist/esm/observation/observable.js +59 -126
  38. package/dist/esm/pending-task.js +16 -0
  39. package/dist/esm/platform.js +21 -0
  40. package/dist/esm/styles/css.js +4 -4
  41. package/dist/esm/{observation/behavior.js → styles/host.js} +0 -0
  42. package/dist/esm/templating/binding-signal.js +21 -17
  43. package/dist/esm/templating/binding-two-way.js +32 -27
  44. package/dist/esm/templating/binding.js +73 -177
  45. package/dist/esm/templating/html-directive.js +78 -7
  46. package/dist/esm/templating/node-observation.js +9 -8
  47. package/dist/esm/templating/ref.js +4 -12
  48. package/dist/esm/templating/render.js +30 -31
  49. package/dist/esm/templating/repeat.js +37 -38
  50. package/dist/esm/templating/template.js +3 -4
  51. package/dist/esm/templating/view.js +96 -24
  52. package/dist/esm/testing/exports.js +1 -0
  53. package/dist/esm/testing/fakes.js +76 -0
  54. package/dist/esm/testing/fixture.js +1 -3
  55. package/dist/fast-element.api.json +5720 -5385
  56. package/dist/fast-element.d.ts +510 -399
  57. package/dist/fast-element.debug.js +492 -509
  58. package/dist/fast-element.debug.min.js +1 -1
  59. package/dist/fast-element.js +492 -509
  60. package/dist/fast-element.min.js +1 -1
  61. package/dist/fast-element.untrimmed.d.ts +519 -405
  62. package/docs/api-report.md +197 -129
  63. package/package.json +5 -1
  64. package/dist/dts/observation/behavior.d.ts +0 -19
@@ -14,29 +14,19 @@ const createInnerHTMLBinding = globalThis.TrustedHTML
14
14
  }
15
15
  : (binding) => binding;
16
16
  class OnChangeBinding extends Binding {
17
- constructor(evaluate, isVolatile) {
18
- super();
19
- this.evaluate = evaluate;
20
- this.isVolatile = isVolatile;
21
- }
22
17
  createObserver(_, subscriber) {
23
18
  return Observable.binding(this.evaluate, subscriber, this.isVolatile);
24
19
  }
25
20
  }
26
21
  class OneTimeBinding extends Binding {
27
- constructor(evaluate) {
28
- super();
29
- this.evaluate = evaluate;
30
- }
31
22
  createObserver() {
32
23
  return this;
33
24
  }
34
- observe(source, context) {
35
- return this.evaluate(source, context);
25
+ bind(controller) {
26
+ return this.evaluate(controller.source, controller.context);
36
27
  }
37
- dispose() { }
38
28
  }
39
- function updateContentTarget(target, aspect, value, source, context) {
29
+ function updateContent(target, aspect, value, controller) {
40
30
  // If there's no actual value, then this equates to the
41
31
  // empty string for the purposes of content bindings.
42
32
  if (value === null || value === undefined) {
@@ -68,14 +58,14 @@ function updateContentTarget(target, aspect, value, source, context) {
68
58
  // and that there's actually no need to compose it.
69
59
  if (!view.isComposed) {
70
60
  view.isComposed = true;
71
- view.bind(source, context);
61
+ view.bind(controller.source);
72
62
  view.insertBefore(target);
73
63
  target.$fastView = view;
74
64
  target.$fastTemplate = value;
75
65
  }
76
66
  else if (view.needsBindOnly) {
77
67
  view.needsBindOnly = false;
78
- view.bind(source, context);
68
+ view.bind(controller.source);
79
69
  }
80
70
  }
81
71
  else {
@@ -95,10 +85,9 @@ function updateContentTarget(target, aspect, value, source, context) {
95
85
  target.textContent = value;
96
86
  }
97
87
  }
98
- function updateTokenListTarget(target, aspect, value) {
88
+ function updateTokenList(target, aspect, value) {
99
89
  var _a;
100
- const directive = this.directive;
101
- const lookup = `${directive.id}-t`;
90
+ const lookup = `${this.id}-t`;
102
91
  const state = (_a = target[lookup]) !== null && _a !== void 0 ? _a : (target[lookup] = { c: 0, v: Object.create(null) });
103
92
  const versions = state.v;
104
93
  let currentVersion = state.c;
@@ -128,154 +117,8 @@ function updateTokenListTarget(target, aspect, value) {
128
117
  }
129
118
  }
130
119
  }
131
- /**
132
- * A binding behavior for bindings that change.
133
- * @public
134
- */
135
- export class BindingBehavior {
136
- /**
137
- * Creates an instance of ChangeBinding.
138
- * @param directive - The directive that has the configuration for this behavior.
139
- * @param updateTarget - The function used to update the target with the latest value.
140
- */
141
- constructor(directive, updateTarget) {
142
- this.directive = directive;
143
- this.updateTarget = updateTarget;
144
- this.observerProperty = `${directive.id}-o`;
145
- }
146
- /**
147
- * Bind this behavior to the source.
148
- * @param source - The source to bind to.
149
- * @param context - The execution context that the binding is operating within.
150
- * @param targets - The targets that behaviors in a view can attach to.
151
- */
152
- bind(source, context, targets) {
153
- const directive = this.directive;
154
- const target = targets[directive.nodeId];
155
- const observer = this.getObserver(target);
156
- observer.target = target;
157
- observer.source = source;
158
- observer.context = context;
159
- this.updateTarget(target, directive.targetAspect, observer.observe(source, context), source, context);
160
- }
161
- /**
162
- * Unbinds this behavior from the source.
163
- * @param source - The source to unbind from.
164
- * @param context - The execution context that the binding is operating within.
165
- * @param targets - The targets that behaviors in a view can attach to.
166
- */
167
- unbind(source, context, targets) {
168
- const target = targets[this.directive.nodeId];
169
- const observer = this.getObserver(target);
170
- observer.dispose();
171
- observer.target = null;
172
- observer.source = null;
173
- observer.context = null;
174
- }
175
- /** @internal */
176
- handleChange(binding, observer) {
177
- const target = observer.target;
178
- const source = observer.source;
179
- const context = observer.context;
180
- this.updateTarget(target, this.directive.targetAspect, observer.observe(source, context), source, context);
181
- }
182
- /**
183
- * Returns the binding observer used to update the node.
184
- * @param target - The target node.
185
- * @returns A BindingObserver.
186
- */
187
- getObserver(target) {
188
- var _a;
189
- return ((_a = target[this.observerProperty]) !== null && _a !== void 0 ? _a : (target[this.observerProperty] = this.directive.dataBinding.createObserver(this.directive, this)));
190
- }
191
- /**
192
- * Creates a behavior.
193
- * @param targets - The targets available for behaviors to be attached to.
194
- */
195
- createBehavior(targets) {
196
- return this;
197
- }
198
- }
199
- /**
200
- * A special binding behavior that can bind node content.
201
- * @public
202
- */
203
- export class ContentBehavior extends BindingBehavior {
204
- /**
205
- * Unbinds this behavior from the source.
206
- * @param source - The source to unbind from.
207
- * @param context - The execution context that the binding is operating within.
208
- * @param targets - The targets that behaviors in a view can attach to.
209
- */
210
- unbind(source, context, targets) {
211
- super.unbind(source, context, targets);
212
- const target = targets[this.directive.nodeId];
213
- const view = target.$fastView;
214
- if (view !== void 0 && view.isComposed) {
215
- view.unbind();
216
- view.needsBindOnly = true;
217
- }
218
- }
219
- }
220
- /**
221
- * A binding behavior for handling events.
222
- * @public
223
- */
224
- export class EventBehavior {
225
- /**
226
- * Creates an instance of EventBinding.
227
- * @param directive - The directive that has the configuration for this behavior.
228
- */
229
- constructor(directive) {
230
- this.directive = directive;
231
- this.sourceProperty = `${directive.id}-s`;
232
- this.contextProperty = `${directive.id}-c`;
233
- }
234
- /**
235
- * Bind this behavior to the source.
236
- * @param source - The source to bind to.
237
- * @param context - The execution context that the binding is operating within.
238
- * @param targets - The targets that behaviors in a view can attach to.
239
- */
240
- bind(source, context, targets) {
241
- const directive = this.directive;
242
- const target = targets[directive.nodeId];
243
- target[this.sourceProperty] = source;
244
- target[this.contextProperty] = context;
245
- target.addEventListener(directive.targetAspect, this, directive.dataBinding.options);
246
- }
247
- /**
248
- * Unbinds this behavior from the source.
249
- * @param source - The source to unbind from.
250
- * @param context - The execution context that the binding is operating within.
251
- * @param targets - The targets that behaviors in a view can attach to.
252
- */
253
- unbind(source, context, targets) {
254
- const directive = this.directive;
255
- const target = targets[directive.nodeId];
256
- target[this.sourceProperty] = target[this.contextProperty] = null;
257
- target.removeEventListener(directive.targetAspect, this, directive.dataBinding.options);
258
- }
259
- /**
260
- * Creates a behavior.
261
- * @param targets - The targets available for behaviors to be attached to.
262
- */
263
- createBehavior(targets) {
264
- return this;
265
- }
266
- /**
267
- * @internal
268
- */
269
- handleEvent(event) {
270
- const target = event.currentTarget;
271
- ExecutionContext.setEvent(event);
272
- const result = this.directive.dataBinding.evaluate(target[this.sourceProperty], target[this.contextProperty]);
273
- ExecutionContext.setEvent(null);
274
- if (result !== true) {
275
- event.preventDefault();
276
- }
277
- }
278
- }
120
+ const setProperty = (t, a, v) => (t[a] = v);
121
+ const eventTarget = () => void 0;
279
122
  /**
280
123
  * A directive that applies bindings.
281
124
  * @public
@@ -287,7 +130,7 @@ export class HTMLBindingDirective {
287
130
  */
288
131
  constructor(dataBinding) {
289
132
  this.dataBinding = dataBinding;
290
- this.factory = null;
133
+ this.updateTarget = null;
291
134
  /**
292
135
  * The unique id of the factory.
293
136
  */
@@ -296,6 +139,9 @@ export class HTMLBindingDirective {
296
139
  * The type of aspect to target.
297
140
  */
298
141
  this.aspectType = Aspect.content;
142
+ /** @internal */
143
+ this.bind = this.bindDefault;
144
+ this.data = `${this.id}-d`;
299
145
  }
300
146
  /**
301
147
  * Creates HTML to be used within a template.
@@ -306,37 +152,87 @@ export class HTMLBindingDirective {
306
152
  }
307
153
  /**
308
154
  * Creates a behavior.
309
- * @param targets - The targets available for behaviors to be attached to.
310
155
  */
311
- createBehavior(targets) {
312
- if (this.factory == null) {
156
+ createBehavior() {
157
+ if (this.updateTarget === null) {
313
158
  if (this.targetAspect === "innerHTML") {
314
159
  this.dataBinding.evaluate = createInnerHTMLBinding(this.dataBinding.evaluate);
315
160
  }
316
161
  switch (this.aspectType) {
317
162
  case 1:
318
- this.factory = new BindingBehavior(this, DOM.setAttribute);
163
+ this.updateTarget = DOM.setAttribute;
319
164
  break;
320
165
  case 2:
321
- this.factory = new BindingBehavior(this, DOM.setBooleanAttribute);
166
+ this.updateTarget = DOM.setBooleanAttribute;
322
167
  break;
323
168
  case 3:
324
- this.factory = new BindingBehavior(this, (t, a, v) => (t[a] = v));
169
+ this.updateTarget = setProperty;
325
170
  break;
326
171
  case 4:
327
- this.factory = new ContentBehavior(this, updateContentTarget);
172
+ this.bind = this.bindContent;
173
+ this.updateTarget = updateContent;
328
174
  break;
329
175
  case 5:
330
- this.factory = new BindingBehavior(this, updateTokenListTarget);
176
+ this.updateTarget = updateTokenList;
331
177
  break;
332
178
  case 6:
333
- this.factory = new EventBehavior(this);
179
+ this.bind = this.bindEvent;
180
+ this.updateTarget = eventTarget;
334
181
  break;
335
182
  default:
336
183
  throw FAST.error(1205 /* Message.unsupportedBindingBehavior */);
337
184
  }
338
185
  }
339
- return this.factory.createBehavior(targets);
186
+ return this;
187
+ }
188
+ /** @internal */
189
+ bindDefault(controller) {
190
+ var _a;
191
+ const target = controller.targets[this.nodeId];
192
+ const observer = (_a = target[this.data]) !== null && _a !== void 0 ? _a : (target[this.data] = this.dataBinding.createObserver(this, this));
193
+ observer.target = target;
194
+ observer.controller = controller;
195
+ this.updateTarget(target, this.targetAspect, observer.bind(controller), controller);
196
+ if (this.updateTarget === updateContent) {
197
+ controller.onUnbind(this);
198
+ }
199
+ }
200
+ /** @internal */
201
+ bindContent(controller) {
202
+ this.bindDefault(controller);
203
+ controller.onUnbind(this);
204
+ }
205
+ /** @internal */
206
+ bindEvent(controller) {
207
+ const target = controller.targets[this.nodeId];
208
+ target[this.data] = controller;
209
+ target.addEventListener(this.targetAspect, this, this.dataBinding.options);
210
+ }
211
+ /** @internal */
212
+ unbind(controller) {
213
+ const target = controller.targets[this.nodeId];
214
+ const view = target.$fastView;
215
+ if (view !== void 0 && view.isComposed) {
216
+ view.unbind();
217
+ view.needsBindOnly = true;
218
+ }
219
+ }
220
+ /** @internal */
221
+ handleEvent(event) {
222
+ const target = event.currentTarget;
223
+ ExecutionContext.setEvent(event);
224
+ const controller = target[this.data];
225
+ const result = this.dataBinding.evaluate(controller.source, controller.context);
226
+ ExecutionContext.setEvent(null);
227
+ if (result !== true) {
228
+ event.preventDefault();
229
+ }
230
+ }
231
+ /** @internal */
232
+ handleChange(binding, observer) {
233
+ const target = observer.target;
234
+ const controller = observer.controller;
235
+ this.updateTarget(target, this.targetAspect, observer.bind(controller), controller);
340
236
  }
341
237
  }
342
238
  HTMLDirective.define(HTMLBindingDirective, { aspected: true });
@@ -1,5 +1,67 @@
1
+ import { ExecutionContext, } from "../observation/observable.js";
1
2
  import { createTypeRegistry } from "../platform.js";
2
3
  import { Markup, nextId } from "./markup.js";
4
+ /**
5
+ * Bridges between ViewBehaviors and HostBehaviors, enabling a host to
6
+ * control ViewBehaviors.
7
+ * @public
8
+ */
9
+ export const ViewBehaviorOrchestrator = Object.freeze({
10
+ /**
11
+ * Creates a ViewBehaviorOrchestrator.
12
+ * @param source - The source to to associate behaviors with.
13
+ * @returns A ViewBehaviorOrchestrator.
14
+ */
15
+ create(source) {
16
+ const behaviors = [];
17
+ const targets = {};
18
+ let unbindables = null;
19
+ let isConnected = false;
20
+ return {
21
+ source,
22
+ context: ExecutionContext.default,
23
+ targets,
24
+ get isBound() {
25
+ return isConnected;
26
+ },
27
+ addBehaviorFactory(factory, target) {
28
+ const nodeId = factory.nodeId || (factory.nodeId = nextId());
29
+ factory.id || (factory.id = nextId());
30
+ this.addTarget(nodeId, target);
31
+ this.addBehavior(factory.createBehavior());
32
+ },
33
+ addTarget(nodeId, target) {
34
+ targets[nodeId] = target;
35
+ },
36
+ addBehavior(behavior) {
37
+ behaviors.push(behavior);
38
+ if (isConnected) {
39
+ behavior.bind(this);
40
+ }
41
+ },
42
+ onUnbind(unbindable) {
43
+ if (unbindables === null) {
44
+ unbindables = [];
45
+ }
46
+ unbindables.push(unbindable);
47
+ },
48
+ connectedCallback(controller) {
49
+ if (!isConnected) {
50
+ isConnected = true;
51
+ behaviors.forEach(x => x.bind(this));
52
+ }
53
+ },
54
+ disconnectedCallback(controller) {
55
+ if (isConnected) {
56
+ isConnected = false;
57
+ if (unbindables !== null) {
58
+ unbindables.forEach(x => x.unbind(this));
59
+ }
60
+ }
61
+ },
62
+ };
63
+ },
64
+ });
3
65
  const registry = createTypeRegistry();
4
66
  /**
5
67
  * Instructs the template engine to apply behavior to a node.
@@ -45,6 +107,15 @@ export function htmlDirective(options) {
45
107
  * @public
46
108
  */
47
109
  export class Binding {
110
+ /**
111
+ * Creates a binding.
112
+ * @param evaluate - Evaluates the binding.
113
+ * @param isVolatile - Indicates whether the binding is volatile.
114
+ */
115
+ constructor(evaluate, isVolatile = false) {
116
+ this.evaluate = evaluate;
117
+ this.isVolatile = isVolatile;
118
+ }
48
119
  }
49
120
  /**
50
121
  * The type of HTML aspect to target.
@@ -144,13 +215,6 @@ export class StatelessAttachedAttributeDirective {
144
215
  */
145
216
  this.id = nextId();
146
217
  }
147
- /**
148
- * Creates a behavior.
149
- * @param targets - The targets available for behaviors to be attached to.
150
- */
151
- createBehavior(targets) {
152
- return this;
153
- }
154
218
  /**
155
219
  * Creates a placeholder string based on the directive's index within the template.
156
220
  * @param index - The index of the directive within the template.
@@ -160,4 +224,11 @@ export class StatelessAttachedAttributeDirective {
160
224
  createHTML(add) {
161
225
  return Markup.attribute(add(this));
162
226
  }
227
+ /**
228
+ * Creates a behavior.
229
+ * @param targets - The targets available for behaviors to be attached to.
230
+ */
231
+ createBehavior() {
232
+ return this;
233
+ }
163
234
  }
@@ -1,5 +1,5 @@
1
1
  import { emptyArray } from "../platform.js";
2
- import { StatelessAttachedAttributeDirective, } from "./html-directive.js";
2
+ import { StatelessAttachedAttributeDirective } from "./html-directive.js";
3
3
  const selectElements = (value) => value.nodeType === 1;
4
4
  /**
5
5
  * Creates a function that can be used to filter a Node array, selecting only elements.
@@ -26,11 +26,12 @@ export class NodeObservationDirective extends StatelessAttachedAttributeDirectiv
26
26
  * @param context - The execution context that the binding is operating within.
27
27
  * @param targets - The targets that behaviors in a view can attach to.
28
28
  */
29
- bind(source, context, targets) {
30
- const target = targets[this.nodeId];
31
- target[this.sourceProperty] = source;
32
- this.updateTarget(source, this.computeNodes(target));
29
+ bind(controller) {
30
+ const target = controller.targets[this.nodeId];
31
+ target[this.sourceProperty] = controller.source;
32
+ this.updateTarget(controller.source, this.computeNodes(target));
33
33
  this.observe(target);
34
+ controller.onUnbind(this);
34
35
  }
35
36
  /**
36
37
  * Unbinds this behavior from the source.
@@ -38,9 +39,9 @@ export class NodeObservationDirective extends StatelessAttachedAttributeDirectiv
38
39
  * @param context - The execution context that the binding is operating within.
39
40
  * @param targets - The targets that behaviors in a view can attach to.
40
41
  */
41
- unbind(source, context, targets) {
42
- const target = targets[this.nodeId];
43
- this.updateTarget(source, emptyArray);
42
+ unbind(controller) {
43
+ const target = controller.targets[this.nodeId];
44
+ this.updateTarget(controller.source, emptyArray);
44
45
  this.disconnect(target);
45
46
  target[this.sourceProperty] = null;
46
47
  }
@@ -5,20 +5,12 @@ import { HTMLDirective, StatelessAttachedAttributeDirective, } from "./html-dire
5
5
  */
6
6
  export class RefDirective extends StatelessAttachedAttributeDirective {
7
7
  /**
8
- * Bind this behavior to the source.
9
- * @param source - The source to bind to.
10
- * @param context - The execution context that the binding is operating within.
11
- * @param targets - The targets that behaviors in a view can attach to.
8
+ * Bind this behavior.
9
+ * @param controller - The view controller that manages the lifecycle of this behavior.
12
10
  */
13
- bind(source, context, targets) {
14
- source[this.options] = targets[this.nodeId];
11
+ bind(controller) {
12
+ controller.source[this.options] = controller.targets[this.nodeId];
15
13
  }
16
- /**
17
- * Unbinds this behavior from the source.
18
- * @param source - The source to unbind from.
19
- */
20
- /* eslint-disable-next-line @typescript-eslint/no-empty-function */
21
- unbind() { }
22
14
  }
23
15
  HTMLDirective.define(RefDirective);
24
16
  /**
@@ -11,57 +11,48 @@ import { html, } from "./template.js";
11
11
  export class RenderBehavior {
12
12
  /**
13
13
  * Creates an instance of RenderBehavior.
14
- * @param location - A Node representing the location where this behavior will render.
15
- * @param dataBinding - A binding expression that returns the data to render.
16
- * @param templateBinding - A binding expression that returns the template to use with the data.
14
+ * @param directive - The render directive that created this behavior.
17
15
  */
18
- constructor(directive, location) {
16
+ constructor(directive) {
19
17
  this.directive = directive;
20
- this.location = location;
21
- this.source = null;
18
+ this.location = null;
19
+ this.controller = null;
22
20
  this.view = null;
23
21
  this.data = null;
24
- this.originalContext = void 0;
25
- this.childContext = void 0;
26
22
  this.dataBindingObserver = directive.dataBinding.createObserver(directive, this);
27
23
  this.templateBindingObserver = directive.templateBinding.createObserver(directive, this);
28
24
  }
29
25
  /**
30
- * Bind this behavior to the source.
31
- * @param source - The source to bind to.
32
- * @param context - The execution context that the binding is operating within.
26
+ * Bind this behavior.
27
+ * @param controller - The view controller that manages the lifecycle of this behavior.
33
28
  */
34
- bind(source, context) {
35
- this.source = source;
36
- this.originalContext = context;
37
- this.childContext = context.createChildContext(source);
38
- this.data = this.dataBindingObserver.observe(source, this.originalContext);
39
- this.template = this.templateBindingObserver.observe(source, this.originalContext);
29
+ bind(controller) {
30
+ this.location = controller.targets[this.directive.nodeId];
31
+ this.controller = controller;
32
+ this.data = this.dataBindingObserver.bind(controller);
33
+ this.template = this.templateBindingObserver.bind(controller);
34
+ controller.onUnbind(this);
40
35
  this.refreshView();
41
36
  }
42
37
  /**
43
- * Unbinds this behavior from the source.
44
- * @param source - The source to unbind from.
38
+ * Unbinds this behavior.
39
+ * @param controller - The view controller that manages the lifecycle of this behavior.
45
40
  */
46
- unbind(source, context) {
47
- this.source = null;
48
- this.data = null;
41
+ unbind(controller) {
49
42
  const view = this.view;
50
43
  if (view !== null && view.isComposed) {
51
44
  view.unbind();
52
45
  view.needsBindOnly = true;
53
46
  }
54
- this.dataBindingObserver.dispose();
55
- this.templateBindingObserver.dispose();
56
47
  }
57
48
  /** @internal */
58
49
  handleChange(source, observer) {
59
50
  if (observer === this.dataBindingObserver) {
60
- this.data = this.dataBindingObserver.observe(this.source, this.originalContext);
51
+ this.data = this.dataBindingObserver.bind(this.controller);
61
52
  }
62
53
  if (this.directive.templateBindingDependsOnData ||
63
54
  observer === this.templateBindingObserver) {
64
- this.template = this.templateBindingObserver.observe(this.source, this.originalContext);
55
+ this.template = this.templateBindingObserver.bind(this.controller);
65
56
  }
66
57
  this.refreshView();
67
58
  }
@@ -70,6 +61,8 @@ export class RenderBehavior {
70
61
  const template = this.template;
71
62
  if (view === null) {
72
63
  this.view = view = template.create();
64
+ this.view.context.parent = this.controller.source;
65
+ this.view.context.parentContext = this.controller.context;
73
66
  }
74
67
  else {
75
68
  // If there is a previous view, but it wasn't created
@@ -82,19 +75,21 @@ export class RenderBehavior {
82
75
  view.unbind();
83
76
  }
84
77
  this.view = view = template.create();
78
+ this.view.context.parent = this.controller.source;
79
+ this.view.context.parentContext = this.controller.context;
85
80
  }
86
81
  }
87
82
  // It's possible that the value is the same as the previous template
88
83
  // and that there's actually no need to compose it.
89
84
  if (!view.isComposed) {
90
85
  view.isComposed = true;
91
- view.bind(this.data, this.childContext);
86
+ view.bind(this.data);
92
87
  view.insertBefore(this.location);
93
88
  view.$fastTemplate = template;
94
89
  }
95
90
  else if (view.needsBindOnly) {
96
91
  view.needsBindOnly = false;
97
- view.bind(this.data, this.childContext);
92
+ view.bind(this.data);
98
93
  }
99
94
  }
100
95
  }
@@ -124,8 +119,8 @@ export class RenderDirective {
124
119
  * Creates a behavior.
125
120
  * @param targets - The targets available for behaviors to be attached to.
126
121
  */
127
- createBehavior(targets) {
128
- return new RenderBehavior(this, targets[this.nodeId]);
122
+ createBehavior() {
123
+ return new RenderBehavior(this);
129
124
  }
130
125
  }
131
126
  HTMLDirective.define(RenderDirective);
@@ -297,7 +292,11 @@ export class NodeTemplate {
297
292
  this.node = node;
298
293
  node.$fastTemplate = this;
299
294
  }
300
- bind(source, context) { }
295
+ get context() {
296
+ // HACK
297
+ return this;
298
+ }
299
+ bind(source) { }
301
300
  unbind() { }
302
301
  insertBefore(refNode) {
303
302
  refNode.parentNode.insertBefore(this.node, refNode);