Developer Wiki

In-depth guide for developers to create stencils and templates

Dynamic DOM Content

In some special cases, a shape content is composed from a dynamic element structure. Pencil provides the DomContent behavior so that DOM content's of an element can be changed dynamically. Value provided to this behavior is a DOM node that will be used to placed as children of the target element. Together with providing this behavior, Pencil also provide ultility functions for quickly building DOM node and fragment from the spec defined as JavaScript objects.


<Shape id="list" displayName="List" icon="Icons/list.png">
  <Properties>
    <PropertyGroup>
      <Property name="box" displayName="Box" type="Dimension">191,235</Property>
    </PropertyGroup>
    <PropertyGroup name="Item Text">

      <Property name="contentText" displayName="Text Content" type="PlainText"
        p:editInfo="({targetName: 'content', bound: Bound.fromBox($box, 0, 52), font: $itemFont, align: new Alignment(0, 0), multi: true})">MenuItem
MenuItem
MenuItem</Property>
      <Property name="itemFont" displayName="Text Font" type="Font">
        <E>$$defaultTextFont</E>
      </Property>
      <Property name="itemColor" displayName="Text Color" type="Color">#000000ff</Property>
    </PropertyGroup>
  </Properties>
  <Behaviors>
    <For ref="content">
      <Bound>Bound.fromBox($box, 0, 54)</Bound>
      <Font>$itemFont</Font>
      <DomContent>
        var items = $contentText.value.split(/[\r\n]+/);
        var specs = [];
        for (var i = 0; i &lt; items.length; i ++) {
          var css = new CSS();
          
          var title = items[i];
          
          if(title.match(/\S/) != null) {
            var lineHeight = (i + 1) * (30 + $itemFont.getPixelHeight());
            
            var css = new CSS();
            css.set("font-size",$itemFont.size);
            css.set("font-family",$itemFont.family);
            css.set("font-style",$itemFont.style);
            css.set("font-weight",$itemFont.weight);
            css.set("font-decor",$itemFont.decor);
            css.set("fill", $itemColor.toRGBString());
            
            specs.push({
                _name: "text",
                _uri: "http://www.w3.org/2000/svg",
                x: 10,
                y: lineHeight,
                _text : title,
                style: css
              },{
                _name: "path",
                _uri: "http://www.w3.org/2000/svg",
                d: "m 10,"+ (lineHeight+10) + " "+($box.w - 20)+",0" ,
                style : "stroke-width:1;stroke:#c9c9c9"
              });
          }
        }
        Dom.newDOMFragment(specs);
      </DomContent>
    </For>
  </Behaviors>
  <p:Content xmlns:p="http://www.evolus.vn/Namespace/Pencil" xmlns="http://www.w3.org/2000/svg">
    <g id="content" />
  </p:Content>
</Shape>

In this example, the text content entered by users is supposed to be in a format of multiple lines. The code inside the behavior splits that text and create for each line a text element containing that line and a path element as the footer of the text.

The utility method Dom.newDOMFragment(specs); is used here to create DOM fragment from the object specs.