internalSetAttribute method

void internalSetAttribute(
  1. String qualifiedName,
  2. String value, {
  3. bool invokedByAttributeSetter = false,
})

Implementation

void internalSetAttribute(String qualifiedName, String value,
    {bool invokedByAttributeSetter = false}) {
  // Track previous value to avoid redundant DevTools events
  final String? oldValue = attributes[qualifiedName];
  final bool changed = oldValue != value;

  attributes[qualifiedName] = value;
  if (qualifiedName == 'class') {
    // When called from setAttribute() and a property handler already ran
    // (i.e., className setter), skip re-entering className to avoid double
    // recalculation and duplicate index updates.
    if (!invokedByAttributeSetter) {
      // className setter performs necessary style recalculation
      className = value;
    }
  } else {
    final isNeedRecalculate = _checkRecalculateStyle([qualifiedName]);
    if (DebugFlags.enableCssBatchRecalc) {
      ownerDocument.markElementStyleDirty(this, reason: 'batch:attr:$qualifiedName');

    } else {
      recalculateStyle(rebuildNested: isNeedRecalculate);
    }
  }

  // Maintain attribute presence index for presence selectors like [attr].
  // Include class/id/name as well so stylesheet invalidation can target them.
  _updateAttrPresenceIndex(qualifiedName, present: true);

  // Emit CDP DOM.attributeModified for DevTools if something actually changed
  if (changed) {
    try {
      final cb = ownerDocument.controller.view.devtoolsAttributeModified;
      if (cb != null) {
        cb(this, qualifiedName, value);
      } else {
        // Fallback to full tree refresh when incremental hooks are not set
        ownerDocument.controller.view.debugDOMTreeChanged?.call();
      }
    } catch (_) {}
  }

  // Mark semantics dirty for accessibility-relevant attributes.
  if (changed) _markSemanticsDirtyIfNeeded(qualifiedName);
}