updateElement method

  1. @override
void updateElement(
  1. String tag,
  2. String? id,
  3. String? classes,
  4. Map<String, String>? styles,
  5. Map<String, String>? attributes,
  6. Map<String, EventCallback>? events,
)
override

Implementation

@override
void updateElement(String tag, String? id, String? classes, Map<String, String>? styles,
    Map<String, String>? attributes, Map<String, EventCallback>? events) {
  late Set<String> attributesToRemove;
  late html.Element elem;

  var namespace = xmlns[tag];
  if ((namespace, parent?.node) case (== null, html.Element pnode)) {
    namespace = pnode.namespaceUri;
  }

  diff:
  if (node == null) {
    var toHydrate = parent!.toHydrate;
    if (toHydrate.isNotEmpty) {
      for (var e in toHydrate) {
        if (e is html.Element && e.tagName.toLowerCase() == tag) {
          if (kVerboseMode) {
            print("Hydrate html node: $e");
          }
          elem = node = e;
          attributesToRemove = elem.attributes.keys.toSet();
          toHydrate.remove(e);
          Iterable<Node> nodes = e.nodes;
          if (kDebugMode) {
            nodes = nodes.where((node) => node is! html.Text || (node.text ?? '').trim().isNotEmpty);
          }
          this.toHydrate = nodes.toList();
          break diff;
        }
      }
    }

    elem = node = _createElement(tag, namespace);
    attributesToRemove = {};
    if (kVerboseMode) {
      print("Create html node: $elem");
    }
  } else {
    if (node is! html.Element || (node as html.Element).tagName.toLowerCase() != tag) {
      elem = _createElement(tag, namespace);
      var old = node;
      node!.replaceWith(elem);
      node = elem;
      if (old != null && old.childNodes.isNotEmpty) {
        var oldChildren = [...old.childNodes];
        for (var child in oldChildren) {
          elem.append(child);
        }
      }
      attributesToRemove = {};
      if (kVerboseMode) {
        print("Replace html node: $elem for $old");
      }
    } else {
      elem = node as html.Element;
      attributesToRemove = elem.attributes.keys.toSet();
    }
  }

  elem.clearOrSetAttribute('id', id);
  elem.clearOrSetAttribute('class', classes == null || classes.isEmpty ? null : classes);
  elem.clearOrSetAttribute('style',
      styles == null || styles.isEmpty ? null : styles.entries.map((e) => '${e.key}: ${e.value}').join('; '));

  if (attributes != null && attributes.isNotEmpty) {
    for (var attr in attributes.entries) {
      if (attr.key == 'value' && elem is InputElement && elem.value != attr.value) {
        if (kVerboseMode) {
          print("Set input value: ${attr.value}");
        }
        elem.value = attr.value;
        continue;
      }
      elem.clearOrSetAttribute(attr.key, attr.value);
    }
  }

  attributesToRemove.removeAll(['id', 'class', 'style', ...?attributes?.keys]);
  if (attributesToRemove.isNotEmpty) {
    for (final name in attributesToRemove) {
      elem.removeAttribute(name);
      if (kVerboseMode) {
        print("Remove attribute: $name");
      }
    }
  }

  if (events != null && events.isNotEmpty) {
    final prevEventTypes = this.events?.keys.toSet();
    this.events ??= <String, EventBinding>{};
    final dataEvents = this.events!;
    events.forEach((type, fn) {
      prevEventTypes?.remove(type);
      final currentBinding = dataEvents[type];
      if (currentBinding != null) {
        currentBinding.fn = fn;
      } else {
        dataEvents[type] = EventBinding(elem, type, fn);
      }
    });
    prevEventTypes?.forEach((type) {
      dataEvents.remove(type)?.clear();
    });
  } else {
    clearEvents();
  }
}