Skip to content
This plugin is new and currently in beta. For the stable version, please use the previous version of the plugin.

Template Modification System

Basic Concept

Using the API call this.api.getDocumentModifier(), you can access the TemplateModifier object.

The TemplateModifier provides a controlled way to modify templates:

javascript
this.api.getDocumentModifier()
    .modifyHtml(immutableNode)     // Select what to modify
    .setInnerHtml('New content')   // Define the modification
    .apply(description);           // Apply with tracking

Modification Flow

1. Get Modifier          2. Select Node           3. Chain Modifications
      ↓                        ↓                          ↓
getDocumentModifier() → modifyHtml(node) → setAttribute().setStyle()...

                              5. Sync                4. Apply
                                 ↓                        ↓
                        Propagate to Users ← apply(ModificationDescription)

This flow ensures that all modifications are:

  • Tracked - Each change is recorded for version history
  • Atomic - Related changes are applied together
  • Collaborative - Changes are synchronized across all users
  • Reversible - Full undo/redo support is maintained

Modification Types

HTML Modifications

The system supports various HTML modifications:

Content Modifications

javascript
.setInnerHtml(html)     // Replace inner HTML
.append(html)           // Add to end
.prepend(html)          // Add to beginning
.replaceWith(html)      // Replace entire element

Attribute Modifications

javascript
.setAttribute(name, value)    // Set attribute
.removeAttribute(name)        // Remove attribute

Text Modifications

javascript
.setText(text)      // Updates the text content of the HTML text node

Style Modifications

javascript
.setStyle(property, value)    // Set CSS property
.removeStyle(property)        // Remove CSS property

Class Modifications

javascript
.setClass(className)          // Add CSS class
.removeClass(className)       // Remove CSS class

Structural Modifications

javascript
.delete()                     // Remove current node

CSS Modifications

The system also supports CSS modifications:

javascript
this.api.getDocumentModifier()
    .modifyCss(immutableCssNode)
    .setProperty('color', 'blue')        // Set a CSS property
    .setProperty('font-size', '16px')    // Set a CSS property
    .removeProperty('text-decoration')   // Remove a CSS property
    .apply(description);

MultiRowStructureModifier

Overview

The MultiRowStructureModifier is a specialized helper interface for creating and modifying complex email layouts with multiple rows and columns. It provides high-level methods to manage email structure containers, handling the intricate details of email-compatible HTML generation.

When to Use MultiRowStructureModifier

Use the MultiRowStructureModifier when you need to:

  • Create multi-row custom blocks - Build responsive custom blocks with multiple structure rows
  • Modify existing structures - Change the layout while preserving content
  • Manage container distribution - Control how content is distributed across containers within the structure

Why Use MultiRowStructureModifier

Traditional email HTML is complex due to:

  1. Table-based layouts - Email clients require nested tables for consistent rendering
  2. MSO compatibility - Outlook needs special conditional comments and markup
  3. Responsive challenges - Mobile and desktop layouts require different approaches

The MultiRowStructureModifier abstracts these complexities by providing:

  • Automatic table structure generation - No need to manually create complex nested tables
  • Built-in MSO/Outlook compatibility - Handles all necessary conditional comments and markup
  • Responsive design handling - Automatically generates mobile-friendly layouts
  • Smart content distribution - Intelligently places content across containers
  • Image scaling and optimization - Ensures images render correctly across email clients

Access and Usage

Access the MultiRowStructureModifier through the multiRowStructureModifier() method:

javascript
const modifier = this.api.getDocumentModifier()
    .modifyHtml(structureNode)
    .multiRowStructureModifier();

Methods

updateLayoutWithContent

Creates a new structure by replacing the current one with specified containers and content.

javascript
// Create a three-column layout with mixed container types
modifier.multiRowStructureModifier()
    .updateLayoutWithContent(
        [
            {width: '25%', contentType: 'EMPTY'},  // Empty placeholder
            '50%',                                 // Content column 1
            '25%'                                  // Content column 2
        ],
        [
            `<${BlockType.BLOCK_TEXT}>
                <p>Content 1</p>
            </${BlockType.BLOCK_TEXT}>`,
            `<${BlockType.BLOCK_TEXT}>
                <p>Content 2</p>
            </${BlockType.BLOCK_TEXT}>`
        ]
    )
    .apply(new ModificationDescription('Created three-column layout'));

Parameters:

  • layout: Array of StructureLayout defining container widths and types
  • containerContent: Array of HTML strings for content containers

Container Types:

  • Content Container (string) - Width percentage for content-holding containers
  • Empty Container - {width: string, contentType: 'EMPTY'} for placeholders awaiting future content
  • Spacer Container - {width: string, contentType: 'SPACER'} for creating empty space

updateLayout

Modifies the container layout of an existing structure while preserving content.

javascript
// Change from two columns to three columns
modifier.multiRowStructureModifier()
    .updateLayout([
        '33%',     // First column
        '34%',     // Second column
        '33%'      // Third column
    ])
    .apply(new ModificationDescription('Changed to three-column layout'));

Parameters:

  • layout: New container layout configuration

Behavior:

  • Preserves existing content when possible during layout changes
  • Redistributes content intelligently among new containers
  • Manages content overflow by automatically creating additional structure beneath the current one when needed

Best Practices

  1. Plan Your Layout - Design your container structure before implementation
  2. Use Meaningful Widths - Ensure widths add up to 100% for proper rendering
  3. Test Content Distribution - Verify content appears in the correct containers
  4. Leverage Spacers - Use spacer containers for consistent margins and padding

