TDom

Central DOM access and manipulation class. ALL CSS and DOM operations in Framework components MUST go through TDom. Provides viewport tracking, element manipulation, event handling, and deferred execution.

Core Utility DOM Access MANDATORY

Overview

TDom is the single point of access for all DOM manipulation in the Appzoola Framework. This is an absolute rule - components must NEVER call JavaScript DOM methods directly. TDom handles nil checks internally, provides consistent error handling, and enables viewport tracking for responsive layouts.

MANDATORY RULE: ALL DOM calls must go through TDom. Never call ElementHandle.style.setProperty() or similar JS DOM methods directly in component code. Use TDom.SetStyle(), TDom.AddClass(), etc. instead.

Unit & Declaration

UNIT Obj.App.DomAccess;

TDom = CLASS(TComponent)
   // Can be instantiated or used via class methods

Key Design Principles

CSS Style Methods (Class Methods)

CLASS PROCEDURE SetStyle(Element: TJSHTMLElement; CONST PropertyName, Value: STRING); OVERLOAD;
CLASS PROCEDURE SetStyle(Control: TControl; CONST PropertyName, Value: STRING); OVERLOAD;

Sets a CSS style property on an element or control. Handles nil checks internally.

TDom.SetStyle(MyButton.ElementHandle, 'background-color', '#4285f4');
TDom.SetStyle(MyDiv, 'display', 'flex');
CLASS PROCEDURE RemoveStyle(Element: TJSHTMLElement; CONST PropertyName: STRING); OVERLOAD;
CLASS PROCEDURE RemoveStyle(Control: TControl; CONST PropertyName: STRING); OVERLOAD;

Removes a CSS style property from an element or control.

TDom.RemoveStyle(MyDiv, 'height');  // Let CSS handle height
CLASS FUNCTION GetStyle(Element: TJSHTMLElement; CONST PropertyName: STRING): STRING;

Gets the current value of a CSS style property.

CSS Class Methods

CLASS PROCEDURE AddClass(Element: TJSHTMLElement; CONST ClassName: STRING); OVERLOAD;
CLASS PROCEDURE AddClass(Control: TControl; CONST ClassName: STRING); OVERLOAD;

Adds a CSS class to an element or control.

TDom.AddClass(MyCard, CssClassDashboardCard);
CLASS PROCEDURE RemoveClass(Element: TJSHTMLElement; CONST ClassName: STRING); OVERLOAD;
CLASS PROCEDURE RemoveClass(Control: TControl; CONST ClassName: STRING); OVERLOAD;

Removes a CSS class from an element or control.

CLASS FUNCTION HasClass(Element: TJSHTMLElement; CONST ClassName: STRING): Boolean;

Checks if an element has a specific CSS class.

CLASS PROCEDURE ToggleClass(Element: TJSHTMLElement; CONST ClassName: STRING);

Toggles a CSS class on an element.

Element Access Methods

CLASS FUNCTION GetBody: TJSHTMLElement;

Returns the document body element.

CLASS FUNCTION GetParentElement(Element: TJSHTMLElement): TJSHTMLElement;

Returns the parent element of the given element.

CLASS FUNCTION GetBoundingClientRect(Element: TJSHTMLElement): TJSDOMRect;

Returns the bounding rectangle of an element (position and size).

CLASS FUNCTION GetOffsetHeight(Element: TJSHTMLElement): Integer;
CLASS FUNCTION GetOffsetWidth(Element: TJSHTMLElement): Integer;

Returns the offset height/width of an element including borders.

Event Methods

CLASS PROCEDURE AddEventListener(Control: TControl; CONST EventName: STRING; Handler: TJSEventHandler);

Adds an event listener to a control's element.

CLASS FUNCTION TryAddEventListener(Control: TControl; CONST EventName: STRING; Handler: TJSEventHandler): Boolean;

Tries to add an event listener. Returns False if element is nil or attachment fails.

CLASS PROCEDURE RemoveEventListener(Control: TControl; CONST EventName: STRING; Handler: TJSEventHandler);

Removes an event listener from a control's element.

CLASS PROCEDURE AddDocumentEventListener(CONST EventName: STRING; Handler: TJSEventHandler);

Adds an event listener to the document (useful for mousemove/mouseup during drag).

CLASS PROCEDURE RemoveDocumentEventListener(CONST EventName: STRING; Handler: TJSEventHandler);

Removes an event listener from the document.

CLASS PROCEDURE PreventDefault(Event: TJSEvent);
CLASS PROCEDURE StopPropagation(Event: TJSEvent);

Prevents default browser action and stops event propagation.

CLASS FUNCTION GetMouseClientX(Event: TJSEvent): Integer;
CLASS FUNCTION GetMouseClientY(Event: TJSEvent): Integer;
CLASS FUNCTION GetMouseButton(Event: TJSEvent): Integer;

