replaceAll method

EditResult replaceAll(
  1. Iterable<TextStoryReplacement> replacements, {
  2. String label = 'Edit text',
  3. StorySelection? selectionAfter,
})

Replaces distinct stories in one admitted publication and undo entry. Any stale story, invalid replacement or denied target rejects the batch.

Implementation

EditResult replaceAll(
  Iterable<TextStoryReplacement> replacements, {
  String label = 'Edit text',
  StorySelection? selectionAfter,
}) {
  final edits = List<TextStoryReplacement>.of(replacements);
  final targets = <(String, String)>{};
  for (final edit in edits) {
    if (!targets.add((edit.elementId, edit.before.id))) {
      return _invalid('A story may be replaced only once per edit');
    }
    if (edit.before.id != edit.after.id) {
      return _invalid('Text replacement must preserve story identity');
    }
    final target = ResolvedDiagramTextTarget.resolve(
      store.scene.elementById(edit.elementId),
      edit.before.id,
    );
    if (target == null) return _noTarget;
    if (_unavailable(target) case final denial?) return denial;
    final source = store.state.document.elementById(edit.elementId);
    if (source == null ||
        !store.diagram.resolver.registry.admitsStory(source, edit.after)) {
      return const EditResult.denied(
        code: DiagramDenialCode.unsupportedOperation,
        reason: 'The text does not fit its text slot',
      );
    }
  }
  if (selectionAfter != null &&
      !targets.contains((selectionAfter.elementId, selectionAfter.storyId))) {
    return _invalid('Text selection must refer to an edited story');
  }
  // Stories of one element, such as several connector labels, replace
  // together in one element replacement.
  final document = store.state.document;
  final replaced = <String, (DiagramElement, DiagramElement)>{};
  for (final edit in edits) {
    final (original, current) =
        replaced[edit.elementId] ??
        (() {
          final element = document.elementById(edit.elementId)!;
          return (element, element);
        })();
    final target = DiagramTextTarget.resolve(current, edit.before.id);
    if (target == null || target.story != edit.before) {
      return EditResult.denied(
        code: DiagramDenialCode.conflict,
        reason: 'Text story ${edit.before.id} changed before the edit',
      );
    }
    replaced[edit.elementId] = (original, target.replaceStory(edit.after));
  }
  return store.edits.dispatch(
    DiagramTransaction(
      label: label,
      steps: [
        for (final (before, after) in replaced.values)
          ReplaceElementStep(before: before, after: after),
      ],
      selectionAfter: selectionAfter,
    ),
  );
}