Skip to main content

Quick Editing Feature - Technical Documentation

Overview

The Quick Editing feature allows real-time modification of widget properties directly from the Content Editor's quick editor interface, with changes immediately reflected in the Displayer preview. This enables content managers to override specific widget values at the message (sub-channel) level without modifying the base content template.

Architecture

Core Components

1. Services

ContentSaverService (contentSaverService.js)
  • Integrates quick edit processing into the save workflow
  • Calls generateQuickEditableWidgetsBlock() before saving content
  • Ensures quick edit configuration is always up-to-date when content is saved
  • Located in: frontend-editor/src/main/webapp/contentEditor/states/stage/
QuickEditableInputMapper (quick-editable-input-mapper.service.ts)
  • Maps widget properties to quick edit configuration parameters
  • Determines which properties can be quick-edited for each widget type
  • Provides configuration for different scopes (widget, page, content level)
  • Returns QuickEditToggleParams with enabled state and options
QuickEditableInputHelper (quick-editable-input-helper.service.ts)
  • Generates the quick edit widgets block for content objects
  • Processes content pages and creates QuickEditPage objects
  • Collects and groups widget attributes by type
  • Manages slide dynamic duration settings
  • Handles content-wide and page-level quick edit attributes
QuickEditorInterface (quick-editor-interface.service.ts)
  • Manages real-time communication between Editor and Displayer
  • Uses BroadcastChannel API for cross-context messaging
  • Receives widget override messages from the editor
  • Applies changes to the displayer in real-time
QuickEditableProcessor (quick-editable-widget-processor.service.ts)
  • Processes and applies widget override values
  • Handles different override scopes (widget, page, content)
  • Manages original value storage and restoration
  • Performs type-specific value processing (caching for media files)
  • Provides visual highlighting for focused widgets

Data Structures

Core Interfaces

interface QuickEditContent {
contents?: QuickEditContent[];
pages: QuickEditPage[];
attributeGroups: QuickEditAttributeGroup[];
id: string; // contentId
name: string; // contentName
slideDynamicDurationSettings?: SlideDynamicDurationSettings;
disableTransitiveQuickEditing?: boolean;
widgetOverrides?: WidgetOverride[];
}

interface QuickEditPage {
widgets: QuickEditWidget[];
attributeGroups: QuickEditAttributeGroup[];
id: string; // pageId
name: string; // pageName
}

interface QuickEditWidget {
attributeGroups: QuickEditAttributeGroup[];
widgetType: WidgetType;
id: string; // widget key (e.g., 'tag1')
name: string; // layerName
widgetOrder: number; // z-index
}

interface QuickEditAttributeGroup {
attributes: QuickEditAttribute[];
type: QuickEditAttributeGroupType;
valueType: QuickEditAttributeGroupValueType;
id: string;
name?: string;
}

interface QuickEditAttribute {
type: QuickEditAttributeType;
overrideRule: QuickEditOverrideRule;
attributeValueType: QuickEditAttributeValueType;
value: string | number | boolean | Object;
id: string; // property name (e.g., 'src', 'text')
}

Enums

enum QuickEditScope {
PAGE_LEVEL = 'PAGE_LEVEL',
CONTENT_LEVEL = 'CONTENT_LEVEL',
WIDGET_LEVEL = 'WIDGET_LEVEL'
}

enum QuickEditAttributeGroupType {
TEXT = 'TEXT',
IMAGE = 'IMAGE',
IMAGE_GALLERY = 'IMAGE_GALLERY',
VIDEO = 'VIDEO',
AUDIO = 'AUDIO',
SHAPE_COLOR = 'SHAPE_COLOR',
QR_CODE = 'QR_CODE',
DATASOURCE = 'DATASOURCE'
}

enum QuickEditAttributeType {
// Text attributes
TEXT_VALUE = 'TEXT_VALUE',
QR_CODE_TEXT = 'QR_CODE_TEXT',

// Media attributes
IMAGE_SRC = 'IMAGE_SRC',
VIDEO_SRC = 'VIDEO_SRC',
AUDIO_SRC = 'AUDIO_SRC',
GALLERY_IMAGES = 'GALLERY_IMAGES',

// Shape attributes
SHAPE_STROKE_COLOR = 'SHAPE_STROKE_COLOR',
SHAPE_FILL_COLOR = 'SHAPE_FILL_COLOR',
SHAPE_GRADIENT_COLOR = 'SHAPE_GRADIENT_COLOR',

// Data attributes
DATASOURCE_ID = 'DATASOURCE_ID'
}

enum QuickEditOverrideRule {
MESSAGE = 'MESSAGE', // Override at message/sub-channel level
URL = 'URL' // Override via URL parameters
}