Modification Descriptions

Purpose

Every modification requires a description that:

  • Documents the change for comprehensive version history
  • Provides context for other users in collaborative editing
  • Enables meaningful labels for undo/redo operations
  • Supports internationalization for multi-language environments

Basic Usage

javascript
.apply(new ModificationDescription('Changed text color'));

With Parameters

javascript
.apply(new ModificationDescription('Changed color to {color}')
    .withParams({ color: '#ff0000' }));

Internationalization

javascript
.apply(new ModificationDescription('color_changed')
    .withParams({ color: '#ff0000' }));
// Uses translation key 'color_changed'

Transaction Model

Atomic Operations

All modifications in a single chain are atomic:

javascript
this.api.getDocumentModifier()
    .modifyHtml(container)
    .setStyle('background', 'blue')          // All three
    .setClass('highlighted')                 // happen
    .setAttribute('data-modified', 'true')   // together
    .apply(description);

Benefits of Transactions

  1. Consistency - All related changes succeed together or fail as a unit
  2. Performance - Batch processing reduces overhead and improves responsiveness
  3. History - Single undo/redo operation for logically related changes
  4. Synchronization - Fewer network requests improve collaborative editing performance

Collaborative Editing Support

How It Works

When a modification is applied:

  1. Local Application: Changes apply immediately locally
  2. Serialization: Modifications are serialized to operations
  3. Transmission: Operations sent to collaboration server
  4. Transformation: Server resolves conflicts if needed
  5. Broadcast: Changes sent to all other users
  6. Application: Remote changes applied to all clients

Conflict Resolution

The system automatically handles conflicts:

User A: Changes heading color to red
User B: Changes heading color to blue (simultaneously)

Result: Last write wins (User B's change)
Both users see: Heading is blue
History shows: Both changes with timestamps

Complex conflicts are resolved using operational transformation:

User A: Inserts text at position 10
User B: Deletes text at position 5-8

System transforms User A's operation:
Original: Insert at position 10
Transformed: Insert at position 7 (adjusted for deletion)

Version History Integration

Automatic Tracking

Every modification is automatically tracked:

javascript
// This single modification creates a history entry
this.api.getDocumentModifier()
    .modifyHtml(element)
    .setInnerHtml('Updated content')
    .apply(new ModificationDescription('Updated welcome message'));

// Version history shows:
// - Timestamp
// - "Updated welcome message"
// - Username
// - Restore option

Undo/Redo Support

The modification system provides built-in undo/redo:

javascript
// User performs modification
modifier.apply(description);

// User clicks undo
// System automatically reverses the modification

// User clicks redo
// System reapplies the modification

Performance Considerations

Batching Strategies

Batch related modifications for better performance:

javascript
// Good - Single transaction
const modifier = this.api.getDocumentModifier();
elements.forEach(el => {
    modifier.modifyHtml(el).setStyle('color', 'blue');
});
modifier.apply(description);

// Avoid - Multiple transactions
elements.forEach(el => {
    this.api.getDocumentModifier()
        .modifyHtml(el)
        .setStyle('color', 'blue')
        .apply(description);
});

Debouncing

For high-frequency updates (like color pickers):

javascript
let modificationTimeout;

onColorChange(color) {
    clearTimeout(modificationTimeout);
    modificationTimeout = setTimeout(() => {
        this.applyColorChange(color);
    }, 100);
}

Best Practices

1. Use Descriptive Messages

javascript
// Good - specific and informative
.apply(new ModificationDescription('Changed button color to match brand'));

// Avoid - too vague
.apply(new ModificationDescription('Updated'));
javascript
// Good - related changes in a single transaction
modifier
    .modifyHtml(button)
    .setStyle('background', color)
    .setStyle('border-color', darkenColor(color))
    .apply(description);

// Avoid - unrelated changes in the same transaction
modifier
    .modifyHtml(button)
    .setStyle('background', color)
    .modifyHtml(heading)  // Different element - should be separate
    .setInnerHtml(title)
    .apply(description);

3. Minimize Unnecessary Modifications

javascript
// Good - only modify when values actually change
if (newValue !== oldValue) {
    modifier.modifyHtml(element)
        .setAttribute('data-value', newValue)
        .apply(description);
}

// Avoid - modifying even when values haven't changed
modifier.modifyHtml(element)
    .setAttribute('data-value', newValue)  // Wasteful if unchanged
    .apply(description);

4. Use Appropriate Methods for Each Task

javascript
// Good - use specialized methods for their intended purpose
modifier.modifyHtml(element)
    .setDisplayCondition(condition)     // For visibility control
    .setNodeConfig(widgetConfig)        // For custom data storage
    .apply(description);

// Avoid - misusing generic attributes for specialized functionality
modifier.modifyHtml(element)
    .setAttribute('data-config', JSON.stringify(config))  // Use setNodeConfig instead
    .apply(description);

Summary

The template modification system provides:

  • Safety - Immutable nodes prevent direct manipulation and ensure data integrity
  • Tracking - All changes are recorded and attributed for complete audit trails
  • Collaboration - Automatic conflict resolution and real-time synchronization
  • History - Built-in undo/redo functionality with comprehensive version tracking
  • Performance - Batched operations and optimized synchronization for scalability
  • Advanced Features - Display conditions and node configurations for complex use cases
  • Layout Management - MultiRowStructureModifier for sophisticated email structures

This system is fundamental to creating reliable, collaborative extensions that maintain template integrity while providing powerful modification capabilities.

See Also