Schema Editor iframe Integration Guide

This guide explains how to embed the schema editor in your application using iframes, including configuration options and communication patterns.

Basic iframe Integration

Embedding an iframe allows you to integrate external applications into your web application. Below is information on how to integrate an iframe and set up message communication using the postMessage method.

Simple iframe Embedding

<!DOCTYPE html>
<html>
<head>
  <style>
    .container {
      height: 100vh;
      display: flex;
      flex-direction: column;
    }
    iframe {
      flex-grow: 1;
      border: none;
    }
  </style>
</head>
<body>
  <div class="container">
    <!-- create iframe using js -->
    <div class="controls">
      <button id="openModalBtn">Open in modal window</button>
      <span id="messageDisplay"></span>
    </div>

    <!-- or html -->
    <iframe src="/app/venues/2/schemas/150" width="100%" height="100%"></iframe>
  </div>
</body>
</html>

Creating a Modal with an iframe

document.getElementById('openModalBtn').addEventListener('click', function() {
  const modal = document.createElement('div');
  modal.style.position = 'fixed';
  modal.style.top = '0';
  modal.style.left = '0';
  modal.style.width = '100%';
  modal.style.height = '100%';
  modal.style.backgroundColor = 'rgba(0,0,0,0.5)';
  
  const iframe = document.createElement('iframe');
  iframe.src = '/app/venues/2/schemas/150?hideNavbar=true';
  iframe.style.width = '95%';
  iframe.style.height = '95%';
  
  modal.appendChild(iframe);
  document.body.appendChild(modal);
});

Message Communication

Message Types

The schema editor supports several message types for communication between the parent application and the iframe.

1. MODAL_CLOSING

Allows closing the modal window safely preventing accidental data loss.

Parent Application Behavior
document.getElementById('closeBtn').addEventListener('click', function() {
  iframe.contentWindow.postMessage({ type: 'MODAL_CLOSING' }, '*');
});
iframe Application Behavior
window.addEventListener('message', (event) => {
  if (event.data.type === 'MODAL_CLOSING') {
    // Check for unsaved changes
    if (hasUnsavedChanges) {
      const shouldClose = window.confirm('You have unsaved changes. Close anyway?');
      window.parent.postMessage({
        type: 'MODAL_CLOSE_RESPONSE',
        canClose: shouldClose
      }, '*');
    } else {
      window.parent.postMessage({
        type: 'MODAL_CLOSE_RESPONSE',
        canClose: true
      }, '*');
    }
  }
});

2. SCHEMA_CHANGED

Allows the iframe to notify the parent application about data modifications.

iframe Application Behavior
// In a state management selector or change detection logic
if (window !== window.parent) {
  window.parent.postMessage({ 
    type: 'SCHEMA_CHANGED', 
    hasChanges: detectChanges(),
    changedEntities: ['seats', 'rows', 'sections']
  }, '*');
}
Parent Application Behavior
window.addEventListener('message', function (event) {
  if (event.data.type === 'SCHEMA_CHANGED') {
    console.log('Schema changed:', event.data.hasChanges);
    // Update UI, trigger save prompts, etc.
    updateSaveStatus(event.data.hasChanges);
  }
});

Schema Editing Screen Configuration

The schema editing interface can be accessed through two primary URL patterns:

/app/venues/{venueId}/schemas/{schemaId}  // Edit existing schema
/app/venues/{venueId}/schemas/new         // Create new schema

Where venueId is the ID of the venue and schemaId is the ID of the schema to edit, or “new” to create a new schema.

Customizing the UI with URL Parameters

The schema editor interface can be customized using various URL parameters:

1. Hiding UI Elements

Use the hidden parameter to hide specific toolbar elements:

/app/venues/2/schemas/150?hidden=pricing,save,shape

The example above would hide the pricing mode button, save button, and shape tools from the interface.

2. Hiding the Navbar

To create a more embedded experience, you can hide the top navigation bar:

/app/venues/2/schemas/150?hideNavbar=true

This is particularly useful for iframe integration, providing a cleaner interface with only the editor components.

3. Forcing Pricing Tools Display