enum QuickEditAttributeValueType {
STRING = 'STRING',
NUMBER = 'NUMBER',
OBJECT = 'OBJECT'
}

enum QuickEditAttributeGroupValueType {
SINGLE_VALUED = 'SINGLE_VALUED',
MULTI_VALUED = 'MULTI_VALUED'
}

Data Flow

1. Configuration Phase (Editor)

Widget Service → initQuickEditable() → Creates quickEditables object

Widget Tab Configuration → quickEditBlock → UI Control

User toggles quick edit → Updates widget.quickEditables[property]

2. Save Integration Phase (Editor)

The quick edit configuration is processed during content save operations:

User clicks Save → contentSaverService.saveCurrentContent()

Stops all widget players

quickEditableInputHelper.generateQuickEditableWidgetsBlock()

Takes content snapshot

Saves to server with quick edit metadata

Location: frontend-editor/src/main/webapp/contentEditor/states/stage/contentSaverService.js

The generateQuickEditableWidgetsBlock() is called automatically during:

  • Manual content save operations
  • Save and exit operations
  • Before content is sent to server

3. Processing Phase (Editor)

QuickEditableInputHelper.generateQuickEditableWidgetsBlock()

Processes all content pages and widgets

Collects quickEditables properties

Groups attributes by type (QuickEditableInputMapper)

Creates QuickEditContent structure

Stores in pageData.quickEditableWidgets

4. Communication Phase (Editor → Displayer)

Quick Editor UI → User modifies value

Creates WidgetOverride message

BroadcastChannel.postMessage()

QuickEditorInterface (Displayer) receives message

QuickEditableProcessor.applyValues()

5. Application Phase (Displayer)

QuickEditableProcessor.applyValues()

Determines override scope (widget/page/content)

Stores original values (for restoration)

Applies type-specific processing

Updates widget properties

Triggers Angular digest cycle

UI updates in real-time

Widget Property Mapping

The system maps widget properties to their quick edit configurations:

Widget TypePropertyAttribute TypeGroup Type
TexttextTEXT_VALUETEXT
ImagesrcIMAGE_SRCIMAGE
VideosrcVIDEO_SRCVIDEO
AudiosrcAUDIO_SRCAUDIO
Shapeshape.fillColorSHAPE_FILL_COLORSHAPE_COLOR
Shapeshape.strokeStyleSHAPE_STROKE_COLORSHAPE_COLOR
Shapeshape.gradColorSHAPE_GRADIENT_COLORSHAPE_COLOR
QR CodetextQR_CODE_TEXTQR_CODE
Image GalleryimagesGALLERY_IMAGESIMAGE_GALLERY

Real-time Communication

The system uses the BroadcastChannel API for real-time communication between the Editor and Displayer contexts:

// Editor sends override
const channel = new BroadcastChannel('quickEditorDataInterface');
channel.postMessage({
pageId: 'page1',
widgetId: 'tag1',
attributesOverrides: [{
type: QuickEditAttributeType.TEXT_VALUE,
value: 'New text value'
}],
isQuickEditFocused: true
});

// Displayer receives and applies
channel.addEventListener('message', (event) => {
quickEditableProcessor.applyValues(
contentObject,
[event.data],
true // fromQuickEditor flag
);
});

Value Processing

Media Files

  • Video, Image, and Audio sources are cached using CacheFileService
  • Invalid sources set validation flags (e.g., validVideoSrc)

Original Value Storage

  • Original values are stored in widget.originalValues
  • Allows restoration when override is removed
  • Null values trigger restoration to original

Visual Feedback

  • Focused widgets receive border highlighting
  • Border removed when focus is lost
  • Helps users identify which widget is being edited

Override Persistence

Quick edit overrides are stored at the message (sub-channel) level:

  • Stored in content.quickEditableWidgets.widgetOverrides
  • Applied when content is scheduled for display
  • Override rules determine application context (MESSAGE vs URL)

Save Process Integration

The quick edit configuration is integrated into the content save workflow:

  1. Save Trigger Points:

    • Manual save button click
    • Keyboard shortcut (Ctrl+S)
    • Save and exit action
    • Auto-save (excludes quick edit processing)
  2. Save Workflow:

    // In contentSaverService.saveCurrentContent()
    contentWidgetPlayer.stopAllPlayers()
    .then(() => {
    // Process quick edit configuration
    quickEditableInputHelper.generateQuickEditableWidgetsBlock();

    // Take snapshot for undo/redo
    contentJsonSnapshotManager.takeSnapshot(content);

    // Save to server with quick edit metadata
    return saveContentToServer();
    });
  3. Data Persistence:

    • Quick edit configuration saved in pageData.quickEditableWidgets
    • Widget-level flags stored in widget.quickEditables
    • Override values stored separately at message level