Gets mouse event coordinates and button from a mouse event.

Deferred Execution Methods

CLASS PROCEDURE RequestAnimationFrame(Callback: TProc);

Schedules a callback for the next animation frame. Use for CSS updates that need to happen after layout.

TDom.RequestAnimationFrame(
   PROCEDURE
   BEGIN
      ApplyStyles;
   END);
CLASS PROCEDURE ExecuteDeferred(Callback: TProc);

Executes a callback after a short delay (typically one RAF cycle). Use for operations that must happen after TMS Web Core's async element creation.

TDom.ExecuteDeferred(@UpdatePosition);
TMS Web Core Timing: ElementHandle may not be immediately available after component creation. Use ExecuteDeferred or RequestAnimationFrame to ensure the DOM element exists before manipulation.

Viewport/Device Mode Tracking

PROCEDURE InitializeViewportTracking;

Starts viewport size monitoring. Must be called in component's Loaded method.

FUNCTION GetViewMode: TDeviceMode;

Returns current device mode based on viewport width.

Mode Viewport Width
dmMobile < 768px
dmTablet 768px - 1023px
dmDesktop ≥ 1024px
PROPERTY OnDeviceModeChanged: TDeviceModeChangeEvent;

Event fired when device mode changes due to viewport resize.

FDom := TDom.Create(Self);
FDom.OnDeviceModeChanged := HandleDeviceModeChange;
FDom.InitializeViewportTracking;

PROCEDURE TMyComponent.HandleDeviceModeChange(Sender: TObject; NewMode: TDeviceMode);
BEGIN
   CASE NewMode OF
      dmMobile:  ApplyMobileLayout;
      dmTablet:  ApplyTabletLayout;
      dmDesktop: ApplyDesktopLayout;
   END;
END;

ResizeObserver Methods

CLASS FUNCTION CreateResizeObserver(Element: TJSHTMLElement; Callback: TResizeObserverCallback; StartObserving: Boolean = True): TJSResizeObserver;

Creates a ResizeObserver for an element. Used by TCoreGridPanel for responsive layout.

CLASS PROCEDURE DestroyResizeObserver(VAR Observer: TJSResizeObserver);

Disconnects and destroys a ResizeObserver.

CLASS PROCEDURE AddWindowResizeListener(Handler: TJSEventHandler);

Adds a window resize event listener.

Usage Examples

Setting Multiple Styles

TDom.SetStyle(Card.ElementHandle, 'position', 'absolute');
TDom.SetStyle(Card.ElementHandle, 'top', '10px');
TDom.SetStyle(Card.ElementHandle, 'left', '20px');
TDom.SetStyle(Card.ElementHandle, 'width', '200px');
TDom.SetStyle(Card.ElementHandle, 'height', '150px');

Using with Controls (Preferred)

// Can pass TControl directly - TDom extracts ElementHandle
TDom.SetStyle(MyButton, 'background-color', Theme.PrimaryColor);
TDom.AddClass(MyPanel, 'card-highlighted');

Deferred Initialization

PROCEDURE TMyComponent.Loaded;
BEGIN
   INHERITED;
   
   {$IFDEF PAS2JS}
   // Defer CSS application until DOM is ready
   TDom.RequestAnimationFrame(
      PROCEDURE
      BEGIN
         ApplyStyles;
         InitializeEvents;
      END);
   {$ENDIF}
END;

Event Handling Pattern

// In component fields:
FMouseDownHandler: TJSEventHandler;

// In constructor:
FMouseDownHandler := @HandleMouseDown;

// In Loaded:
TDom.ExecuteDeferred(@AttachEventListeners);

// Attach procedure:
PROCEDURE TMyComponent.AttachEventListeners;
BEGIN
   IF NOT TDom.TryAddEventListener(DragHandle, 'mousedown', FMouseDownHandler) THEN
      console.log('Failed to attach event listener');
END;

// Cleanup in destructor:
TDom.RemoveEventListener(DragHandle, 'mousedown', FMouseDownHandler);

Common Patterns

Component Styling (NO nil checks needed)

PROCEDURE TMyCard.ApplyStyles;
BEGIN
   // TDom handles nil checks internally - just call it
   TDom.SetStyle(ElementHandle, 'background', '#ffffff');
   TDom.SetStyle(ElementHandle, 'border-radius', '8px');
   TDom.SetStyle(ElementHandle, 'box-shadow', '0 2px 4px rgba(0,0,0,0.1)');
END;

DO NOT DO THIS

// WRONG - Direct DOM access
IF Assigned(ElementHandle) THEN
   ElementHandle.style.setProperty('background', '#ffffff');

// WRONG - Checking nil before TDom
IF ElementHandle <> NIL THEN
   TDom.SetStyle(ElementHandle, 'background', '#ffffff');

// CORRECT - Just use TDom
TDom.SetStyle(ElementHandle, 'background', '#ffffff');

See Also