JavaScript on the sheet
When HTML attributes are not enough (some math, a special button, a rule of your system), JavaScript
comes in. Everything goes through the RPGDesk object, which rpgdesk.js creates. The complete list of
functions is in The rpgdesk.js API.
Connect
Section titled “Connect”RPGDesk.connect().then(({ doc, me, item, room, kind, language, test }) => { // everything that uses the document starts here});RPGDesk.connect() waits for the connection with RPG Desk (or with test mode) and returns the
context:
| Field | What it is |
|---|---|
doc |
the sheet’s document (see below) |
me |
who is looking: { id, nick, role, isOwner }. role is 'gm', 'player' or 'spectator' |
item |
the sheet: { id, name, type, ownerId } |
room |
the room: { id, name, system } |
kind |
'sheet' or 'table' (room table) |
language |
'pt' or 'en', the RPG Desk language of whoever is looking |
test |
true in test mode, outside RPG Desk |
plugin |
your plugin’s { id, version } |
You can call RPGDesk.connect() as many times as you want: it is always the same connection. Once
connected, RPGDesk.context and RPGDesk.doc also give you the context and the document.
Read and write
Section titled “Read and write”doc.get('name'); // 'Aria'doc.get('hp'); // { current: 18, max: 22 } (a group becomes an object)doc.get('does_not_exist'); // undefined
await doc.set('level', 4); // writes a fieldawait doc.set('hp', { current: 10, max: 12 }); // writes field by field (what is missing stays)await doc.set('notes', null); // deletesawait doc.update({ 'hp.current': 3, 'hp.max': 10 }); // several at once- Values are texts, numbers, true/false or objects made of them. Lists are written through the list API (see below).
setandupdatereturn a promise: the write goes to RPG Desk, which checks the permission and sends the change back in milliseconds.doc.batch(() => { … })joins several writes into a single batch, applied whole or refused whole.doc.canWrite('hp.current')says whether the person can write there.
A write without permission (a player writing on someone else’s sheet) is refused. To find out:
doc.on('rejected', (message) => RPGDesk.ui.toast(message, 'error'));Follow the changes
Section titled “Follow the changes”const stop = doc.watch('hp', (hp, { local }) => { bar.style.width = `${(hp.current / hp.max) * 100}%`;}, { now: true });watchtells you about every change on the path, or on any field inside it, whoever made it.{ now: true }calls the function right away, with the current value.localsays whether the change came from this browser.watchreturns the function that stops it.
Computed fields
Section titled “Computed fields”A value that comes from others (an attribute’s modifier, the total load) is computed with
doc.compute:
const mod = (value) => Math.floor(((Number(value) || 10) - 10) / 2);doc.compute('str_mod', ['strength'], mod);doc.compute('defense', ['dexterity', 'armor'], (dex, armor) => 10 + mod(dex) + (Number(armor) || 0));doc.compute(target, [sources], function) writes the target when a source changes. Show the result
with data-text or use it in rolls (data-roll="1d20 + {str_mod}").
const inv = doc.list('inventory');
inv.items(); // [{ id: 'i1…', name: 'Rope', qty: 1 }, …]inv.length; // 1const id = inv.add({ name: 'Torch', qty: 3 }); // at the end; inv.add(value, 0) puts it firstawait inv.item(id).set('qty', 2);await inv.move(id, 0); // changes its positionawait inv.remove(id);inv.watch((items) => totalEl.textContent = items.length, { now: true });- Each item has its own
id, whichaddreturns right away. inv.item(id)hasget,set,watchandremove, with paths relative to the item.- Paths can also be arrays:
['inventory', '#' + id, 'qty']is theqtyfield of itemid.
Room events
Section titled “Room events”RPGDesk.on('players', (players) => { /* someone joined or left */ });RPGDesk.on('me', (me) => { /* my role changed */ });RPGDesk.on('language', (lang) => { /* 'pt' or 'en' */ });RPGDesk.on('theme', (colors) => { /* the theme colors changed */ });RPGDesk.on('library', (items) => { /* the library changed */ });RPGDesk.on returns the function that stops listening.
A sheet in two languages
Section titled “A sheet in two languages”Use language to switch the texts:
const TEXTS = { pt: { roll: 'Rolar' }, en: { roll: 'Roll' } };RPGDesk.connect().then(({ language }) => { for (const b of document.querySelectorAll('[data-roll]')) b.textContent = TEXTS[language].roll;});The plugin’s name and the sheet’s title, in the manifest, also accept both languages:
"title": { "pt": "Personagem", "en": "Character" }. See The manifest.
When something fails
Section titled “When something fails”An error in your code does not bring the room down: the sheet shows a badge with the number of Page errors, and the panel has Copy errors. In test mode, errors show up in the Log. See Test and develop.