Even if pricing tools are hidden by default or through the hidden parameter, you can force them to appear:

/app/venues/2/schemas/150?showPricing=true

4. Combining Parameters

These parameters can be combined to create a highly customized editing experience:

/app/venues/2/schemas/150?hideNavbar=true&hidden=save,shape&showPricing=true

Complete Implementation Example

Here’s a complete example that demonstrates embedding the schema editor in a modal with customized UI and message handling:

function openSchemaEditor(venueId, schemaId, options = {}) {
  // Create modal container
  const modal = document.createElement('div');
  modal.style.position = 'fixed';
  modal.style.top = '0';
  modal.style.left = '0';
  modal.style.width = '100%';
  modal.style.height = '100%';
  modal.style.backgroundColor = 'rgba(0,0,0,0.5)';
  modal.style.zIndex = '9999';
  modal.style.display = 'flex';
  modal.style.justifyContent = 'center';
  modal.style.alignItems = 'center';
  
  // Create close button
  const closeBtn = document.createElement('button');
  closeBtn.textContent = 'Close';
  closeBtn.style.position = 'absolute';
  closeBtn.style.top = '10px';
  closeBtn.style.right = '10px';
  closeBtn.style.zIndex = '10000';
  modal.appendChild(closeBtn);
  
  // Create iframe
  const iframe = document.createElement('iframe');
  
  // Build the base URL
  let url = `/app/venues/${venueId}/schemas/${schemaId}`;
  
  // Build query parameters
  const params = new URLSearchParams();
  
  // Hide specific UI elements if specified
  if (options.hiddenElements && options.hiddenElements.length > 0) {
    params.set('hidden', options.hiddenElements.join(','));
  }
  
  // Hide navbar if specified (default to true for modal)
  if (options.hideNavbar !== false) {
    params.set('hideNavbar', 'true');
  }
  
  // Force show pricing if specified
  if (options.showPricing) {
    params.set('showPricing', 'true');
  }
  
  // Append parameters if any exist
  if (params.toString()) {
    url += `?${params.toString()}`;
  }
  
  iframe.src = url;
  iframe.style.width = '95%';
  iframe.style.height = '95%';
  iframe.style.border = 'none';
  
  modal.appendChild(iframe);
  document.body.appendChild(modal);
  
  let hasUnsavedChanges = false;
  
  // Set up message listener for schema changes
  window.addEventListener('message', function(event) {
    // Handle schema changes
    if (event.data.type === 'SCHEMA_CHANGED') {
      console.log('Schema modified:', event.data);
      hasUnsavedChanges = event.data.hasChanges;
      
      // Update UI to indicate unsaved changes
      if (hasUnsavedChanges) {
        closeBtn.textContent = 'Close*';
      } else {
        closeBtn.textContent = 'Close';
      }
    }
    
    // Handle close confirmation response
    if (event.data.type === 'MODAL_CLOSE_RESPONSE' && event.data.canClose) {
      document.body.removeChild(modal);
    }
  });
  
  // Set up close button handler with confirmation
  closeBtn.addEventListener('click', function() {
    if (hasUnsavedChanges) {
      iframe.contentWindow.postMessage({ type: 'MODAL_CLOSING' }, '*');
    } else {
      document.body.removeChild(modal);
    }
  });
  
  // Return control functions
  return {
    close: function() {
      if (hasUnsavedChanges) {
        iframe.contentWindow.postMessage({ type: 'MODAL_CLOSING' }, '*');
      } else {
        document.body.removeChild(modal);
      }
    },
    getIframe: function() {
      return iframe;
    }
  };
}

// Example usage:
document.getElementById('openEditorBtn').addEventListener('click', function() {
  const editor = openSchemaEditor(2, 150, {
    hiddenElements: ['save', 'tool.shape.circle', 'tool.shape.polygon'],
    showPricing: true
  });
});

Available UI Elements

The schema editor toolbar consists of several modes and tools that can be selectively hidden:

Editor Modes

// Mode options that can be hidden
const modes = {
  'mode.schema': 'Schema editing mode',
  'mode.underlay': 'Underlay/background editing',
  'mode.venueShape': 'Venue shape editing',
  'mode.pricingZones': 'Pricing zones configuration',
  'mode.pricing': 'Pricing management',
  'mode.section': 'Section editing mode'
};

