Options
All
  • Public
  • Public/Protected
  • All
Menu

Class CRichText<F>

A collaborative rich-text string, i.e., a text string with inline formatting.

Each character has an associated format of type Record<string, any>, which maps from format keys to format values. Use format to format a range, and use formatted to access an efficient representation of the formatted text. Otherwise, the API is similar to CText.

You can restrict the allowed format keys and their value types by using an interface for the generic type F, e.g.,

interface MyFormat {
bold: true;
link: string;
}
const text = new CRichText<MyFormat>(...);

Note that undefined is always allowed as a format value, indicating that a key is not present. Thus we use type Partial<F> to describe a character's format.

Internally, formats are controlled by formatting spans, which set (or delete) a format key-value pair in a given range of text. A span affects all characters in its range, including concurrent or future characters, until overridden by another span.

For a detailed discussion of formatting spans' behavior, see Peritext, which this Collab approximately implements. Note that you can tune spans' behavior using the noGrowAtEnd constructor option.

It is not safe to modify a CRichText while iterating over it. The iterator will attempt to throw an exception if it detects such modification, but this is not guaranteed.

See also:

Type Parameters

  • F extends Record<string, any> = Record<string, any>

    The allowed format keys and value types, represented as an interface (or Record type) mapping string keys to their value types. Default: Record<string, any>.

Hierarchy

Implements

Index

Constructors

  • new CRichText<F>(init: InitToken, options?: { formatSerializer?: Serializer<F[keyof F & string]>; noGrowAtEnd?: Iterable<keyof F & string> }): CRichText<F>
  • Constructs a CRichText.

    Type Parameters

    • F extends Record<string, any> = Record<string, any>

    Parameters

    • init: InitToken
    • Optional options: { formatSerializer?: Serializer<F[keyof F & string]>; noGrowAtEnd?: Iterable<keyof F & string> }
      • Optional formatSerializer?: Serializer<F[keyof F & string]>

        Serializer for format values. Defaults to DefaultSerializer.

      • Optional noGrowAtEnd?: Iterable<keyof F & string>

        A collection of format keys whose spans will not grow at the end: they will not affect concurrent and future characters inserted at the end of their original range (but will still affect the middle).

        By default, this is empty. You may wish to include formats like hyperlinks, as described in Peritext's Example 9.

    Returns CRichText<F>

Properties

children: Map<string, Collab<CollabEventsRecord>>

The children (registered Collab properties), keyed by name.

This map should only be read, not mutated. It is exposed to subclasses as a convenience for methods that loop over all children.

name: string

Internal (this/parent) use only.

This Collab's name, which distinguishes it among its siblings in the tree of Collabs.

parent: Parent

Internal (this/parent) use only.

This Collab's parent in the tree of Collabs.

runtime: IRuntime

The ambient IRuntime.

Use this to access utilities like IRuntime.replicaID.

Accessors

  • get length(): number
  • The length of the text string.

    Returns number

  • The abstract total order underlying this text CRDT.

    Access this to construct separate LocalList views on top of the same total order.

    Returns CTotalOrder

