@microsoft/fast-element 2.0.0-beta.1 → 2.0.0-beta.10
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/CHANGELOG.json +333 -0
- package/CHANGELOG.md +106 -1
- package/dist/dts/components/attributes.d.ts +10 -0
- package/dist/dts/components/{controller.d.ts → element-controller.d.ts} +24 -25
- package/dist/dts/components/fast-definitions.d.ts +43 -9
- package/dist/dts/components/fast-element.d.ts +15 -21
- package/dist/dts/context.d.ts +157 -0
- package/dist/dts/di/di.d.ts +899 -0
- package/dist/dts/index.d.ts +2 -2
- package/dist/dts/interfaces.d.ts +44 -12
- package/dist/dts/metadata.d.ts +25 -0
- package/dist/dts/observation/arrays.d.ts +1 -1
- package/dist/dts/observation/observable.d.ts +101 -75
- package/dist/dts/pending-task.d.ts +20 -0
- package/dist/dts/platform.d.ts +6 -0
- package/dist/dts/state/exports.d.ts +3 -0
- package/dist/dts/state/reactive.d.ts +8 -0
- package/dist/dts/state/state.d.ts +141 -0
- package/dist/dts/state/visitor.d.ts +6 -0
- package/dist/dts/state/watch.d.ts +10 -0
- package/dist/dts/styles/css-directive.d.ts +2 -2
- package/dist/dts/styles/element-styles.d.ts +9 -3
- package/dist/dts/styles/host.d.ts +68 -0
- package/dist/dts/templating/binding-signal.d.ts +21 -0
- package/dist/dts/templating/binding-two-way.d.ts +39 -0
- package/dist/dts/templating/binding.d.ts +69 -294
- package/dist/dts/templating/children.d.ts +1 -1
- package/dist/dts/templating/compiler.d.ts +1 -2
- package/dist/dts/templating/html-directive.d.ts +93 -35
- package/dist/dts/templating/node-observation.d.ts +4 -5
- package/dist/dts/templating/ref.d.ts +5 -13
- package/dist/dts/templating/render.d.ts +272 -0
- package/dist/dts/templating/repeat.d.ts +20 -75
- package/dist/dts/templating/slotted.d.ts +1 -1
- package/dist/dts/templating/template.d.ts +12 -61
- package/dist/dts/templating/view.d.ts +77 -12
- package/dist/dts/templating/when.d.ts +3 -3
- package/dist/dts/testing/exports.d.ts +3 -0
- package/dist/dts/testing/fakes.d.ts +4 -0
- package/dist/dts/testing/fixture.d.ts +84 -0
- package/dist/dts/testing/timeout.d.ts +7 -0
- package/dist/{tsdoc-metadata.json → dts/tsdoc-metadata.json} +0 -0
- package/dist/dts/utilities.d.ts +0 -18
- package/dist/esm/components/attributes.js +13 -4
- package/dist/esm/components/{controller.js → element-controller.js} +95 -105
- package/dist/esm/components/fast-definitions.js +38 -28
- package/dist/esm/components/fast-element.js +31 -12
- package/dist/esm/context.js +163 -0
- package/dist/esm/debug.js +36 -4
- package/dist/esm/di/di.js +1435 -0
- package/dist/esm/index.js +2 -1
- package/dist/esm/interfaces.js +4 -0
- package/dist/esm/metadata.js +60 -0
- package/dist/esm/observation/arrays.js +304 -3
- package/dist/esm/observation/observable.js +81 -87
- package/dist/esm/pending-task.js +16 -0
- package/dist/esm/platform.js +25 -1
- package/dist/esm/state/exports.js +3 -0
- package/dist/esm/state/reactive.js +34 -0
- package/dist/esm/state/state.js +148 -0
- package/dist/esm/state/visitor.js +28 -0
- package/dist/esm/state/watch.js +36 -0
- package/dist/esm/styles/css.js +4 -4
- package/dist/esm/styles/element-styles.js +14 -0
- package/dist/esm/{observation/behavior.js → styles/host.js} +0 -0
- package/dist/esm/templating/binding-signal.js +83 -0
- package/dist/esm/templating/binding-two-way.js +103 -0
- package/dist/esm/templating/binding.js +134 -414
- package/dist/esm/templating/compiler.js +30 -7
- package/dist/esm/templating/html-directive.js +100 -28
- package/dist/esm/templating/node-observation.js +9 -8
- package/dist/esm/templating/ref.js +4 -12
- package/dist/esm/templating/render.js +391 -0
- package/dist/esm/templating/repeat.js +96 -72
- package/dist/esm/templating/template.js +11 -29
- package/dist/esm/templating/view.js +107 -29
- package/dist/esm/templating/when.js +5 -4
- package/dist/esm/testing/exports.js +3 -0
- package/dist/esm/testing/fakes.js +76 -0
- package/dist/esm/testing/fixture.js +86 -0
- package/dist/esm/testing/timeout.js +24 -0
- package/dist/esm/utilities.js +0 -95
- package/dist/fast-element.api.json +9034 -10524
- package/dist/fast-element.d.ts +707 -811
- package/dist/fast-element.debug.js +1133 -850
- package/dist/fast-element.debug.min.js +1 -1
- package/dist/fast-element.js +1097 -846
- package/dist/fast-element.min.js +1 -1
- package/dist/fast-element.untrimmed.d.ts +724 -818
- package/docs/api-report.md +264 -305
- package/package.json +39 -10
- package/dist/dts/hooks.d.ts +0 -20
- package/dist/dts/observation/behavior.d.ts +0 -19
- package/dist/dts/observation/splice-strategies.d.ts +0 -13
- package/dist/esm/hooks.js +0 -32
- package/dist/esm/observation/splice-strategies.js +0 -400
package/dist/fast-element.js
CHANGED
|
@@ -112,7 +112,7 @@ if (FAST.error === void 0) {
|
|
|
112
112
|
Object.assign(FAST, {
|
|
113
113
|
warn() { },
|
|
114
114
|
error(code) {
|
|
115
|
-
return new Error(`
|
|
115
|
+
return new Error(`Error ${code}`);
|
|
116
116
|
},
|
|
117
117
|
addMessages() { },
|
|
118
118
|
});
|
|
@@ -143,10 +143,34 @@ function createTypeRegistry() {
|
|
|
143
143
|
return typeToDefinition.get(key);
|
|
144
144
|
},
|
|
145
145
|
getForInstance(object) {
|
|
146
|
+
if (object === null || object === void 0) {
|
|
147
|
+
return void 0;
|
|
148
|
+
}
|
|
146
149
|
return typeToDefinition.get(object.constructor);
|
|
147
150
|
},
|
|
148
151
|
});
|
|
149
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* Creates a function capable of locating metadata associated with a type.
|
|
155
|
+
* @returns A metadata locator function.
|
|
156
|
+
* @internal
|
|
157
|
+
*/
|
|
158
|
+
function createMetadataLocator() {
|
|
159
|
+
const metadataLookup = new WeakMap();
|
|
160
|
+
return function (target) {
|
|
161
|
+
let metadata = metadataLookup.get(target);
|
|
162
|
+
if (metadata === void 0) {
|
|
163
|
+
let currentTarget = Reflect.getPrototypeOf(target);
|
|
164
|
+
while (metadata === void 0 && currentTarget !== null) {
|
|
165
|
+
metadata = metadataLookup.get(currentTarget);
|
|
166
|
+
currentTarget = Reflect.getPrototypeOf(currentTarget);
|
|
167
|
+
}
|
|
168
|
+
metadata = metadata === void 0 ? [] : metadata.slice(0);
|
|
169
|
+
metadataLookup.set(target, metadata);
|
|
170
|
+
}
|
|
171
|
+
return metadata;
|
|
172
|
+
};
|
|
173
|
+
}
|
|
150
174
|
|
|
151
175
|
/**
|
|
152
176
|
* @internal
|
|
@@ -388,6 +412,21 @@ class PropertyChangeNotifier {
|
|
|
388
412
|
}
|
|
389
413
|
}
|
|
390
414
|
|
|
415
|
+
/**
|
|
416
|
+
* Describes how the source's lifetime relates to its controller's lifetime.
|
|
417
|
+
* @public
|
|
418
|
+
*/
|
|
419
|
+
const SourceLifetime = Object.freeze({
|
|
420
|
+
/**
|
|
421
|
+
* The source to controller lifetime relationship is unknown.
|
|
422
|
+
*/
|
|
423
|
+
unknown: void 0,
|
|
424
|
+
/**
|
|
425
|
+
* The source and controller lifetimes are coupled to one another.
|
|
426
|
+
* They can/will be GC'd together.
|
|
427
|
+
*/
|
|
428
|
+
coupled: 1,
|
|
429
|
+
});
|
|
391
430
|
/**
|
|
392
431
|
* Common Observable APIs.
|
|
393
432
|
* @public
|
|
@@ -396,7 +435,6 @@ const Observable = FAST.getById(2 /* KernelServiceId.observable */, () => {
|
|
|
396
435
|
const queueUpdate = Updates.enqueue;
|
|
397
436
|
const volatileRegex = /(:|&&|\|\||if)/;
|
|
398
437
|
const notifierLookup = new WeakMap();
|
|
399
|
-
const accessorLookup = new WeakMap();
|
|
400
438
|
let watcher = void 0;
|
|
401
439
|
let createArrayObserver = (array) => {
|
|
402
440
|
throw FAST.error(1101 /* Message.needsArrayObservation */);
|
|
@@ -411,19 +449,7 @@ const Observable = FAST.getById(2 /* KernelServiceId.observable */, () => {
|
|
|
411
449
|
}
|
|
412
450
|
return found;
|
|
413
451
|
}
|
|
414
|
-
|
|
415
|
-
let accessors = accessorLookup.get(target);
|
|
416
|
-
if (accessors === void 0) {
|
|
417
|
-
let currentTarget = Reflect.getPrototypeOf(target);
|
|
418
|
-
while (accessors === void 0 && currentTarget !== null) {
|
|
419
|
-
accessors = accessorLookup.get(currentTarget);
|
|
420
|
-
currentTarget = Reflect.getPrototypeOf(currentTarget);
|
|
421
|
-
}
|
|
422
|
-
accessors = accessors === void 0 ? [] : accessors.slice(0);
|
|
423
|
-
accessorLookup.set(target, accessors);
|
|
424
|
-
}
|
|
425
|
-
return accessors;
|
|
426
|
-
}
|
|
452
|
+
const getAccessors = createMetadataLocator();
|
|
427
453
|
class DefaultObservableAccessor {
|
|
428
454
|
constructor(name) {
|
|
429
455
|
this.name = name;
|
|
@@ -449,10 +475,10 @@ const Observable = FAST.getById(2 /* KernelServiceId.observable */, () => {
|
|
|
449
475
|
}
|
|
450
476
|
}
|
|
451
477
|
}
|
|
452
|
-
class
|
|
453
|
-
constructor(
|
|
454
|
-
super(
|
|
455
|
-
this.
|
|
478
|
+
class ExpressionNotifierImplementation extends SubscriberSet {
|
|
479
|
+
constructor(expression, initialSubscriber, isVolatileBinding = false) {
|
|
480
|
+
super(expression, initialSubscriber);
|
|
481
|
+
this.expression = expression;
|
|
456
482
|
this.isVolatileBinding = isVolatileBinding;
|
|
457
483
|
this.needsRefresh = true;
|
|
458
484
|
this.needsQueue = true;
|
|
@@ -467,6 +493,22 @@ const Observable = FAST.getById(2 /* KernelServiceId.observable */, () => {
|
|
|
467
493
|
setMode(isAsync) {
|
|
468
494
|
this.isAsync = this.needsQueue = isAsync;
|
|
469
495
|
}
|
|
496
|
+
bind(controller) {
|
|
497
|
+
this.controller = controller;
|
|
498
|
+
const value = this.observe(controller.source, controller.context);
|
|
499
|
+
if (!controller.isBound && this.requiresUnbind(controller)) {
|
|
500
|
+
controller.onUnbind(this);
|
|
501
|
+
}
|
|
502
|
+
return value;
|
|
503
|
+
}
|
|
504
|
+
requiresUnbind(controller) {
|
|
505
|
+
return (controller.sourceLifetime !== SourceLifetime.coupled ||
|
|
506
|
+
this.first !== this.last ||
|
|
507
|
+
this.first.propertySource !== controller.source);
|
|
508
|
+
}
|
|
509
|
+
unbind(controller) {
|
|
510
|
+
this.dispose();
|
|
511
|
+
}
|
|
470
512
|
observe(source, context) {
|
|
471
513
|
if (this.needsRefresh && this.last !== null) {
|
|
472
514
|
this.dispose();
|
|
@@ -474,10 +516,19 @@ const Observable = FAST.getById(2 /* KernelServiceId.observable */, () => {
|
|
|
474
516
|
const previousWatcher = watcher;
|
|
475
517
|
watcher = this.needsRefresh ? this : void 0;
|
|
476
518
|
this.needsRefresh = this.isVolatileBinding;
|
|
477
|
-
|
|
478
|
-
|
|
519
|
+
let result;
|
|
520
|
+
try {
|
|
521
|
+
result = this.expression(source, context);
|
|
522
|
+
}
|
|
523
|
+
finally {
|
|
524
|
+
watcher = previousWatcher;
|
|
525
|
+
}
|
|
479
526
|
return result;
|
|
480
527
|
}
|
|
528
|
+
// backwards compat with v1 kernel
|
|
529
|
+
disconnect() {
|
|
530
|
+
this.dispose();
|
|
531
|
+
}
|
|
481
532
|
dispose() {
|
|
482
533
|
if (this.last !== null) {
|
|
483
534
|
let current = this.first;
|
|
@@ -604,22 +655,22 @@ const Observable = FAST.getById(2 /* KernelServiceId.observable */, () => {
|
|
|
604
655
|
*/
|
|
605
656
|
getAccessors,
|
|
606
657
|
/**
|
|
607
|
-
* Creates a {@link
|
|
608
|
-
* provided {@link
|
|
609
|
-
* @param
|
|
658
|
+
* Creates a {@link ExpressionNotifier} that can watch the
|
|
659
|
+
* provided {@link Expression} for changes.
|
|
660
|
+
* @param expression - The binding to observe.
|
|
610
661
|
* @param initialSubscriber - An initial subscriber to changes in the binding value.
|
|
611
662
|
* @param isVolatileBinding - Indicates whether the binding's dependency list must be re-evaluated on every value evaluation.
|
|
612
663
|
*/
|
|
613
|
-
binding(
|
|
614
|
-
return new
|
|
664
|
+
binding(expression, initialSubscriber, isVolatileBinding = this.isVolatileBinding(expression)) {
|
|
665
|
+
return new ExpressionNotifierImplementation(expression, initialSubscriber, isVolatileBinding);
|
|
615
666
|
},
|
|
616
667
|
/**
|
|
617
668
|
* Determines whether a binding expression is volatile and needs to have its dependency list re-evaluated
|
|
618
669
|
* on every evaluation of the value.
|
|
619
|
-
* @param
|
|
670
|
+
* @param expression - The binding to inspect.
|
|
620
671
|
*/
|
|
621
|
-
isVolatileBinding(
|
|
622
|
-
return volatileRegex.test(
|
|
672
|
+
isVolatileBinding(expression) {
|
|
673
|
+
return volatileRegex.test(expression.toString());
|
|
623
674
|
},
|
|
624
675
|
});
|
|
625
676
|
});
|
|
@@ -658,73 +709,40 @@ const contextEvent = FAST.getById(3 /* KernelServiceId.contextEvent */, () => {
|
|
|
658
709
|
},
|
|
659
710
|
};
|
|
660
711
|
});
|
|
661
|
-
class DefaultExecutionContext {
|
|
662
|
-
constructor(parentSource = null, parentContext = null) {
|
|
663
|
-
this.index = 0;
|
|
664
|
-
this.length = 0;
|
|
665
|
-
this.parent = parentSource;
|
|
666
|
-
this.parentContext = parentContext;
|
|
667
|
-
}
|
|
668
|
-
get event() {
|
|
669
|
-
return contextEvent.get();
|
|
670
|
-
}
|
|
671
|
-
get isEven() {
|
|
672
|
-
return this.index % 2 === 0;
|
|
673
|
-
}
|
|
674
|
-
get isOdd() {
|
|
675
|
-
return this.index % 2 !== 0;
|
|
676
|
-
}
|
|
677
|
-
get isFirst() {
|
|
678
|
-
return this.index === 0;
|
|
679
|
-
}
|
|
680
|
-
get isInMiddle() {
|
|
681
|
-
return !this.isFirst && !this.isLast;
|
|
682
|
-
}
|
|
683
|
-
get isLast() {
|
|
684
|
-
return this.index === this.length - 1;
|
|
685
|
-
}
|
|
686
|
-
eventDetail() {
|
|
687
|
-
return this.event.detail;
|
|
688
|
-
}
|
|
689
|
-
eventTarget() {
|
|
690
|
-
return this.event.target;
|
|
691
|
-
}
|
|
692
|
-
updatePosition(index, length) {
|
|
693
|
-
this.index = index;
|
|
694
|
-
this.length = length;
|
|
695
|
-
}
|
|
696
|
-
createChildContext(parentSource) {
|
|
697
|
-
return new DefaultExecutionContext(parentSource, this);
|
|
698
|
-
}
|
|
699
|
-
createItemContext(index, length) {
|
|
700
|
-
const childContext = Object.create(this);
|
|
701
|
-
childContext.index = index;
|
|
702
|
-
childContext.length = length;
|
|
703
|
-
return childContext;
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
Observable.defineProperty(DefaultExecutionContext.prototype, "index");
|
|
707
|
-
Observable.defineProperty(DefaultExecutionContext.prototype, "length");
|
|
708
712
|
/**
|
|
709
|
-
*
|
|
713
|
+
* Provides additional contextual information available to behaviors and expressions.
|
|
710
714
|
* @public
|
|
711
715
|
*/
|
|
712
716
|
const ExecutionContext = Object.freeze({
|
|
713
|
-
default: new DefaultExecutionContext(),
|
|
714
717
|
/**
|
|
715
|
-
*
|
|
716
|
-
* @param event - The event to set.
|
|
717
|
-
* @internal
|
|
718
|
+
* A default execution context.
|
|
718
719
|
*/
|
|
719
|
-
|
|
720
|
-
|
|
720
|
+
default: {
|
|
721
|
+
index: 0,
|
|
722
|
+
length: 0,
|
|
723
|
+
get event() {
|
|
724
|
+
return ExecutionContext.getEvent();
|
|
725
|
+
},
|
|
726
|
+
eventDetail() {
|
|
727
|
+
return this.event.detail;
|
|
728
|
+
},
|
|
729
|
+
eventTarget() {
|
|
730
|
+
return this.event.target;
|
|
731
|
+
},
|
|
721
732
|
},
|
|
722
733
|
/**
|
|
723
|
-
*
|
|
724
|
-
* @returns
|
|
734
|
+
* Gets the current event.
|
|
735
|
+
* @returns An event object.
|
|
725
736
|
*/
|
|
726
|
-
|
|
727
|
-
return
|
|
737
|
+
getEvent() {
|
|
738
|
+
return contextEvent.get();
|
|
739
|
+
},
|
|
740
|
+
/**
|
|
741
|
+
* Sets the current event.
|
|
742
|
+
* @param event - An event object.
|
|
743
|
+
*/
|
|
744
|
+
setEvent(event) {
|
|
745
|
+
contextEvent.set(event);
|
|
728
746
|
},
|
|
729
747
|
});
|
|
730
748
|
|
|
@@ -793,10 +811,311 @@ const SpliceStrategySupport = Object.freeze({
|
|
|
793
811
|
const reset = new Splice(0, emptyArray, 0);
|
|
794
812
|
reset.reset = true;
|
|
795
813
|
const resetSplices = [reset];
|
|
814
|
+
// Note: This function is *based* on the computation of the Levenshtein
|
|
815
|
+
// "edit" distance. The one change is that "updates" are treated as two
|
|
816
|
+
// edits - not one. With Array splices, an update is really a delete
|
|
817
|
+
// followed by an add. By retaining this, we optimize for "keeping" the
|
|
818
|
+
// maximum array items in the original array. For example:
|
|
819
|
+
//
|
|
820
|
+
// 'xxxx123' to '123yyyy'
|
|
821
|
+
//
|
|
822
|
+
// With 1-edit updates, the shortest path would be just to update all seven
|
|
823
|
+
// characters. With 2-edit updates, we delete 4, leave 3, and add 4. This
|
|
824
|
+
// leaves the substring '123' intact.
|
|
825
|
+
function calcEditDistances(current, currentStart, currentEnd, old, oldStart, oldEnd) {
|
|
826
|
+
// "Deletion" columns
|
|
827
|
+
const rowCount = oldEnd - oldStart + 1;
|
|
828
|
+
const columnCount = currentEnd - currentStart + 1;
|
|
829
|
+
const distances = new Array(rowCount);
|
|
830
|
+
let north;
|
|
831
|
+
let west;
|
|
832
|
+
// "Addition" rows. Initialize null column.
|
|
833
|
+
for (let i = 0; i < rowCount; ++i) {
|
|
834
|
+
distances[i] = new Array(columnCount);
|
|
835
|
+
distances[i][0] = i;
|
|
836
|
+
}
|
|
837
|
+
// Initialize null row
|
|
838
|
+
for (let j = 0; j < columnCount; ++j) {
|
|
839
|
+
distances[0][j] = j;
|
|
840
|
+
}
|
|
841
|
+
for (let i = 1; i < rowCount; ++i) {
|
|
842
|
+
for (let j = 1; j < columnCount; ++j) {
|
|
843
|
+
if (current[currentStart + j - 1] === old[oldStart + i - 1]) {
|
|
844
|
+
distances[i][j] = distances[i - 1][j - 1];
|
|
845
|
+
}
|
|
846
|
+
else {
|
|
847
|
+
north = distances[i - 1][j] + 1;
|
|
848
|
+
west = distances[i][j - 1] + 1;
|
|
849
|
+
distances[i][j] = north < west ? north : west;
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
return distances;
|
|
854
|
+
}
|
|
855
|
+
// This starts at the final weight, and walks "backward" by finding
|
|
856
|
+
// the minimum previous weight recursively until the origin of the weight
|
|
857
|
+
// matrix.
|
|
858
|
+
function spliceOperationsFromEditDistances(distances) {
|
|
859
|
+
let i = distances.length - 1;
|
|
860
|
+
let j = distances[0].length - 1;
|
|
861
|
+
let current = distances[i][j];
|
|
862
|
+
const edits = [];
|
|
863
|
+
while (i > 0 || j > 0) {
|
|
864
|
+
if (i === 0) {
|
|
865
|
+
edits.push(2 /* Edit.add */);
|
|
866
|
+
j--;
|
|
867
|
+
continue;
|
|
868
|
+
}
|
|
869
|
+
if (j === 0) {
|
|
870
|
+
edits.push(3 /* Edit.delete */);
|
|
871
|
+
i--;
|
|
872
|
+
continue;
|
|
873
|
+
}
|
|
874
|
+
const northWest = distances[i - 1][j - 1];
|
|
875
|
+
const west = distances[i - 1][j];
|
|
876
|
+
const north = distances[i][j - 1];
|
|
877
|
+
let min;
|
|
878
|
+
if (west < north) {
|
|
879
|
+
min = west < northWest ? west : northWest;
|
|
880
|
+
}
|
|
881
|
+
else {
|
|
882
|
+
min = north < northWest ? north : northWest;
|
|
883
|
+
}
|
|
884
|
+
if (min === northWest) {
|
|
885
|
+
if (northWest === current) {
|
|
886
|
+
edits.push(0 /* Edit.leave */);
|
|
887
|
+
}
|
|
888
|
+
else {
|
|
889
|
+
edits.push(1 /* Edit.update */);
|
|
890
|
+
current = northWest;
|
|
891
|
+
}
|
|
892
|
+
i--;
|
|
893
|
+
j--;
|
|
894
|
+
}
|
|
895
|
+
else if (min === west) {
|
|
896
|
+
edits.push(3 /* Edit.delete */);
|
|
897
|
+
i--;
|
|
898
|
+
current = west;
|
|
899
|
+
}
|
|
900
|
+
else {
|
|
901
|
+
edits.push(2 /* Edit.add */);
|
|
902
|
+
j--;
|
|
903
|
+
current = north;
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
return edits.reverse();
|
|
907
|
+
}
|
|
908
|
+
function sharedPrefix(current, old, searchLength) {
|
|
909
|
+
for (let i = 0; i < searchLength; ++i) {
|
|
910
|
+
if (current[i] !== old[i]) {
|
|
911
|
+
return i;
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
return searchLength;
|
|
915
|
+
}
|
|
916
|
+
function sharedSuffix(current, old, searchLength) {
|
|
917
|
+
let index1 = current.length;
|
|
918
|
+
let index2 = old.length;
|
|
919
|
+
let count = 0;
|
|
920
|
+
while (count < searchLength && current[--index1] === old[--index2]) {
|
|
921
|
+
count++;
|
|
922
|
+
}
|
|
923
|
+
return count;
|
|
924
|
+
}
|
|
925
|
+
function intersect(start1, end1, start2, end2) {
|
|
926
|
+
// Disjoint
|
|
927
|
+
if (end1 < start2 || end2 < start1) {
|
|
928
|
+
return -1;
|
|
929
|
+
}
|
|
930
|
+
// Adjacent
|
|
931
|
+
if (end1 === start2 || end2 === start1) {
|
|
932
|
+
return 0;
|
|
933
|
+
}
|
|
934
|
+
// Non-zero intersect, span1 first
|
|
935
|
+
if (start1 < start2) {
|
|
936
|
+
if (end1 < end2) {
|
|
937
|
+
return end1 - start2; // Overlap
|
|
938
|
+
}
|
|
939
|
+
return end2 - start2; // Contained
|
|
940
|
+
}
|
|
941
|
+
// Non-zero intersect, span2 first
|
|
942
|
+
if (end2 < end1) {
|
|
943
|
+
return end2 - start1; // Overlap
|
|
944
|
+
}
|
|
945
|
+
return end1 - start1; // Contained
|
|
946
|
+
}
|
|
947
|
+
/**
|
|
948
|
+
* @remarks
|
|
949
|
+
* Lacking individual splice mutation information, the minimal set of
|
|
950
|
+
* splices can be synthesized given the previous state and final state of an
|
|
951
|
+
* array. The basic approach is to calculate the edit distance matrix and
|
|
952
|
+
* choose the shortest path through it.
|
|
953
|
+
*
|
|
954
|
+
* Complexity: O(l * p)
|
|
955
|
+
* l: The length of the current array
|
|
956
|
+
* p: The length of the old array
|
|
957
|
+
*/
|
|
958
|
+
function calc(current, currentStart, currentEnd, old, oldStart, oldEnd) {
|
|
959
|
+
let prefixCount = 0;
|
|
960
|
+
let suffixCount = 0;
|
|
961
|
+
const minLength = Math.min(currentEnd - currentStart, oldEnd - oldStart);
|
|
962
|
+
if (currentStart === 0 && oldStart === 0) {
|
|
963
|
+
prefixCount = sharedPrefix(current, old, minLength);
|
|
964
|
+
}
|
|
965
|
+
if (currentEnd === current.length && oldEnd === old.length) {
|
|
966
|
+
suffixCount = sharedSuffix(current, old, minLength - prefixCount);
|
|
967
|
+
}
|
|
968
|
+
currentStart += prefixCount;
|
|
969
|
+
oldStart += prefixCount;
|
|
970
|
+
currentEnd -= suffixCount;
|
|
971
|
+
oldEnd -= suffixCount;
|
|
972
|
+
if (currentEnd - currentStart === 0 && oldEnd - oldStart === 0) {
|
|
973
|
+
return emptyArray;
|
|
974
|
+
}
|
|
975
|
+
if (currentStart === currentEnd) {
|
|
976
|
+
const splice = new Splice(currentStart, [], 0);
|
|
977
|
+
while (oldStart < oldEnd) {
|
|
978
|
+
splice.removed.push(old[oldStart++]);
|
|
979
|
+
}
|
|
980
|
+
return [splice];
|
|
981
|
+
}
|
|
982
|
+
else if (oldStart === oldEnd) {
|
|
983
|
+
return [new Splice(currentStart, [], currentEnd - currentStart)];
|
|
984
|
+
}
|
|
985
|
+
const ops = spliceOperationsFromEditDistances(calcEditDistances(current, currentStart, currentEnd, old, oldStart, oldEnd));
|
|
986
|
+
const splices = [];
|
|
987
|
+
let splice = void 0;
|
|
988
|
+
let index = currentStart;
|
|
989
|
+
let oldIndex = oldStart;
|
|
990
|
+
for (let i = 0; i < ops.length; ++i) {
|
|
991
|
+
switch (ops[i]) {
|
|
992
|
+
case 0 /* Edit.leave */:
|
|
993
|
+
if (splice !== void 0) {
|
|
994
|
+
splices.push(splice);
|
|
995
|
+
splice = void 0;
|
|
996
|
+
}
|
|
997
|
+
index++;
|
|
998
|
+
oldIndex++;
|
|
999
|
+
break;
|
|
1000
|
+
case 1 /* Edit.update */:
|
|
1001
|
+
if (splice === void 0) {
|
|
1002
|
+
splice = new Splice(index, [], 0);
|
|
1003
|
+
}
|
|
1004
|
+
splice.addedCount++;
|
|
1005
|
+
index++;
|
|
1006
|
+
splice.removed.push(old[oldIndex]);
|
|
1007
|
+
oldIndex++;
|
|
1008
|
+
break;
|
|
1009
|
+
case 2 /* Edit.add */:
|
|
1010
|
+
if (splice === void 0) {
|
|
1011
|
+
splice = new Splice(index, [], 0);
|
|
1012
|
+
}
|
|
1013
|
+
splice.addedCount++;
|
|
1014
|
+
index++;
|
|
1015
|
+
break;
|
|
1016
|
+
case 3 /* Edit.delete */:
|
|
1017
|
+
if (splice === void 0) {
|
|
1018
|
+
splice = new Splice(index, [], 0);
|
|
1019
|
+
}
|
|
1020
|
+
splice.removed.push(old[oldIndex]);
|
|
1021
|
+
oldIndex++;
|
|
1022
|
+
break;
|
|
1023
|
+
// no default
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
if (splice !== void 0) {
|
|
1027
|
+
splices.push(splice);
|
|
1028
|
+
}
|
|
1029
|
+
return splices;
|
|
1030
|
+
}
|
|
1031
|
+
function merge(splice, splices) {
|
|
1032
|
+
let inserted = false;
|
|
1033
|
+
let insertionOffset = 0;
|
|
1034
|
+
for (let i = 0; i < splices.length; i++) {
|
|
1035
|
+
const current = splices[i];
|
|
1036
|
+
current.index += insertionOffset;
|
|
1037
|
+
if (inserted) {
|
|
1038
|
+
continue;
|
|
1039
|
+
}
|
|
1040
|
+
const intersectCount = intersect(splice.index, splice.index + splice.removed.length, current.index, current.index + current.addedCount);
|
|
1041
|
+
if (intersectCount >= 0) {
|
|
1042
|
+
// Merge the two splices
|
|
1043
|
+
splices.splice(i, 1);
|
|
1044
|
+
i--;
|
|
1045
|
+
insertionOffset -= current.addedCount - current.removed.length;
|
|
1046
|
+
splice.addedCount += current.addedCount - intersectCount;
|
|
1047
|
+
const deleteCount = splice.removed.length + current.removed.length - intersectCount;
|
|
1048
|
+
if (!splice.addedCount && !deleteCount) {
|
|
1049
|
+
// merged splice is a noop. discard.
|
|
1050
|
+
inserted = true;
|
|
1051
|
+
}
|
|
1052
|
+
else {
|
|
1053
|
+
let currentRemoved = current.removed;
|
|
1054
|
+
if (splice.index < current.index) {
|
|
1055
|
+
// some prefix of splice.removed is prepended to current.removed.
|
|
1056
|
+
const prepend = splice.removed.slice(0, current.index - splice.index);
|
|
1057
|
+
prepend.push(...currentRemoved);
|
|
1058
|
+
currentRemoved = prepend;
|
|
1059
|
+
}
|
|
1060
|
+
if (splice.index + splice.removed.length >
|
|
1061
|
+
current.index + current.addedCount) {
|
|
1062
|
+
// some suffix of splice.removed is appended to current.removed.
|
|
1063
|
+
const append = splice.removed.slice(current.index + current.addedCount - splice.index);
|
|
1064
|
+
currentRemoved.push(...append);
|
|
1065
|
+
}
|
|
1066
|
+
splice.removed = currentRemoved;
|
|
1067
|
+
if (current.index < splice.index) {
|
|
1068
|
+
splice.index = current.index;
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
else if (splice.index < current.index) {
|
|
1073
|
+
// Insert splice here.
|
|
1074
|
+
inserted = true;
|
|
1075
|
+
splices.splice(i, 0, splice);
|
|
1076
|
+
i++;
|
|
1077
|
+
const offset = splice.addedCount - splice.removed.length;
|
|
1078
|
+
current.index += offset;
|
|
1079
|
+
insertionOffset += offset;
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
if (!inserted) {
|
|
1083
|
+
splices.push(splice);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
function project(array, changes) {
|
|
1087
|
+
let splices = [];
|
|
1088
|
+
const initialSplices = [];
|
|
1089
|
+
for (let i = 0, ii = changes.length; i < ii; i++) {
|
|
1090
|
+
merge(changes[i], initialSplices);
|
|
1091
|
+
}
|
|
1092
|
+
for (let i = 0, ii = initialSplices.length; i < ii; ++i) {
|
|
1093
|
+
const splice = initialSplices[i];
|
|
1094
|
+
if (splice.addedCount === 1 && splice.removed.length === 1) {
|
|
1095
|
+
if (splice.removed[0] !== array[splice.index]) {
|
|
1096
|
+
splices.push(splice);
|
|
1097
|
+
}
|
|
1098
|
+
continue;
|
|
1099
|
+
}
|
|
1100
|
+
splices = splices.concat(calc(array, splice.index, splice.index + splice.addedCount, splice.removed, 0, splice.removed.length));
|
|
1101
|
+
}
|
|
1102
|
+
return splices;
|
|
1103
|
+
}
|
|
1104
|
+
/**
|
|
1105
|
+
* A SpliceStrategy that attempts to merge all splices into the minimal set of
|
|
1106
|
+
* splices needed to represent the change from the old array to the new array.
|
|
1107
|
+
* @public
|
|
1108
|
+
*/
|
|
796
1109
|
let defaultSpliceStrategy = Object.freeze({
|
|
797
|
-
support: SpliceStrategySupport.
|
|
1110
|
+
support: SpliceStrategySupport.optimized,
|
|
798
1111
|
normalize(previous, current, changes) {
|
|
799
|
-
|
|
1112
|
+
if (previous === void 0) {
|
|
1113
|
+
if (changes === void 0) {
|
|
1114
|
+
return emptyArray;
|
|
1115
|
+
}
|
|
1116
|
+
return changes.length > 1 ? project(current, changes) : changes;
|
|
1117
|
+
}
|
|
1118
|
+
return resetSplices;
|
|
800
1119
|
},
|
|
801
1120
|
pop(array, observer, pop, args) {
|
|
802
1121
|
const notEmpty = array.length > 0;
|
|
@@ -981,7 +1300,7 @@ const ArrayObserver = Object.freeze({
|
|
|
981
1300
|
* @returns The length of the array.
|
|
982
1301
|
* @public
|
|
983
1302
|
*/
|
|
984
|
-
function
|
|
1303
|
+
function lengthOf(array) {
|
|
985
1304
|
if (!array) {
|
|
986
1305
|
return 0;
|
|
987
1306
|
}
|
|
@@ -1065,6 +1384,20 @@ class ElementStyles {
|
|
|
1065
1384
|
static setDefaultStrategy(Strategy) {
|
|
1066
1385
|
DefaultStyleStrategy = Strategy;
|
|
1067
1386
|
}
|
|
1387
|
+
/**
|
|
1388
|
+
* Normalizes a set of composable style options.
|
|
1389
|
+
* @param styles - The style options to normalize.
|
|
1390
|
+
* @returns A singular ElementStyles instance or undefined.
|
|
1391
|
+
*/
|
|
1392
|
+
static normalize(styles) {
|
|
1393
|
+
return styles === void 0
|
|
1394
|
+
? void 0
|
|
1395
|
+
: Array.isArray(styles)
|
|
1396
|
+
? new ElementStyles(styles)
|
|
1397
|
+
: styles instanceof ElementStyles
|
|
1398
|
+
? styles
|
|
1399
|
+
: new ElementStyles([styles]);
|
|
1400
|
+
}
|
|
1068
1401
|
}
|
|
1069
1402
|
/**
|
|
1070
1403
|
* Indicates whether the DOM supports the adoptedStyleSheets feature.
|
|
@@ -1209,11 +1542,11 @@ class CSSPartial {
|
|
|
1209
1542
|
}
|
|
1210
1543
|
return this.css;
|
|
1211
1544
|
}
|
|
1212
|
-
|
|
1213
|
-
|
|
1545
|
+
addedCallback(controller) {
|
|
1546
|
+
controller.addStyles(this.styles);
|
|
1214
1547
|
}
|
|
1215
|
-
|
|
1216
|
-
|
|
1548
|
+
removedCallback(controller) {
|
|
1549
|
+
controller.removeStyles(this.styles);
|
|
1217
1550
|
}
|
|
1218
1551
|
}
|
|
1219
1552
|
CSSDirective.define(CSSPartial);
|
|
@@ -1352,6 +1685,67 @@ const Parser = Object.freeze({
|
|
|
1352
1685
|
},
|
|
1353
1686
|
});
|
|
1354
1687
|
|
|
1688
|
+
/**
|
|
1689
|
+
* Bridges between ViewBehaviors and HostBehaviors, enabling a host to
|
|
1690
|
+
* control ViewBehaviors.
|
|
1691
|
+
* @public
|
|
1692
|
+
*/
|
|
1693
|
+
const ViewBehaviorOrchestrator = Object.freeze({
|
|
1694
|
+
/**
|
|
1695
|
+
* Creates a ViewBehaviorOrchestrator.
|
|
1696
|
+
* @param source - The source to to associate behaviors with.
|
|
1697
|
+
* @returns A ViewBehaviorOrchestrator.
|
|
1698
|
+
*/
|
|
1699
|
+
create(source) {
|
|
1700
|
+
const behaviors = [];
|
|
1701
|
+
const targets = {};
|
|
1702
|
+
let unbindables = null;
|
|
1703
|
+
let isConnected = false;
|
|
1704
|
+
return {
|
|
1705
|
+
source,
|
|
1706
|
+
context: ExecutionContext.default,
|
|
1707
|
+
targets,
|
|
1708
|
+
get isBound() {
|
|
1709
|
+
return isConnected;
|
|
1710
|
+
},
|
|
1711
|
+
addBehaviorFactory(factory, target) {
|
|
1712
|
+
const nodeId = factory.nodeId || (factory.nodeId = nextId());
|
|
1713
|
+
factory.id || (factory.id = nextId());
|
|
1714
|
+
this.addTarget(nodeId, target);
|
|
1715
|
+
this.addBehavior(factory.createBehavior());
|
|
1716
|
+
},
|
|
1717
|
+
addTarget(nodeId, target) {
|
|
1718
|
+
targets[nodeId] = target;
|
|
1719
|
+
},
|
|
1720
|
+
addBehavior(behavior) {
|
|
1721
|
+
behaviors.push(behavior);
|
|
1722
|
+
if (isConnected) {
|
|
1723
|
+
behavior.bind(this);
|
|
1724
|
+
}
|
|
1725
|
+
},
|
|
1726
|
+
onUnbind(unbindable) {
|
|
1727
|
+
if (unbindables === null) {
|
|
1728
|
+
unbindables = [];
|
|
1729
|
+
}
|
|
1730
|
+
unbindables.push(unbindable);
|
|
1731
|
+
},
|
|
1732
|
+
connectedCallback(controller) {
|
|
1733
|
+
if (!isConnected) {
|
|
1734
|
+
isConnected = true;
|
|
1735
|
+
behaviors.forEach(x => x.bind(this));
|
|
1736
|
+
}
|
|
1737
|
+
},
|
|
1738
|
+
disconnectedCallback(controller) {
|
|
1739
|
+
if (isConnected) {
|
|
1740
|
+
isConnected = false;
|
|
1741
|
+
if (unbindables !== null) {
|
|
1742
|
+
unbindables.forEach(x => x.unbind(this));
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1745
|
+
},
|
|
1746
|
+
};
|
|
1747
|
+
},
|
|
1748
|
+
});
|
|
1355
1749
|
const registry = createTypeRegistry();
|
|
1356
1750
|
/**
|
|
1357
1751
|
* Instructs the template engine to apply behavior to a node.
|
|
@@ -1391,6 +1785,22 @@ function htmlDirective(options) {
|
|
|
1391
1785
|
HTMLDirective.define(type, options);
|
|
1392
1786
|
};
|
|
1393
1787
|
}
|
|
1788
|
+
/**
|
|
1789
|
+
* Captures a binding expression along with related information and capabilities.
|
|
1790
|
+
*
|
|
1791
|
+
* @public
|
|
1792
|
+
*/
|
|
1793
|
+
class Binding {
|
|
1794
|
+
/**
|
|
1795
|
+
* Creates a binding.
|
|
1796
|
+
* @param evaluate - Evaluates the binding.
|
|
1797
|
+
* @param isVolatile - Indicates whether the binding is volatile.
|
|
1798
|
+
*/
|
|
1799
|
+
constructor(evaluate, isVolatile = false) {
|
|
1800
|
+
this.evaluate = evaluate;
|
|
1801
|
+
this.isVolatile = isVolatile;
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1394
1804
|
/**
|
|
1395
1805
|
* The type of HTML aspect to target.
|
|
1396
1806
|
* @public
|
|
@@ -1428,26 +1838,22 @@ const Aspect = Object.freeze({
|
|
|
1428
1838
|
*
|
|
1429
1839
|
* @param directive - The directive to assign the aspect to.
|
|
1430
1840
|
* @param value - The value to base the aspect determination on.
|
|
1841
|
+
* @remarks
|
|
1842
|
+
* If a falsy value is provided, then the content aspect will be assigned.
|
|
1431
1843
|
*/
|
|
1432
1844
|
assign(directive, value) {
|
|
1433
|
-
directive.sourceAspect = value;
|
|
1434
1845
|
if (!value) {
|
|
1846
|
+
directive.aspectType = Aspect.content;
|
|
1435
1847
|
return;
|
|
1436
1848
|
}
|
|
1849
|
+
directive.sourceAspect = value;
|
|
1437
1850
|
switch (value[0]) {
|
|
1438
1851
|
case ":":
|
|
1439
1852
|
directive.targetAspect = value.substring(1);
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
case "classList":
|
|
1445
|
-
directive.aspectType = Aspect.tokenList;
|
|
1446
|
-
break;
|
|
1447
|
-
default:
|
|
1448
|
-
directive.aspectType = Aspect.property;
|
|
1449
|
-
break;
|
|
1450
|
-
}
|
|
1853
|
+
directive.aspectType =
|
|
1854
|
+
directive.targetAspect === "classList"
|
|
1855
|
+
? Aspect.tokenList
|
|
1856
|
+
: Aspect.property;
|
|
1451
1857
|
break;
|
|
1452
1858
|
case "?":
|
|
1453
1859
|
directive.targetAspect = value.substring(1);
|
|
@@ -1458,14 +1864,8 @@ const Aspect = Object.freeze({
|
|
|
1458
1864
|
directive.aspectType = Aspect.event;
|
|
1459
1865
|
break;
|
|
1460
1866
|
default:
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
directive.aspectType = Aspect.property;
|
|
1464
|
-
}
|
|
1465
|
-
else {
|
|
1466
|
-
directive.targetAspect = value;
|
|
1467
|
-
directive.aspectType = Aspect.attribute;
|
|
1468
|
-
}
|
|
1867
|
+
directive.targetAspect = value;
|
|
1868
|
+
directive.aspectType = Aspect.attribute;
|
|
1469
1869
|
break;
|
|
1470
1870
|
}
|
|
1471
1871
|
},
|
|
@@ -1481,13 +1881,10 @@ class StatelessAttachedAttributeDirective {
|
|
|
1481
1881
|
*/
|
|
1482
1882
|
constructor(options) {
|
|
1483
1883
|
this.options = options;
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
*/
|
|
1489
|
-
createBehavior(targets) {
|
|
1490
|
-
return this;
|
|
1884
|
+
/**
|
|
1885
|
+
* The unique id of the factory.
|
|
1886
|
+
*/
|
|
1887
|
+
this.id = nextId();
|
|
1491
1888
|
}
|
|
1492
1889
|
/**
|
|
1493
1890
|
* Creates a placeholder string based on the directive's index within the template.
|
|
@@ -1498,6 +1895,13 @@ class StatelessAttachedAttributeDirective {
|
|
|
1498
1895
|
createHTML(add) {
|
|
1499
1896
|
return Markup.attribute(add(this));
|
|
1500
1897
|
}
|
|
1898
|
+
/**
|
|
1899
|
+
* Creates a behavior.
|
|
1900
|
+
* @param targets - The targets available for behaviors to be attached to.
|
|
1901
|
+
*/
|
|
1902
|
+
createBehavior() {
|
|
1903
|
+
return this;
|
|
1904
|
+
}
|
|
1501
1905
|
}
|
|
1502
1906
|
|
|
1503
1907
|
const createInnerHTMLBinding = globalThis.TrustedHTML
|
|
@@ -1509,107 +1913,26 @@ const createInnerHTMLBinding = globalThis.TrustedHTML
|
|
|
1509
1913
|
throw FAST.error(1202 /* Message.bindingInnerHTMLRequiresTrustedTypes */);
|
|
1510
1914
|
}
|
|
1511
1915
|
: (binding) => binding;
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
*/
|
|
1516
|
-
const BindingMode = Object.freeze({
|
|
1517
|
-
/**
|
|
1518
|
-
* Creates a binding mode based on the supplied behavior types.
|
|
1519
|
-
* @param UpdateType - The base behavior type used to update aspects.
|
|
1520
|
-
* @param EventType - The base behavior type used to respond to events.
|
|
1521
|
-
* @returns A new binding mode.
|
|
1522
|
-
*/
|
|
1523
|
-
define(UpdateType, EventType = EventBinding) {
|
|
1524
|
-
return Object.freeze({
|
|
1525
|
-
[1]: d => new UpdateType(d, DOM.setAttribute),
|
|
1526
|
-
[2]: d => new UpdateType(d, DOM.setBooleanAttribute),
|
|
1527
|
-
[3]: d => new UpdateType(d, (t, a, v) => (t[a] = v)),
|
|
1528
|
-
[4]: d => new (createContentBinding(UpdateType))(d, updateContentTarget),
|
|
1529
|
-
[5]: d => new UpdateType(d, updateTokenListTarget),
|
|
1530
|
-
[6]: d => new EventType(d),
|
|
1531
|
-
});
|
|
1532
|
-
},
|
|
1533
|
-
});
|
|
1534
|
-
/**
|
|
1535
|
-
* Describes the configuration for a binding expression.
|
|
1536
|
-
* @public
|
|
1537
|
-
*/
|
|
1538
|
-
const BindingConfig = Object.freeze({
|
|
1539
|
-
/**
|
|
1540
|
-
* Creates a binding configuration based on the provided mode and options.
|
|
1541
|
-
* @param mode - The mode to use for the configuration.
|
|
1542
|
-
* @param defaultOptions - The default options to use for the configuration.
|
|
1543
|
-
* @returns A new binding configuration.
|
|
1544
|
-
*/
|
|
1545
|
-
define(mode, defaultOptions) {
|
|
1546
|
-
const config = (options) => {
|
|
1547
|
-
return {
|
|
1548
|
-
mode: config.mode,
|
|
1549
|
-
options: Object.assign({}, defaultOptions, options),
|
|
1550
|
-
};
|
|
1551
|
-
};
|
|
1552
|
-
config.options = defaultOptions;
|
|
1553
|
-
config.mode = mode;
|
|
1554
|
-
return config;
|
|
1555
|
-
},
|
|
1556
|
-
});
|
|
1557
|
-
/**
|
|
1558
|
-
* A base binding behavior for DOM updates.
|
|
1559
|
-
* @public
|
|
1560
|
-
*/
|
|
1561
|
-
class UpdateBinding {
|
|
1562
|
-
/**
|
|
1563
|
-
* Creates an instance of UpdateBinding.
|
|
1564
|
-
* @param directive - The directive that has the configuration for this behavior.
|
|
1565
|
-
* @param updateTarget - The function used to update the target with the latest value.
|
|
1566
|
-
*/
|
|
1567
|
-
constructor(directive, updateTarget) {
|
|
1568
|
-
this.directive = directive;
|
|
1569
|
-
this.updateTarget = updateTarget;
|
|
1916
|
+
class OnChangeBinding extends Binding {
|
|
1917
|
+
createObserver(_, subscriber) {
|
|
1918
|
+
return Observable.binding(this.evaluate, subscriber, this.isVolatile);
|
|
1570
1919
|
}
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
* @param context - The execution context that the binding is operating within.
|
|
1575
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
1576
|
-
*/
|
|
1577
|
-
bind(source, context, targets) { }
|
|
1578
|
-
/**
|
|
1579
|
-
* Unbinds this behavior from the source.
|
|
1580
|
-
* @param source - The source to unbind from.
|
|
1581
|
-
* @param context - The execution context that the binding is operating within.
|
|
1582
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
1583
|
-
*/
|
|
1584
|
-
unbind(source, context, targets) { }
|
|
1585
|
-
/**
|
|
1586
|
-
* Creates a behavior.
|
|
1587
|
-
* @param targets - The targets available for behaviors to be attached to.
|
|
1588
|
-
*/
|
|
1589
|
-
createBehavior(targets) {
|
|
1920
|
+
}
|
|
1921
|
+
class OneTimeBinding extends Binding {
|
|
1922
|
+
createObserver() {
|
|
1590
1923
|
return this;
|
|
1591
1924
|
}
|
|
1925
|
+
bind(controller) {
|
|
1926
|
+
return this.evaluate(controller.source, controller.context);
|
|
1927
|
+
}
|
|
1592
1928
|
}
|
|
1593
|
-
function
|
|
1594
|
-
return class extends Type {
|
|
1595
|
-
unbind(source, context, targets) {
|
|
1596
|
-
super.unbind(source, context, targets);
|
|
1597
|
-
const target = targets[this.directive.nodeId];
|
|
1598
|
-
const view = target.$fastView;
|
|
1599
|
-
if (view !== void 0 && view.isComposed) {
|
|
1600
|
-
view.unbind();
|
|
1601
|
-
view.needsBindOnly = true;
|
|
1602
|
-
}
|
|
1603
|
-
}
|
|
1604
|
-
};
|
|
1605
|
-
}
|
|
1606
|
-
function updateContentTarget(target, aspect, value, source, context) {
|
|
1929
|
+
function updateContent(target, aspect, value, controller) {
|
|
1607
1930
|
// If there's no actual value, then this equates to the
|
|
1608
1931
|
// empty string for the purposes of content bindings.
|
|
1609
1932
|
if (value === null || value === undefined) {
|
|
1610
1933
|
value = "";
|
|
1611
1934
|
}
|
|
1612
|
-
// If the value has a "create" method, then it's a
|
|
1935
|
+
// If the value has a "create" method, then it's a ContentTemplate.
|
|
1613
1936
|
if (value.create) {
|
|
1614
1937
|
target.textContent = "";
|
|
1615
1938
|
let view = target.$fastView;
|
|
@@ -1635,14 +1958,14 @@ function updateContentTarget(target, aspect, value, source, context) {
|
|
|
1635
1958
|
// and that there's actually no need to compose it.
|
|
1636
1959
|
if (!view.isComposed) {
|
|
1637
1960
|
view.isComposed = true;
|
|
1638
|
-
view.bind(source, context);
|
|
1961
|
+
view.bind(controller.source, controller.context);
|
|
1639
1962
|
view.insertBefore(target);
|
|
1640
1963
|
target.$fastView = view;
|
|
1641
1964
|
target.$fastTemplate = value;
|
|
1642
1965
|
}
|
|
1643
1966
|
else if (view.needsBindOnly) {
|
|
1644
1967
|
view.needsBindOnly = false;
|
|
1645
|
-
view.bind(source, context);
|
|
1968
|
+
view.bind(controller.source, controller.context);
|
|
1646
1969
|
}
|
|
1647
1970
|
}
|
|
1648
1971
|
else {
|
|
@@ -1662,10 +1985,9 @@ function updateContentTarget(target, aspect, value, source, context) {
|
|
|
1662
1985
|
target.textContent = value;
|
|
1663
1986
|
}
|
|
1664
1987
|
}
|
|
1665
|
-
function
|
|
1988
|
+
function updateTokenList(target, aspect, value) {
|
|
1666
1989
|
var _a;
|
|
1667
|
-
const
|
|
1668
|
-
const lookup = `${directive.id}-t`;
|
|
1990
|
+
const lookup = `${this.id}-t`;
|
|
1669
1991
|
const state = (_a = target[lookup]) !== null && _a !== void 0 ? _a : (target[lookup] = { c: 0, v: Object.create(null) });
|
|
1670
1992
|
const versions = state.v;
|
|
1671
1993
|
let currentVersion = state.c;
|
|
@@ -1695,311 +2017,8 @@ function updateTokenListTarget(target, aspect, value) {
|
|
|
1695
2017
|
}
|
|
1696
2018
|
}
|
|
1697
2019
|
}
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
* @public
|
|
1701
|
-
*/
|
|
1702
|
-
class OneTimeBinding extends UpdateBinding {
|
|
1703
|
-
/**
|
|
1704
|
-
* Bind this behavior to the source.
|
|
1705
|
-
* @param source - The source to bind to.
|
|
1706
|
-
* @param context - The execution context that the binding is operating within.
|
|
1707
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
1708
|
-
*/
|
|
1709
|
-
bind(source, context, targets) {
|
|
1710
|
-
const directive = this.directive;
|
|
1711
|
-
this.updateTarget(targets[directive.nodeId], directive.targetAspect, directive.binding(source, context), source, context);
|
|
1712
|
-
}
|
|
1713
|
-
}
|
|
1714
|
-
const signals = Object.create(null);
|
|
1715
|
-
/**
|
|
1716
|
-
* A binding behavior for signal bindings.
|
|
1717
|
-
* @public
|
|
1718
|
-
*/
|
|
1719
|
-
class SignalBinding extends UpdateBinding {
|
|
1720
|
-
constructor() {
|
|
1721
|
-
super(...arguments);
|
|
1722
|
-
this.handlerProperty = `${this.directive.id}-h`;
|
|
1723
|
-
}
|
|
1724
|
-
/**
|
|
1725
|
-
* Bind this behavior to the source.
|
|
1726
|
-
* @param source - The source to bind to.
|
|
1727
|
-
* @param context - The execution context that the binding is operating within.
|
|
1728
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
1729
|
-
*/
|
|
1730
|
-
bind(source, context, targets) {
|
|
1731
|
-
const directive = this.directive;
|
|
1732
|
-
const target = targets[directive.nodeId];
|
|
1733
|
-
const signal = this.getSignal(source, context);
|
|
1734
|
-
const handler = (target[this.handlerProperty] = () => {
|
|
1735
|
-
this.updateTarget(target, directive.targetAspect, directive.binding(source, context), source, context);
|
|
1736
|
-
});
|
|
1737
|
-
handler();
|
|
1738
|
-
const found = signals[signal];
|
|
1739
|
-
if (found) {
|
|
1740
|
-
Array.isArray(found)
|
|
1741
|
-
? found.push(handler)
|
|
1742
|
-
: (signals[signal] = [found, handler]);
|
|
1743
|
-
}
|
|
1744
|
-
else {
|
|
1745
|
-
signals[signal] = handler;
|
|
1746
|
-
}
|
|
1747
|
-
}
|
|
1748
|
-
/**
|
|
1749
|
-
* Unbinds this behavior from the source.
|
|
1750
|
-
* @param source - The source to unbind from.
|
|
1751
|
-
* @param context - The execution context that the binding is operating within.
|
|
1752
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
1753
|
-
*/
|
|
1754
|
-
unbind(source, context, targets) {
|
|
1755
|
-
const signal = this.getSignal(source, context);
|
|
1756
|
-
const found = signals[signal];
|
|
1757
|
-
if (found && Array.isArray(found)) {
|
|
1758
|
-
const directive = this.directive;
|
|
1759
|
-
const target = targets[directive.nodeId];
|
|
1760
|
-
const handler = target[this.handlerProperty];
|
|
1761
|
-
const index = found.indexOf(handler);
|
|
1762
|
-
if (index !== -1) {
|
|
1763
|
-
found.splice(index, 1);
|
|
1764
|
-
}
|
|
1765
|
-
}
|
|
1766
|
-
else {
|
|
1767
|
-
signals[signal] = void 0;
|
|
1768
|
-
}
|
|
1769
|
-
}
|
|
1770
|
-
getSignal(source, context) {
|
|
1771
|
-
const options = this.directive.options;
|
|
1772
|
-
return isString(options) ? options : options(source, context);
|
|
1773
|
-
}
|
|
1774
|
-
/**
|
|
1775
|
-
* Sends the specified signal to signaled bindings.
|
|
1776
|
-
* @param signal - The signal to send.
|
|
1777
|
-
* @public
|
|
1778
|
-
*/
|
|
1779
|
-
static send(signal) {
|
|
1780
|
-
const found = signals[signal];
|
|
1781
|
-
if (found) {
|
|
1782
|
-
Array.isArray(found) ? found.forEach(x => x()) : found();
|
|
1783
|
-
}
|
|
1784
|
-
}
|
|
1785
|
-
}
|
|
1786
|
-
/**
|
|
1787
|
-
* A binding behavior for bindings that change.
|
|
1788
|
-
* @public
|
|
1789
|
-
*/
|
|
1790
|
-
class ChangeBinding extends UpdateBinding {
|
|
1791
|
-
/**
|
|
1792
|
-
* Creates an instance of ChangeBinding.
|
|
1793
|
-
* @param directive - The directive that has the configuration for this behavior.
|
|
1794
|
-
* @param updateTarget - The function used to update the target with the latest value.
|
|
1795
|
-
*/
|
|
1796
|
-
constructor(directive, updateTarget) {
|
|
1797
|
-
super(directive, updateTarget);
|
|
1798
|
-
this.isBindingVolatile = Observable.isVolatileBinding(directive.binding);
|
|
1799
|
-
this.observerProperty = `${directive.id}-o`;
|
|
1800
|
-
}
|
|
1801
|
-
/**
|
|
1802
|
-
* Returns the binding observer used to update the node.
|
|
1803
|
-
* @param target - The target node.
|
|
1804
|
-
* @returns A BindingObserver.
|
|
1805
|
-
*/
|
|
1806
|
-
getObserver(target) {
|
|
1807
|
-
var _a;
|
|
1808
|
-
return ((_a = target[this.observerProperty]) !== null && _a !== void 0 ? _a : (target[this.observerProperty] = Observable.binding(this.directive.binding, this, this.isBindingVolatile)));
|
|
1809
|
-
}
|
|
1810
|
-
/**
|
|
1811
|
-
* Bind this behavior to the source.
|
|
1812
|
-
* @param source - The source to bind to.
|
|
1813
|
-
* @param context - The execution context that the binding is operating within.
|
|
1814
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
1815
|
-
*/
|
|
1816
|
-
bind(source, context, targets) {
|
|
1817
|
-
const directive = this.directive;
|
|
1818
|
-
const target = targets[directive.nodeId];
|
|
1819
|
-
const observer = this.getObserver(target);
|
|
1820
|
-
observer.target = target;
|
|
1821
|
-
observer.source = source;
|
|
1822
|
-
observer.context = context;
|
|
1823
|
-
this.updateTarget(target, directive.targetAspect, observer.observe(source, context), source, context);
|
|
1824
|
-
}
|
|
1825
|
-
/**
|
|
1826
|
-
* Unbinds this behavior from the source.
|
|
1827
|
-
* @param source - The source to unbind from.
|
|
1828
|
-
* @param context - The execution context that the binding is operating within.
|
|
1829
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
1830
|
-
*/
|
|
1831
|
-
unbind(source, context, targets) {
|
|
1832
|
-
const target = targets[this.directive.nodeId];
|
|
1833
|
-
const observer = this.getObserver(target);
|
|
1834
|
-
observer.dispose();
|
|
1835
|
-
observer.target = null;
|
|
1836
|
-
observer.source = null;
|
|
1837
|
-
observer.context = null;
|
|
1838
|
-
}
|
|
1839
|
-
/** @internal */
|
|
1840
|
-
handleChange(binding, observer) {
|
|
1841
|
-
const target = observer.target;
|
|
1842
|
-
const source = observer.source;
|
|
1843
|
-
const context = observer.context;
|
|
1844
|
-
this.updateTarget(target, this.directive.targetAspect, observer.observe(source, context), source, context);
|
|
1845
|
-
}
|
|
1846
|
-
}
|
|
1847
|
-
/**
|
|
1848
|
-
* A binding behavior for handling events.
|
|
1849
|
-
* @public
|
|
1850
|
-
*/
|
|
1851
|
-
class EventBinding {
|
|
1852
|
-
/**
|
|
1853
|
-
* Creates an instance of EventBinding.
|
|
1854
|
-
* @param directive - The directive that has the configuration for this behavior.
|
|
1855
|
-
*/
|
|
1856
|
-
constructor(directive) {
|
|
1857
|
-
this.directive = directive;
|
|
1858
|
-
this.sourceProperty = `${directive.id}-s`;
|
|
1859
|
-
this.contextProperty = `${directive.id}-c`;
|
|
1860
|
-
}
|
|
1861
|
-
/**
|
|
1862
|
-
* Bind this behavior to the source.
|
|
1863
|
-
* @param source - The source to bind to.
|
|
1864
|
-
* @param context - The execution context that the binding is operating within.
|
|
1865
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
1866
|
-
*/
|
|
1867
|
-
bind(source, context, targets) {
|
|
1868
|
-
const directive = this.directive;
|
|
1869
|
-
const target = targets[directive.nodeId];
|
|
1870
|
-
target[this.sourceProperty] = source;
|
|
1871
|
-
target[this.contextProperty] = context;
|
|
1872
|
-
target.addEventListener(directive.targetAspect, this, directive.options);
|
|
1873
|
-
}
|
|
1874
|
-
/**
|
|
1875
|
-
* Unbinds this behavior from the source.
|
|
1876
|
-
* @param source - The source to unbind from.
|
|
1877
|
-
* @param context - The execution context that the binding is operating within.
|
|
1878
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
1879
|
-
*/
|
|
1880
|
-
unbind(source, context, targets) {
|
|
1881
|
-
const directive = this.directive;
|
|
1882
|
-
const target = targets[directive.nodeId];
|
|
1883
|
-
target[this.sourceProperty] = target[this.contextProperty] = null;
|
|
1884
|
-
target.removeEventListener(directive.targetAspect, this, directive.options);
|
|
1885
|
-
}
|
|
1886
|
-
/**
|
|
1887
|
-
* Creates a behavior.
|
|
1888
|
-
* @param targets - The targets available for behaviors to be attached to.
|
|
1889
|
-
*/
|
|
1890
|
-
createBehavior(targets) {
|
|
1891
|
-
return this;
|
|
1892
|
-
}
|
|
1893
|
-
/**
|
|
1894
|
-
* @internal
|
|
1895
|
-
*/
|
|
1896
|
-
handleEvent(event) {
|
|
1897
|
-
const target = event.currentTarget;
|
|
1898
|
-
ExecutionContext.setEvent(event);
|
|
1899
|
-
const result = this.directive.binding(target[this.sourceProperty], target[this.contextProperty]);
|
|
1900
|
-
ExecutionContext.setEvent(null);
|
|
1901
|
-
if (result !== true) {
|
|
1902
|
-
event.preventDefault();
|
|
1903
|
-
}
|
|
1904
|
-
}
|
|
1905
|
-
}
|
|
1906
|
-
let twoWaySettings = {
|
|
1907
|
-
determineChangeEvent() {
|
|
1908
|
-
return "change";
|
|
1909
|
-
},
|
|
1910
|
-
};
|
|
1911
|
-
/**
|
|
1912
|
-
* A binding behavior for bindings that update in two directions.
|
|
1913
|
-
* @public
|
|
1914
|
-
*/
|
|
1915
|
-
class TwoWayBinding extends ChangeBinding {
|
|
1916
|
-
/**
|
|
1917
|
-
* Bind this behavior to the source.
|
|
1918
|
-
* @param source - The source to bind to.
|
|
1919
|
-
* @param context - The execution context that the binding is operating within.
|
|
1920
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
1921
|
-
*/
|
|
1922
|
-
bind(source, context, targets) {
|
|
1923
|
-
var _a;
|
|
1924
|
-
super.bind(source, context, targets);
|
|
1925
|
-
const directive = this.directive;
|
|
1926
|
-
const target = targets[directive.nodeId];
|
|
1927
|
-
if (!this.changeEvent) {
|
|
1928
|
-
this.changeEvent =
|
|
1929
|
-
(_a = directive.options.changeEvent) !== null && _a !== void 0 ? _a : twoWaySettings.determineChangeEvent(directive, target);
|
|
1930
|
-
}
|
|
1931
|
-
target.addEventListener(this.changeEvent, this);
|
|
1932
|
-
}
|
|
1933
|
-
/**
|
|
1934
|
-
* Unbinds this behavior from the source.
|
|
1935
|
-
* @param source - The source to unbind from.
|
|
1936
|
-
* @param context - The execution context that the binding is operating within.
|
|
1937
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
1938
|
-
*/
|
|
1939
|
-
unbind(source, context, targets) {
|
|
1940
|
-
super.unbind(source, context, targets);
|
|
1941
|
-
targets[this.directive.nodeId].removeEventListener(this.changeEvent, this);
|
|
1942
|
-
}
|
|
1943
|
-
/** @internal */
|
|
1944
|
-
handleEvent(event) {
|
|
1945
|
-
const directive = this.directive;
|
|
1946
|
-
const target = event.currentTarget;
|
|
1947
|
-
let value;
|
|
1948
|
-
switch (directive.aspectType) {
|
|
1949
|
-
case 1:
|
|
1950
|
-
value = target.getAttribute(directive.targetAspect);
|
|
1951
|
-
break;
|
|
1952
|
-
case 2:
|
|
1953
|
-
value = target.hasAttribute(directive.targetAspect);
|
|
1954
|
-
break;
|
|
1955
|
-
case 4:
|
|
1956
|
-
value = target.innerText;
|
|
1957
|
-
break;
|
|
1958
|
-
default:
|
|
1959
|
-
value = target[directive.targetAspect];
|
|
1960
|
-
break;
|
|
1961
|
-
}
|
|
1962
|
-
const observer = this.getObserver(target);
|
|
1963
|
-
const last = observer.last; // using internal API!!!
|
|
1964
|
-
last.propertySource[last.propertyName] = directive.options.fromView(value);
|
|
1965
|
-
}
|
|
1966
|
-
/**
|
|
1967
|
-
* Configures two-way binding.
|
|
1968
|
-
* @param settings - The settings to use for the two-way binding system.
|
|
1969
|
-
*/
|
|
1970
|
-
static configure(settings) {
|
|
1971
|
-
twoWaySettings = settings;
|
|
1972
|
-
}
|
|
1973
|
-
}
|
|
1974
|
-
/**
|
|
1975
|
-
* The default onChange binding configuration.
|
|
1976
|
-
* @public
|
|
1977
|
-
*/
|
|
1978
|
-
const onChange = BindingConfig.define(BindingMode.define(ChangeBinding), {});
|
|
1979
|
-
/**
|
|
1980
|
-
* The default twoWay binding configuration.
|
|
1981
|
-
* @public
|
|
1982
|
-
*/
|
|
1983
|
-
const twoWay = BindingConfig.define(BindingMode.define(TwoWayBinding), {
|
|
1984
|
-
fromView: v => v,
|
|
1985
|
-
});
|
|
1986
|
-
/**
|
|
1987
|
-
* The default onTime binding configuration.
|
|
1988
|
-
* @public
|
|
1989
|
-
*/
|
|
1990
|
-
const oneTime = BindingConfig.define(BindingMode.define(OneTimeBinding), {
|
|
1991
|
-
once: true,
|
|
1992
|
-
});
|
|
1993
|
-
const signalMode = BindingMode.define(SignalBinding);
|
|
1994
|
-
/**
|
|
1995
|
-
* Creates a signal binding configuration with the supplied options.
|
|
1996
|
-
* @param options - The signal name or a binding to use to retrieve the signal name.
|
|
1997
|
-
* @returns A binding configuration.
|
|
1998
|
-
* @public
|
|
1999
|
-
*/
|
|
2000
|
-
const signal = (options) => {
|
|
2001
|
-
return { mode: signalMode, options };
|
|
2002
|
-
};
|
|
2020
|
+
const setProperty = (t, a, v) => (t[a] = v);
|
|
2021
|
+
const eventTarget = () => void 0;
|
|
2003
2022
|
/**
|
|
2004
2023
|
* A directive that applies bindings.
|
|
2005
2024
|
* @public
|
|
@@ -2007,19 +2026,22 @@ const signal = (options) => {
|
|
|
2007
2026
|
class HTMLBindingDirective {
|
|
2008
2027
|
/**
|
|
2009
2028
|
* Creates an instance of HTMLBindingDirective.
|
|
2010
|
-
* @param
|
|
2011
|
-
* @param mode - The binding mode to use when applying the binding.
|
|
2012
|
-
* @param options - The options to configure the binding with.
|
|
2029
|
+
* @param dataBinding - The binding configuration to apply.
|
|
2013
2030
|
*/
|
|
2014
|
-
constructor(
|
|
2015
|
-
this.
|
|
2016
|
-
this.
|
|
2017
|
-
|
|
2018
|
-
|
|
2031
|
+
constructor(dataBinding) {
|
|
2032
|
+
this.dataBinding = dataBinding;
|
|
2033
|
+
this.updateTarget = null;
|
|
2034
|
+
/**
|
|
2035
|
+
* The unique id of the factory.
|
|
2036
|
+
*/
|
|
2037
|
+
this.id = nextId();
|
|
2019
2038
|
/**
|
|
2020
2039
|
* The type of aspect to target.
|
|
2021
2040
|
*/
|
|
2022
2041
|
this.aspectType = Aspect.content;
|
|
2042
|
+
/** @internal */
|
|
2043
|
+
this.bind = this.bindDefault;
|
|
2044
|
+
this.data = `${this.id}-d`;
|
|
2023
2045
|
}
|
|
2024
2046
|
/**
|
|
2025
2047
|
* Creates HTML to be used within a template.
|
|
@@ -2030,31 +2052,133 @@ class HTMLBindingDirective {
|
|
|
2030
2052
|
}
|
|
2031
2053
|
/**
|
|
2032
2054
|
* Creates a behavior.
|
|
2033
|
-
* @param targets - The targets available for behaviors to be attached to.
|
|
2034
2055
|
*/
|
|
2035
|
-
createBehavior(
|
|
2036
|
-
if (this.
|
|
2056
|
+
createBehavior() {
|
|
2057
|
+
if (this.updateTarget === null) {
|
|
2037
2058
|
if (this.targetAspect === "innerHTML") {
|
|
2038
|
-
this.
|
|
2059
|
+
this.dataBinding.evaluate = createInnerHTMLBinding(this.dataBinding.evaluate);
|
|
2039
2060
|
}
|
|
2040
|
-
|
|
2061
|
+
switch (this.aspectType) {
|
|
2062
|
+
case 1:
|
|
2063
|
+
this.updateTarget = DOM.setAttribute;
|
|
2064
|
+
break;
|
|
2065
|
+
case 2:
|
|
2066
|
+
this.updateTarget = DOM.setBooleanAttribute;
|
|
2067
|
+
break;
|
|
2068
|
+
case 3:
|
|
2069
|
+
this.updateTarget = setProperty;
|
|
2070
|
+
break;
|
|
2071
|
+
case 4:
|
|
2072
|
+
this.bind = this.bindContent;
|
|
2073
|
+
this.updateTarget = updateContent;
|
|
2074
|
+
break;
|
|
2075
|
+
case 5:
|
|
2076
|
+
this.updateTarget = updateTokenList;
|
|
2077
|
+
break;
|
|
2078
|
+
case 6:
|
|
2079
|
+
this.bind = this.bindEvent;
|
|
2080
|
+
this.updateTarget = eventTarget;
|
|
2081
|
+
break;
|
|
2082
|
+
default:
|
|
2083
|
+
throw FAST.error(1205 /* Message.unsupportedBindingBehavior */);
|
|
2084
|
+
}
|
|
2085
|
+
}
|
|
2086
|
+
return this;
|
|
2087
|
+
}
|
|
2088
|
+
/** @internal */
|
|
2089
|
+
bindDefault(controller) {
|
|
2090
|
+
var _a;
|
|
2091
|
+
const target = controller.targets[this.nodeId];
|
|
2092
|
+
const observer = (_a = target[this.data]) !== null && _a !== void 0 ? _a : (target[this.data] = this.dataBinding.createObserver(this, this));
|
|
2093
|
+
observer.target = target;
|
|
2094
|
+
observer.controller = controller;
|
|
2095
|
+
this.updateTarget(target, this.targetAspect, observer.bind(controller), controller);
|
|
2096
|
+
if (this.updateTarget === updateContent) {
|
|
2097
|
+
controller.onUnbind(this);
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2100
|
+
/** @internal */
|
|
2101
|
+
bindContent(controller) {
|
|
2102
|
+
this.bindDefault(controller);
|
|
2103
|
+
controller.onUnbind(this);
|
|
2104
|
+
}
|
|
2105
|
+
/** @internal */
|
|
2106
|
+
bindEvent(controller) {
|
|
2107
|
+
const target = controller.targets[this.nodeId];
|
|
2108
|
+
target[this.data] = controller;
|
|
2109
|
+
target.addEventListener(this.targetAspect, this, this.dataBinding.options);
|
|
2110
|
+
}
|
|
2111
|
+
/** @internal */
|
|
2112
|
+
unbind(controller) {
|
|
2113
|
+
const target = controller.targets[this.nodeId];
|
|
2114
|
+
const view = target.$fastView;
|
|
2115
|
+
if (view !== void 0 && view.isComposed) {
|
|
2116
|
+
view.unbind();
|
|
2117
|
+
view.needsBindOnly = true;
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
2120
|
+
/** @internal */
|
|
2121
|
+
handleEvent(event) {
|
|
2122
|
+
const target = event.currentTarget;
|
|
2123
|
+
ExecutionContext.setEvent(event);
|
|
2124
|
+
const controller = target[this.data];
|
|
2125
|
+
const result = this.dataBinding.evaluate(controller.source, controller.context);
|
|
2126
|
+
ExecutionContext.setEvent(null);
|
|
2127
|
+
if (result !== true) {
|
|
2128
|
+
event.preventDefault();
|
|
2041
2129
|
}
|
|
2042
|
-
|
|
2130
|
+
}
|
|
2131
|
+
/** @internal */
|
|
2132
|
+
handleChange(binding, observer) {
|
|
2133
|
+
const target = observer.target;
|
|
2134
|
+
const controller = observer.controller;
|
|
2135
|
+
this.updateTarget(target, this.targetAspect, observer.bind(controller), controller);
|
|
2043
2136
|
}
|
|
2044
2137
|
}
|
|
2045
2138
|
HTMLDirective.define(HTMLBindingDirective, { aspected: true });
|
|
2046
2139
|
/**
|
|
2047
|
-
* Creates
|
|
2048
|
-
* @param binding - The binding
|
|
2049
|
-
* @param
|
|
2050
|
-
* @returns A binding
|
|
2140
|
+
* Creates an standard binding.
|
|
2141
|
+
* @param binding - The binding to refresh when changed.
|
|
2142
|
+
* @param isVolatile - Indicates whether the binding is volatile or not.
|
|
2143
|
+
* @returns A binding configuration.
|
|
2144
|
+
* @public
|
|
2145
|
+
*/
|
|
2146
|
+
function bind(binding, isVolatile = Observable.isVolatileBinding(binding)) {
|
|
2147
|
+
return new OnChangeBinding(binding, isVolatile);
|
|
2148
|
+
}
|
|
2149
|
+
/**
|
|
2150
|
+
* Creates a one time binding
|
|
2151
|
+
* @param binding - The binding to refresh when signaled.
|
|
2152
|
+
* @returns A binding configuration.
|
|
2051
2153
|
* @public
|
|
2052
2154
|
*/
|
|
2053
|
-
function
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2155
|
+
function oneTime(binding) {
|
|
2156
|
+
return new OneTimeBinding(binding);
|
|
2157
|
+
}
|
|
2158
|
+
/**
|
|
2159
|
+
* Creates an event listener binding.
|
|
2160
|
+
* @param binding - The binding to invoke when the event is raised.
|
|
2161
|
+
* @param options - Event listener options.
|
|
2162
|
+
* @returns A binding configuration.
|
|
2163
|
+
* @public
|
|
2164
|
+
*/
|
|
2165
|
+
function listener(binding, options) {
|
|
2166
|
+
const config = new OnChangeBinding(binding, false);
|
|
2167
|
+
config.options = options;
|
|
2168
|
+
return config;
|
|
2169
|
+
}
|
|
2170
|
+
/**
|
|
2171
|
+
* Normalizes the input value into a binding.
|
|
2172
|
+
* @param value - The value to create the default binding for.
|
|
2173
|
+
* @returns A binding configuration for the provided value.
|
|
2174
|
+
* @public
|
|
2175
|
+
*/
|
|
2176
|
+
function normalizeBinding(value) {
|
|
2177
|
+
return isFunction(value)
|
|
2178
|
+
? bind(value)
|
|
2179
|
+
: value instanceof Binding
|
|
2180
|
+
? value
|
|
2181
|
+
: oneTime(() => value);
|
|
2058
2182
|
}
|
|
2059
2183
|
|
|
2060
2184
|
function removeNodeSequence(firstNode, lastNode) {
|
|
@@ -2083,17 +2207,87 @@ class HTMLView {
|
|
|
2083
2207
|
this.factories = factories;
|
|
2084
2208
|
this.targets = targets;
|
|
2085
2209
|
this.behaviors = null;
|
|
2210
|
+
this.unbindables = [];
|
|
2086
2211
|
/**
|
|
2087
2212
|
* The data that the view is bound to.
|
|
2088
2213
|
*/
|
|
2089
2214
|
this.source = null;
|
|
2215
|
+
/**
|
|
2216
|
+
* Indicates whether the controller is bound.
|
|
2217
|
+
*/
|
|
2218
|
+
this.isBound = false;
|
|
2219
|
+
/**
|
|
2220
|
+
* Indicates how the source's lifetime relates to the controller's lifetime.
|
|
2221
|
+
*/
|
|
2222
|
+
this.sourceLifetime = SourceLifetime.unknown;
|
|
2090
2223
|
/**
|
|
2091
2224
|
* The execution context the view is running within.
|
|
2092
2225
|
*/
|
|
2093
|
-
this.context =
|
|
2226
|
+
this.context = this;
|
|
2227
|
+
/**
|
|
2228
|
+
* The index of the current item within a repeat context.
|
|
2229
|
+
*/
|
|
2230
|
+
this.index = 0;
|
|
2231
|
+
/**
|
|
2232
|
+
* The length of the current collection within a repeat context.
|
|
2233
|
+
*/
|
|
2234
|
+
this.length = 0;
|
|
2094
2235
|
this.firstChild = fragment.firstChild;
|
|
2095
2236
|
this.lastChild = fragment.lastChild;
|
|
2096
2237
|
}
|
|
2238
|
+
/**
|
|
2239
|
+
* The current event within an event handler.
|
|
2240
|
+
*/
|
|
2241
|
+
get event() {
|
|
2242
|
+
return ExecutionContext.getEvent();
|
|
2243
|
+
}
|
|
2244
|
+
/**
|
|
2245
|
+
* Indicates whether the current item within a repeat context
|
|
2246
|
+
* has an even index.
|
|
2247
|
+
*/
|
|
2248
|
+
get isEven() {
|
|
2249
|
+
return this.index % 2 === 0;
|
|
2250
|
+
}
|
|
2251
|
+
/**
|
|
2252
|
+
* Indicates whether the current item within a repeat context
|
|
2253
|
+
* has an odd index.
|
|
2254
|
+
*/
|
|
2255
|
+
get isOdd() {
|
|
2256
|
+
return this.index % 2 !== 0;
|
|
2257
|
+
}
|
|
2258
|
+
/**
|
|
2259
|
+
* Indicates whether the current item within a repeat context
|
|
2260
|
+
* is the first item in the collection.
|
|
2261
|
+
*/
|
|
2262
|
+
get isFirst() {
|
|
2263
|
+
return this.index === 0;
|
|
2264
|
+
}
|
|
2265
|
+
/**
|
|
2266
|
+
* Indicates whether the current item within a repeat context
|
|
2267
|
+
* is somewhere in the middle of the collection.
|
|
2268
|
+
*/
|
|
2269
|
+
get isInMiddle() {
|
|
2270
|
+
return !this.isFirst && !this.isLast;
|
|
2271
|
+
}
|
|
2272
|
+
/**
|
|
2273
|
+
* Indicates whether the current item within a repeat context
|
|
2274
|
+
* is the last item in the collection.
|
|
2275
|
+
*/
|
|
2276
|
+
get isLast() {
|
|
2277
|
+
return this.index === this.length - 1;
|
|
2278
|
+
}
|
|
2279
|
+
/**
|
|
2280
|
+
* Returns the typed event detail of a custom event.
|
|
2281
|
+
*/
|
|
2282
|
+
eventDetail() {
|
|
2283
|
+
return this.event.detail;
|
|
2284
|
+
}
|
|
2285
|
+
/**
|
|
2286
|
+
* Returns the typed event target of the event.
|
|
2287
|
+
*/
|
|
2288
|
+
eventTarget() {
|
|
2289
|
+
return this.event.target;
|
|
2290
|
+
}
|
|
2097
2291
|
/**
|
|
2098
2292
|
* Appends the view's DOM nodes to the referenced node.
|
|
2099
2293
|
* @param node - The parent node to append the view's DOM nodes to.
|
|
@@ -2110,8 +2304,10 @@ class HTMLView {
|
|
|
2110
2304
|
node.parentNode.insertBefore(this.fragment, node);
|
|
2111
2305
|
}
|
|
2112
2306
|
else {
|
|
2113
|
-
const parentNode = node.parentNode;
|
|
2114
2307
|
const end = this.lastChild;
|
|
2308
|
+
if (node.previousSibling === end)
|
|
2309
|
+
return;
|
|
2310
|
+
const parentNode = node.parentNode;
|
|
2115
2311
|
let current = this.firstChild;
|
|
2116
2312
|
let next;
|
|
2117
2313
|
while (current !== end) {
|
|
@@ -2146,58 +2342,61 @@ class HTMLView {
|
|
|
2146
2342
|
removeNodeSequence(this.firstChild, this.lastChild);
|
|
2147
2343
|
this.unbind();
|
|
2148
2344
|
}
|
|
2345
|
+
onUnbind(behavior) {
|
|
2346
|
+
this.unbindables.push(behavior);
|
|
2347
|
+
}
|
|
2149
2348
|
/**
|
|
2150
2349
|
* Binds a view's behaviors to its binding source.
|
|
2151
2350
|
* @param source - The binding source for the view's binding behaviors.
|
|
2152
2351
|
* @param context - The execution context to run the behaviors within.
|
|
2153
2352
|
*/
|
|
2154
|
-
bind(source, context) {
|
|
2155
|
-
|
|
2156
|
-
const oldSource = this.source;
|
|
2157
|
-
if (oldSource === source) {
|
|
2353
|
+
bind(source, context = this) {
|
|
2354
|
+
if (this.source === source) {
|
|
2158
2355
|
return;
|
|
2159
2356
|
}
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
for (let i = 0, ii = behaviors.length; i < ii; ++i) {
|
|
2165
|
-
const current = behaviors[i];
|
|
2166
|
-
current.unbind(oldSource, context, targets);
|
|
2167
|
-
current.bind(source, context, targets);
|
|
2168
|
-
}
|
|
2169
|
-
}
|
|
2170
|
-
else if (behaviors === null) {
|
|
2357
|
+
let behaviors = this.behaviors;
|
|
2358
|
+
if (behaviors === null) {
|
|
2359
|
+
this.source = source;
|
|
2360
|
+
this.context = context;
|
|
2171
2361
|
this.behaviors = behaviors = new Array(this.factories.length);
|
|
2172
2362
|
const factories = this.factories;
|
|
2173
2363
|
for (let i = 0, ii = factories.length; i < ii; ++i) {
|
|
2174
|
-
const behavior = factories[i].createBehavior(
|
|
2175
|
-
behavior.bind(
|
|
2364
|
+
const behavior = factories[i].createBehavior();
|
|
2365
|
+
behavior.bind(this);
|
|
2176
2366
|
behaviors[i] = behavior;
|
|
2177
2367
|
}
|
|
2178
2368
|
}
|
|
2179
2369
|
else {
|
|
2370
|
+
if (this.source !== null) {
|
|
2371
|
+
this.evaluateUnbindables();
|
|
2372
|
+
}
|
|
2373
|
+
this.isBound = false;
|
|
2374
|
+
this.source = source;
|
|
2375
|
+
this.context = context;
|
|
2180
2376
|
for (let i = 0, ii = behaviors.length; i < ii; ++i) {
|
|
2181
|
-
behaviors[i].bind(
|
|
2377
|
+
behaviors[i].bind(this);
|
|
2182
2378
|
}
|
|
2183
2379
|
}
|
|
2380
|
+
this.isBound = true;
|
|
2184
2381
|
}
|
|
2185
2382
|
/**
|
|
2186
2383
|
* Unbinds a view's behaviors from its binding source.
|
|
2187
2384
|
*/
|
|
2188
2385
|
unbind() {
|
|
2189
|
-
|
|
2190
|
-
if (oldSource === null) {
|
|
2386
|
+
if (!this.isBound || this.source === null) {
|
|
2191
2387
|
return;
|
|
2192
2388
|
}
|
|
2193
|
-
|
|
2194
|
-
const context = this.context;
|
|
2195
|
-
const behaviors = this.behaviors;
|
|
2196
|
-
for (let i = 0, ii = behaviors.length; i < ii; ++i) {
|
|
2197
|
-
behaviors[i].unbind(oldSource, context, targets);
|
|
2198
|
-
}
|
|
2389
|
+
this.evaluateUnbindables();
|
|
2199
2390
|
this.source = null;
|
|
2200
|
-
this.context =
|
|
2391
|
+
this.context = this;
|
|
2392
|
+
this.isBound = false;
|
|
2393
|
+
}
|
|
2394
|
+
evaluateUnbindables() {
|
|
2395
|
+
const unbindables = this.unbindables;
|
|
2396
|
+
for (let i = 0, ii = unbindables.length; i < ii; ++i) {
|
|
2397
|
+
unbindables[i].unbind(this);
|
|
2398
|
+
}
|
|
2399
|
+
unbindables.length = 0;
|
|
2201
2400
|
}
|
|
2202
2401
|
/**
|
|
2203
2402
|
* Efficiently disposes of a contiguous range of synthetic view instances.
|
|
@@ -2213,6 +2412,8 @@ class HTMLView {
|
|
|
2213
2412
|
}
|
|
2214
2413
|
}
|
|
2215
2414
|
}
|
|
2415
|
+
Observable.defineProperty(HTMLView.prototype, "index");
|
|
2416
|
+
Observable.defineProperty(HTMLView.prototype, "length");
|
|
2216
2417
|
|
|
2217
2418
|
const targetIdFrom = (parentId, nodeIndex) => `${parentId}.${nodeIndex}`;
|
|
2218
2419
|
const descriptorCache = {};
|
|
@@ -2221,6 +2422,22 @@ const next = {
|
|
|
2221
2422
|
index: 0,
|
|
2222
2423
|
node: null,
|
|
2223
2424
|
};
|
|
2425
|
+
function tryWarn(name) {
|
|
2426
|
+
if (!name.startsWith("fast-")) {
|
|
2427
|
+
FAST.warn(1204 /* Message.hostBindingWithoutHost */, { name });
|
|
2428
|
+
}
|
|
2429
|
+
}
|
|
2430
|
+
const warningHost = new Proxy(document.createElement("div"), {
|
|
2431
|
+
get(target, property) {
|
|
2432
|
+
tryWarn(property);
|
|
2433
|
+
const value = Reflect.get(target, property);
|
|
2434
|
+
return isFunction(value) ? value.bind(target) : value;
|
|
2435
|
+
},
|
|
2436
|
+
set(target, property, value) {
|
|
2437
|
+
tryWarn(property);
|
|
2438
|
+
return Reflect.set(target, property, value);
|
|
2439
|
+
},
|
|
2440
|
+
});
|
|
2224
2441
|
class CompilationContext {
|
|
2225
2442
|
constructor(fragment, directives) {
|
|
2226
2443
|
this.fragment = fragment;
|
|
@@ -2271,7 +2488,7 @@ class CompilationContext {
|
|
|
2271
2488
|
const fragment = this.fragment.cloneNode(true);
|
|
2272
2489
|
const targets = Object.create(this.proto);
|
|
2273
2490
|
targets.r = fragment;
|
|
2274
|
-
targets.h = hostBindingTarget !== null && hostBindingTarget !== void 0 ? hostBindingTarget :
|
|
2491
|
+
targets.h = hostBindingTarget !== null && hostBindingTarget !== void 0 ? hostBindingTarget : warningHost;
|
|
2275
2492
|
for (const id of this.nodeIds) {
|
|
2276
2493
|
targets[id]; // trigger locator
|
|
2277
2494
|
}
|
|
@@ -2288,7 +2505,7 @@ function compileAttributes(context, parentId, node, nodeId, nodeIndex, includeBa
|
|
|
2288
2505
|
let result = null;
|
|
2289
2506
|
if (parseResult === null) {
|
|
2290
2507
|
if (includeBasicValues) {
|
|
2291
|
-
result =
|
|
2508
|
+
result = new HTMLBindingDirective(oneTime(() => attrValue));
|
|
2292
2509
|
Aspect.assign(result, attr.name);
|
|
2293
2510
|
}
|
|
2294
2511
|
}
|
|
@@ -2325,6 +2542,7 @@ function compileContent(context, node, parentId, nodeId, nodeIndex) {
|
|
|
2325
2542
|
}
|
|
2326
2543
|
else {
|
|
2327
2544
|
currentNode.textContent = " ";
|
|
2545
|
+
Aspect.assign(currentPart);
|
|
2328
2546
|
context.addFactory(currentPart, parentId, nodeId, nodeIndex);
|
|
2329
2547
|
}
|
|
2330
2548
|
lastNode = currentNode;
|
|
@@ -2457,22 +2675,28 @@ const Compiler = {
|
|
|
2457
2675
|
return parts[0];
|
|
2458
2676
|
}
|
|
2459
2677
|
let sourceAspect;
|
|
2678
|
+
let binding;
|
|
2679
|
+
let isVolatile = false;
|
|
2460
2680
|
const partCount = parts.length;
|
|
2461
2681
|
const finalParts = parts.map((x) => {
|
|
2462
2682
|
if (isString(x)) {
|
|
2463
2683
|
return () => x;
|
|
2464
2684
|
}
|
|
2465
2685
|
sourceAspect = x.sourceAspect || sourceAspect;
|
|
2466
|
-
|
|
2686
|
+
binding = x.dataBinding || binding;
|
|
2687
|
+
isVolatile = isVolatile || x.dataBinding.isVolatile;
|
|
2688
|
+
return x.dataBinding.evaluate;
|
|
2467
2689
|
});
|
|
2468
|
-
const
|
|
2690
|
+
const expression = (scope, context) => {
|
|
2469
2691
|
let output = "";
|
|
2470
2692
|
for (let i = 0; i < partCount; ++i) {
|
|
2471
2693
|
output += finalParts[i](scope, context);
|
|
2472
2694
|
}
|
|
2473
2695
|
return output;
|
|
2474
2696
|
};
|
|
2475
|
-
|
|
2697
|
+
binding.evaluate = expression;
|
|
2698
|
+
binding.isVolatile = isVolatile;
|
|
2699
|
+
const directive = new HTMLBindingDirective(binding);
|
|
2476
2700
|
Aspect.assign(directive, sourceAspect);
|
|
2477
2701
|
return directive;
|
|
2478
2702
|
},
|
|
@@ -2510,9 +2734,9 @@ class ViewTemplate {
|
|
|
2510
2734
|
* @param hostBindingTarget - An HTML element to target the host bindings at if different from the
|
|
2511
2735
|
* host that the template is being attached to.
|
|
2512
2736
|
*/
|
|
2513
|
-
render(source, host, hostBindingTarget
|
|
2514
|
-
const view = this.create(hostBindingTarget
|
|
2515
|
-
view.bind(source
|
|
2737
|
+
render(source, host, hostBindingTarget) {
|
|
2738
|
+
const view = this.create(hostBindingTarget);
|
|
2739
|
+
view.bind(source);
|
|
2516
2740
|
view.appendTo(host);
|
|
2517
2741
|
return view;
|
|
2518
2742
|
}
|
|
@@ -2552,12 +2776,12 @@ function html(strings, ...values) {
|
|
|
2552
2776
|
let definition;
|
|
2553
2777
|
html += currentString;
|
|
2554
2778
|
if (isFunction(currentValue)) {
|
|
2555
|
-
html += createAspectedHTML(bind(currentValue), currentString, add);
|
|
2779
|
+
html += createAspectedHTML(new HTMLBindingDirective(bind(currentValue)), currentString, add);
|
|
2556
2780
|
}
|
|
2557
2781
|
else if (isString(currentValue)) {
|
|
2558
2782
|
const match = lastAttributeNameRegex.exec(currentString);
|
|
2559
2783
|
if (match !== null) {
|
|
2560
|
-
const directive =
|
|
2784
|
+
const directive = new HTMLBindingDirective(oneTime(() => currentValue));
|
|
2561
2785
|
Aspect.assign(directive, match[2]);
|
|
2562
2786
|
html += directive.createHTML(add);
|
|
2563
2787
|
}
|
|
@@ -2565,8 +2789,11 @@ function html(strings, ...values) {
|
|
|
2565
2789
|
html += currentValue;
|
|
2566
2790
|
}
|
|
2567
2791
|
}
|
|
2792
|
+
else if (currentValue instanceof Binding) {
|
|
2793
|
+
html += createAspectedHTML(new HTMLBindingDirective(currentValue), currentString, add);
|
|
2794
|
+
}
|
|
2568
2795
|
else if ((definition = HTMLDirective.getForInstance(currentValue)) === void 0) {
|
|
2569
|
-
html += createAspectedHTML(
|
|
2796
|
+
html += createAspectedHTML(new HTMLBindingDirective(oneTime(() => currentValue)), currentString, add);
|
|
2570
2797
|
}
|
|
2571
2798
|
else {
|
|
2572
2799
|
if (definition.aspected) {
|
|
@@ -2579,26 +2806,6 @@ function html(strings, ...values) {
|
|
|
2579
2806
|
}
|
|
2580
2807
|
return new ViewTemplate(html + strings[strings.length - 1], factories);
|
|
2581
2808
|
}
|
|
2582
|
-
/**
|
|
2583
|
-
* Transforms a template literal string into a ChildViewTemplate.
|
|
2584
|
-
* @param strings - The string fragments that are interpolated with the values.
|
|
2585
|
-
* @param values - The values that are interpolated with the string fragments.
|
|
2586
|
-
* @remarks
|
|
2587
|
-
* The html helper supports interpolation of strings, numbers, binding expressions,
|
|
2588
|
-
* other template instances, and Directive instances.
|
|
2589
|
-
* @public
|
|
2590
|
-
*/
|
|
2591
|
-
const child = html;
|
|
2592
|
-
/**
|
|
2593
|
-
* Transforms a template literal string into an ItemViewTemplate.
|
|
2594
|
-
* @param strings - The string fragments that are interpolated with the values.
|
|
2595
|
-
* @param values - The values that are interpolated with the string fragments.
|
|
2596
|
-
* @remarks
|
|
2597
|
-
* The html helper supports interpolation of strings, numbers, binding expressions,
|
|
2598
|
-
* other template instances, and Directive instances.
|
|
2599
|
-
* @public
|
|
2600
|
-
*/
|
|
2601
|
-
const item = html;
|
|
2602
2809
|
|
|
2603
2810
|
/**
|
|
2604
2811
|
* The runtime behavior for template references.
|
|
@@ -2606,20 +2813,12 @@ const item = html;
|
|
|
2606
2813
|
*/
|
|
2607
2814
|
class RefDirective extends StatelessAttachedAttributeDirective {
|
|
2608
2815
|
/**
|
|
2609
|
-
* Bind this behavior
|
|
2610
|
-
* @param
|
|
2611
|
-
* @param context - The execution context that the binding is operating within.
|
|
2612
|
-
* @param targets - The targets that behaviors in a view can attach to.
|
|
2816
|
+
* Bind this behavior.
|
|
2817
|
+
* @param controller - The view controller that manages the lifecycle of this behavior.
|
|
2613
2818
|
*/
|
|
2614
|
-
bind(
|
|
2615
|
-
source[this.options] = targets[this.nodeId];
|
|
2819
|
+
bind(controller) {
|
|
2820
|
+
controller.source[this.options] = controller.targets[this.nodeId];
|
|
2616
2821
|
}
|
|
2617
|
-
/**
|
|
2618
|
-
* Unbinds this behavior from the source.
|
|
2619
|
-
* @param source - The source to unbind from.
|
|
2620
|
-
*/
|
|
2621
|
-
/* eslint-disable-next-line @typescript-eslint/no-empty-function */
|
|
2622
|
-
unbind() { }
|
|
2623
2822
|
}
|
|
2624
2823
|
HTMLDirective.define(RefDirective);
|
|
2625
2824
|
/**
|
|
@@ -2631,27 +2830,34 @@ const ref = (propertyName) => new RefDirective(propertyName);
|
|
|
2631
2830
|
|
|
2632
2831
|
/**
|
|
2633
2832
|
* A directive that enables basic conditional rendering in a template.
|
|
2634
|
-
* @param
|
|
2833
|
+
* @param condition - The condition to test for rendering.
|
|
2635
2834
|
* @param templateOrTemplateBinding - The template or a binding that gets
|
|
2636
2835
|
* the template to render when the condition is true.
|
|
2637
2836
|
* @public
|
|
2638
2837
|
*/
|
|
2639
|
-
function when(
|
|
2640
|
-
const
|
|
2838
|
+
function when(condition, templateOrTemplateBinding) {
|
|
2839
|
+
const dataBinding = isFunction(condition) ? condition : () => condition;
|
|
2840
|
+
const templateBinding = isFunction(templateOrTemplateBinding)
|
|
2641
2841
|
? templateOrTemplateBinding
|
|
2642
2842
|
: () => templateOrTemplateBinding;
|
|
2643
|
-
return (source, context) =>
|
|
2843
|
+
return (source, context) => dataBinding(source, context) ? templateBinding(source, context) : null;
|
|
2644
2844
|
}
|
|
2645
2845
|
|
|
2646
2846
|
const defaultRepeatOptions = Object.freeze({
|
|
2647
2847
|
positioning: false,
|
|
2648
2848
|
recycle: true,
|
|
2649
2849
|
});
|
|
2650
|
-
function bindWithoutPositioning(view, items, index,
|
|
2651
|
-
view.
|
|
2850
|
+
function bindWithoutPositioning(view, items, index, controller) {
|
|
2851
|
+
view.context.parent = controller.source;
|
|
2852
|
+
view.context.parentContext = controller.context;
|
|
2853
|
+
view.bind(items[index]);
|
|
2652
2854
|
}
|
|
2653
|
-
function bindWithPositioning(view, items, index,
|
|
2654
|
-
view.
|
|
2855
|
+
function bindWithPositioning(view, items, index, controller) {
|
|
2856
|
+
view.context.parent = controller.source;
|
|
2857
|
+
view.context.parentContext = controller.context;
|
|
2858
|
+
view.context.length = items.length;
|
|
2859
|
+
view.context.index = index;
|
|
2860
|
+
view.bind(items[index]);
|
|
2655
2861
|
}
|
|
2656
2862
|
/**
|
|
2657
2863
|
* A behavior that renders a template for each item in an array.
|
|
@@ -2661,57 +2867,45 @@ class RepeatBehavior {
|
|
|
2661
2867
|
/**
|
|
2662
2868
|
* Creates an instance of RepeatBehavior.
|
|
2663
2869
|
* @param location - The location in the DOM to render the repeat.
|
|
2664
|
-
* @param
|
|
2870
|
+
* @param dataBinding - The array to render.
|
|
2665
2871
|
* @param isItemsBindingVolatile - Indicates whether the items binding has volatile dependencies.
|
|
2666
2872
|
* @param templateBinding - The template to render for each item.
|
|
2667
2873
|
* @param isTemplateBindingVolatile - Indicates whether the template binding has volatile dependencies.
|
|
2668
2874
|
* @param options - Options used to turn on special repeat features.
|
|
2669
2875
|
*/
|
|
2670
|
-
constructor(
|
|
2671
|
-
this.
|
|
2672
|
-
this.itemsBinding = itemsBinding;
|
|
2673
|
-
this.templateBinding = templateBinding;
|
|
2674
|
-
this.options = options;
|
|
2675
|
-
this.source = null;
|
|
2876
|
+
constructor(directive) {
|
|
2877
|
+
this.directive = directive;
|
|
2676
2878
|
this.views = [];
|
|
2677
2879
|
this.items = null;
|
|
2678
2880
|
this.itemsObserver = null;
|
|
2679
|
-
this.context = void 0;
|
|
2680
|
-
this.childContext = void 0;
|
|
2681
2881
|
this.bindView = bindWithoutPositioning;
|
|
2682
|
-
this.itemsBindingObserver =
|
|
2683
|
-
this.templateBindingObserver =
|
|
2684
|
-
if (options.positioning) {
|
|
2882
|
+
this.itemsBindingObserver = directive.dataBinding.createObserver(directive, this);
|
|
2883
|
+
this.templateBindingObserver = directive.templateBinding.createObserver(directive, this);
|
|
2884
|
+
if (directive.options.positioning) {
|
|
2685
2885
|
this.bindView = bindWithPositioning;
|
|
2686
2886
|
}
|
|
2687
2887
|
}
|
|
2688
2888
|
/**
|
|
2689
|
-
* Bind this behavior
|
|
2690
|
-
* @param
|
|
2691
|
-
* @param context - The execution context that the binding is operating within.
|
|
2889
|
+
* Bind this behavior.
|
|
2890
|
+
* @param controller - The view controller that manages the lifecycle of this behavior.
|
|
2692
2891
|
*/
|
|
2693
|
-
bind(
|
|
2694
|
-
this.
|
|
2695
|
-
this.
|
|
2696
|
-
this.
|
|
2697
|
-
this.
|
|
2698
|
-
this.template = this.templateBindingObserver.observe(source, this.context);
|
|
2892
|
+
bind(controller) {
|
|
2893
|
+
this.location = controller.targets[this.directive.nodeId];
|
|
2894
|
+
this.controller = controller;
|
|
2895
|
+
this.items = this.itemsBindingObserver.bind(controller);
|
|
2896
|
+
this.template = this.templateBindingObserver.bind(controller);
|
|
2699
2897
|
this.observeItems(true);
|
|
2700
2898
|
this.refreshAllViews();
|
|
2899
|
+
controller.onUnbind(this);
|
|
2701
2900
|
}
|
|
2702
2901
|
/**
|
|
2703
|
-
* Unbinds this behavior
|
|
2704
|
-
* @param source - The source to unbind from.
|
|
2902
|
+
* Unbinds this behavior.
|
|
2705
2903
|
*/
|
|
2706
2904
|
unbind() {
|
|
2707
|
-
this.source = null;
|
|
2708
|
-
this.items = null;
|
|
2709
2905
|
if (this.itemsObserver !== null) {
|
|
2710
2906
|
this.itemsObserver.unsubscribe(this);
|
|
2711
2907
|
}
|
|
2712
2908
|
this.unbindAllViews();
|
|
2713
|
-
this.itemsBindingObserver.dispose();
|
|
2714
|
-
this.templateBindingObserver.dispose();
|
|
2715
2909
|
}
|
|
2716
2910
|
/**
|
|
2717
2911
|
* Handles changes in the array, its items, and the repeat template.
|
|
@@ -2719,15 +2913,18 @@ class RepeatBehavior {
|
|
|
2719
2913
|
* @param args - The details about what was changed.
|
|
2720
2914
|
*/
|
|
2721
2915
|
handleChange(source, args) {
|
|
2722
|
-
if (
|
|
2723
|
-
this.items = this.itemsBindingObserver.
|
|
2916
|
+
if (args === this.itemsBindingObserver) {
|
|
2917
|
+
this.items = this.itemsBindingObserver.bind(this.controller);
|
|
2724
2918
|
this.observeItems();
|
|
2725
2919
|
this.refreshAllViews();
|
|
2726
2920
|
}
|
|
2727
|
-
else if (
|
|
2728
|
-
this.template = this.templateBindingObserver.
|
|
2921
|
+
else if (args === this.templateBindingObserver) {
|
|
2922
|
+
this.template = this.templateBindingObserver.bind(this.controller);
|
|
2729
2923
|
this.refreshAllViews(true);
|
|
2730
2924
|
}
|
|
2925
|
+
else if (!args[0]) {
|
|
2926
|
+
return;
|
|
2927
|
+
}
|
|
2731
2928
|
else if (args[0].reset) {
|
|
2732
2929
|
this.refreshAllViews();
|
|
2733
2930
|
}
|
|
@@ -2752,39 +2949,57 @@ class RepeatBehavior {
|
|
|
2752
2949
|
}
|
|
2753
2950
|
updateViews(splices) {
|
|
2754
2951
|
const views = this.views;
|
|
2755
|
-
const childContext = this.childContext;
|
|
2756
|
-
const totalRemoved = [];
|
|
2757
2952
|
const bindView = this.bindView;
|
|
2758
|
-
let removeDelta = 0;
|
|
2759
|
-
for (let i = 0, ii = splices.length; i < ii; ++i) {
|
|
2760
|
-
const splice = splices[i];
|
|
2761
|
-
const removed = splice.removed;
|
|
2762
|
-
totalRemoved.push(...views.splice(splice.index + removeDelta, removed.length));
|
|
2763
|
-
removeDelta -= splice.addedCount;
|
|
2764
|
-
}
|
|
2765
2953
|
const items = this.items;
|
|
2766
2954
|
const template = this.template;
|
|
2955
|
+
const controller = this.controller;
|
|
2956
|
+
const recycle = this.directive.options.recycle;
|
|
2957
|
+
const leftoverViews = [];
|
|
2958
|
+
let leftoverIndex = 0;
|
|
2959
|
+
let availableViews = 0;
|
|
2767
2960
|
for (let i = 0, ii = splices.length; i < ii; ++i) {
|
|
2768
2961
|
const splice = splices[i];
|
|
2962
|
+
const removed = splice.removed;
|
|
2963
|
+
let removeIndex = 0;
|
|
2769
2964
|
let addIndex = splice.index;
|
|
2770
2965
|
const end = addIndex + splice.addedCount;
|
|
2966
|
+
const removedViews = views.splice(splice.index, removed.length);
|
|
2967
|
+
const totalAvailableViews = (availableViews =
|
|
2968
|
+
leftoverViews.length + removedViews.length);
|
|
2771
2969
|
for (; addIndex < end; ++addIndex) {
|
|
2772
2970
|
const neighbor = views[addIndex];
|
|
2773
2971
|
const location = neighbor ? neighbor.firstChild : this.location;
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2972
|
+
let view;
|
|
2973
|
+
if (recycle && availableViews > 0) {
|
|
2974
|
+
if (removeIndex <= totalAvailableViews && removedViews.length > 0) {
|
|
2975
|
+
view = removedViews[removeIndex];
|
|
2976
|
+
removeIndex++;
|
|
2977
|
+
}
|
|
2978
|
+
else {
|
|
2979
|
+
view = leftoverViews[leftoverIndex];
|
|
2980
|
+
leftoverIndex++;
|
|
2981
|
+
}
|
|
2982
|
+
availableViews--;
|
|
2983
|
+
}
|
|
2984
|
+
else {
|
|
2985
|
+
view = template.create();
|
|
2986
|
+
}
|
|
2777
2987
|
views.splice(addIndex, 0, view);
|
|
2778
|
-
bindView(view, items, addIndex,
|
|
2988
|
+
bindView(view, items, addIndex, controller);
|
|
2779
2989
|
view.insertBefore(location);
|
|
2780
2990
|
}
|
|
2991
|
+
if (removedViews[removeIndex]) {
|
|
2992
|
+
leftoverViews.push(...removedViews.slice(removeIndex));
|
|
2993
|
+
}
|
|
2781
2994
|
}
|
|
2782
|
-
for (let i =
|
|
2783
|
-
|
|
2995
|
+
for (let i = leftoverIndex, ii = leftoverViews.length; i < ii; ++i) {
|
|
2996
|
+
leftoverViews[i].dispose();
|
|
2784
2997
|
}
|
|
2785
|
-
if (this.options.positioning) {
|
|
2998
|
+
if (this.directive.options.positioning) {
|
|
2786
2999
|
for (let i = 0, ii = views.length; i < ii; ++i) {
|
|
2787
|
-
views[i].context
|
|
3000
|
+
const context = views[i].context;
|
|
3001
|
+
context.length = i;
|
|
3002
|
+
context.index = ii;
|
|
2788
3003
|
}
|
|
2789
3004
|
}
|
|
2790
3005
|
}
|
|
@@ -2793,11 +3008,11 @@ class RepeatBehavior {
|
|
|
2793
3008
|
const template = this.template;
|
|
2794
3009
|
const location = this.location;
|
|
2795
3010
|
const bindView = this.bindView;
|
|
2796
|
-
const
|
|
3011
|
+
const controller = this.controller;
|
|
2797
3012
|
let itemsLength = items.length;
|
|
2798
3013
|
let views = this.views;
|
|
2799
3014
|
let viewsLength = views.length;
|
|
2800
|
-
if (itemsLength === 0 || templateChanged) {
|
|
3015
|
+
if (itemsLength === 0 || templateChanged || !this.directive.options.recycle) {
|
|
2801
3016
|
// all views need to be removed
|
|
2802
3017
|
HTMLView.disposeContiguousBatch(views);
|
|
2803
3018
|
viewsLength = 0;
|
|
@@ -2807,7 +3022,7 @@ class RepeatBehavior {
|
|
|
2807
3022
|
this.views = views = new Array(itemsLength);
|
|
2808
3023
|
for (let i = 0; i < itemsLength; ++i) {
|
|
2809
3024
|
const view = template.create();
|
|
2810
|
-
bindView(view, items, i,
|
|
3025
|
+
bindView(view, items, i, controller);
|
|
2811
3026
|
views[i] = view;
|
|
2812
3027
|
view.insertBefore(location);
|
|
2813
3028
|
}
|
|
@@ -2818,11 +3033,11 @@ class RepeatBehavior {
|
|
|
2818
3033
|
for (; i < itemsLength; ++i) {
|
|
2819
3034
|
if (i < viewsLength) {
|
|
2820
3035
|
const view = views[i];
|
|
2821
|
-
bindView(view, items, i,
|
|
3036
|
+
bindView(view, items, i, controller);
|
|
2822
3037
|
}
|
|
2823
3038
|
else {
|
|
2824
3039
|
const view = template.create();
|
|
2825
|
-
bindView(view, items, i,
|
|
3040
|
+
bindView(view, items, i, controller);
|
|
2826
3041
|
views.push(view);
|
|
2827
3042
|
view.insertBefore(location);
|
|
2828
3043
|
}
|
|
@@ -2847,17 +3062,19 @@ class RepeatBehavior {
|
|
|
2847
3062
|
class RepeatDirective {
|
|
2848
3063
|
/**
|
|
2849
3064
|
* Creates an instance of RepeatDirective.
|
|
2850
|
-
* @param
|
|
3065
|
+
* @param dataBinding - The binding that provides the array to render.
|
|
2851
3066
|
* @param templateBinding - The template binding used to obtain a template to render for each item in the array.
|
|
2852
3067
|
* @param options - Options used to turn on special repeat features.
|
|
2853
3068
|
*/
|
|
2854
|
-
constructor(
|
|
2855
|
-
this.
|
|
3069
|
+
constructor(dataBinding, templateBinding, options) {
|
|
3070
|
+
this.dataBinding = dataBinding;
|
|
2856
3071
|
this.templateBinding = templateBinding;
|
|
2857
3072
|
this.options = options;
|
|
3073
|
+
/**
|
|
3074
|
+
* The unique id of the factory.
|
|
3075
|
+
*/
|
|
3076
|
+
this.id = nextId();
|
|
2858
3077
|
ArrayObserver.enable();
|
|
2859
|
-
this.isItemsBindingVolatile = Observable.isVolatileBinding(itemsBinding);
|
|
2860
|
-
this.isTemplateBindingVolatile = Observable.isVolatileBinding(templateBinding);
|
|
2861
3078
|
}
|
|
2862
3079
|
/**
|
|
2863
3080
|
* Creates a placeholder string based on the directive's index within the template.
|
|
@@ -2870,16 +3087,23 @@ class RepeatDirective {
|
|
|
2870
3087
|
* Creates a behavior for the provided target node.
|
|
2871
3088
|
* @param target - The node instance to create the behavior for.
|
|
2872
3089
|
*/
|
|
2873
|
-
createBehavior(
|
|
2874
|
-
return new RepeatBehavior(
|
|
3090
|
+
createBehavior() {
|
|
3091
|
+
return new RepeatBehavior(this);
|
|
2875
3092
|
}
|
|
2876
3093
|
}
|
|
2877
3094
|
HTMLDirective.define(RepeatDirective);
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
3095
|
+
/**
|
|
3096
|
+
* A directive that enables list rendering.
|
|
3097
|
+
* @param items - The array to render.
|
|
3098
|
+
* @param template - The template or a template binding used obtain a template
|
|
3099
|
+
* to render for each item in the array.
|
|
3100
|
+
* @param options - Options used to turn on special repeat features.
|
|
3101
|
+
* @public
|
|
3102
|
+
*/
|
|
3103
|
+
function repeat(items, template, options = defaultRepeatOptions) {
|
|
3104
|
+
const dataBinding = normalizeBinding(items);
|
|
3105
|
+
const templateBinding = normalizeBinding(template);
|
|
3106
|
+
return new RepeatDirective(dataBinding, templateBinding, Object.assign(Object.assign({}, defaultRepeatOptions), options));
|
|
2883
3107
|
}
|
|
2884
3108
|
|
|
2885
3109
|
const selectElements = (value) => value.nodeType === 1;
|
|
@@ -2908,11 +3132,12 @@ class NodeObservationDirective extends StatelessAttachedAttributeDirective {
|
|
|
2908
3132
|
* @param context - The execution context that the binding is operating within.
|
|
2909
3133
|
* @param targets - The targets that behaviors in a view can attach to.
|
|
2910
3134
|
*/
|
|
2911
|
-
bind(
|
|
2912
|
-
const target = targets[this.nodeId];
|
|
2913
|
-
target[this.sourceProperty] = source;
|
|
2914
|
-
this.updateTarget(source, this.computeNodes(target));
|
|
3135
|
+
bind(controller) {
|
|
3136
|
+
const target = controller.targets[this.nodeId];
|
|
3137
|
+
target[this.sourceProperty] = controller.source;
|
|
3138
|
+
this.updateTarget(controller.source, this.computeNodes(target));
|
|
2915
3139
|
this.observe(target);
|
|
3140
|
+
controller.onUnbind(this);
|
|
2916
3141
|
}
|
|
2917
3142
|
/**
|
|
2918
3143
|
* Unbinds this behavior from the source.
|
|
@@ -2920,9 +3145,9 @@ class NodeObservationDirective extends StatelessAttachedAttributeDirective {
|
|
|
2920
3145
|
* @param context - The execution context that the binding is operating within.
|
|
2921
3146
|
* @param targets - The targets that behaviors in a view can attach to.
|
|
2922
3147
|
*/
|
|
2923
|
-
unbind(
|
|
2924
|
-
const target = targets[this.nodeId];
|
|
2925
|
-
this.updateTarget(source, emptyArray);
|
|
3148
|
+
unbind(controller) {
|
|
3149
|
+
const target = controller.targets[this.nodeId];
|
|
3150
|
+
this.updateTarget(controller.source, emptyArray);
|
|
2926
3151
|
this.disconnect(target);
|
|
2927
3152
|
target[this.sourceProperty] = null;
|
|
2928
3153
|
}
|
|
@@ -3071,6 +3296,16 @@ function children(propertyOrOptions) {
|
|
|
3071
3296
|
|
|
3072
3297
|
const booleanMode = "boolean";
|
|
3073
3298
|
const reflectMode = "reflect";
|
|
3299
|
+
/**
|
|
3300
|
+
* Metadata used to configure a custom attribute's behavior.
|
|
3301
|
+
* @public
|
|
3302
|
+
*/
|
|
3303
|
+
const AttributeConfiguration = Object.freeze({
|
|
3304
|
+
/**
|
|
3305
|
+
* Locates all attribute configurations associated with a type.
|
|
3306
|
+
*/
|
|
3307
|
+
locate: createMetadataLocator(),
|
|
3308
|
+
});
|
|
3074
3309
|
/**
|
|
3075
3310
|
* A {@link ValueConverter} that converts to and from `boolean` values.
|
|
3076
3311
|
* @remarks
|
|
@@ -3208,7 +3443,7 @@ class AttributeDefinition {
|
|
|
3208
3443
|
*/
|
|
3209
3444
|
static collect(Owner, ...attributeLists) {
|
|
3210
3445
|
const attributes = [];
|
|
3211
|
-
attributeLists.push(Owner
|
|
3446
|
+
attributeLists.push(AttributeConfiguration.locate(Owner));
|
|
3212
3447
|
for (let i = 0, ii = attributeLists.length; i < ii; ++i) {
|
|
3213
3448
|
const list = attributeLists[i];
|
|
3214
3449
|
if (list === void 0) {
|
|
@@ -3238,9 +3473,7 @@ function attr(configOrTarget, prop) {
|
|
|
3238
3473
|
// - @attr({...opts})
|
|
3239
3474
|
config.property = $prop;
|
|
3240
3475
|
}
|
|
3241
|
-
|
|
3242
|
-
($target.constructor.attributes = []);
|
|
3243
|
-
attributes.push(config);
|
|
3476
|
+
AttributeConfiguration.locate($target.constructor).push(config);
|
|
3244
3477
|
}
|
|
3245
3478
|
if (arguments.length > 1) {
|
|
3246
3479
|
// Non invocation:
|
|
@@ -3258,25 +3491,24 @@ function attr(configOrTarget, prop) {
|
|
|
3258
3491
|
|
|
3259
3492
|
const defaultShadowOptions = { mode: "open" };
|
|
3260
3493
|
const defaultElementOptions = {};
|
|
3494
|
+
const fastElementBaseTypes = new Set();
|
|
3261
3495
|
const fastElementRegistry = FAST.getById(4 /* KernelServiceId.elementRegistry */, () => createTypeRegistry());
|
|
3262
3496
|
/**
|
|
3263
3497
|
* Defines metadata for a FASTElement.
|
|
3264
3498
|
* @public
|
|
3265
3499
|
*/
|
|
3266
3500
|
class FASTElementDefinition {
|
|
3267
|
-
/**
|
|
3268
|
-
* Creates an instance of FASTElementDefinition.
|
|
3269
|
-
* @param type - The type this definition is being created for.
|
|
3270
|
-
* @param nameOrConfig - The name of the element to define or a config object
|
|
3271
|
-
* that describes the element to define.
|
|
3272
|
-
*/
|
|
3273
3501
|
constructor(type, nameOrConfig = type.definition) {
|
|
3502
|
+
var _a;
|
|
3503
|
+
this.platformDefined = false;
|
|
3274
3504
|
if (isString(nameOrConfig)) {
|
|
3275
3505
|
nameOrConfig = { name: nameOrConfig };
|
|
3276
3506
|
}
|
|
3277
3507
|
this.type = type;
|
|
3278
3508
|
this.name = nameOrConfig.name;
|
|
3279
3509
|
this.template = nameOrConfig.template;
|
|
3510
|
+
this.registry = (_a = nameOrConfig.registry) !== null && _a !== void 0 ? _a : customElements;
|
|
3511
|
+
const proto = type.prototype;
|
|
3280
3512
|
const attributes = AttributeDefinition.collect(type, nameOrConfig.attributes);
|
|
3281
3513
|
const observedAttributes = new Array(attributes.length);
|
|
3282
3514
|
const propertyLookup = {};
|
|
@@ -3286,9 +3518,13 @@ class FASTElementDefinition {
|
|
|
3286
3518
|
observedAttributes[i] = current.attribute;
|
|
3287
3519
|
propertyLookup[current.name] = current;
|
|
3288
3520
|
attributeLookup[current.attribute] = current;
|
|
3521
|
+
Observable.defineProperty(proto, current);
|
|
3289
3522
|
}
|
|
3523
|
+
Reflect.defineProperty(type, "observedAttributes", {
|
|
3524
|
+
value: observedAttributes,
|
|
3525
|
+
enumerable: true,
|
|
3526
|
+
});
|
|
3290
3527
|
this.attributes = attributes;
|
|
3291
|
-
this.observedAttributes = observedAttributes;
|
|
3292
3528
|
this.propertyLookup = propertyLookup;
|
|
3293
3529
|
this.attributeLookup = attributeLookup;
|
|
3294
3530
|
this.shadowOptions =
|
|
@@ -3301,43 +3537,50 @@ class FASTElementDefinition {
|
|
|
3301
3537
|
nameOrConfig.elementOptions === void 0
|
|
3302
3538
|
? defaultElementOptions
|
|
3303
3539
|
: Object.assign(Object.assign({}, defaultElementOptions), nameOrConfig.elementOptions);
|
|
3304
|
-
this.styles =
|
|
3305
|
-
|
|
3306
|
-
? void 0
|
|
3307
|
-
: Array.isArray(nameOrConfig.styles)
|
|
3308
|
-
? new ElementStyles(nameOrConfig.styles)
|
|
3309
|
-
: nameOrConfig.styles instanceof ElementStyles
|
|
3310
|
-
? nameOrConfig.styles
|
|
3311
|
-
: new ElementStyles([nameOrConfig.styles]);
|
|
3540
|
+
this.styles = ElementStyles.normalize(nameOrConfig.styles);
|
|
3541
|
+
fastElementRegistry.register(this);
|
|
3312
3542
|
}
|
|
3313
3543
|
/**
|
|
3314
3544
|
* Indicates if this element has been defined in at least one registry.
|
|
3315
3545
|
*/
|
|
3316
3546
|
get isDefined() {
|
|
3317
|
-
return
|
|
3547
|
+
return this.platformDefined;
|
|
3318
3548
|
}
|
|
3319
3549
|
/**
|
|
3320
3550
|
* Defines a custom element based on this definition.
|
|
3321
3551
|
* @param registry - The element registry to define the element in.
|
|
3552
|
+
* @remarks
|
|
3553
|
+
* This operation is idempotent per registry.
|
|
3322
3554
|
*/
|
|
3323
|
-
define(registry =
|
|
3555
|
+
define(registry = this.registry) {
|
|
3324
3556
|
const type = this.type;
|
|
3325
|
-
if (fastElementRegistry.register(this)) {
|
|
3326
|
-
const attributes = this.attributes;
|
|
3327
|
-
const proto = type.prototype;
|
|
3328
|
-
for (let i = 0, ii = attributes.length; i < ii; ++i) {
|
|
3329
|
-
Observable.defineProperty(proto, attributes[i]);
|
|
3330
|
-
}
|
|
3331
|
-
Reflect.defineProperty(type, "observedAttributes", {
|
|
3332
|
-
value: this.observedAttributes,
|
|
3333
|
-
enumerable: true,
|
|
3334
|
-
});
|
|
3335
|
-
}
|
|
3336
3557
|
if (!registry.get(this.name)) {
|
|
3558
|
+
this.platformDefined = true;
|
|
3337
3559
|
registry.define(this.name, type, this.elementOptions);
|
|
3338
3560
|
}
|
|
3339
3561
|
return this;
|
|
3340
3562
|
}
|
|
3563
|
+
/**
|
|
3564
|
+
* Creates an instance of FASTElementDefinition.
|
|
3565
|
+
* @param type - The type this definition is being created for.
|
|
3566
|
+
* @param nameOrDef - The name of the element to define or a config object
|
|
3567
|
+
* that describes the element to define.
|
|
3568
|
+
*/
|
|
3569
|
+
static compose(type, nameOrDef) {
|
|
3570
|
+
if (fastElementBaseTypes.has(type) || fastElementRegistry.getByType(type)) {
|
|
3571
|
+
return new FASTElementDefinition(class extends type {
|
|
3572
|
+
}, nameOrDef);
|
|
3573
|
+
}
|
|
3574
|
+
return new FASTElementDefinition(type, nameOrDef);
|
|
3575
|
+
}
|
|
3576
|
+
/**
|
|
3577
|
+
* Registers a FASTElement base type.
|
|
3578
|
+
* @param type - The type to register as a base type.
|
|
3579
|
+
* @internal
|
|
3580
|
+
*/
|
|
3581
|
+
static registerBaseType(type) {
|
|
3582
|
+
fastElementBaseTypes.add(type);
|
|
3583
|
+
}
|
|
3341
3584
|
}
|
|
3342
3585
|
/**
|
|
3343
3586
|
* Gets the element definition associated with the specified type.
|
|
@@ -3350,22 +3593,22 @@ FASTElementDefinition.getByType = fastElementRegistry.getByType;
|
|
|
3350
3593
|
*/
|
|
3351
3594
|
FASTElementDefinition.getForInstance = fastElementRegistry.getForInstance;
|
|
3352
3595
|
|
|
3353
|
-
const shadowRoots = new WeakMap();
|
|
3354
3596
|
const defaultEventOptions = {
|
|
3355
3597
|
bubbles: true,
|
|
3356
3598
|
composed: true,
|
|
3357
3599
|
cancelable: true,
|
|
3358
3600
|
};
|
|
3601
|
+
const isConnectedPropertyName = "isConnected";
|
|
3602
|
+
const shadowRoots = new WeakMap();
|
|
3359
3603
|
function getShadowRoot(element) {
|
|
3360
3604
|
var _a, _b;
|
|
3361
3605
|
return (_b = (_a = element.shadowRoot) !== null && _a !== void 0 ? _a : shadowRoots.get(element)) !== null && _b !== void 0 ? _b : null;
|
|
3362
3606
|
}
|
|
3363
|
-
const isConnectedPropertyName = "isConnected";
|
|
3364
3607
|
/**
|
|
3365
3608
|
* Controls the lifecycle and rendering of a `FASTElement`.
|
|
3366
3609
|
* @public
|
|
3367
3610
|
*/
|
|
3368
|
-
class
|
|
3611
|
+
class ElementController extends PropertyChangeNotifier {
|
|
3369
3612
|
/**
|
|
3370
3613
|
* Creates a Controller to control the specified element.
|
|
3371
3614
|
* @param element - The element to be controlled by this controller.
|
|
@@ -3376,12 +3619,12 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3376
3619
|
constructor(element, definition) {
|
|
3377
3620
|
super(element);
|
|
3378
3621
|
this.boundObservables = null;
|
|
3379
|
-
this.behaviors = null;
|
|
3380
3622
|
this.needsInitialization = true;
|
|
3381
3623
|
this.hasExistingShadowRoot = false;
|
|
3382
3624
|
this._template = null;
|
|
3383
|
-
this._styles = null;
|
|
3384
3625
|
this._isConnected = false;
|
|
3626
|
+
this.behaviors = null;
|
|
3627
|
+
this._mainStyles = null;
|
|
3385
3628
|
/**
|
|
3386
3629
|
* This allows Observable.getNotifier(...) to return the Controller
|
|
3387
3630
|
* when the notifier for the Controller itself is being requested. The
|
|
@@ -3397,7 +3640,7 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3397
3640
|
* If `null` then the element is managing its own rendering.
|
|
3398
3641
|
*/
|
|
3399
3642
|
this.view = null;
|
|
3400
|
-
this.
|
|
3643
|
+
this.source = element;
|
|
3401
3644
|
this.definition = definition;
|
|
3402
3645
|
const shadowOptions = definition.shadowOptions;
|
|
3403
3646
|
if (shadowOptions !== void 0) {
|
|
@@ -3451,9 +3694,9 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3451
3694
|
// 1. Template overrides take top precedence.
|
|
3452
3695
|
if (this._template === null) {
|
|
3453
3696
|
const definition = this.definition;
|
|
3454
|
-
if (this.
|
|
3697
|
+
if (this.source.resolveTemplate) {
|
|
3455
3698
|
// 2. Allow for element instance overrides next.
|
|
3456
|
-
this._template = this.
|
|
3699
|
+
this._template = this.source.resolveTemplate();
|
|
3457
3700
|
}
|
|
3458
3701
|
else if (definition.template) {
|
|
3459
3702
|
// 3. Default to the static definition.
|
|
@@ -3472,48 +3715,92 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3472
3715
|
}
|
|
3473
3716
|
}
|
|
3474
3717
|
/**
|
|
3475
|
-
*
|
|
3476
|
-
*
|
|
3477
|
-
* This value can only be accurately read after connect but can be set at any time.
|
|
3718
|
+
* The main set of styles used for the component, independent
|
|
3719
|
+
* of any dynamically added styles.
|
|
3478
3720
|
*/
|
|
3479
|
-
get
|
|
3721
|
+
get mainStyles() {
|
|
3480
3722
|
var _a;
|
|
3481
3723
|
// 1. Styles overrides take top precedence.
|
|
3482
|
-
if (this.
|
|
3724
|
+
if (this._mainStyles === null) {
|
|
3483
3725
|
const definition = this.definition;
|
|
3484
|
-
if (this.
|
|
3726
|
+
if (this.source.resolveStyles) {
|
|
3485
3727
|
// 2. Allow for element instance overrides next.
|
|
3486
|
-
this.
|
|
3728
|
+
this._mainStyles = this.source.resolveStyles();
|
|
3487
3729
|
}
|
|
3488
3730
|
else if (definition.styles) {
|
|
3489
3731
|
// 3. Default to the static definition.
|
|
3490
|
-
this.
|
|
3732
|
+
this._mainStyles = (_a = definition.styles) !== null && _a !== void 0 ? _a : null;
|
|
3491
3733
|
}
|
|
3492
3734
|
}
|
|
3493
|
-
return this.
|
|
3735
|
+
return this._mainStyles;
|
|
3494
3736
|
}
|
|
3495
|
-
set
|
|
3496
|
-
if (this.
|
|
3737
|
+
set mainStyles(value) {
|
|
3738
|
+
if (this._mainStyles === value) {
|
|
3497
3739
|
return;
|
|
3498
3740
|
}
|
|
3499
|
-
if (this.
|
|
3500
|
-
this.removeStyles(this.
|
|
3741
|
+
if (this._mainStyles !== null) {
|
|
3742
|
+
this.removeStyles(this._mainStyles);
|
|
3501
3743
|
}
|
|
3502
|
-
this.
|
|
3744
|
+
this._mainStyles = value;
|
|
3503
3745
|
if (!this.needsInitialization) {
|
|
3504
3746
|
this.addStyles(value);
|
|
3505
3747
|
}
|
|
3506
3748
|
}
|
|
3749
|
+
/**
|
|
3750
|
+
* Adds the behavior to the component.
|
|
3751
|
+
* @param behavior - The behavior to add.
|
|
3752
|
+
*/
|
|
3753
|
+
addBehavior(behavior) {
|
|
3754
|
+
var _a, _b;
|
|
3755
|
+
const targetBehaviors = (_a = this.behaviors) !== null && _a !== void 0 ? _a : (this.behaviors = new Map());
|
|
3756
|
+
const count = (_b = targetBehaviors.get(behavior)) !== null && _b !== void 0 ? _b : 0;
|
|
3757
|
+
if (count === 0) {
|
|
3758
|
+
targetBehaviors.set(behavior, 1);
|
|
3759
|
+
behavior.addedCallback && behavior.addedCallback(this);
|
|
3760
|
+
if (behavior.connectedCallback && this.isConnected) {
|
|
3761
|
+
behavior.connectedCallback(this);
|
|
3762
|
+
}
|
|
3763
|
+
}
|
|
3764
|
+
else {
|
|
3765
|
+
targetBehaviors.set(behavior, count + 1);
|
|
3766
|
+
}
|
|
3767
|
+
}
|
|
3768
|
+
/**
|
|
3769
|
+
* Removes the behavior from the component.
|
|
3770
|
+
* @param behavior - The behavior to remove.
|
|
3771
|
+
* @param force - Forces removal even if this behavior was added more than once.
|
|
3772
|
+
*/
|
|
3773
|
+
removeBehavior(behavior, force = false) {
|
|
3774
|
+
const targetBehaviors = this.behaviors;
|
|
3775
|
+
if (targetBehaviors === null) {
|
|
3776
|
+
return;
|
|
3777
|
+
}
|
|
3778
|
+
const count = targetBehaviors.get(behavior);
|
|
3779
|
+
if (count === void 0) {
|
|
3780
|
+
return;
|
|
3781
|
+
}
|
|
3782
|
+
if (count === 1 || force) {
|
|
3783
|
+
targetBehaviors.delete(behavior);
|
|
3784
|
+
if (behavior.disconnectedCallback && this.isConnected) {
|
|
3785
|
+
behavior.disconnectedCallback(this);
|
|
3786
|
+
}
|
|
3787
|
+
behavior.removedCallback && behavior.removedCallback(this);
|
|
3788
|
+
}
|
|
3789
|
+
else {
|
|
3790
|
+
targetBehaviors.set(behavior, count - 1);
|
|
3791
|
+
}
|
|
3792
|
+
}
|
|
3507
3793
|
/**
|
|
3508
3794
|
* Adds styles to this element. Providing an HTMLStyleElement will attach the element instance to the shadowRoot.
|
|
3509
3795
|
* @param styles - The styles to add.
|
|
3510
3796
|
*/
|
|
3511
3797
|
addStyles(styles) {
|
|
3798
|
+
var _a;
|
|
3512
3799
|
if (!styles) {
|
|
3513
3800
|
return;
|
|
3514
3801
|
}
|
|
3515
|
-
const
|
|
3516
|
-
|
|
3802
|
+
const source = this.source;
|
|
3803
|
+
const target = (_a = getShadowRoot(source)) !== null && _a !== void 0 ? _a : source.getRootNode();
|
|
3517
3804
|
if (styles instanceof HTMLElement) {
|
|
3518
3805
|
target.append(styles);
|
|
3519
3806
|
}
|
|
@@ -3521,7 +3808,9 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3521
3808
|
const sourceBehaviors = styles.behaviors;
|
|
3522
3809
|
styles.addStylesTo(target);
|
|
3523
3810
|
if (sourceBehaviors !== null) {
|
|
3524
|
-
|
|
3811
|
+
for (let i = 0, ii = sourceBehaviors.length; i < ii; ++i) {
|
|
3812
|
+
this.addBehavior(sourceBehaviors[i]);
|
|
3813
|
+
}
|
|
3525
3814
|
}
|
|
3526
3815
|
}
|
|
3527
3816
|
}
|
|
@@ -3530,11 +3819,12 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3530
3819
|
* @param styles - the styles to remove.
|
|
3531
3820
|
*/
|
|
3532
3821
|
removeStyles(styles) {
|
|
3822
|
+
var _a;
|
|
3533
3823
|
if (!styles) {
|
|
3534
3824
|
return;
|
|
3535
3825
|
}
|
|
3536
|
-
const
|
|
3537
|
-
|
|
3826
|
+
const source = this.source;
|
|
3827
|
+
const target = (_a = getShadowRoot(source)) !== null && _a !== void 0 ? _a : source.getRootNode();
|
|
3538
3828
|
if (styles instanceof HTMLElement) {
|
|
3539
3829
|
target.removeChild(styles);
|
|
3540
3830
|
}
|
|
@@ -3542,85 +3832,29 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3542
3832
|
const sourceBehaviors = styles.behaviors;
|
|
3543
3833
|
styles.removeStylesFrom(target);
|
|
3544
3834
|
if (sourceBehaviors !== null) {
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
}
|
|
3549
|
-
/**
|
|
3550
|
-
* Adds behaviors to this element.
|
|
3551
|
-
* @param behaviors - The behaviors to add.
|
|
3552
|
-
*/
|
|
3553
|
-
addBehaviors(behaviors) {
|
|
3554
|
-
var _a;
|
|
3555
|
-
const targetBehaviors = (_a = this.behaviors) !== null && _a !== void 0 ? _a : (this.behaviors = new Map());
|
|
3556
|
-
const length = behaviors.length;
|
|
3557
|
-
const behaviorsToBind = [];
|
|
3558
|
-
for (let i = 0; i < length; ++i) {
|
|
3559
|
-
const behavior = behaviors[i];
|
|
3560
|
-
if (targetBehaviors.has(behavior)) {
|
|
3561
|
-
targetBehaviors.set(behavior, targetBehaviors.get(behavior) + 1);
|
|
3562
|
-
}
|
|
3563
|
-
else {
|
|
3564
|
-
targetBehaviors.set(behavior, 1);
|
|
3565
|
-
behaviorsToBind.push(behavior);
|
|
3566
|
-
}
|
|
3567
|
-
}
|
|
3568
|
-
if (this._isConnected) {
|
|
3569
|
-
const element = this.element;
|
|
3570
|
-
const context = ExecutionContext.default;
|
|
3571
|
-
for (let i = 0; i < behaviorsToBind.length; ++i) {
|
|
3572
|
-
behaviorsToBind[i].bind(element, context);
|
|
3573
|
-
}
|
|
3574
|
-
}
|
|
3575
|
-
}
|
|
3576
|
-
/**
|
|
3577
|
-
* Removes behaviors from this element.
|
|
3578
|
-
* @param behaviors - The behaviors to remove.
|
|
3579
|
-
* @param force - Forces unbinding of behaviors.
|
|
3580
|
-
*/
|
|
3581
|
-
removeBehaviors(behaviors, force = false) {
|
|
3582
|
-
const targetBehaviors = this.behaviors;
|
|
3583
|
-
if (targetBehaviors === null) {
|
|
3584
|
-
return;
|
|
3585
|
-
}
|
|
3586
|
-
const length = behaviors.length;
|
|
3587
|
-
const behaviorsToUnbind = [];
|
|
3588
|
-
for (let i = 0; i < length; ++i) {
|
|
3589
|
-
const behavior = behaviors[i];
|
|
3590
|
-
if (targetBehaviors.has(behavior)) {
|
|
3591
|
-
const count = targetBehaviors.get(behavior) - 1;
|
|
3592
|
-
count === 0 || force
|
|
3593
|
-
? targetBehaviors.delete(behavior) && behaviorsToUnbind.push(behavior)
|
|
3594
|
-
: targetBehaviors.set(behavior, count);
|
|
3595
|
-
}
|
|
3596
|
-
}
|
|
3597
|
-
if (this._isConnected) {
|
|
3598
|
-
const element = this.element;
|
|
3599
|
-
const context = ExecutionContext.default;
|
|
3600
|
-
for (let i = 0; i < behaviorsToUnbind.length; ++i) {
|
|
3601
|
-
behaviorsToUnbind[i].unbind(element, context);
|
|
3835
|
+
for (let i = 0, ii = sourceBehaviors.length; i < ii; ++i) {
|
|
3836
|
+
this.addBehavior(sourceBehaviors[i]);
|
|
3837
|
+
}
|
|
3602
3838
|
}
|
|
3603
3839
|
}
|
|
3604
3840
|
}
|
|
3605
3841
|
/**
|
|
3606
3842
|
* Runs connected lifecycle behavior on the associated element.
|
|
3607
3843
|
*/
|
|
3608
|
-
|
|
3844
|
+
connect() {
|
|
3609
3845
|
if (this._isConnected) {
|
|
3610
3846
|
return;
|
|
3611
3847
|
}
|
|
3612
|
-
const element = this.element;
|
|
3613
|
-
const context = ExecutionContext.default;
|
|
3614
3848
|
if (this.needsInitialization) {
|
|
3615
3849
|
this.finishInitialization();
|
|
3616
3850
|
}
|
|
3617
3851
|
else if (this.view !== null) {
|
|
3618
|
-
this.view.bind(
|
|
3852
|
+
this.view.bind(this.source);
|
|
3619
3853
|
}
|
|
3620
3854
|
const behaviors = this.behaviors;
|
|
3621
3855
|
if (behaviors !== null) {
|
|
3622
|
-
for (const
|
|
3623
|
-
|
|
3856
|
+
for (const key of behaviors.keys()) {
|
|
3857
|
+
key.connectedCallback && key.connectedCallback(this);
|
|
3624
3858
|
}
|
|
3625
3859
|
}
|
|
3626
3860
|
this.setIsConnected(true);
|
|
@@ -3628,21 +3862,18 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3628
3862
|
/**
|
|
3629
3863
|
* Runs disconnected lifecycle behavior on the associated element.
|
|
3630
3864
|
*/
|
|
3631
|
-
|
|
3865
|
+
disconnect() {
|
|
3632
3866
|
if (!this._isConnected) {
|
|
3633
3867
|
return;
|
|
3634
3868
|
}
|
|
3635
3869
|
this.setIsConnected(false);
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
view.unbind();
|
|
3870
|
+
if (this.view !== null) {
|
|
3871
|
+
this.view.unbind();
|
|
3639
3872
|
}
|
|
3640
3873
|
const behaviors = this.behaviors;
|
|
3641
3874
|
if (behaviors !== null) {
|
|
3642
|
-
const
|
|
3643
|
-
|
|
3644
|
-
for (const behavior of behaviors.keys()) {
|
|
3645
|
-
behavior.unbind(element, context);
|
|
3875
|
+
for (const key of behaviors.keys()) {
|
|
3876
|
+
key.disconnectedCallback && key.disconnectedCallback(this);
|
|
3646
3877
|
}
|
|
3647
3878
|
}
|
|
3648
3879
|
}
|
|
@@ -3655,7 +3886,7 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3655
3886
|
onAttributeChangedCallback(name, oldValue, newValue) {
|
|
3656
3887
|
const attrDef = this.definition.attributeLookup[name];
|
|
3657
3888
|
if (attrDef !== void 0) {
|
|
3658
|
-
attrDef.onAttributeChangedCallback(this.
|
|
3889
|
+
attrDef.onAttributeChangedCallback(this.source, newValue);
|
|
3659
3890
|
}
|
|
3660
3891
|
}
|
|
3661
3892
|
/**
|
|
@@ -3668,12 +3899,12 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3668
3899
|
*/
|
|
3669
3900
|
emit(type, detail, options) {
|
|
3670
3901
|
if (this._isConnected) {
|
|
3671
|
-
return this.
|
|
3902
|
+
return this.source.dispatchEvent(new CustomEvent(type, Object.assign(Object.assign({ detail }, defaultEventOptions), options)));
|
|
3672
3903
|
}
|
|
3673
3904
|
return false;
|
|
3674
3905
|
}
|
|
3675
3906
|
finishInitialization() {
|
|
3676
|
-
const element = this.
|
|
3907
|
+
const element = this.source;
|
|
3677
3908
|
const boundObservables = this.boundObservables;
|
|
3678
3909
|
// If we have any observables that were bound, re-apply their values.
|
|
3679
3910
|
if (boundObservables !== null) {
|
|
@@ -3685,15 +3916,15 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3685
3916
|
this.boundObservables = null;
|
|
3686
3917
|
}
|
|
3687
3918
|
this.renderTemplate(this.template);
|
|
3688
|
-
this.addStyles(this.
|
|
3919
|
+
this.addStyles(this.mainStyles);
|
|
3689
3920
|
this.needsInitialization = false;
|
|
3690
3921
|
}
|
|
3691
3922
|
renderTemplate(template) {
|
|
3692
3923
|
var _a;
|
|
3693
|
-
const element = this.element;
|
|
3694
3924
|
// When getting the host to render to, we start by looking
|
|
3695
3925
|
// up the shadow root. If there isn't one, then that means
|
|
3696
3926
|
// we're doing a Light DOM render to the element's direct children.
|
|
3927
|
+
const element = this.source;
|
|
3697
3928
|
const host = (_a = getShadowRoot(element)) !== null && _a !== void 0 ? _a : element;
|
|
3698
3929
|
if (this.view !== null) {
|
|
3699
3930
|
// If there's already a view, we need to unbind and remove through dispose.
|
|
@@ -3710,6 +3941,8 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3710
3941
|
if (template) {
|
|
3711
3942
|
// If a new template was provided, render it.
|
|
3712
3943
|
this.view = template.render(element, host, element);
|
|
3944
|
+
this.view.sourceLifetime =
|
|
3945
|
+
SourceLifetime.coupled;
|
|
3713
3946
|
}
|
|
3714
3947
|
}
|
|
3715
3948
|
/**
|
|
@@ -3729,31 +3962,48 @@ class Controller extends PropertyChangeNotifier {
|
|
|
3729
3962
|
if (definition === void 0) {
|
|
3730
3963
|
throw FAST.error(1401 /* Message.missingElementDefinition */);
|
|
3731
3964
|
}
|
|
3732
|
-
return (element.$fastController = new
|
|
3965
|
+
return (element.$fastController = new ElementController(element, definition));
|
|
3733
3966
|
}
|
|
3734
3967
|
}
|
|
3735
3968
|
|
|
3736
3969
|
/* eslint-disable-next-line @typescript-eslint/explicit-function-return-type */
|
|
3737
3970
|
function createFASTElement(BaseType) {
|
|
3738
|
-
|
|
3971
|
+
const type = class extends BaseType {
|
|
3739
3972
|
constructor() {
|
|
3740
3973
|
/* eslint-disable-next-line */
|
|
3741
3974
|
super();
|
|
3742
|
-
|
|
3975
|
+
ElementController.forCustomElement(this);
|
|
3743
3976
|
}
|
|
3744
3977
|
$emit(type, detail, options) {
|
|
3745
3978
|
return this.$fastController.emit(type, detail, options);
|
|
3746
3979
|
}
|
|
3747
3980
|
connectedCallback() {
|
|
3748
|
-
this.$fastController.
|
|
3981
|
+
this.$fastController.connect();
|
|
3749
3982
|
}
|
|
3750
3983
|
disconnectedCallback() {
|
|
3751
|
-
this.$fastController.
|
|
3984
|
+
this.$fastController.disconnect();
|
|
3752
3985
|
}
|
|
3753
3986
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
3754
3987
|
this.$fastController.onAttributeChangedCallback(name, oldValue, newValue);
|
|
3755
3988
|
}
|
|
3756
3989
|
};
|
|
3990
|
+
FASTElementDefinition.registerBaseType(type);
|
|
3991
|
+
return type;
|
|
3992
|
+
}
|
|
3993
|
+
function compose(type, nameOrDef) {
|
|
3994
|
+
if (isFunction(type)) {
|
|
3995
|
+
return FASTElementDefinition.compose(type, nameOrDef);
|
|
3996
|
+
}
|
|
3997
|
+
return FASTElementDefinition.compose(this, type);
|
|
3998
|
+
}
|
|
3999
|
+
function define(type, nameOrDef) {
|
|
4000
|
+
if (isFunction(type)) {
|
|
4001
|
+
return FASTElementDefinition.compose(type, nameOrDef).define().type;
|
|
4002
|
+
}
|
|
4003
|
+
return FASTElementDefinition.compose(this, type).define().type;
|
|
4004
|
+
}
|
|
4005
|
+
function from(BaseType) {
|
|
4006
|
+
return createFASTElement(BaseType);
|
|
3757
4007
|
}
|
|
3758
4008
|
/**
|
|
3759
4009
|
* A minimal base class for FASTElements that also provides
|
|
@@ -3766,18 +4016,19 @@ const FASTElement = Object.assign(createFASTElement(HTMLElement), {
|
|
|
3766
4016
|
* provided base type.
|
|
3767
4017
|
* @param BaseType - The base element type to inherit from.
|
|
3768
4018
|
*/
|
|
3769
|
-
from
|
|
3770
|
-
return createFASTElement(BaseType);
|
|
3771
|
-
},
|
|
4019
|
+
from,
|
|
3772
4020
|
/**
|
|
3773
4021
|
* Defines a platform custom element based on the provided type and definition.
|
|
3774
4022
|
* @param type - The custom element type to define.
|
|
3775
4023
|
* @param nameOrDef - The name of the element to define or a definition object
|
|
3776
4024
|
* that describes the element to define.
|
|
3777
4025
|
*/
|
|
3778
|
-
define
|
|
3779
|
-
|
|
3780
|
-
|
|
4026
|
+
define,
|
|
4027
|
+
/**
|
|
4028
|
+
* Defines metadata for a FASTElement which can be used to later define the element.
|
|
4029
|
+
* @public
|
|
4030
|
+
*/
|
|
4031
|
+
compose,
|
|
3781
4032
|
});
|
|
3782
4033
|
/**
|
|
3783
4034
|
* Decorator: Defines a platform custom element based on `FASTElement`.
|
|
@@ -3788,8 +4039,8 @@ const FASTElement = Object.assign(createFASTElement(HTMLElement), {
|
|
|
3788
4039
|
function customElement(nameOrDef) {
|
|
3789
4040
|
/* eslint-disable-next-line @typescript-eslint/explicit-function-return-type */
|
|
3790
4041
|
return function (type) {
|
|
3791
|
-
|
|
4042
|
+
define(type, nameOrDef);
|
|
3792
4043
|
};
|
|
3793
4044
|
}
|
|
3794
4045
|
|
|
3795
|
-
export { AdoptedStyleSheetsStrategy, ArrayObserver, Aspect,
|
|
4046
|
+
export { AdoptedStyleSheetsStrategy, ArrayObserver, Aspect, AttributeConfiguration, AttributeDefinition, Binding, CSSDirective, ChildrenDirective, Compiler, DOM, ElementController, ElementStyles, ExecutionContext, FAST, FASTElement, FASTElementDefinition, HTMLBindingDirective, HTMLDirective, HTMLView, Markup, NodeObservationDirective, Observable, Parser, PropertyChangeNotifier, RefDirective, RepeatBehavior, RepeatDirective, SlottedDirective, SourceLifetime, Splice, SpliceStrategy, SpliceStrategySupport, StatelessAttachedAttributeDirective, SubscriberSet, Updates, ViewBehaviorOrchestrator, ViewTemplate, attr, bind, booleanConverter, children, createMetadataLocator, createTypeRegistry, css, cssDirective, cssPartial, customElement, elements, emptyArray, html, htmlDirective, lengthOf, listener, normalizeBinding, nullableNumberConverter, observable, oneTime, ref, repeat, slotted, volatile, when };
|