_callObserver(transaction, parentSubs) {
    super._callObserver(transaction, parentSubs);

    const event = new YTextEvent(this, transaction, parentSubs);
    const doc = transaction.doc;
    callTypeObservers(this, transaction, event); // If a remote change happened, we try to cleanup potential formatting duplicates.

    if (!transaction.local) {
      // check if another formatting item was inserted
      let foundFormattingItem = false;

      for (const [client, afterClock] of transaction.afterState.entries()) {
        const clock = transaction.beforeState.get(client) || 0;

        if (afterClock === clock) {
          continue;
        }

        iterateStructs(transaction,
        /** @type {Array<Item|GC>} */
        doc.store.clients.get(client), clock, afterClock, item => {
          if (!item.deleted &&
          /** @type {Item} */
          item.content.constructor === ContentFormat) {
            foundFormattingItem = true;
          }
        });

        if (foundFormattingItem) {
          break;
        }
      }

      if (!foundFormattingItem) {
        iterateDeletedStructs(transaction, transaction.deleteSet, item => {
          if (item instanceof GC || foundFormattingItem) {
            return;
          }

          if (item.parent === this && item.content.constructor === ContentFormat) {
            foundFormattingItem = true;
          }
        });
      }

      transact(doc, t => {
        if (foundFormattingItem) {
          // If a formatting item was inserted, we simply clean the whole type.
          // We need to compute currentAttributes for the current position anyway.
          cleanupYTextFormatting(this);
        } else {
          // If no formatting attribute was inserted, we can make due with contextless
          // formatting cleanups.
          // Contextless: it is not necessary to compute currentAttributes for the affected position.
          iterateDeletedStructs(t, t.deleteSet, item => {
            if (item instanceof GC) {
              return;
            }

            if (item.parent === this) {
              cleanupContextlessFormattingGap(t, item);
            }
          });
        }
      });
    }
  }
Creates YTextEvent and calls observers.

@param {Transaction} transaction
@param {Set<null|string>} parentSubs Keys changed on this type. `null` if list was modified.