parent
d97994b27f
commit
a63fd2d0f5
|
@ -83,23 +83,23 @@ describe('i18n support in the view compiler', () => {
|
|||
$r3$.ɵi18nEnd();
|
||||
$r3$.ɵelementEnd();
|
||||
$r3$.ɵelementStart(2, "div");
|
||||
$r3$.ɵi18nAttribute(3, $_c2$);
|
||||
$r3$.ɵi18nAttributes(3, $_c2$);
|
||||
$r3$.ɵtext(4, "Content B");
|
||||
$r3$.ɵelementEnd();
|
||||
$r3$.ɵelementStart(5, "div");
|
||||
$r3$.ɵi18nAttribute(6, $_c4$);
|
||||
$r3$.ɵi18nAttributes(6, $_c4$);
|
||||
$r3$.ɵtext(7, "Content C");
|
||||
$r3$.ɵelementEnd();
|
||||
$r3$.ɵelementStart(8, "div");
|
||||
$r3$.ɵi18nAttribute(9, $_c6$);
|
||||
$r3$.ɵi18nAttributes(9, $_c6$);
|
||||
$r3$.ɵtext(10, "Content D");
|
||||
$r3$.ɵelementEnd();
|
||||
$r3$.ɵelementStart(11, "div");
|
||||
$r3$.ɵi18nAttribute(12, $_c8$);
|
||||
$r3$.ɵi18nAttributes(12, $_c8$);
|
||||
$r3$.ɵtext(13, "Content E");
|
||||
$r3$.ɵelementEnd();
|
||||
$r3$.ɵelementStart(14, "div");
|
||||
$r3$.ɵi18nAttribute(15, $_c10$);
|
||||
$r3$.ɵi18nAttributes(15, $_c10$);
|
||||
$r3$.ɵtext(16, "Content F");
|
||||
$r3$.ɵelementEnd();
|
||||
}
|
||||
|
@ -142,7 +142,7 @@ describe('i18n support in the view compiler', () => {
|
|||
template: function MyComponent_Template(rf, ctx) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵelementStart(0, "div", $_c0$);
|
||||
$r3$.ɵi18nAttribute(1, $_c2$);
|
||||
$r3$.ɵi18nAttributes(1, $_c2$);
|
||||
$r3$.ɵelementEnd();
|
||||
}
|
||||
}
|
||||
|
@ -207,10 +207,10 @@ describe('i18n support in the view compiler', () => {
|
|||
if (rf & 1) {
|
||||
$r3$.ɵelementStart(0, "div", $_c0$);
|
||||
$r3$.ɵpipe(1, "uppercase");
|
||||
$r3$.ɵi18nAttribute(2, $_c4$);
|
||||
$r3$.ɵi18nAttributes(2, $_c4$);
|
||||
$r3$.ɵelementEnd();
|
||||
$r3$.ɵelementStart(3, "div", $_c5$);
|
||||
$r3$.ɵi18nAttribute(4, $_c8$);
|
||||
$r3$.ɵi18nAttributes(4, $_c8$);
|
||||
$r3$.ɵelementEnd();
|
||||
}
|
||||
if (rf & 2) {
|
||||
|
@ -265,7 +265,7 @@ describe('i18n support in the view compiler', () => {
|
|||
$r3$.ɵelementStart(0, "div");
|
||||
$r3$.ɵelementStart(1, "div");
|
||||
$r3$.ɵpipe(2, "uppercase");
|
||||
$r3$.ɵi18nAttribute(3, $_c2$);
|
||||
$r3$.ɵi18nAttributes(3, $_c2$);
|
||||
$r3$.ɵelementEnd();
|
||||
$r3$.ɵelementEnd();
|
||||
}
|
||||
|
@ -345,10 +345,10 @@ describe('i18n support in the view compiler', () => {
|
|||
if (rf & 1) {
|
||||
$r3$.ɵelementStart(0, "div", $_c0$);
|
||||
$r3$.ɵpipe(1, "uppercase");
|
||||
$r3$.ɵi18nAttribute(2, $_c4$);
|
||||
$r3$.ɵi18nAttributes(2, $_c4$);
|
||||
$r3$.ɵelementEnd();
|
||||
$r3$.ɵelementStart(3, "div", $_c5$);
|
||||
$r3$.ɵi18nAttribute(4, $_c8$);
|
||||
$r3$.ɵi18nAttributes(4, $_c8$);
|
||||
$r3$.ɵelementEnd();
|
||||
}
|
||||
if (rf & 2) {
|
||||
|
@ -403,7 +403,7 @@ describe('i18n support in the view compiler', () => {
|
|||
$r3$.ɵelementStart(0, "div");
|
||||
$r3$.ɵelementStart(1, "div");
|
||||
$r3$.ɵpipe(2, "uppercase");
|
||||
$r3$.ɵi18nAttribute(3, $_c2$);
|
||||
$r3$.ɵi18nAttributes(3, $_c2$);
|
||||
$r3$.ɵelementEnd();
|
||||
$r3$.ɵelementEnd();
|
||||
}
|
||||
|
@ -693,7 +693,7 @@ describe('i18n support in the view compiler', () => {
|
|||
$r3$.ɵelementStart(0, "div");
|
||||
$r3$.ɵi18nStart(1, $MSG_APP_SPEC_TS_0$);
|
||||
$r3$.ɵelementStart(2, "span");
|
||||
$r3$.ɵi18nAttribute(3, $_c2$);
|
||||
$r3$.ɵi18nAttributes(3, $_c2$);
|
||||
$r3$.ɵelementEnd();
|
||||
$r3$.ɵi18nEnd();
|
||||
$r3$.ɵelementEnd();
|
||||
|
@ -701,7 +701,7 @@ describe('i18n support in the view compiler', () => {
|
|||
$r3$.ɵi18nStart(5, $MSG_APP_SPEC_TS_3$);
|
||||
$r3$.ɵpipe(6, "uppercase");
|
||||
$r3$.ɵelementStart(7, "span");
|
||||
$r3$.ɵi18nAttribute(8, $_c5$);
|
||||
$r3$.ɵi18nAttributes(8, $_c5$);
|
||||
$r3$.ɵelementEnd();
|
||||
$r3$.ɵi18nEnd();
|
||||
$r3$.ɵelementEnd();
|
||||
|
|
|
@ -95,7 +95,7 @@ export class Identifiers {
|
|||
static pipeBind4: o.ExternalReference = {name: 'ɵpipeBind4', moduleName: CORE};
|
||||
static pipeBindV: o.ExternalReference = {name: 'ɵpipeBindV', moduleName: CORE};
|
||||
|
||||
static i18nAttribute: o.ExternalReference = {name: 'ɵi18nAttribute', moduleName: CORE};
|
||||
static i18nAttributes: o.ExternalReference = {name: 'ɵi18nAttributes', moduleName: CORE};
|
||||
static i18nExp: o.ExternalReference = {name: 'ɵi18nExp', moduleName: CORE};
|
||||
static i18nStart: o.ExternalReference = {name: 'ɵi18nStart', moduleName: CORE};
|
||||
static i18nEnd: o.ExternalReference = {name: 'ɵi18nEnd', moduleName: CORE};
|
||||
|
|
|
@ -490,7 +490,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
|||
if (i18nAttrArgs.length) {
|
||||
const index: o.Expression = o.literal(this.allocateDataSlot());
|
||||
const args = this.constantPool.getConstLiteral(o.literalArr(i18nAttrArgs), true);
|
||||
this.creationInstruction(element.sourceSpan, R3.i18nAttribute, [index, args]);
|
||||
this.creationInstruction(element.sourceSpan, R3.i18nAttributes, [index, args]);
|
||||
if (hasBindings) {
|
||||
this.updateInstruction(element.sourceSpan, R3.i18nApply, [index]);
|
||||
}
|
||||
|
|
|
@ -107,24 +107,12 @@ export {
|
|||
PipeDef as ɵPipeDef,
|
||||
PipeDefWithMeta as ɵPipeDefWithMeta,
|
||||
whenRendered as ɵwhenRendered,
|
||||
i18nAttribute as ɵi18nAttribute,
|
||||
i18nAttributes as ɵi18nAttributes,
|
||||
i18nExp as ɵi18nExp,
|
||||
i18nStart as ɵi18nStart,
|
||||
i18nEnd as ɵi18nEnd,
|
||||
i18nApply as ɵi18nApply,
|
||||
i18nExpMapping as ɵi18nExpMapping,
|
||||
i18nInterpolation1 as ɵi18nInterpolation1,
|
||||
i18nInterpolation2 as ɵi18nInterpolation2,
|
||||
i18nInterpolation3 as ɵi18nInterpolation3,
|
||||
i18nInterpolation4 as ɵi18nInterpolation4,
|
||||
i18nInterpolation5 as ɵi18nInterpolation5,
|
||||
i18nInterpolation6 as ɵi18nInterpolation6,
|
||||
i18nInterpolation7 as ɵi18nInterpolation7,
|
||||
i18nInterpolation8 as ɵi18nInterpolation8,
|
||||
i18nInterpolationV as ɵi18nInterpolationV,
|
||||
i18nMapping as ɵi18nMapping,
|
||||
I18nInstruction as ɵI18nInstruction,
|
||||
I18nExpInstruction as ɵI18nExpInstruction,
|
||||
i18nIcuReplaceVars as ɵi18nIcuReplaceVars,
|
||||
WRAP_RENDERER_FACTORY2 as ɵWRAP_RENDERER_FACTORY2,
|
||||
setClassMetadata as ɵsetClassMetadata,
|
||||
} from './render3/index';
|
||||
|
|
|
@ -205,12 +205,12 @@ The goal is for the `@Component` (and friends) to be the compiler of template. S
|
|||
### I18N
|
||||
| Feature | Runtime | Spec | Compiler |
|
||||
| ----------------------------------- | ------- | -------- | -------- |
|
||||
| i18nStart | ❌ | ✅ | ✅ |
|
||||
| i18nEnd | ❌ | ✅ | ✅ |
|
||||
| i18nAttributes | ❌ | ✅ | ✅ |
|
||||
| i18nExp | ❌ | ✅ | ✅ |
|
||||
| i18nApply | ❌ | ✅ | ✅ |
|
||||
| ICU expressions | ❌ | ✅ | ❌ |
|
||||
| i18nStart | ✅ | ✅ | ✅ |
|
||||
| i18nEnd | ✅ | ✅ | ✅ |
|
||||
| i18nAttributes | ✅ | ✅ | ✅ |
|
||||
| i18nExp | ✅ | ✅ | ✅ |
|
||||
| i18nApply | ✅ | ✅ | ✅ |
|
||||
| ICU expressions | ✅ | ✅ | ❌ |
|
||||
| closure support for g3 | ✅ | ✅ | ❌ |
|
||||
| runtime service for external world | ❌ | ❌ | ❌ |
|
||||
| migration tool | ❌ | ❌ | ❌ |
|
||||
|
|
|
@ -12,11 +12,11 @@ For example index `123` may point to a component instance in the `LViewData` but
|
|||
The layout is as such:
|
||||
|
||||
| Section | `LViewData` | `TView.data`
|
||||
| ---------- | --------------------------------------------- | --------------------------------------------------
|
||||
| ---------- | ------------------------------------------------------------ | --------------------------------------------------
|
||||
| `HEADER` | contextual data | mostly `null`
|
||||
| `CONSTS` | DOM, pipe, and local ref instances |
|
||||
| `VARS` | binding values | property names
|
||||
| `EXPANDO` | host bindings; directive instances; providers | host prop names; directive tokens; provider tokens
|
||||
| `EXPANDO` | host bindings; directive instances; providers; dynamic nodes | host prop names; directive tokens; provider tokens; `null`
|
||||
|
||||
|
||||
## `HEADER`
|
||||
|
|
|
@ -23,7 +23,7 @@ class MyComponent {
|
|||
```
|
||||
NOTE:
|
||||
- There really is only two kinds of i18n text.
|
||||
1. In attribute as in `i18n-title`.
|
||||
1. In attribute as in `title` (with `i18n-title` present).
|
||||
2. In element body marked as as `<div i18n>`.
|
||||
- The element body i18n can have internal DOM structure which may consist of sub-templates.
|
||||
|
||||
|
@ -160,8 +160,8 @@ i18nAttributes(1, MSG_div_attr);
|
|||
```
|
||||
The above instruction checks the `TView.data` cache at position `1` and if empty will create `I18nUpdateOpCodes` like so:
|
||||
```typescript
|
||||
<I18nUpdateOpCodes>[
|
||||
// The following OpCodes represent: `<div i18n-title="Hello <20>0<EFBFBD>!">`
|
||||
const i18nUpdateOpCodes = <I18nUpdateOpCodes>[
|
||||
// The following OpCodes represent: `<div i18n-title title="Hello <20>0<EFBFBD>!">`
|
||||
// If `changeMask & 0b11`
|
||||
// has changed then execute update OpCodes.
|
||||
// has NOT changed then skip `7` values and start processing next OpCodes.
|
||||
|
@ -170,12 +170,13 @@ The above instruction checks the `TView.data` cache at position `1` and if empty
|
|||
'Hello ', // accumulate('Hello ');
|
||||
-1, // accumulate(-1);
|
||||
'!', // accumulate('!');
|
||||
// Update attribute: `elementAttribute(1, 'title', accumulatorFlush(null));`
|
||||
// Update attribute: `elementAttribute(0, 'title', accumulatorFlush(null));`
|
||||
// NOTE: `null` means don't sanitize
|
||||
1 << SHIFT_REF | Attr, 'title', null,
|
||||
0 << SHIFT_REF | Attr, 'title', null,
|
||||
]
|
||||
```
|
||||
NOTE:
|
||||
- `i18nAttributes` updates the attributes of the previous element.
|
||||
- If there is more than one attribute which needs to be internationalized it is added to the array as `[attributeName, translation]` tuple.
|
||||
- Even attributes which don't have bindings must go through `i18nAttributes` so that they correctly work with i18n in server environment.
|
||||
|
||||
|
@ -216,7 +217,7 @@ will generate
|
|||
```typescript
|
||||
// Text broken down to allow addition of comments (Generated code will not have comments)
|
||||
const MSG_div =
|
||||
'List: '
|
||||
'List: ' +
|
||||
'<27>*2:1<>' + // template(2, MyComponent_NgIf_Template_0, ...);
|
||||
'<27>#1:1<>' + // elementStart(1, 'ul');
|
||||
'<27>*2:2<>' + // template(2, MyComponent_NgIf_NgFor_Template_1, ...);
|
||||
|
@ -298,7 +299,7 @@ i18nEnd(); // The instruction which is responsible for inserting text node
|
|||
The `i18nStart` generates these instructions which are cached in the `TView` and then processed by `i18nEnd`.
|
||||
|
||||
```typescript
|
||||
<TI18n>{
|
||||
const tI18n = <TI18n>{
|
||||
vars: 2, // Number of slots to allocate in EXPANDO.
|
||||
expandoStartIndex: 100, // Assume in this example EXPANDO starts at 100
|
||||
create: <I18nMutateOpCodes>[ // Processed by `i18nEnd`
|
||||
|
@ -362,7 +363,7 @@ This case is more complex because it contains an ICU.
|
|||
ICUs are pre-parsed and then stored in the `TVIEW.data` as follows.
|
||||
|
||||
```typescript
|
||||
<TI18n>{
|
||||
const tI18n = <TI18n>{
|
||||
vars: 3 + Math.max(4, 3, 3), // Number of slots to allocate in EXPANDO. (Max of all ICUs + fixed)
|
||||
expandoStartIndex: 200, // Assume in this example EXPANDO starts at 200
|
||||
create: <I18nMutateOpCodes>[
|
||||
|
@ -379,16 +380,16 @@ ICUs are pre-parsed and then stored in the `TVIEW.data` as follows.
|
|||
// has NOT changed then skip `2` values and start processing next OpCodes.
|
||||
0b1, 2,
|
||||
-1, // accumulate(-1);
|
||||
// Switch ICU: `icuSwitchCase(lViewData[0 /*SHIFT_ICU*/], 0 /*SHIFT_REF*/, accumulatorFlush());`
|
||||
0 << SHIFT_ICU | 0 << SHIFT_REF | IcuSwitch,
|
||||
// Switch ICU: `icuSwitchCase(lViewData[200 /*SHIFT_REF*/], 0 /*SHIFT_ICU*/, accumulatorFlush());`
|
||||
200 << SHIFT_REF | 0 << SHIFT_ICU | IcuSwitch,
|
||||
|
||||
// NOTE: the bit mask here is the logical OR of all of the masks in the ICU.
|
||||
0b1, 1,
|
||||
// Update ICU: `icuUpdateCase(lViewData[0 /*SHIFT_ICU*/], 0 /*SHIFT_REF*/);`
|
||||
// SHIFT_ICU: points to: `i18nStart(0, MSG_div, 1);`
|
||||
// SHIFT_REF: is an index into which ICU is being updated. In our example we only have
|
||||
// Update ICU: `icuUpdateCase(lViewData[200 /*SHIFT_REF*/], 0 /*SHIFT_ICU*/);`
|
||||
// SHIFT_REF: points to: `i18nStart(0, MSG_div, 1);`
|
||||
// SHIFT_ICU: is an index into which ICU is being updated. In our example we only have
|
||||
// one ICU so it is 0-th ICU to update.
|
||||
0 << SHIFT_ICU | 0 << SHIFT_REF | IcuUpdate,
|
||||
200 << SHIFT_REF | 0 << SHIFT_ICU | IcuUpdate,
|
||||
],
|
||||
icus: [
|
||||
<TIcu>{
|
||||
|
@ -544,7 +545,7 @@ The OpCodes require that offsets for the EXPANDO index for the reference.
|
|||
The question is how do we compute this:
|
||||
|
||||
```typescript
|
||||
<TI18n>{
|
||||
const tI18n = <TI18n>{
|
||||
vars: 1,
|
||||
expandoStartIndex: 100, // Retrieved from `tView.blueprint.length` at i18nStart invocation.
|
||||
create: <I18nMutateOpCodes>[
|
||||
|
@ -623,7 +624,7 @@ The rules for attribute ICUs should be the same as for normal ICUs.
|
|||
For this reason we would like to reuse as much code as possible for parsing and processing of the ICU for simplicity and consistency.
|
||||
|
||||
```typescript
|
||||
<TI18n>{
|
||||
const tI18n = <TI18n>{
|
||||
vars: 0, // Number of slots to allocate in EXPANDO. (Max of all ICUs + fixed)
|
||||
expandoStartIndex: 200, // Assume in this example EXPANDO starts at 200
|
||||
create: <I18nMutateOpCodes>[
|
||||
|
@ -635,18 +636,18 @@ For this reason we would like to reuse as much code as possible for parsing and
|
|||
// has NOT changed then skip `2` values and start processing next OpCodes.
|
||||
0b1, 2,
|
||||
-1, // accumulate(-1)
|
||||
// Switch ICU: `icuSwitchCase(lViewData[0 /*SHIFT_ICU*/], 0 /*SHIFT_REF*/, accumulatorFlush());`
|
||||
0 << SHIFT_ICU | 0 << SHIFT_REF | IcuSwitch,
|
||||
// Switch ICU: `icuSwitchCase(lViewData[200 /*SHIFT_REF*/], 0 /*SHIFT_ICU*/, accumulatorFlush());`
|
||||
200 << SHIFT_REF | 0 << SHIFT_ICU | IcuSwitch,
|
||||
|
||||
// NOTE: the bit mask here is the logical OR of all of the masks in the ICU.
|
||||
0b1, 4,
|
||||
'You have ', // accumulate('You have ');
|
||||
|
||||
// Update ICU: `icuUpdateCase(lViewData[0 /*SHIFT_ICU*/], 0 /*SHIFT_REF*/);`
|
||||
// SHIFT_ICU: points to: `i18nStart(0, MSG_div, 1);`
|
||||
// SHIFT_REF: is an index into which ICU is being updated. In our example we only have
|
||||
// Update ICU: `icuUpdateCase(lViewData[200 /*SHIFT_REF*/], 0 /*SHIFT_ICU*/);`
|
||||
// SHIFT_REF: points to: `i18nStart(0, MSG_div, 1);`
|
||||
// SHIFT_ICU: is an index into which ICU is being updated. In our example we only have
|
||||
// one ICU so it is 0-th ICU to update.
|
||||
0 << SHIFT_ICU | 0 << SHIFT_REF | IcuUpdate,
|
||||
200 << SHIFT_REF | 0 << SHIFT_ICU | IcuUpdate,
|
||||
|
||||
'.', // accumulate('.');
|
||||
|
||||
|
@ -699,7 +700,7 @@ For this reason we would like to reuse as much code as possible for parsing and
|
|||
// has changed then execute update OpCodes.
|
||||
// has NOT changed then skip `1` values and start processing next OpCodes.
|
||||
-1, 2,
|
||||
-1, // accumulate(lviewData[bindIndex-1]);
|
||||
-1, // accumulate(lViewData[bindIndex-1]);
|
||||
'emails', // accumulate('no emails');
|
||||
]
|
||||
]
|
||||
|
@ -724,7 +725,7 @@ Given
|
|||
```
|
||||
The above needs to be parsed into:
|
||||
```TypeScript
|
||||
{
|
||||
const icu = {
|
||||
type: 'plural', // or 'select'
|
||||
expressionBindingIndex: 0, // from <20>0<EFBFBD>,
|
||||
cases: [
|
||||
|
@ -757,7 +758,7 @@ NOTE: The updates to attributes with placeholders require that we go through san
|
|||
|
||||
## Translation without top level element
|
||||
|
||||
Placing `i18n` attribute on an existing elements is easy because the element defines parent and the translated element can be insert synchronously.
|
||||
Placing `i18n` attribute on an existing elements is easy because the element defines parent and the translated element can be inserted synchronously.
|
||||
For virtual elements such as `<ng-container>` or `<ng-template>` this is more complicated because there is no common root element to insert into.
|
||||
In such a case the `i18nStart` acts as the element to insert into.
|
||||
This is similar to `<ng-container>` behavior.
|
||||
|
@ -783,7 +784,7 @@ function MyComponent_Template_0(rf: RenderFlags, ctx: any) {
|
|||
|
||||
Which would get parsed into:
|
||||
```typescript
|
||||
<TI18n>{
|
||||
const tI18n = <TI18n>{
|
||||
vars: 2, // Number of slots to allocate in EXPANDO.
|
||||
expandoStartIndex: 100, // Assume in this example EXPANDO starts at 100
|
||||
create: <I18nMutateOpCodes>[ // Processed by `i18nEnd`
|
||||
|
@ -869,7 +870,7 @@ NOTE:
|
|||
|
||||
The internal data structure will be:
|
||||
```typescript
|
||||
<TI18n>{
|
||||
const tI18n = <TI18n>{
|
||||
vars: 2, // Number of slots to allocate in EXPANDO.
|
||||
expandoStartIndex: 100, // Assume in this example EXPANDO starts at 100
|
||||
create: <I18nMutateOpCodes>[ // Processed by `i18nEnd`
|
||||
|
@ -881,16 +882,16 @@ The internal data structure will be:
|
|||
// has NOT changed then skip `2` values and start processing next OpCodes.
|
||||
0b1, 2,
|
||||
-1, // accumulate(-1);
|
||||
// Switch ICU: `icuSwitchCase(lViewData[0 /*SHIFT_ICU*/], 0 /*SHIFT_REF*/, accumulatorFlush());`
|
||||
0 << SHIFT_ICU | 0 << SHIFT_REF | IcuSwitch,
|
||||
// Switch ICU: `icuSwitchCase(lViewData[100 /*SHIFT_REF*/], 0 /*SHIFT_ICU*/, accumulatorFlush());`
|
||||
100 << SHIFT_REF | 0 << SHIFT_ICU | IcuSwitch,
|
||||
|
||||
// NOTE: the bit mask here is the logical OR of all of the masks in the ICU.
|
||||
0b1, 1,
|
||||
// Update ICU: `icuUpdateCase(lViewData[0 /*SHIFT_ICU*/], 0 /*SHIFT_REF*/);`
|
||||
// SHIFT_ICU: points to: `i18nStart(0, MSG_div, 1);`
|
||||
// SHIFT_REF: is an index into which ICU is being updated. In our example we only have
|
||||
// Update ICU: `icuUpdateCase(lViewData[100 /*SHIFT_REF*/], 0 /*SHIFT_ICU*/);`
|
||||
// SHIFT_REF: points to: `i18nStart(0, MSG_div, 1);`
|
||||
// SHIFT_ICU: is an index into which ICU is being updated. In our example we only have
|
||||
// one ICU so it is 0-th ICU to update.
|
||||
0 << SHIFT_ICU | 0 << SHIFT_REF | IcuUpdate,
|
||||
100 << SHIFT_REF | 0 << SHIFT_ICU | IcuUpdate,
|
||||
],
|
||||
icus: [
|
||||
<TIcu>{ // {<7B>0<EFBFBD>, plural, =0 {zero} other {<7B>0<EFBFBD> <!--subICU-->}}
|
||||
|
@ -906,7 +907,7 @@ The internal data structure will be:
|
|||
'', 1 << SHIFT_PARENT | AppendChild, // Expando location: 100
|
||||
COMMENT_MARKER, '', 0 << SHIFT_PARENT | AppendChild, // Expando location: 101
|
||||
],
|
||||
]
|
||||
],
|
||||
remove: [
|
||||
<I18nMutateOpCodes>[ // Case: `0`: `{zero}`
|
||||
1 << SHIFT_PARENT | 100 << SHIFT_REF | Remove,
|
||||
|
@ -921,16 +922,16 @@ The internal data structure will be:
|
|||
],
|
||||
<I18nMutateOpCodes>[ // Case: `other`: `{<7B>0<EFBFBD> <!--subICU-->}`
|
||||
0b1, 3,
|
||||
-2, ' ', 100 << SHIFT_REF | Text // Case: `<60>0<EFBFBD> `
|
||||
-2, ' ', 100 << SHIFT_REF | Text, // Case: `<60>0<EFBFBD> `
|
||||
0b10, 5,
|
||||
-1
|
||||
// Switch ICU: `icuSwitchCase(lViewData[0 /*SHIFT_ICU*/], 1 /*SHIFT_REF*/, accumulatorFlush());`
|
||||
0 << SHIFT_ICU | 1 << SHIFT_REF | IcuSwitch,
|
||||
-1,
|
||||
// Switch ICU: `icuSwitchCase(lViewData[101 /*SHIFT_REF*/], 0 /*SHIFT_ICU*/, accumulatorFlush());`
|
||||
101 << SHIFT_REF | 0 << SHIFT_ICU | IcuSwitch,
|
||||
|
||||
// NOTE: the bit mask here is the logical OR of all of the masks int the ICU.
|
||||
0b10, 1,
|
||||
// Update ICU: `icuUpdateCase(lViewData[0 /*SHIFT_ICU*/], 1 /*SHIFT_REF*/);`
|
||||
0 << SHIFT_ICU | 1 << SHIFT_REF | IcuUpdate,
|
||||
// Update ICU: `icuUpdateCase(lViewData[101 /*SHIFT_REF*/], 0 /*SHIFT_ICU*/);`
|
||||
101 << SHIFT_REF | 0 << SHIFT_ICU | IcuUpdate,
|
||||
],
|
||||
]
|
||||
},
|
||||
|
@ -1057,7 +1058,7 @@ Here is a more complete example.
|
|||
|
||||
Given this Angular's template:
|
||||
```HTML
|
||||
<div i18n-title="Hello {{name}}!" i18n="Some description.">
|
||||
<div i18n-title title="Hello {{name}}!" i18n="Some description.">
|
||||
{{count}} is rendered as:
|
||||
<b *ngIf="true">
|
||||
{ count, plural,
|
||||
|
@ -1111,7 +1112,7 @@ To generate code where the extracted i18n messages have the same ids, the `ngtsc
|
|||
|
||||
Given this Angular's template:
|
||||
```HTML
|
||||
<div i18n-title="Hello {{name}}!" i18n="Some description.">
|
||||
<div i18n-title title="Hello {{name}}!" i18n="Some description.">
|
||||
{{count}} is rendered as:
|
||||
<b *ngIf="true">
|
||||
{ count, plural,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -87,24 +87,12 @@ export {
|
|||
} from './state';
|
||||
|
||||
export {
|
||||
i18nAttribute,
|
||||
i18nAttributes,
|
||||
i18nExp,
|
||||
i18nStart,
|
||||
i18nEnd,
|
||||
i18nApply,
|
||||
i18nMapping,
|
||||
i18nInterpolation1,
|
||||
i18nInterpolation2,
|
||||
i18nInterpolation3,
|
||||
i18nInterpolation4,
|
||||
i18nInterpolation5,
|
||||
i18nInterpolation6,
|
||||
i18nInterpolation7,
|
||||
i18nInterpolation8,
|
||||
i18nInterpolationV,
|
||||
i18nExpMapping,
|
||||
I18nInstruction,
|
||||
I18nExpInstruction
|
||||
i18nIcuReplaceVars,
|
||||
} from './i18n';
|
||||
|
||||
export {NgModuleFactory, NgModuleRef, NgModuleType} from './ng_module_ref';
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
*/
|
||||
|
||||
import './ng_dev_mode';
|
||||
|
||||
import {resolveForwardRef} from '../di/forward_ref';
|
||||
import {InjectionToken} from '../di/injection_token';
|
||||
import {InjectFlags} from '../di/injector_compatibility';
|
||||
|
@ -16,7 +15,6 @@ import {Sanitizer} from '../sanitization/security';
|
|||
import {StyleSanitizeFn} from '../sanitization/style_sanitizer';
|
||||
import {Type} from '../type';
|
||||
import {noop} from '../util/noop';
|
||||
|
||||
import {assertDefined, assertEqual, assertLessThan, assertNotEqual} from './assert';
|
||||
import {attachPatchData, getComponentViewByInstance} from './context_discovery';
|
||||
import {diPublicInInjector, getNodeInjectable, getOrCreateInjectable, getOrCreateNodeInjectorForNode, injectAttributeImpl} from './di';
|
||||
|
@ -25,11 +23,12 @@ import {executeHooks, executeInitHooks, queueInitHooks, queueLifecycleHooks} fro
|
|||
import {ACTIVE_INDEX, LContainer, VIEWS} from './interfaces/container';
|
||||
import {ComponentDef, ComponentQuery, ComponentTemplate, DirectiveDef, DirectiveDefListOrFactory, InitialStylingFlags, PipeDefListOrFactory, RenderFlags} from './interfaces/definition';
|
||||
import {INJECTOR_SIZE, NodeInjectorFactory} from './interfaces/injector';
|
||||
import {AttributeMarker, InitialInputData, InitialInputs, LocalRefExtractor, PropertyAliasValue, PropertyAliases, TAttributes, TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeProviderIndexes, TNodeType, TProjectionNode, TViewNode} from './interfaces/node';
|
||||
import {AttributeMarker, InitialInputData, InitialInputs, LocalRefExtractor, PropertyAliasValue, PropertyAliases, TAttributes, TContainerNode, TElementContainerNode, TElementNode, TIcuContainerNode, TNode, TNodeFlags, TNodeProviderIndexes, TNodeType, TProjectionNode, TViewNode} from './interfaces/node';
|
||||
import {PlayerFactory} from './interfaces/player';
|
||||
import {CssSelectorList, NG_PROJECT_AS_ATTR_NAME} from './interfaces/projection';
|
||||
import {LQueries} from './interfaces/query';
|
||||
import {ProceduralRenderer3, RComment, RElement, RNode, RText, Renderer3, RendererFactory3, isProceduralRenderer} from './interfaces/renderer';
|
||||
import {SanitizerFn} from './interfaces/sanitization';
|
||||
import {StylingIndex} from './interfaces/styling';
|
||||
import {BINDING_INDEX, CLEANUP, CONTAINER_INDEX, CONTENT_QUERIES, CONTEXT, DECLARATION_VIEW, FLAGS, HEADER_OFFSET, HOST, HOST_NODE, INJECTOR, LViewData, LViewFlags, NEXT, OpaqueViewState, PARENT, QUERIES, RENDERER, RootContext, RootContextFlags, SANITIZER, TAIL, TVIEW, TView} from './interfaces/view';
|
||||
import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert';
|
||||
|
@ -42,7 +41,6 @@ import {getStylingContext} from './styling/util';
|
|||
import {NO_CHANGE} from './tokens';
|
||||
import {getComponentViewByIndex, getNativeByIndex, getNativeByTNode, getRootContext, getRootView, getTNode, isComponent, isComponentDef, isDifferent, loadInternal, readPatchedLViewData, stringify} from './util';
|
||||
|
||||
|
||||
/**
|
||||
* A permanent marker promise which signifies that the current CD tree is
|
||||
* clean.
|
||||
|
@ -54,11 +52,6 @@ const enum BindingDirection {
|
|||
Output,
|
||||
}
|
||||
|
||||
/**
|
||||
* Function used to sanitize the value before writing it into the renderer.
|
||||
*/
|
||||
type SanitizerFn = (value: any) => string;
|
||||
|
||||
/**
|
||||
* Refreshes the view, executing the following steps in that order:
|
||||
* triggers init hooks, refreshes dynamic embedded views, triggers content hooks, sets host
|
||||
|
@ -197,9 +190,13 @@ export function createNodeAtIndex(
|
|||
export function createNodeAtIndex(
|
||||
index: number, type: TNodeType.ElementContainer, native: RComment, name: null,
|
||||
attrs: TAttributes | null): TElementContainerNode;
|
||||
export function createNodeAtIndex(
|
||||
index: number, type: TNodeType.IcuContainer, native: RComment, name: null,
|
||||
attrs: TAttributes | null): TElementContainerNode;
|
||||
export function createNodeAtIndex(
|
||||
index: number, type: TNodeType, native: RText | RElement | RComment | null, name: string | null,
|
||||
attrs: TAttributes | null): TElementNode&TContainerNode&TElementContainerNode&TProjectionNode {
|
||||
attrs: TAttributes | null): TElementNode&TContainerNode&TElementContainerNode&TProjectionNode&
|
||||
TIcuContainerNode {
|
||||
const viewData = getViewData();
|
||||
const tView = getTView();
|
||||
const adjustedIndex = index + HEADER_OFFSET;
|
||||
|
@ -233,7 +230,7 @@ export function createNodeAtIndex(
|
|||
setPreviousOrParentTNode(tNode);
|
||||
setIsParent(true);
|
||||
return tNode as TElementNode & TViewNode & TContainerNode & TElementContainerNode &
|
||||
TProjectionNode;
|
||||
TProjectionNode & TIcuContainerNode;
|
||||
}
|
||||
|
||||
export function createViewNode(index: number, view: LViewData) {
|
||||
|
@ -255,11 +252,12 @@ export function createViewNode(index: number, view: LViewData) {
|
|||
* i18nApply() or ComponentFactory.create), we need to adjust the blueprint for future
|
||||
* template passes.
|
||||
*/
|
||||
export function adjustBlueprintForNewNode(view: LViewData) {
|
||||
export function allocExpando(view: LViewData) {
|
||||
const tView = view[TVIEW];
|
||||
if (tView.firstTemplatePass) {
|
||||
tView.expandoStartIndex++;
|
||||
tView.blueprint.push(null);
|
||||
tView.data.push(null);
|
||||
view.push(null);
|
||||
}
|
||||
}
|
||||
|
@ -914,7 +912,7 @@ export function elementEnd(): void {
|
|||
* @param sanitizer An optional function used to sanitize the value.
|
||||
*/
|
||||
export function elementAttribute(
|
||||
index: number, name: string, value: any, sanitizer?: SanitizerFn): void {
|
||||
index: number, name: string, value: any, sanitizer?: SanitizerFn | null): void {
|
||||
if (value !== NO_CHANGE) {
|
||||
const viewData = getViewData();
|
||||
const renderer = getRenderer();
|
||||
|
@ -947,7 +945,7 @@ export function elementAttribute(
|
|||
*/
|
||||
|
||||
export function elementProperty<T>(
|
||||
index: number, propName: string, value: T | NO_CHANGE, sanitizer?: SanitizerFn): void {
|
||||
index: number, propName: string, value: T | NO_CHANGE, sanitizer?: SanitizerFn | null): void {
|
||||
if (value === NO_CHANGE) return;
|
||||
const viewData = getViewData();
|
||||
const element = getNativeByIndex(index, viewData) as RElement | RComment;
|
||||
|
|
|
@ -16,24 +16,32 @@
|
|||
*
|
||||
* See: `I18nCreateOpCodes` for example of usage.
|
||||
*/
|
||||
import {SanitizerFn} from './sanitization';
|
||||
|
||||
export const enum I18nMutateOpCode {
|
||||
/// Stores shift amount for bits 17-2 that contain reference index.
|
||||
SHIFT_REF = 2,
|
||||
/// Stores shift amount for bits 17-3 that contain reference index.
|
||||
SHIFT_REF = 3,
|
||||
/// Stores shift amount for bits 31-17 that contain parent index.
|
||||
SHIFT_PARENT = 17,
|
||||
/// Mask for OpCode
|
||||
MASK_OPCODE = 0b11,
|
||||
MASK_OPCODE = 0b111,
|
||||
/// Mask for reference index.
|
||||
MASK_REF = ((2 ^ 16) - 1) << SHIFT_REF,
|
||||
|
||||
/// OpCode to select a node. (next OpCode will contain the operation.)
|
||||
Select = 0b00,
|
||||
Select = 0b000,
|
||||
/// OpCode to append the current node to `PARENT`.
|
||||
AppendChild = 0b01,
|
||||
AppendChild = 0b001,
|
||||
/// OpCode to insert the current node to `PARENT` before `REF`.
|
||||
InsertBefore = 0b10,
|
||||
InsertBefore = 0b010,
|
||||
/// OpCode to remove the `REF` node from `PARENT`.
|
||||
Remove = 0b11,
|
||||
Remove = 0b011,
|
||||
/// OpCode to set the attribute of a node.
|
||||
Attr = 0b100,
|
||||
/// OpCode to simulate elementEnd()
|
||||
ElementEnd = 0b101,
|
||||
/// OpCode to read the remove OpCodes for the nested ICU
|
||||
RemoveNestedIcu = 0b110,
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -114,8 +122,8 @@ export interface COMMENT_MARKER { marker: 'comment'; }
|
|||
* // For removing existing nodes
|
||||
* // --------------------------------------------------
|
||||
* // const node = lViewData[1];
|
||||
* // lViewData[2].remove(node);
|
||||
* 2 << SHIFT_PARENT | 1 << SHIFT_REF | Remove,
|
||||
* // removeChild(tView.data(1), node, lViewData);
|
||||
* 1 << SHIFT_REF | Remove,
|
||||
*
|
||||
* // For writing attributes
|
||||
* // --------------------------------------------------
|
||||
|
@ -178,7 +186,7 @@ export const enum I18nUpdateOpCode {
|
|||
* }
|
||||
* ```
|
||||
* We can assume that each call to `i18nExp` sets an internal `changeMask` bit depending on the
|
||||
* index of `i18nExp` index.
|
||||
* index of `i18nExp`.
|
||||
*
|
||||
* OpCodes
|
||||
* ```
|
||||
|
@ -222,7 +230,7 @@ export const enum I18nUpdateOpCode {
|
|||
* ```
|
||||
*
|
||||
*/
|
||||
export interface I18nUpdateOpCodes extends Array<string|number|((text: string) => string | null)> {}
|
||||
export interface I18nUpdateOpCodes extends Array<string|number|SanitizerFn|null> {}
|
||||
|
||||
/**
|
||||
* Store information for the i18n translation block.
|
||||
|
@ -355,10 +363,6 @@ export interface TIcu {
|
|||
update: I18nUpdateOpCodes[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores currently selected case in each ICU.
|
||||
*
|
||||
* For each ICU in translation, the `Li18n` stores the currently selected case for the current
|
||||
* `LView`. For perf reasons this array is only created if a translation block has an ICU.
|
||||
*/
|
||||
export interface LI18n extends Array<number> {}
|
||||
// Note: This hack is necessary so we don't erroneously get a circular dependency
|
||||
// failure based on types.
|
||||
export const unusedValueExportToPlacateAjd = 1;
|
||||
|
|
|
@ -21,6 +21,7 @@ export const enum TNodeType {
|
|||
Element = 0b011,
|
||||
ViewOrElement = 0b010,
|
||||
ElementContainer = 0b100,
|
||||
IcuContainer = 0b101,
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -255,7 +256,7 @@ export interface TNode {
|
|||
parent: TElementNode|TContainerNode|null;
|
||||
|
||||
/**
|
||||
* If this node is part of an i18n block, it indicates whether this container is part of the DOM
|
||||
* If this node is part of an i18n block, it indicates whether this node is part of the DOM.
|
||||
* If this node is not part of an i18n block, this field is null.
|
||||
*/
|
||||
detached: boolean|null;
|
||||
|
@ -358,7 +359,6 @@ export interface TContainerNode extends TNode {
|
|||
projection: null;
|
||||
}
|
||||
|
||||
|
||||
/** Static data for an <ng-container> */
|
||||
export interface TElementContainerNode extends TNode {
|
||||
/** Index in the LViewData[] array. */
|
||||
|
@ -369,6 +369,21 @@ export interface TElementContainerNode extends TNode {
|
|||
projection: null;
|
||||
}
|
||||
|
||||
/** Static data for an ICU expression */
|
||||
export interface TIcuContainerNode extends TNode {
|
||||
/** Index in the LViewData[] array. */
|
||||
index: number;
|
||||
child: TElementNode|TTextNode|null;
|
||||
parent: TElementNode|TElementContainerNode|null;
|
||||
tViews: null;
|
||||
projection: null;
|
||||
/**
|
||||
* Indicates the current active case for an ICU expression.
|
||||
* It is null when there is no active case.
|
||||
*/
|
||||
activeCaseIndex: number|null;
|
||||
}
|
||||
|
||||
/** Static data for a view */
|
||||
export interface TViewNode extends TNode {
|
||||
/** If -1, it's a dynamically created view. Otherwise, it is the view block ID. */
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
/**
|
||||
* Function used to sanitize the value before writing it into the renderer.
|
||||
*/
|
||||
export type SanitizerFn = (value: any) => string;
|
|
@ -11,9 +11,9 @@ import {Injector} from '../../di/injector';
|
|||
import {QueryList} from '../../linker';
|
||||
import {Sanitizer} from '../../sanitization/security';
|
||||
import {Type} from '../../type';
|
||||
|
||||
import {LContainer} from './container';
|
||||
import {ComponentDef, ComponentQuery, ComponentTemplate, DirectiveDef, DirectiveDefList, HostBindingsFunction, PipeDef, PipeDefList} from './definition';
|
||||
import {I18nUpdateOpCodes, TI18n} from './i18n';
|
||||
import {TElementNode, TNode, TViewNode} from './node';
|
||||
import {PlayerHandler} from './player';
|
||||
import {LQueries} from './query';
|
||||
|
@ -297,7 +297,7 @@ export interface TView {
|
|||
/** Whether or not this template has been processed. */
|
||||
firstTemplatePass: boolean;
|
||||
|
||||
/** Static data equivalent of LView.data[]. Contains TNodes. */
|
||||
/** Static data equivalent of LView.data[]. Contains TNodes, PipeDefInternal or TI18n. */
|
||||
data: TData;
|
||||
|
||||
/**
|
||||
|
@ -535,7 +535,7 @@ export type HookData = (number | (() => void))[];
|
|||
*/
|
||||
export type TData =
|
||||
(TNode | PipeDef<any>| DirectiveDef<any>| ComponentDef<any>| number | Type<any>|
|
||||
InjectionToken<any>| null)[];
|
||||
InjectionToken<any>| TI18n | I18nUpdateOpCodes | null)[];
|
||||
|
||||
// Note: This hack is necessary so we don't erroneously get a circular dependency
|
||||
// failure based on types.
|
||||
|
|
|
@ -97,7 +97,7 @@ export const angularCoreEnv: {[name: string]: Function} = {
|
|||
'ɵtextBinding': r3.textBinding,
|
||||
'ɵembeddedViewStart': r3.embeddedViewStart,
|
||||
'ɵembeddedViewEnd': r3.embeddedViewEnd,
|
||||
'ɵi18nAttribute': r3.i18nAttribute,
|
||||
'ɵi18nAttributes': r3.i18nAttributes,
|
||||
'ɵi18nExp': r3.i18nExp,
|
||||
'ɵi18nStart': r3.i18nStart,
|
||||
'ɵi18nEnd': r3.i18nEnd,
|
||||
|
|
|
@ -21,8 +21,23 @@ const unusedValueToPlacateAjd = unused1 + unused2 + unused3 + unused4 + unused5;
|
|||
|
||||
/** Retrieves the parent element of a given node. */
|
||||
export function getParentNative(tNode: TNode, currentView: LViewData): RElement|RComment|null {
|
||||
return tNode.parent == null ? getHostNative(currentView) :
|
||||
getNativeByTNode(tNode.parent, currentView);
|
||||
if (tNode.parent == null) {
|
||||
return getHostNative(currentView);
|
||||
} else {
|
||||
const parentTNode = getFirstParentNative(tNode);
|
||||
return getNativeByTNode(parentTNode, currentView);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first parent of a node that isn't an IcuContainer TNode
|
||||
*/
|
||||
function getFirstParentNative(tNode: TNode): TNode {
|
||||
let parent = tNode.parent;
|
||||
while (parent && parent.type === TNodeType.IcuContainer) {
|
||||
parent = parent.parent;
|
||||
}
|
||||
return parent !;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -578,17 +593,22 @@ function canInsertNativeChildOfView(viewTNode: TViewNode, view: LViewData): bool
|
|||
*
|
||||
|
||||
*
|
||||
* @param parent The parent where the child will be inserted into.
|
||||
* @param tNode The tNode of the node that we want to insert.
|
||||
* @param currentView Current LView being processed.
|
||||
* @return boolean Whether the child should be inserted now (or delayed until later).
|
||||
* @return boolean Whether the node should be inserted now (or delayed until later).
|
||||
*/
|
||||
export function canInsertNativeNode(tNode: TNode, currentView: LViewData): boolean {
|
||||
let currentNode = tNode;
|
||||
let parent: TNode|null = tNode.parent;
|
||||
|
||||
if (tNode.parent && tNode.parent.type === TNodeType.ElementContainer) {
|
||||
if (tNode.parent) {
|
||||
if (tNode.parent.type === TNodeType.ElementContainer) {
|
||||
currentNode = getHighestElementContainer(tNode);
|
||||
parent = currentNode.parent;
|
||||
} else if (tNode.parent.type === TNodeType.IcuContainer) {
|
||||
currentNode = getFirstParentNative(currentNode);
|
||||
parent = currentNode.parent;
|
||||
}
|
||||
}
|
||||
if (parent === null) parent = currentView[HOST_NODE];
|
||||
|
||||
|
@ -639,7 +659,7 @@ export function nativeNextSibling(renderer: Renderer3, node: RNode): RNode|null
|
|||
* @returns Whether or not the child was appended
|
||||
*/
|
||||
export function appendChild(
|
||||
childEl: RNode | null, childTNode: TNode, currentView: LViewData): boolean {
|
||||
childEl: RNode | null = null, childTNode: TNode, currentView: LViewData): boolean {
|
||||
if (childEl !== null && canInsertNativeNode(childTNode, currentView)) {
|
||||
const renderer = currentView[RENDERER];
|
||||
const parentEl = getParentNative(childTNode, currentView);
|
||||
|
@ -655,6 +675,9 @@ export function appendChild(
|
|||
} else if (parentTNode.type === TNodeType.ElementContainer) {
|
||||
const renderParent = getRenderParent(childTNode, currentView) !;
|
||||
nativeInsertBefore(renderer, renderParent, childEl, parentEl);
|
||||
} else if (parentTNode.type === TNodeType.IcuContainer) {
|
||||
const icuAnchorNode = getNativeByTNode(childTNode.parent !, currentView) !as RElement;
|
||||
nativeInsertBefore(renderer, parentEl as RElement, childEl, icuAnchorNode);
|
||||
} else {
|
||||
isProceduralRenderer(renderer) ? renderer.appendChild(parentEl !as RElement, childEl) :
|
||||
parentEl !.appendChild(childEl);
|
||||
|
|
|
@ -157,6 +157,10 @@ export function getCurrentView(): OpaqueViewState {
|
|||
return viewData as any as OpaqueViewState;
|
||||
}
|
||||
|
||||
export function _getViewData(): LViewData {
|
||||
return viewData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores `contextViewData` to the given OpaqueViewState instance.
|
||||
*
|
||||
|
|
|
@ -250,3 +250,15 @@ export const defaultScheduler =
|
|||
(typeof requestAnimationFrame !== 'undefined' && requestAnimationFrame || // browser only
|
||||
setTimeout // everything else
|
||||
).bind(global);
|
||||
|
||||
/**
|
||||
* Equivalent to ES6 spread, add each item to an array.
|
||||
*
|
||||
* @param items The items to add
|
||||
* @param arr The array to which you want to add the items
|
||||
*/
|
||||
export function addAllToArray(items: any[], arr: any[]) {
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
arr.push(items[i]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,14 +57,14 @@ const INLINE_ELEMENTS = merge(
|
|||
'bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,picture,q,ruby,rp,rt,s,' +
|
||||
'samp,small,source,span,strike,strong,sub,sup,time,track,tt,u,var,video'));
|
||||
|
||||
const VALID_ELEMENTS =
|
||||
export const VALID_ELEMENTS =
|
||||
merge(VOID_ELEMENTS, BLOCK_ELEMENTS, INLINE_ELEMENTS, OPTIONAL_END_TAG_ELEMENTS);
|
||||
|
||||
// Attributes that have href and hence need to be sanitized
|
||||
const URI_ATTRS = tagSet('background,cite,href,itemtype,longdesc,poster,src,xlink:href');
|
||||
export const URI_ATTRS = tagSet('background,cite,href,itemtype,longdesc,poster,src,xlink:href');
|
||||
|
||||
// Attributes that have special href set hence need to be sanitized
|
||||
const SRCSET_ATTRS = tagSet('srcset');
|
||||
export const SRCSET_ATTRS = tagSet('srcset');
|
||||
|
||||
const HTML_ATTRS = tagSet(
|
||||
'abbr,accesskey,align,alt,autoplay,axis,bgcolor,border,cellpadding,cellspacing,class,clear,color,cols,colspan,' +
|
||||
|
@ -81,7 +81,7 @@ const HTML_ATTRS = tagSet(
|
|||
// can be sanitized, but they increase security surface area without a legitimate use case, so they
|
||||
// are left out here.
|
||||
|
||||
const VALID_ATTRS = merge(URI_ATTRS, SRCSET_ATTRS, HTML_ATTRS);
|
||||
export const VALID_ATTRS = merge(URI_ATTRS, SRCSET_ATTRS, HTML_ATTRS);
|
||||
|
||||
/**
|
||||
* SanitizingHtmlSerializer serializes a DOM fragment, stripping out any unsafe elements and unsafe
|
||||
|
@ -265,7 +265,7 @@ export function _sanitizeHtml(defaultDoc: any, unsafeHtmlInput: string): string
|
|||
}
|
||||
}
|
||||
|
||||
function getTemplateContent(el: Node): Node|null {
|
||||
export function getTemplateContent(el: Node): Node|null {
|
||||
return 'content' in (el as any /** Microsoft/TypeScript#21517 */) && isTemplateElement(el) ?
|
||||
el.content :
|
||||
null;
|
||||
|
|
|
@ -623,6 +623,9 @@
|
|||
{
|
||||
"name": "getElementDepthCount"
|
||||
},
|
||||
{
|
||||
"name": "getFirstParentNative"
|
||||
},
|
||||
{
|
||||
"name": "getFirstTemplatePass"
|
||||
},
|
||||
|
|
|
@ -260,6 +260,9 @@
|
|||
{
|
||||
"name": "getDirectiveDef"
|
||||
},
|
||||
{
|
||||
"name": "getFirstParentNative"
|
||||
},
|
||||
{
|
||||
"name": "getFirstTemplatePass"
|
||||
},
|
||||
|
|
|
@ -845,6 +845,9 @@
|
|||
{
|
||||
"name": "getErrorLogger"
|
||||
},
|
||||
{
|
||||
"name": "getFirstParentNative"
|
||||
},
|
||||
{
|
||||
"name": "getFirstTemplatePass"
|
||||
},
|
||||
|
@ -1104,7 +1107,7 @@
|
|||
"name": "markViewDirty"
|
||||
},
|
||||
{
|
||||
"name": "merge"
|
||||
"name": "merge$1"
|
||||
},
|
||||
{
|
||||
"name": "mergeAll"
|
||||
|
|
|
@ -665,6 +665,9 @@
|
|||
{
|
||||
"name": "getElementDepthCount"
|
||||
},
|
||||
{
|
||||
"name": "getFirstParentNative"
|
||||
},
|
||||
{
|
||||
"name": "getFirstTemplatePass"
|
||||
},
|
||||
|
|
|
@ -678,7 +678,7 @@
|
|||
"name": "PlatformRef"
|
||||
},
|
||||
{
|
||||
"name": "Plural"
|
||||
"name": "Plural$1"
|
||||
},
|
||||
{
|
||||
"name": "QUERIES"
|
||||
|
@ -1688,6 +1688,9 @@
|
|||
{
|
||||
"name": "getErrorLogger"
|
||||
},
|
||||
{
|
||||
"name": "getFirstParentNative"
|
||||
},
|
||||
{
|
||||
"name": "getFirstTemplatePass"
|
||||
},
|
||||
|
@ -1851,7 +1854,7 @@
|
|||
"name": "getPlayerContext"
|
||||
},
|
||||
{
|
||||
"name": "getPluralCategory"
|
||||
"name": "getPluralCategory$1"
|
||||
},
|
||||
{
|
||||
"name": "getPointers"
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue