merge-and-insert

How to get merge-and-insert

Depend on fontoxml-base-flow to make this operation available.

Merge a structure with the passed structure, and insert new structures within it.

Merge the contextStencil with the contextNode, and insert the insertionStencils.

Usage:

                                             .------------------------------------------------.
"data": {                                    | Note: do not forget optional multiple gap(s)   |
    "contextNodeId": "42",                   |  if the parent may contain other nodes         |
    "contextStencil": [                      '------------------------------------------------'
        "someElement",                                .-------------'|
        [{ "required": false, "multiple": true }],    |
        [                                     .----------------------'
            "someElementWhichMightExist",    |
            [{ "required": false, "multiple": true }]
            [{ "bindTo": "newElement", "empty": true ]}
        ]                '--------'
    ],                         '.      .----------------------------------------------------------.
    "insertionStencils": {       >-----| Note: bindTo corresponds to the key in insertionStencils |
        .---------.-------------'      '----------------------------------------------------------'
        "newElement": {
            "stencil": [
                "someNewElement",
                {
                    "someAttribute", { "bindTo": "someAttributeValue" }
                }
            ],
            "model": {
                "someAttributeValue": "value_0"
            }
        }
    }

This example will do the following:

  • It might add a 'someElementWhichMightExist' if it doesn't exist

  • It will add an element 'someNewElement' under the 'someElementWhichMightExist'

  • It will set the attribute in 'someNewElement'

Another example: append-structure

Merge and insert is used for implementing the append-structure operation:

"append-structure": {
    "steps": {
        "type": "operation/merge-and-insert",
        "data": {
          "contextNodeId": "{{contextNodeId}}",
           "contextStencil": [
        null,
                [{ "multiple": true, "bindTo": "childNodes"}]
          ],
             "insertionStencils": {
                   "childNodes.end": {
                           "stencil": "{{childNodeStructure}}",
                       "model": "{{model}}"
               }
           }
        }
   }
}

This example works by generating the needed context from the context node, matching it as the root of the structure. It then attempts to match all childNodes in a named gap. This named gap will generate a range, having a start and an end. Inserting at the end position effectively appends a structure.

Given the aforementioned stencil and the following the (DOM) tree:

    O    
   / \   
  A   B  

 The stencil will match this way:
     O 
    / \ 
   A   B 
 |       '- childNodes.end
  'childNodes.start

Inserting at childNodes.end, the position after B will be used for inserting.

Example: creating optional structures

Use case: a body may optionally have an optional list element as the last child. In that list, we want to append an item, with a given text. If this list does not yet exist, create it.

 "insert-item": {
   "steps": {
        "type": "operation/merge-and-insert",
        "data": {
          "contextNodeId": "{{contextNodeId}}",
           "contextStencil": [
        "body",
                   [{ "multiple": true}],
        [
          "list",
          [{ "bindTo": "items", "multiple": true }]
        ]
          ],
             "insertionStencils": {
                   "items.end": {
                           "stencil": ["item", [{ "bindTo": "textContent", "required": false}]],
                       "model": { "textContent": "{{itemText}}" ]
               }
           }
        }
   }
 }

This works by matching the body as the root, then matching a list, if it exists. If it does not, it will create it. It will then use an append-structure like approach to append the item at items.end.

Imported operation data

Name Type Description
contextStencil StencilJsonML

A stencil describing the structure in which to perform the insertions. Should contain a named gap for each insertion to be performed.

contextNodeId NodeId

The id of the node with which the stencil is aligned.

insertionStencils Object<string, StencilJsonML>

Mapping from position names referencing the context stencil to objects containing a stencil and optional model to be inserted at the corresponding location. If the targeted gap is of a range type, all possible positions will be considered. If the selection is positioned in this range, the position directly after it will be considered first.

[overrideRange] OverrideRange

The range to set the selection in as defined by the stencil instead of the selectionRange