* Apply `I18nMutateOpCodes` OpCodes. * * @param tView Current `TView` * @param mutableOpCodes Mutable OpCodes to process * @param lView Current `LView` * @param anchorRNode place where the i18n node should be inserted.
( tView: TView, mutableOpCodes: IcuCreateOpCodes, lView: LView, anchorRNode: RNode, )
| 243 | * @param anchorRNode place where the i18n node should be inserted. |
| 244 | */ |
| 245 | function applyMutableOpCodes( |
| 246 | tView: TView, |
| 247 | mutableOpCodes: IcuCreateOpCodes, |
| 248 | lView: LView, |
| 249 | anchorRNode: RNode, |
| 250 | ): void { |
| 251 | ngDevMode && assertDomNode(anchorRNode); |
| 252 | const renderer = lView[RENDERER]; |
| 253 | // `rootIdx` represents the node into which all inserts happen. |
| 254 | let rootIdx: number | null = null; |
| 255 | // `rootRNode` represents the real node into which we insert. This can be different from |
| 256 | // `lView[rootIdx]` if we have projection. |
| 257 | // - null we don't have a parent (as can be the case in when we are inserting into a root of |
| 258 | // LView which has no parent.) |
| 259 | // - `RElement` The element representing the root after taking projection into account. |
| 260 | let rootRNode!: RElement | null; |
| 261 | for (let i = 0; i < mutableOpCodes.length; i++) { |
| 262 | const opCode = mutableOpCodes[i]; |
| 263 | if (typeof opCode == 'string') { |
| 264 | const textNodeIndex = mutableOpCodes[++i] as number; |
| 265 | if (lView[textNodeIndex] === null) { |
| 266 | ngDevMode && assertIndexInRange(lView, textNodeIndex); |
| 267 | lView[textNodeIndex] = _locateOrCreateNode(lView, textNodeIndex, opCode, Node.TEXT_NODE); |
| 268 | } |
| 269 | } else if (typeof opCode == 'number') { |
| 270 | switch (opCode & IcuCreateOpCode.MASK_INSTRUCTION) { |
| 271 | case IcuCreateOpCode.AppendChild: |
| 272 | const parentIdx = getParentFromIcuCreateOpCode(opCode); |
| 273 | if (rootIdx === null) { |
| 274 | // The first operation should save the `rootIdx` because the first operation |
| 275 | // must insert into the root. (Only subsequent operations can insert into a dynamic |
| 276 | // parent) |
| 277 | rootIdx = parentIdx; |
| 278 | rootRNode = renderer.parentNode(anchorRNode); |
| 279 | } |
| 280 | let insertInFrontOf: RNode | null; |
| 281 | let parentRNode: RElement | null; |
| 282 | if (parentIdx === rootIdx) { |
| 283 | insertInFrontOf = anchorRNode; |
| 284 | parentRNode = rootRNode; |
| 285 | } else { |
| 286 | insertInFrontOf = null; |
| 287 | parentRNode = unwrapRNode(lView[parentIdx]) as RElement; |
| 288 | } |
| 289 | // FIXME(misko): Refactor with `processI18nText` |
| 290 | if (parentRNode !== null) { |
| 291 | // This can happen if the `LView` we are adding to is not attached to a parent `LView`. |
| 292 | // In such a case there is no "root" we can attach to. This is fine, as we still need to |
| 293 | // create the elements. When the `LView` gets later added to a parent these "root" nodes |
| 294 | // get picked up and added. |
| 295 | ngDevMode && assertDomNode(parentRNode); |
| 296 | const refIdx = getRefFromIcuCreateOpCode(opCode); |
| 297 | ngDevMode && assertGreaterThan(refIdx, HEADER_OFFSET, 'Missing ref'); |
| 298 | // `unwrapRNode` is not needed here as all of these point to RNodes as part of the i18n |
| 299 | // which can't have components. |
| 300 | const child = lView[refIdx] as RElement; |
| 301 | ngDevMode && assertDomNode(child); |
| 302 | nativeInsertBefore(renderer, parentRNode, child, insertInFrontOf, false); |
no test coverage detected
searching dependent graphs…