Schema Tools

// Tools available in Schema mode
const schemaTools = {
  'tool.select': 'Selection tool',
  'tool.seatRows': 'Add seat rows tool',
  'tool.table': 'Add table tool',
  'tool.shape': 'Add shapes (all types)',
  'tool.shape.rect': 'Add rectangle shape',
  'tool.shape.circle': 'Add circle shape', 
  'tool.shape.line': 'Add line shape',
  'tool.shape.polygon': 'Add polygon shape',
  'tool.label': 'Add label tool'
};

Section Tools

// Tools available in Section mode
const sectionTools = {
  'tool.selectSeats': 'Select individual seats',
  'tool.selectRows': 'Select entire rows',
  'tool.addSeat': 'Add individual seats',
  'tool.numberSeats': 'Number seats automatically'
};

Pricing Tools

// Tools available in Pricing modes
const pricingTools = {
  'tool.selectSeats': 'Select individual seats',
  'tool.selectRows': 'Select entire rows',
  'tool.selectSections': 'Select entire sections'
};

Underlay Tools

// Tools available in Underlay mode
const underlayTools = {
  'tool.importSvgBackground': 'Import SVG as background',
  'tool.exportSvgBackground': 'Export SVG background',
  'tool.removeSvgBackground': 'Remove SVG background',
  'tool.viewbox': 'Adjust viewbox'
};

Global Tools

// Global tools
const globalTools = {
  'tool.save': 'Save changes',
  'tool.publish': 'Publish schema (only appears when in draft mode)',
  'tool.preview': 'Preview schema (only appears when event ID is available)'
};

Hiding Elements in the URL

You can use either the full identifier (e.g., mode.schema) or the short identifier (e.g., schema) in the URL parameter:

?hidden=schema,pricing,save

Or using full identifiers:

?hidden=mode.schema,mode.pricing,tool.save

Editor Layout Adjustments

When hiding the navbar using hideNavbar=true, the editor automatically adjusts its layout:

  1. The top navigation bar is completely removed
  2. The content area and sidebar heights are increased to fill the available space
  3. The publish button is hidden in the sidebar (controlled by the hidePublishing prop)

This creates a cleaner, more focused editing experience ideal for iframe embedding.

Use Cases and Examples

1. Read-Only View for Customers

// Open a read-only view of the schema with minimal UI
openSchemaEditor(2, 150, {
  hideNavbar: true,
  hiddenElements: [
    'save', 'tool.shape', 'tool.table', 'tool.label', 'tool.seatRows',
    'mode.underlay', 'mode.venueShape', 'mode.pricingZones', 'mode.pricing',
    'tool.addSeat', 'tool.numberSeats'
  ]
});

2. Pricing-Focused Editor

// Open editor focused on pricing configuration
openSchemaEditor(2, 150, {
  hideNavbar: true,
  showPricing: true,
  hiddenElements: [
    'mode.schema', 'mode.underlay', 'mode.venueShape',
    'tool.shape', 'tool.label', 'tool.seatRows', 'tool.table'
  ]
});

3. Schema Creation Wizard

// Open editor for creating a new schema with step-by-step guidance
openSchemaEditor(2, 'new', {
  hideNavbar: true,
  hiddenElements: [
    'mode.pricing', 'mode.pricingZones',
    'tool.shape.polygon', 'tool.shape.line'
  ]
});

Implementing Custom Message Types

You can extend the message communication between the parent application and the schema editor by implementing custom message types:

// In the parent application
function sendCustomCommand(iframe, command, data) {
  iframe.contentWindow.postMessage({
    type: 'CUSTOM_COMMAND',
    command: command,
    data: data
  }, '*');
}

// Example: Set zoom level
sendCustomCommand(editorIframe, 'SET_ZOOM', { level: 0.75 });

// Example: Focus on a specific section
sendCustomCommand(editorIframe, 'FOCUS_SECTION', { sectionId: 'A3' });

These custom commands would need corresponding handlers in the iframe application.