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