Methods

  • Iterates over an efficient representation of the formatted text.

    Specifically, this method iterates over the formatted ranges in text order (as returned by formatted).

    Returns IterableIterator<RichTextRange<F>>

  • canGC(): boolean
  • Internal (parent) use only.

    By default, this method returns true if canGC returns true on every child. Override to change this behavior.

    See Collab.canGC.

    Returns boolean

  • charAt(index: number): string
  • Returns a string consisting of the single character (UTF-16 codepoint) at index.

    throws

    If index is not in [0, this.length). Note that this differs from an ordinary string, which would instead return an empty string.

    Parameters

    • index: number

    Returns string

  • Internal (Collab.send) use only.

    Sends the given message on behalf of child. In general, this parent is then responsible for delivering the given message to Collab.receive on each replica of child, with guarantees set by the runtime.

    Parameters

    Returns void

  • clear(): void
  • Deletes every character in the text string.

    Returns void

  • delete(index: number, count?: number): void
  • Delete count characters starting at index, i.e., characters [index, index + count - 1).

    All later characters shift to the left, decreasing their indices by count.

    throws

    if index < 0 or index + count >= this.length.

    Parameters

    • index: number
    • Optional count: number

      The number of characters to delete. Defaults to 1 (delete the character at index only).

    Returns void

  • Emits an event, which triggers all the registered event handlers.

    See CollabEventsRecord for advice on what events to emit.

    This is a wrapper around EventEmitter.emit that forces events to extend CollabEvent and also emits an "Any" event.

    Type Parameters

    Parameters

    • eventName: K
    • event: RichTextEventsRecord<F>[K] & CollabEvent
    • Optional options: { skipAnyEvent?: boolean }
      • Optional skipAnyEvent?: boolean

        Set to true to skip emitting an "Any" event.

    Returns void

  • entries(): IterableIterator<[index: number, value: string, format: Partial<F>, position: string]>
  • Returns an iterator of [index, value, format, position] tuples for every character (value) in the text string, in order.

    Typically, you should instead use formatted, which returns a more efficient representation of the formatted text.

    Returns IterableIterator<[index: number, value: string, format: Partial<F>, position: string]>

  • finalize(): void
  • Internal (parent) use only.

    By default, this methods calls finalize on every child. Override to change this behavior, e.g., to add your own finalization steps (but consider calling super.finalize()).

    Returns void

  • format<K>(startIndex: number, endIndex: number, key: K, value: undefined | F[K]): void
  • Formats the range of text [startIndex, endIndex) (i.e., text.slice(startIndex, endIndex)), setting the given format key to value.

    Internally, this creates a new formatting span, even if it is redundant. The span's grow-at-end behavior is determined by the noGrowAtEnd constructor option.

    Type Parameters

    • K extends string

    Parameters

    • startIndex: number
    • endIndex: number
    • key: K
    • value: undefined | F[K]

      If undefined, the format key is deleted, clearing its current value.

    Returns void

  • Returns an efficient representation of the formatted text.

    Specifically, returns an array of formatted ranges in text order.

    Returns RichTextRange<F>[]

  • fromID<C>(id: CollabID<C>, startIndex?: number): undefined | C
  • Inverse of idOf.

    Specifically, given a CollabID returned by idOf on some replica of this parent, returns this replica's copy of the original descendant. If that descendant does not exist (e.g., it was deleted or it is not present in this program version), returns undefined.

    Type Parameters

    Parameters

    • id: CollabID<C>
    • Optional startIndex: number

    Returns undefined | C

  • getByPosition(position: string): undefined | string
  • Returns the value at position, or undefined if it is not currently present (hasPosition returns false).

    Parameters

    • position: string

    Returns undefined | string

  • getFormat(index: number): Partial<F>
  • Returns the format for the character at index.

    throws

    If index is not in [0, this.length).

    Parameters

    • index: number

    Returns Partial<F>

  • getPosition(index: number): string
  • Parameters

    • index: number

    Returns string

    The position currently at index.

  • hasPosition(position: string): boolean
  • Returns whether position is currently present in the list, i.e., its value is present.

    Parameters

    • position: string

    Returns boolean

  • Returns a CollabID for the given strict descendant of this parent.

    The CollabID may be passed to fromID on any replica of this parent (but not other parents) to obtain that replica's copy of descendant.

    Type Parameters

    Parameters

    • descendant: C

    Returns CollabID<C>

  • indexOfPosition(position: string, searchDir?: "none" | "left" | "right"): number
  • Returns the current index of position.

    If position is not currently present in the list (hasPosition returns false), then the result depends on searchDir:

    • "none" (default): Returns -1.
    • "left": Returns the next index to the left of position. If there are no values to the left of position, returns -1.
    • "right": Returns the next index to the right of position. If there are no values to the left of position, returns length.

    Parameters

    • position: string
    • Optional searchDir: "none" | "left" | "right"

    Returns number

  • insert(index: number, values: string, format: Partial<F>): void
  • Inserts values as a substring at the given index, with the given initial format.

    All values currently at or after index shift to the right, increasing their indices by values.length.

    Initially, the characters inherit some format from existing formatting spans. If this does not match format, we create new formatting spans for the differing format keys.

    throws

    If index is not in [0, this.length].

    Parameters

    • index: number

      The insertion index in the range [0, this.length]. If this.length, the values are appended to the end of the list.

    • values: string

      The characters to insert. They are inserted as individual UTF-16 codepoints.

    • format: Partial<F>

      The characters' initial format.

    Returns void

  • Internal (parent) use only.

    Called by this Collab's parent to load saved state. See Collab.load.

    A CObject subclass may override this method to load additional state from Collab.save or to perform extra setup - e.g., refreshing functional views that were not automatically updated by children's load events. It is recommended to do so as follows:

    load(savedStateTree: SavedStateTree | null, meta: SavedStateMeta) {
    super.load(savedStateTree, meta);
    // Process your extra saved state from savedStateTree.self.
    const savedState = savedStateTree === null? null: savedStateTree.self!;
    ...
    // Perform extra setup as needed.
    ...
    }

    Parameters

    Returns void

  • Registers an event handler that is triggered when the event happens.

    Type Parameters

    Parameters

    • eventName: K

      Name of the event to listen on.

    • handler: ((event: RichTextEventsRecord<F>[K], caller: CRichText<F>) => void)

      Callback that handles the event.

    • Optional options: { once?: boolean }
      • Optional once?: boolean

        If true, the event handler is triggered at most once (the next time the event happens), then unsubscribed.

    Returns (() => void)

    An "off" function that removes the event handler when called.

      • (): void
      • Registers an event handler that is triggered when the event happens.

        Returns void

        An "off" function that removes the event handler when called.

  • positions(): IterableIterator<string>
  • Returns an iterator for present positions, in list order.

    Returns IterableIterator<string>

  • push(values: string, format: Partial<F>): void
  • Inserts values as a substring at the end of the text, with the given format. Equivalent to this.insert(this.length, values, format).

    Parameters

    • values: string
    • format: Partial<F>

    Returns void

  • receive(messageStack: (string | Uint8Array)[], meta: MessageMeta): void
  • Internal (parent) use only.

    Receives a message sent by send on a local or remote replica of this Collab.

    This method processes the message, changes the local state accordingly, and emits events describing the local changes.

    This method should make assumptions and ensure consistency guarantees appropriate to its use case. For example, CRDTs may assume eventual, exactly-once, causal-order message delivery, and they must ensure strong eventual consistency.

    Parameters

    Returns void

  • registerCollab<C>(name: string, collabCallback: ((init: InitToken) => C)): C
  • Registers a Collab property of this CObject with the given name, making it one of our children.

    Typically, you will call this method during the constructor in the style:

    this.foo = this.registerCollab("foo", (init) => new FooClass(init, constructor args...));
    

    where readonly foo: FooClass; is a Collab property. See Data Modeling for examples.

    Registrations must be identical across all replicas.

    See also: CRuntime.registerCollab.

    Type Parameters

    Parameters

    • name: string

      A name for this property, unique among this class's registerCollab calls. We recommend using the same name as the property, but you can also use short strings to reduce network usage ("", "0", "1", ...).

    • collabCallback: ((init: InitToken) => C)

      A callback that uses the given InitToken to construct the registered Collab.

    Returns C

    The registered Collab.

  • Internal (parent) use only.

    Returns saved state describing the current state of this CObject. See Collab.save.

    A CObject subclass may override this method to save additional state. It is recommended to do so as follows:

    save() {
    const ans = super.save();
    // Put your extra saved state in ans.self, which is otherwise unused.
    ans.self = <subclass's saved state>;
    return ans;
    }

    Returns SavedStateTree

  • send(messageStack: (string | Uint8Array)[], metaRequests: MetaRequest[]): void
  • Broadcasts a message to other replicas of this Collab. The message will be delivered to all replicas' receive, including locally.

    For convenience, the message may be expressed as a stack of (Uint8Array | string), instead of just a single Uint8Array. This is useful for parents sending messages on behalf of their children; see the implementation of CObject for an example.

    Parameters

    • messageStack: (string | Uint8Array)[]

      The message to send, in the form of a stack of Uint8Arrays. Note that this method may mutate it in-place.

    • metaRequests: MetaRequest[]

      A stack of metadata requests. The runtime will use the union of these when creating the MessageMeta for receive. Note that the stack need not align with messageStack, and this method may mutate it in place.

    Returns void

  • slice(start?: number, end?: number): string
  • Returns a section of this text string, with behavior like String.slice.

    Parameters

    • Optional start: number
    • Optional end: number

    Returns string

  • splice(start: number, deleteCount: number): string
  • splice(start: number, deleteCount: undefined | number, values: string, format: Partial<F>): string
  • Deletes and inserts values like Array.splice.

    If deleteCount is provided, this method first deletes deleteCount values starting at start. Next, this method inserts values as a substring at start, with the given format.

    All values currently at or after start + deleteCount shift to accommodate the change in length.

    Parameters

    • start: number
    • deleteCount: number

    Returns string

    The deleted substring.

  • Parameters

    • start: number
    • deleteCount: undefined | number
    • values: string
    • format: Partial<F>

    Returns string

  • toString(): string
  • Returns the plain text as an ordinary string.

    Returns string

  • unshift(values: string, format: Partial<F>): void
  • Inserts values as a substring at the beginning of the text, with the given format. Equivalent to this.insert(0, values, format).

    Parameters

    • values: string
    • format: Partial<F>

    Returns void

  • values(): IterableIterator<string>
  • Returns an iterator for characters (values) in the text string, in order.

    See also: toString, which returns the entire (plain) text as a string.

    Returns IterableIterator<string>

Generated using TypeDoc