feat: instance embed SSE live push and lighter tab revisit
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -60,45 +60,52 @@
|
||||
else history.pushState({ embedTab: tab }, "", url);
|
||||
}
|
||||
|
||||
function runPageInit(tab) {
|
||||
function runPageInit(tab, opts) {
|
||||
const options = opts || {};
|
||||
const revisit = !!options.revisit;
|
||||
document.body.setAttribute("data-page", tab);
|
||||
if (typeof global.attachListWindowToExports === "function") {
|
||||
global.attachListWindowToExports();
|
||||
}
|
||||
if (tab === "trade") {
|
||||
if (typeof global.refreshOrderDefaults === "function") global.refreshOrderDefaults();
|
||||
if (typeof global.initOrderEntryModelSelect === "function") {
|
||||
if (!revisit && typeof global.refreshOrderDefaults === "function") global.refreshOrderDefaults();
|
||||
if (!revisit && typeof global.initOrderEntryModelSelect === "function") {
|
||||
const root = pageRoot() || document;
|
||||
global.initOrderEntryModelSelect(root);
|
||||
}
|
||||
if (global.ManualOrderRrPreview && typeof global.ManualOrderRrPreview.wire === "function") {
|
||||
if (!revisit && global.ManualOrderRrPreview && typeof global.ManualOrderRrPreview.wire === "function") {
|
||||
global.ManualOrderRrPreview.wire();
|
||||
}
|
||||
}
|
||||
if (tab === "key_monitor" && global.KeyMonitorForm && typeof global.KeyMonitorForm.init === "function") {
|
||||
if (!revisit && tab === "key_monitor" && global.KeyMonitorForm && typeof global.KeyMonitorForm.init === "function") {
|
||||
global.KeyMonitorForm.init();
|
||||
}
|
||||
if (tab === "strategy" && typeof global.initStrategyRollForm === "function") {
|
||||
if (!revisit && tab === "strategy" && typeof global.initStrategyRollForm === "function") {
|
||||
global.initStrategyRollForm();
|
||||
}
|
||||
if (tab === "records") {
|
||||
if (!revisit && tab === "records") {
|
||||
if (typeof global.loadJournals === "function") global.loadJournals();
|
||||
if (typeof global.loadReviews === "function") global.loadReviews();
|
||||
if (typeof global.toggleReviewMode === "function") global.toggleReviewMode();
|
||||
}
|
||||
if (tab === "stats") {
|
||||
if (!revisit && tab === "stats") {
|
||||
if (typeof global.initStatsSegmentFromUrl === "function") global.initStatsSegmentFromUrl();
|
||||
}
|
||||
if (typeof global.refreshPriceSnapshotConditional === "function") {
|
||||
global.refreshPriceSnapshotConditional();
|
||||
if (revisit && tab === "options" && global.OptionsPanelLive && typeof global.OptionsPanelLive.refreshSoft === "function") {
|
||||
global.OptionsPanelLive.refreshSoft();
|
||||
}
|
||||
if (global.SymbolLivePrice && typeof global.SymbolLivePrice.init === "function") {
|
||||
const root = pageRoot() || document;
|
||||
global.SymbolLivePrice.init(root);
|
||||
}
|
||||
if (global.JournalUploadSlots && typeof global.JournalUploadSlots.init === "function") {
|
||||
const root = pageRoot() || document;
|
||||
global.JournalUploadSlots.init(root);
|
||||
if (!revisit) {
|
||||
if (typeof global.refreshPriceSnapshotConditional === "function") {
|
||||
global.refreshPriceSnapshotConditional();
|
||||
}
|
||||
if (global.SymbolLivePrice && typeof global.SymbolLivePrice.init === "function") {
|
||||
const root = pageRoot() || document;
|
||||
global.SymbolLivePrice.init(root);
|
||||
}
|
||||
if (global.JournalUploadSlots && typeof global.JournalUploadSlots.init === "function") {
|
||||
const root = pageRoot() || document;
|
||||
global.JournalUploadSlots.init(root);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,7 +199,7 @@
|
||||
showPane(tab);
|
||||
setNavActive(tab);
|
||||
if (!options.skipUrl) syncUrl(tab, !!options.replace);
|
||||
runPageInit(tab);
|
||||
runPageInit(tab, { revisit: !!options.revisit });
|
||||
}
|
||||
|
||||
async function loadTab(tab, opts) {
|
||||
@@ -200,7 +207,7 @@
|
||||
if (!tab) return;
|
||||
|
||||
if (tabPanes.has(tab) && !options.force) {
|
||||
activateTab(tab, options);
|
||||
activateTab(tab, Object.assign({}, options, { revisit: true }));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* embed 壳:SSE 收到后台 tick 后拉 JSON 快照更新 DOM,切换 tab 不再重复请求 HTML。
|
||||
*/
|
||||
(function (global) {
|
||||
let liveEventSource = null;
|
||||
let liveReconnectTimer = null;
|
||||
let localLiveVersion = -1;
|
||||
let sseConnected = false;
|
||||
|
||||
function isEmbedShell() {
|
||||
return document.body && document.body.getAttribute("data-embed-shell") === "1";
|
||||
}
|
||||
|
||||
function currentTab() {
|
||||
if (global.InstanceEmbed && typeof global.InstanceEmbed.getTab === "function") {
|
||||
return global.InstanceEmbed.getTab();
|
||||
}
|
||||
return document.body.getAttribute("data-page") || "trade";
|
||||
}
|
||||
|
||||
function refreshTabData(tab, opts) {
|
||||
const options = opts || {};
|
||||
if (typeof global.refreshAccountSnapshot === "function") {
|
||||
global.refreshAccountSnapshot();
|
||||
}
|
||||
if (typeof global.refreshPriceSnapshotConditional === "function") {
|
||||
global.refreshPriceSnapshotConditional();
|
||||
}
|
||||
if (tab === "options" && global.OptionsPanelLive && typeof global.OptionsPanelLive.refreshSoft === "function") {
|
||||
global.OptionsPanelLive.refreshSoft(options);
|
||||
}
|
||||
}
|
||||
|
||||
function onLiveEvent(data) {
|
||||
const ver = Number(data && data.live_version) || 0;
|
||||
if (!ver || ver === localLiveVersion) return;
|
||||
localLiveVersion = ver;
|
||||
refreshTabData(currentTab(), { silent: true });
|
||||
}
|
||||
|
||||
function closeLiveStream() {
|
||||
if (liveEventSource) {
|
||||
liveEventSource.close();
|
||||
liveEventSource = null;
|
||||
}
|
||||
if (liveReconnectTimer) {
|
||||
clearTimeout(liveReconnectTimer);
|
||||
liveReconnectTimer = null;
|
||||
}
|
||||
sseConnected = false;
|
||||
}
|
||||
|
||||
function connectLiveStream() {
|
||||
if (!isEmbedShell()) return;
|
||||
closeLiveStream();
|
||||
liveEventSource = new EventSource("/api/instance/live/stream");
|
||||
liveEventSource.addEventListener("live", function (ev) {
|
||||
try {
|
||||
onLiveEvent(JSON.parse(ev.data || "{}"));
|
||||
} catch (_) {}
|
||||
});
|
||||
liveEventSource.onopen = function () {
|
||||
sseConnected = true;
|
||||
};
|
||||
liveEventSource.onerror = function () {
|
||||
sseConnected = false;
|
||||
closeLiveStream();
|
||||
liveReconnectTimer = setTimeout(function () {
|
||||
connectLiveStream();
|
||||
refreshTabData(currentTab(), { silent: true });
|
||||
}, 8000);
|
||||
};
|
||||
}
|
||||
|
||||
function startLive() {
|
||||
if (!isEmbedShell()) return;
|
||||
refreshTabData(currentTab());
|
||||
connectLiveStream();
|
||||
}
|
||||
|
||||
global.InstanceLive = {
|
||||
start: startLive,
|
||||
refreshTabData: refreshTabData,
|
||||
isConnected: function () {
|
||||
return sseConnected;
|
||||
},
|
||||
};
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", startLive);
|
||||
} else {
|
||||
startLive();
|
||||
}
|
||||
})(typeof window !== "undefined" ? window : globalThis);
|
||||
@@ -473,9 +473,6 @@
|
||||
renderExpiries();
|
||||
renderStrikes();
|
||||
refreshAllPositions();
|
||||
requestAnimationFrame(function () {
|
||||
loadChain();
|
||||
});
|
||||
return;
|
||||
}
|
||||
requestAnimationFrame(function () {
|
||||
@@ -523,4 +520,11 @@
|
||||
});
|
||||
|
||||
bootOptionsPanel();
|
||||
|
||||
window.OptionsPanelLive = {
|
||||
refreshSoft: function () {
|
||||
refreshAllPositions();
|
||||
},
|
||||
refreshChain: loadChain,
|
||||
};
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user