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 Type | Property | Attribute Type | Group Type |
---|---|---|---|
Text | text | TEXT_VALUE | TEXT |
Image | src | IMAGE_SRC | IMAGE |
Video | src | VIDEO_SRC | VIDEO |
Audio | src | AUDIO_SRC | AUDIO |
Shape | shape.fillColor | SHAPE_FILL_COLOR | SHAPE_COLOR |
Shape | shape.strokeStyle | SHAPE_STROKE_COLOR | SHAPE_COLOR |
Shape | shape.gradColor | SHAPE_GRADIENT_COLOR | SHAPE_COLOR |
QR Code | text | QR_CODE_TEXT | QR_CODE |
Image Gallery | images | GALLERY_IMAGES | IMAGE_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:
-
Save Trigger Points:
- Manual save button click
- Keyboard shortcut (Ctrl+S)
- Save and exit action
- Auto-save (excludes quick edit processing)
-
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();
}); -
Data Persistence:
- Quick edit configuration saved in
pageData.quickEditableWidgets
- Widget-level flags stored in
widget.quickEditables
- Override values stored separately at message level
- Quick edit configuration saved in