merge-and-insert

Type: Operation

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

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

Usage:

Other

                                             .------------------------------------------------.
"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:

Other

"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:

Other

    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.

Other

 "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

  1. contextStencil

    (Required)

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

  2. contextNodeId

    (Required)

    Type: NodeId

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

  3. insertionStencils

    (Required)

    Type: 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.

  4. overrideRange

    (Optional)

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