Tintero Developers

Events

The 18 events a plugin can subscribe to, and what each one carries.

On this page

Events are how you react to what someone does without checking on a timer. Subscribe with tintero.events.on(). No permission is needed, because subscribing never leaves your own frame. Tintero pushes events out to whichever plugins are running.

Subscribing

plugin.onActivate = async function () {
  const refresh = async () => {
    const count = await tintero.editor.getWordCount();
    document.getElementById('n').textContent = count.words;
  };

  await refresh();
  tintero.events.on('editor.activeDocumentChanged', refresh);
};

tintero.events.off() removes a handler. Handlers do not survive a reload, because every start builds a brand new frame, so subscribe in onActivate every time.

One event does not fit the table, because it hands you a whole object rather than a set of named fields: debug.log gives your callback a single ConsoleEntry, the same shape tintero.debug.getLogs() returns a list of.

project

project.loaded

Payload: projectId , projectName

project.saved

Payload: projectId

project.changed

Fired with nothing attached.

file

file.opened

Payload: fileId , fileName

file.saved

Payload: fileId , fileName

file.closed

Payload: fileId

character

character.added

Payload: characterId , characterName

character.updated

Payload: characterId , characterName

character.deleted

Payload: characterId

worldbuilding

worldbuilding.added

Payload: elementId , elementType

worldbuilding.updated

Payload: elementId , elementType

worldbuilding.deleted

Payload: elementId

editor

editor.selectionChanged

Payload: documentId : string , from : number , to : number , empty : boolean

editor.activeDocumentChanged

Payload: documentId : string , name : string | null

plugin

plugin.activated

Declared in the type definitions, but nothing in the app fires it. Subscribing does nothing.

plugin.deactivated

Declared in the type definitions, but nothing in the app fires it. Subscribing does nothing.

storage

storage.changed

Payload: key ?: string

debug

debug.log

Fired with a whole object rather than a field list. See the note above.

When events arrive

Your plugin only receives events once it has signalled that it is ready, which the SDK does for you as soon as your script finishes running. Anything that happened before then is not replayed Read the current state in onActivate rather than waiting for an event to tell you what it already is.

storage.changed is the exception worth knowing: it fires on your plugin's other surfaces, never on the one that performed the write. That asymmetry is what makes it usable for keeping a sidebar panel and a full view in sync without a loop.