receiveChanges method

void receiveChanges(
  1. Map<String, dynamic> message
)

Implementation

void receiveChanges(Map<String, dynamic> message) {
  final nodeID = message["target"] as String?;
  final target = message["root"] == true ? root : root.getNodeByID(nodeID!);
  // process element deltas

  num retain = 0;
  for (final delta in message["elements"]) {
    if (delta["retain"] != null) {
      retain += delta["retain"];
    }
    if (delta["insert"] != null) {
      for (final insert in delta["insert"] as List) {
        if (insert["element"] != null) {
          target!._children.insert(retain.toInt(), _createNode(target, insert));
          retain++;
        } else if (insert["text"] != null) {
          target!._children.insert(retain.toInt(), _createNode(target, insert));
          retain++;
        } else {
          throw Exception("Unsupported element delta");
        }
      }
    } else if (delta["delete"] != null) {
      target!._children.removeRange(retain.toInt(), (retain + (delta["delete"] as num)).toInt());
      retain -= delta["delete"];
    }
  }

  // process text deltas
  List? text = message["text"];
  if (text != null && text.isNotEmpty) {
    if (target!.tagName != "text") {
      throw Exception('Node is not a text node: $target.tagName');
    }

    final textNode = target._children[0] as TextElement;
    num retain = 0;
    int i = 0;
    num offset = 0;
    var targetDelta = textNode.delta;

    for (final delta in text) {
      if (delta["insert"] != null) {
        if (i == targetDelta.length) {
          targetDelta.add({"insert": delta["insert"], "attributes": delta["attributes"] ?? {}});
          i++;
          offset += (delta["insert"] as String).length;
          retain += (delta["insert"] as String).length;
        } else {
          final str = targetDelta[i]["insert"] as String;
          targetDelta[i]["insert"] =
              str.substring(0, (retain - offset).toInt()) + delta["insert"] + str.substring((retain - offset).toInt());
          retain += (delta["insert"] as String).length;
        }
      } else if (delta["delete"] != null) {
        num deleted = 0;
        while (delta["delete"] > deleted) {
          num remaining = delta["delete"] - deleted;

          // delete ends after item
          if (retain > offset) {
            // delete end
            final str = targetDelta[i]["insert"] as String;
            final start = str.substring(0, (retain - offset).toInt());
            final end = str.substring((retain - offset).toInt());

            if (remaining >= end.length) {
              targetDelta[i]["insert"] = start;
              deleted += end.length;
              i++;
              offset += str.length;
            } else {
              targetDelta[i]["insert"] = start + end.substring(remaining.toInt());
              deleted += (targetDelta[i]["insert"] as String).length;
            }
          } else if (delta["delete"] - deleted >= (targetDelta[i]["insert"] as String).length) {
            // delete segment
            deleted += (targetDelta[i]["insert"] as String).length;
            targetDelta.removeAt(i);
            //offset += targetDelta.splice(i, 1);
          } else {
            // delete ends inside item, delete front
            final str = targetDelta[i]["insert"] as String;
            final start = str.substring(0, remaining.toInt());
            final end = str.substring(remaining.toInt());
            targetDelta[i]["insert"] = end;
            deleted += start.length;
          }
        }
      } else if (delta["attributes"] != null) {
        num formatted = 0;
        while (delta["retain"] as num > formatted) {
          // format ends after item
          num remaining = delta["retain"] - formatted;

          if (targetDelta[i]["attributes"] == null) {
            targetDelta[i]["attributes"] = <String, dynamic>{};
          }

          if (retain > offset) {
            // format end
            final str = targetDelta[i]["insert"] as String;
            final start = str.substring(0, (retain - offset).toInt());
            final end = str.substring((retain - offset).toInt());

            if (remaining >= end.length) {
              targetDelta[i]["insert"] = start;
              targetDelta.insert(i + 1, {
                "insert": end,
                "attributes": {...targetDelta[i]["attributes"] as Map, ...delta["attributes"] as Map},
              });

              formatted += end.length;
              // move to next item
              i++;
              i++;
              offset += str.length;
            } else {
              targetDelta[i]["insert"] = start;
              targetDelta.insert(i + 1, {
                "insert": end.substring(0, remaining.toInt()),
                "attributes": {...targetDelta[i]["attributes"] as Map, ...delta["attributes"] as Map},
              });
              targetDelta.insert(i + 2, {
                "insert": end.substring(remaining.toInt()),
                "attributes": {...targetDelta[i]["attributes"] as Map},
              });

              formatted += remaining;
              i++;
              i++;
              i++;
              offset += start.length + remaining;
            }
          } else if (delta["retain"] - formatted >= (targetDelta[i]["insert"] as String).length) {
            formatted += (targetDelta[i]["insert"] as String).length;

            // format whole item
            for (final k in (delta["attributes"] as Map<String, dynamic>).keys) {
              targetDelta[i]["attributes"][k] = delta["attributes"][k];
            }
            offset += (targetDelta[i]["insert"] as String).length;
            i++;
          } else {
            // format ends inside item, format front
            final str = targetDelta[i]["insert"] as String;
            final start = str.substring(0, remaining.toInt());
            final end = str.substring(remaining.toInt());
            targetDelta[i]["insert"] = start;
            targetDelta.add({
              "insert": end,
              "attributes": {...targetDelta[i]["attributes"] as Map},
            });
            for (final k in (delta["attributes"] as Map).keys) {
              targetDelta[i]["attributes"][k] = delta["attributes"][k];
            }
            formatted += (delta["retain"] - formatted);
          }
        }
        retain += delta["retain"];
      } else if (delta["retain"] != null) {
        if (delta["retain"] != null) {
          retain += delta["retain"];
        }

        while (retain > (offset + ((targetDelta[i]["insert"] as String?)?.length ?? 0)).toInt()) {
          offset += (targetDelta[i]["insert"] as String).length;
          i++;
        }
      }
    }
  }

  for (final change in message["attributes"]["set"] as List) {
    target!.attributes[change["name"]] = change["value"];
    target.notifyListeners();
  }

  for (final name in message["attributes"]["delete"] as List) {
    target!.attributes.remove(name);
    target.notifyListeners();
  }

  notifyListeners();
  _changes.add(message);
}