Read this section before generating any widget code.
Start from the canonical skeleton
Unless the user's request is incompatible with it, base every widget on the canonical widget skeleton. Do not derive the framework include URLs, the new
Decision tree: component type if writing a trading algo
When in doubt, write the algo as a widget. Scripts and UDIXes are specialist options.
Decision tree: storage
Decision tree: data sources
Worked examples: wrong vs right
Wrong — calling Framework before it's ready:
var Framework = new FXB.Framework();
Framework.Ask(...); // undefined behaviour: framework not loaded yet
Framework.OnLoad = function() { /* ... */ };
Right:
var Framework = new FXB.Framework();
Framework.OnLoad = function() {
Framework.Ask(...); // framework guaranteed ready here
};
Wrong — treating Dictionary forEach() like an array's forEach():
Framework.Instruments.forEach( (instr) => {
// The first parameter, instr, is a key, not an object
});
Right:
Framework.Instruments.forEach( (key, instr) => {
// The second parameter is the FXB.Instrument object
});
Wrong — silent failure on floating widgets:
Framework.OnLoad = function() {
var s = Framework.privateSettings || {};
// ... user opens this widget as a floating dialog ...
// ... every time, `s` is empty. Widget appears broken.
};
Right:
var SETTINGS_ID = "my-widget";
Framework.OnLoad = function() {
Framework.LoadCategorySettings(SETTINGS_ID, function(s) {
s = s || {};
// ... always populated correctly, in any context ...
});
};
Wrong — silently dropping updates:
// A single message can carry multiple types simultaneously.
// `switch` and `else if` only match one, dropping the rest.
Framework.OnMessage = function(msg) {
switch (msg.type) {
case FXB.MessageTypes.PRICE: updateQuotes(); break;
case FXB.MessageTypes.ORDER_OPEN: refreshTrades(); break;
}
};
Right:
Framework.OnMessage = function(Msg) {
if (Msg.is(FXB.MessageTypes.PRICE)) updateQuotes();
if (Msg.is(FXB.MessageTypes.ORDER_OPEN)) refreshTrades();
};
Wrong — content clipped by platform chrome, or broken in RTL:
.header { padding: 10px 14px; } /* icons overlap content */
.header { padding: 10px 40px 10px 14px; } /* breaks in Arabic/Hebrew */
Right:
.header {
padding-block: 10px;
padding-inline-start: 14px;
padding-inline-end: var(--widget-chrome-inset-horizontal, 40px);
}
Do not:
Do not invent framework method names. If you cannot find a method in §2 or §3, say so — do not guess.
Do not hard-code theme colours. Always reference CSS variables with a fallback: color: var(--clr-text, #e4e4e4);.
Do not add content at the top inline-end corner of the widget (top-right in LTR, top-left in RTL) without reserving var(--widget-chrome-inset-horizontal, 40px) of space. Never hard-code padding-right for this — use padding-inline-end.
Do not use SavePrivateSettings as a default. Use SaveCategorySettings unless you specifically need per-instance state inside the page container.