(text:string, authorId = '')
| 582 | } |
| 583 | |
| 584 | async init(text:string, authorId = '') { |
| 585 | // try to load the pad |
| 586 | const value = await this.db.get(`pad:${this.id}`) as Record<string, any> | null; |
| 587 | |
| 588 | // if this pad exists, load it |
| 589 | if (value != null) { |
| 590 | Object.assign(this, value); |
| 591 | if ('pool' in value) this.pool = new AttributePool().fromJsonable(value.pool); |
| 592 | } else { |
| 593 | // Auto-generated default content (settings.defaultPadText or whatever a |
| 594 | // padDefaultContent hook substitutes) is not written by the user who |
| 595 | // happens to open the pad first, so the text must not carry their author |
| 596 | // attribute — otherwise the welcome text shows up in the creator's |
| 597 | // authorship colour (issue #7885). Track whether the text came from the |
| 598 | // default-content path so its insert op can be attributed to the system |
| 599 | // author. |
| 600 | const usedDefaultContent = (text == null); |
| 601 | if (usedDefaultContent) { |
| 602 | const context = {pad: this, authorId, type: 'text', content: settings.defaultPadText}; |
| 603 | await hooks.aCallAll('padDefaultContent', context); |
| 604 | if (context.type !== 'text') throw new Error(`unsupported content type: ${context.type}`); |
| 605 | text = exports.cleanText(context.content); |
| 606 | } |
| 607 | // The author *attribute* applied to the initial text — i.e. what colours |
| 608 | // it in the editor — is the stable system author when the content is |
| 609 | // auto-generated default text (#7885), or when non-empty text was |
| 610 | // supplied without an authorId (internal getPad calls during HTTP API |
| 611 | // setup, plugin-driven pad creation). The latter keeps the insert op |
| 612 | // carrying an `author` attribute, mirroring the substitution |
| 613 | // setText/appendText already do via spliceText. |
| 614 | const attribAuthorId = |
| 615 | ((usedDefaultContent || !authorId) && text.length > 0) |
| 616 | ? Pad.SYSTEM_AUTHOR_ID : authorId; |
| 617 | const firstAttribs = attribAuthorId |
| 618 | ? [['author', attribAuthorId] as [string, string]] |
| 619 | : undefined; |
| 620 | // The *revision* author (revs:0 meta.author) stays the real creator so |
| 621 | // pad ownership is preserved: isPadCreator() / the pad-wide settings gate |
| 622 | // and the deletion token all key off getRevisionAuthor(0). Only when no |
| 623 | // author was supplied at all do we fall back to the system author, so the |
| 624 | // initial revision still records a stable, non-empty author. |
| 625 | const revisionAuthorId = |
| 626 | authorId || (text.length > 0 ? Pad.SYSTEM_AUTHOR_ID : ''); |
| 627 | const firstChangeset = makeSplice('\n', 0, 0, text, firstAttribs, this.pool); |
| 628 | await this.appendRevision(firstChangeset, revisionAuthorId); |
| 629 | } |
| 630 | this.padSettings = Pad.normalizePadSettings(this.padSettings); |
| 631 | await hooks.aCallAll('padLoad', {pad: this}); |
| 632 | } |
| 633 | |
| 634 | async copy(destinationID: string, force: boolean) { |
| 635 | // Kick everyone from this pad. |
no test coverage detected