Skip to main content

Shared Runtime

The shared runtime contains behavior that multiple forms can reuse.

Two important parts were:

  • reusable shared functions
  • render-timing control

Reusable shared functions​

Shared functions live in shared/functions.js.

A simplified example:

window.disableButton =
window.disableButton ||
function disableButton(button) {
if (!button) return;
button.disabled = true;
};

A form-specific module can reuse it:

if (isAddBlock()) {
const submitButton = document.querySelector(".submit-button");
disableButton(submitButton);
}

Why expose selected helpers globally?​

The Planon scripts are dynamically loaded rather than bundled like a conventional SPA.

The global shared layer makes selected utilities available to independently loaded form modules.

shared/functions.js
│
├── FORM_001.js
├── FORM_002.js
└── FORM_003.js

Handling asynchronous rendering​

Some Planon elements do not exist immediately when JavaScript starts.

script starts
│
├── field does not exist yet
│
▼
Planon renders field later

Direct DOM access can therefore fail.

Shared timing helper​

window.waitForElement = function (selector, timeout = 5000) {
return new Promise((resolve, reject) => {
const startedAt = Date.now();

const timer = setInterval(() => {
const element = document.querySelector(selector);

if (element) {
clearInterval(timer);
resolve(element);
return;
}

if (Date.now() - startedAt > timeout) {
clearInterval(timer);
reject(new Error(`Element not found: ${selector}`));
}
}, 100);
});
};

Usage:

waitForElement(".example-field").then(() => {
runFormLogic();
});

Why centralize timing?​

Without a shared helper, individual forms tend to invent their own delays and polling logic.

With one timing utility:

many forms
↓
one timing strategy
↓
more predictable behavior