Fix turbo nav for settings and stats pages.
Extract settings.js, preserve inline scripts from raw HTML (DOMParser strips them), and load trade config via JSON script tag. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,126 @@
|
|||||||
|
/* Copyright (c) 2025-2026 马建军. All rights reserved.
|
||||||
|
* 专有软件 — 未经授权禁止复制、传播、转售。
|
||||||
|
* 详见 LICENSE.zh-CN.txt
|
||||||
|
*/
|
||||||
|
(function () {
|
||||||
|
function bootSettingsPage() {
|
||||||
|
if (!document.querySelector('.settings-page')) return;
|
||||||
|
|
||||||
|
var sel = document.getElementById('position-sizing-mode');
|
||||||
|
var lotsField = document.getElementById('field-fixed-lots');
|
||||||
|
var amountField = document.getElementById('field-fixed-amount');
|
||||||
|
function syncSizingFields() {
|
||||||
|
if (!sel) return;
|
||||||
|
var isAmount = sel.value === 'amount';
|
||||||
|
if (lotsField) lotsField.hidden = isAmount;
|
||||||
|
if (amountField) amountField.hidden = !isAmount;
|
||||||
|
}
|
||||||
|
if (sel && !sel.dataset.settingsBound) {
|
||||||
|
sel.dataset.settingsBound = '1';
|
||||||
|
sel.addEventListener('change', syncSizingFields);
|
||||||
|
}
|
||||||
|
syncSizingFields();
|
||||||
|
|
||||||
|
var SETTINGS_FOLD_KEY = 'qihuo_settings_fold';
|
||||||
|
function setSettingsFold(el, collapsed) {
|
||||||
|
if (!el) return;
|
||||||
|
el.classList.toggle('is-collapsed', collapsed);
|
||||||
|
var head = el.querySelector('.settings-fold-head');
|
||||||
|
if (head) head.setAttribute('aria-expanded', collapsed ? 'false' : 'true');
|
||||||
|
}
|
||||||
|
function saveSettingsFoldState() {
|
||||||
|
var state = {};
|
||||||
|
document.querySelectorAll('[data-settings-fold]').forEach(function (el) {
|
||||||
|
state[el.getAttribute('data-settings-fold')] = el.classList.contains('is-collapsed');
|
||||||
|
});
|
||||||
|
try { localStorage.setItem(SETTINGS_FOLD_KEY, JSON.stringify(state)); } catch (e) { /* ignore */ }
|
||||||
|
}
|
||||||
|
function loadSettingsFoldState() {
|
||||||
|
try {
|
||||||
|
var raw = localStorage.getItem(SETTINGS_FOLD_KEY);
|
||||||
|
if (!raw) return;
|
||||||
|
var state = JSON.parse(raw);
|
||||||
|
document.querySelectorAll('[data-settings-fold]').forEach(function (el) {
|
||||||
|
var key = el.getAttribute('data-settings-fold');
|
||||||
|
if (Object.prototype.hasOwnProperty.call(state, key)) {
|
||||||
|
setSettingsFold(el, !!state[key]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (e) { /* ignore */ }
|
||||||
|
}
|
||||||
|
document.querySelectorAll('.settings-fold-head').forEach(function (btn) {
|
||||||
|
if (btn.dataset.settingsBound) return;
|
||||||
|
btn.dataset.settingsBound = '1';
|
||||||
|
btn.addEventListener('click', function () {
|
||||||
|
var panel = btn.closest('[data-settings-fold]');
|
||||||
|
if (!panel) return;
|
||||||
|
setSettingsFold(panel, !panel.classList.contains('is-collapsed'));
|
||||||
|
saveSettingsFoldState();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
loadSettingsFoldState();
|
||||||
|
|
||||||
|
var CTP_FOLD_KEY = 'qihuo_ctp_fold';
|
||||||
|
function setCtpFold(el, collapsed) {
|
||||||
|
if (!el) return;
|
||||||
|
el.classList.toggle('is-collapsed', collapsed);
|
||||||
|
var head = el.querySelector('.settings-ctp-fold-head');
|
||||||
|
if (head) head.setAttribute('aria-expanded', collapsed ? 'false' : 'true');
|
||||||
|
}
|
||||||
|
function saveCtpFoldState() {
|
||||||
|
var state = {};
|
||||||
|
document.querySelectorAll('[data-ctp-fold]').forEach(function (el) {
|
||||||
|
state[el.getAttribute('data-ctp-fold')] = el.classList.contains('is-collapsed');
|
||||||
|
});
|
||||||
|
try { localStorage.setItem(CTP_FOLD_KEY, JSON.stringify(state)); } catch (e) { /* ignore */ }
|
||||||
|
}
|
||||||
|
function loadCtpFoldState() {
|
||||||
|
try {
|
||||||
|
var raw = localStorage.getItem(CTP_FOLD_KEY);
|
||||||
|
if (!raw) return;
|
||||||
|
var state = JSON.parse(raw);
|
||||||
|
document.querySelectorAll('[data-ctp-fold]').forEach(function (el) {
|
||||||
|
var key = el.getAttribute('data-ctp-fold');
|
||||||
|
if (Object.prototype.hasOwnProperty.call(state, key)) {
|
||||||
|
setCtpFold(el, !!state[key]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (e) { /* ignore */ }
|
||||||
|
}
|
||||||
|
document.querySelectorAll('.settings-ctp-fold-head').forEach(function (btn) {
|
||||||
|
if (btn.dataset.settingsBound) return;
|
||||||
|
btn.dataset.settingsBound = '1';
|
||||||
|
btn.addEventListener('click', function () {
|
||||||
|
var panel = btn.closest('[data-ctp-fold]');
|
||||||
|
if (!panel) return;
|
||||||
|
setCtpFold(panel, !panel.classList.contains('is-collapsed'));
|
||||||
|
saveCtpFoldState();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
loadCtpFoldState();
|
||||||
|
|
||||||
|
var ctpForm = document.getElementById('ctp-settings-form');
|
||||||
|
if (ctpForm && !ctpForm.dataset.settingsBound) {
|
||||||
|
ctpForm.dataset.settingsBound = '1';
|
||||||
|
ctpForm.addEventListener('submit', function (ev) {
|
||||||
|
var ctpCard = document.querySelector('[data-settings-fold="ctp"]');
|
||||||
|
if (ctpCard) setSettingsFold(ctpCard, false);
|
||||||
|
var simnowFold = document.querySelector('[data-ctp-fold="simnow"]');
|
||||||
|
if (simnowFold) setCtpFold(simnowFold, false);
|
||||||
|
var pwd = document.getElementById('simnow_password');
|
||||||
|
var pwdVal = pwd && pwd.value ? pwd.value.trim() : '';
|
||||||
|
var pwdWasSet = ctpForm.getAttribute('data-simnow-pwd-set') === '1';
|
||||||
|
if (pwdWasSet && !pwdVal) {
|
||||||
|
var ok = window.confirm(
|
||||||
|
'SimNow 交易密码为空,保存后不会更新密码(仍用旧密码)。\n\n'
|
||||||
|
+ '若快期已改密,请取消后在「交易密码」框手打新密码再保存。\n\n仍要保存其他项?'
|
||||||
|
);
|
||||||
|
if (!ok) ev.preventDefault();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window.qihuoPageBoot) window.qihuoPageBoot(bootSettingsPage, '.settings-page');
|
||||||
|
else document.addEventListener('DOMContentLoaded', bootSettingsPage);
|
||||||
|
})();
|
||||||
+6
-2
@@ -138,8 +138,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function loadStats() {
|
function loadStats() {
|
||||||
fetch('/api/stats')
|
fetch('/api/stats', { credentials: 'same-origin' })
|
||||||
.then(function (r) { return r.json(); })
|
.then(function (r) {
|
||||||
|
if (!r.ok) throw new Error('HTTP ' + r.status);
|
||||||
|
return r.json();
|
||||||
|
})
|
||||||
.then(applyData)
|
.then(applyData)
|
||||||
.catch(function () {
|
.catch(function () {
|
||||||
var updated = document.getElementById('stats-updated');
|
var updated = document.getElementById('stats-updated');
|
||||||
@@ -148,6 +151,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function bootStatsPage() {
|
function bootStatsPage() {
|
||||||
|
if (!document.getElementById('stats-summary')) return;
|
||||||
var viewSel = document.getElementById('stats-view-select');
|
var viewSel = document.getElementById('stats-view-select');
|
||||||
if (viewSel && !viewSel.dataset.statsBound) {
|
if (viewSel && !viewSel.dataset.statsBound) {
|
||||||
viewSel.dataset.statsBound = '1';
|
viewSel.dataset.statsBound = '1';
|
||||||
|
|||||||
+22
-6
@@ -3,8 +3,7 @@
|
|||||||
* 详见 LICENSE.zh-CN.txt
|
* 详见 LICENSE.zh-CN.txt
|
||||||
*/
|
*/
|
||||||
(function () {
|
(function () {
|
||||||
var sizingMode = window.TRADE_SIZING_MODE || 'fixed';
|
var sizingMode = 'fixed';
|
||||||
if (sizingMode === 'risk') sizingMode = 'amount';
|
|
||||||
var list = document.getElementById('position-live-list');
|
var list = document.getElementById('position-live-list');
|
||||||
var orderList = document.getElementById('order-live-list');
|
var orderList = document.getElementById('order-live-list');
|
||||||
var syncBadge = document.getElementById('sync-badge');
|
var syncBadge = document.getElementById('sync-badge');
|
||||||
@@ -33,7 +32,7 @@
|
|||||||
var hasSlTpMonitoring = false;
|
var hasSlTpMonitoring = false;
|
||||||
var ctpConnected = false;
|
var ctpConnected = false;
|
||||||
var ctpConnecting = false;
|
var ctpConnecting = false;
|
||||||
var ctpAutoConnectEnabled = window.CTP_AUTO_CONNECT !== false;
|
var ctpAutoConnectEnabled = true;
|
||||||
var positionsRendered = false;
|
var positionsRendered = false;
|
||||||
var selectedMaxLots = null;
|
var selectedMaxLots = null;
|
||||||
var recommendMaxByProduct = {};
|
var recommendMaxByProduct = {};
|
||||||
@@ -45,10 +44,26 @@
|
|||||||
var REC_SORT_CACHE = 'qihuo_rec_sort_v2';
|
var REC_SORT_CACHE = 'qihuo_rec_sort_v2';
|
||||||
var REC_INDUSTRY_CACHE = 'qihuo_rec_industry_v1';
|
var REC_INDUSTRY_CACHE = 'qihuo_rec_industry_v1';
|
||||||
var REC_COLSPAN = 18;
|
var REC_COLSPAN = 18;
|
||||||
var marketNavEnabled = !!window.MARKET_NAV_ENABLED;
|
var marketNavEnabled = false;
|
||||||
var productCategories = window.PRODUCT_CATEGORIES || [];
|
var productCategories = [];
|
||||||
var POS_CACHE_KEY = 'qihuo_trading_live_v5';
|
var POS_CACHE_KEY = 'qihuo_trading_live_v5';
|
||||||
|
|
||||||
|
function loadTradeConfig() {
|
||||||
|
var el = document.getElementById('trade-page-data');
|
||||||
|
if (!el) return;
|
||||||
|
try {
|
||||||
|
var cfg = JSON.parse(el.textContent);
|
||||||
|
sizingMode = cfg.sizing_mode || 'fixed';
|
||||||
|
if (sizingMode === 'risk') sizingMode = 'amount';
|
||||||
|
ctpAutoConnectEnabled = cfg.ctp_auto_connect !== false;
|
||||||
|
marketNavEnabled = !!cfg.market_nav_enabled;
|
||||||
|
productCategories = cfg.product_categories || [];
|
||||||
|
window.TRADE_FIXED_LOTS = cfg.fixed_lots;
|
||||||
|
window.TRADE_FIXED_AMOUNT = cfg.fixed_amount;
|
||||||
|
window.__RECOMMEND_ROWS__ = cfg.recommend_rows || [];
|
||||||
|
} catch (e) { /* ignore */ }
|
||||||
|
}
|
||||||
|
|
||||||
function fmtNum(v, digits) {
|
function fmtNum(v, digits) {
|
||||||
if (v === null || v === undefined) return '--';
|
if (v === null || v === undefined) return '--';
|
||||||
return Number(v).toFixed(digits === undefined ? 2 : digits);
|
return Number(v).toFixed(digits === undefined ? 2 : digits);
|
||||||
@@ -1607,6 +1622,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function bootTradePage() {
|
function bootTradePage() {
|
||||||
|
loadTradeConfig();
|
||||||
if (!list && !orderList) return;
|
if (!list && !orderList) return;
|
||||||
updateCtpConnectButtonState();
|
updateCtpConnectButtonState();
|
||||||
setPriceType('limit');
|
setPriceType('limit');
|
||||||
@@ -1648,7 +1664,7 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (window.qihuoPageBoot) window.qihuoPageBoot(bootTradePage, '#position-live-list, #order-live-list');
|
if (window.qihuoPageBoot) window.qihuoPageBoot(bootTradePage, '.trade-page');
|
||||||
else if (window.qihuoOnPageLoad) window.qihuoOnPageLoad(bootTradePage);
|
else if (window.qihuoOnPageLoad) window.qihuoOnPageLoad(bootTradePage);
|
||||||
else bootTradePage();
|
else bootTradePage();
|
||||||
if (window.qihuoOnPageLeave) window.qihuoOnPageLeave(cleanupTradePage);
|
if (window.qihuoOnPageLeave) window.qihuoOnPageLeave(cleanupTradePage);
|
||||||
|
|||||||
+63
-35
@@ -4,7 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
(function () {
|
(function () {
|
||||||
var PERMANENT_CSS = ['/static/css/base.css', '/static/css/tech.css', '/static/css/responsive.css'];
|
var PERMANENT_CSS = ['/static/css/base.css', '/static/css/tech.css', '/static/css/responsive.css'];
|
||||||
var CORE_SCRIPT_MARKERS = ['theme.js', 'symbol.js', 'page.js', 'nav.js', 'pwa.js', 'turbonav.js'];
|
var CORE_SCRIPT_RE = /theme\.js|symbol\.js|page\.js|nav\.js|pwa\.js|turbonav\.js/;
|
||||||
var pageCache = new Map();
|
var pageCache = new Map();
|
||||||
var MAX_CACHE = 10;
|
var MAX_CACHE = 10;
|
||||||
var inflight = null;
|
var inflight = null;
|
||||||
@@ -21,12 +21,6 @@
|
|||||||
return PERMANENT_CSS.some(function (p) { return href.indexOf(p) !== -1; });
|
return PERMANENT_CSS.some(function (p) { return href.indexOf(p) !== -1; });
|
||||||
}
|
}
|
||||||
|
|
||||||
function isCoreScript(el) {
|
|
||||||
var src = el.getAttribute('src') || '';
|
|
||||||
if (!src) return false;
|
|
||||||
return CORE_SCRIPT_MARKERS.some(function (m) { return src.indexOf(m) !== -1; });
|
|
||||||
}
|
|
||||||
|
|
||||||
function shouldTurboClick(e, link) {
|
function shouldTurboClick(e, link) {
|
||||||
if (!link || !link.href) return false;
|
if (!link || !link.href) return false;
|
||||||
if (e.defaultPrevented) return false;
|
if (e.defaultPrevented) return false;
|
||||||
@@ -55,13 +49,13 @@
|
|||||||
if (!res.ok) throw new Error('HTTP ' + res.status);
|
if (!res.ok) throw new Error('HTTP ' + res.status);
|
||||||
return res.text();
|
return res.text();
|
||||||
}).then(function (html) {
|
}).then(function (html) {
|
||||||
var doc = parseHtml(html);
|
var pack = { doc: parseHtml(html), html: html };
|
||||||
pageCache.set(key, doc);
|
pageCache.set(key, pack);
|
||||||
if (pageCache.size > MAX_CACHE) {
|
if (pageCache.size > MAX_CACHE) {
|
||||||
var first = pageCache.keys().next().value;
|
var first = pageCache.keys().next().value;
|
||||||
pageCache.delete(first);
|
pageCache.delete(first);
|
||||||
}
|
}
|
||||||
return doc;
|
return pack;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,24 +78,42 @@
|
|||||||
return fetchedMain.innerHTML;
|
return fetchedMain.innerHTML;
|
||||||
}
|
}
|
||||||
|
|
||||||
function collectPageScripts(doc) {
|
/** DOMParser strips inline script bodies — parse from raw HTML instead. */
|
||||||
var out = [];
|
function collectPageScripts(rawHtml) {
|
||||||
var pastCore = false;
|
var scripts = [];
|
||||||
doc.body.querySelectorAll(':scope > script').forEach(function (el) {
|
var bodyMatch = /<body[\s\S]*?>([\s\S]*)<\/body>/i.exec(rawHtml);
|
||||||
if (isCoreScript(el)) {
|
if (!bodyMatch) return scripts;
|
||||||
if ((el.getAttribute('src') || '').indexOf('pwa.js') !== -1) pastCore = true;
|
var body = bodyMatch[1];
|
||||||
return;
|
var re = /<script(\s[^>]*)?>([\s\S]*?)<\/script>/gi;
|
||||||
|
var pastPwa = false;
|
||||||
|
var m;
|
||||||
|
while ((m = re.exec(body)) !== null) {
|
||||||
|
var attrs = m[1] || '';
|
||||||
|
var text = m[2];
|
||||||
|
var srcMatch = /\ssrc=["']([^"']+)["']/i.exec(attrs);
|
||||||
|
var typeMatch = /\stype=["']([^"']+)["']/i.exec(attrs);
|
||||||
|
var idMatch = /\sid=["']([^"']+)["']/i.exec(attrs);
|
||||||
|
var src = srcMatch ? srcMatch[1] : '';
|
||||||
|
var type = typeMatch ? typeMatch[1].toLowerCase() : 'text/javascript';
|
||||||
|
var id = idMatch ? idMatch[1] : '';
|
||||||
|
if (src) {
|
||||||
|
if (/pwa\.js/.test(src)) pastPwa = true;
|
||||||
|
if (CORE_SCRIPT_RE.test(src)) continue;
|
||||||
|
if (!pastPwa) continue;
|
||||||
|
scripts.push({ src: src, text: '', type: type, id: id });
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if (!pastCore) return;
|
if (!pastPwa) continue;
|
||||||
if (isCoreScript(el)) return;
|
scripts.push({ src: '', text: text, type: type, id: id });
|
||||||
out.push(el);
|
}
|
||||||
});
|
return scripts;
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function removePageAssets() {
|
function removePageAssets() {
|
||||||
document.querySelectorAll('[data-page-css]').forEach(function (el) { el.remove(); });
|
document.querySelectorAll('[data-page-css]').forEach(function (el) { el.remove(); });
|
||||||
document.querySelectorAll('body script[data-page-js]').forEach(function (el) { el.remove(); });
|
document.querySelectorAll('body script[data-page-js], body script[data-page-data]').forEach(function (el) {
|
||||||
|
el.remove();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyPageCss(items) {
|
function applyPageCss(items) {
|
||||||
@@ -124,24 +136,37 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function runPageScripts(items) {
|
function runPageScripts(items) {
|
||||||
return items.reduce(function (chain, srcEl) {
|
return items.reduce(function (chain, item) {
|
||||||
return chain.then(function () {
|
return chain.then(function () {
|
||||||
return new Promise(function (resolve) {
|
return new Promise(function (resolve) {
|
||||||
var s = document.createElement('script');
|
var s = document.createElement('script');
|
||||||
s.setAttribute('data-page-js', '');
|
if (item.src) {
|
||||||
var src = srcEl.getAttribute('src');
|
s.setAttribute('data-page-js', '');
|
||||||
if (src) {
|
var bust = (item.src.indexOf('?') >= 0 ? '&' : '?') + '_turbo=' + Date.now();
|
||||||
var bust = (src.indexOf('?') >= 0 ? '&' : '?') + '_turbo=' + Date.now();
|
s.src = item.src + bust;
|
||||||
s.src = src + bust;
|
|
||||||
s.async = false;
|
s.async = false;
|
||||||
s.onload = function () { resolve(); };
|
s.onload = function () { resolve(); };
|
||||||
s.onerror = function () { resolve(); };
|
s.onerror = function () { resolve(); };
|
||||||
document.body.appendChild(s);
|
document.body.appendChild(s);
|
||||||
} else {
|
return;
|
||||||
s.textContent = srcEl.textContent;
|
}
|
||||||
|
if (item.type === 'application/json') {
|
||||||
|
s.type = 'application/json';
|
||||||
|
if (item.id) s.id = item.id;
|
||||||
|
s.setAttribute('data-page-data', '');
|
||||||
|
s.textContent = item.text;
|
||||||
document.body.appendChild(s);
|
document.body.appendChild(s);
|
||||||
resolve();
|
resolve();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
if (item.type && item.type !== 'text/javascript' && item.type !== 'module') {
|
||||||
|
resolve();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s.setAttribute('data-page-js', '');
|
||||||
|
s.textContent = item.text;
|
||||||
|
document.body.appendChild(s);
|
||||||
|
resolve();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
@@ -166,7 +191,9 @@
|
|||||||
if (main) main.classList.toggle('nav-loading', on);
|
if (main) main.classList.toggle('nav-loading', on);
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyDocument(doc, url, fromPopstate) {
|
function applyDocument(pack, url, fromPopstate) {
|
||||||
|
var doc = pack.doc;
|
||||||
|
var rawHtml = pack.html;
|
||||||
var main = document.querySelector('.main');
|
var main = document.querySelector('.main');
|
||||||
if (!main || !doc.querySelector('.main')) {
|
if (!main || !doc.querySelector('.main')) {
|
||||||
window.location.href = url;
|
window.location.href = url;
|
||||||
@@ -178,12 +205,13 @@
|
|||||||
|
|
||||||
var cssItems = collectPageCss(doc);
|
var cssItems = collectPageCss(doc);
|
||||||
var mainHtml = prepareMainHtml(doc);
|
var mainHtml = prepareMainHtml(doc);
|
||||||
|
var scriptItems = collectPageScripts(rawHtml);
|
||||||
|
|
||||||
return applyPageCss(cssItems).then(function () {
|
return applyPageCss(cssItems).then(function () {
|
||||||
main.innerHTML = mainHtml;
|
main.innerHTML = mainHtml;
|
||||||
document.title = doc.title || document.title;
|
document.title = doc.title || document.title;
|
||||||
syncNavActive(doc, url);
|
syncNavActive(doc, url);
|
||||||
return runPageScripts(collectPageScripts(doc));
|
return runPageScripts(scriptItems);
|
||||||
}).then(function () {
|
}).then(function () {
|
||||||
currentUrl = normalizeUrl(url);
|
currentUrl = normalizeUrl(url);
|
||||||
if (!fromPopstate) {
|
if (!fromPopstate) {
|
||||||
@@ -205,10 +233,10 @@
|
|||||||
inflight = ctrl;
|
inflight = ctrl;
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
return fetchPage(target, ctrl.signal).then(function (doc) {
|
return fetchPage(target, ctrl.signal).then(function (pack) {
|
||||||
if (ctrl.signal.aborted) return;
|
if (ctrl.signal.aborted) return;
|
||||||
inflight = null;
|
inflight = null;
|
||||||
return applyDocument(doc, target, !!opts.fromPopstate);
|
return applyDocument(pack, target, !!opts.fromPopstate);
|
||||||
}).catch(function () {
|
}).catch(function () {
|
||||||
if (ctrl.signal.aborted) return;
|
if (ctrl.signal.aborted) return;
|
||||||
inflight = null;
|
inflight = null;
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
* 专有软件 — 未经授权禁止复制、传播、转售。
|
* 专有软件 — 未经授权禁止复制、传播、转售。
|
||||||
* 详见 LICENSE.zh-CN.txt
|
* 详见 LICENSE.zh-CN.txt
|
||||||
*/
|
*/
|
||||||
var CACHE_VERSION = 'qihuo-v7';
|
var CACHE_VERSION = 'qihuo-v8';
|
||||||
var STATIC_CACHE = CACHE_VERSION + '-static';
|
var STATIC_CACHE = CACHE_VERSION + '-static';
|
||||||
var STATIC_ASSETS = [
|
var STATIC_ASSETS = [
|
||||||
'/static/css/base.css',
|
'/static/css/base.css',
|
||||||
|
|||||||
+2
-110
@@ -212,7 +212,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<form action="{{ url_for('settings') }}" method="post" id="ctp-settings-form">
|
<form action="{{ url_for('settings') }}" method="post" id="ctp-settings-form" data-simnow-pwd-set="{{ '1' if ctp_cfg.simnow_password_set else '0' }}">
|
||||||
<input type="hidden" name="action" value="ctp">
|
<input type="hidden" name="action" value="ctp">
|
||||||
|
|
||||||
<div class="settings-ctp-auto card" style="margin-bottom:.85rem;padding:.75rem 1rem">
|
<div class="settings-ctp-auto card" style="margin-bottom:.85rem;padding:.75rem 1rem">
|
||||||
@@ -478,113 +478,5 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block extra_js %}
|
{% block extra_js %}
|
||||||
<script>
|
<script src="{{ url_for('static', filename='js/settings.js') }}"></script>
|
||||||
(function () {
|
|
||||||
var sel = document.getElementById('position-sizing-mode');
|
|
||||||
var lotsField = document.getElementById('field-fixed-lots');
|
|
||||||
var amountField = document.getElementById('field-fixed-amount');
|
|
||||||
function syncSizingFields() {
|
|
||||||
if (!sel) return;
|
|
||||||
var isAmount = sel.value === 'amount';
|
|
||||||
if (lotsField) lotsField.hidden = isAmount;
|
|
||||||
if (amountField) amountField.hidden = !isAmount;
|
|
||||||
}
|
|
||||||
if (sel) sel.addEventListener('change', syncSizingFields);
|
|
||||||
syncSizingFields();
|
|
||||||
|
|
||||||
var SETTINGS_FOLD_KEY = 'qihuo_settings_fold';
|
|
||||||
function setSettingsFold(el, collapsed) {
|
|
||||||
if (!el) return;
|
|
||||||
el.classList.toggle('is-collapsed', collapsed);
|
|
||||||
var head = el.querySelector('.settings-fold-head');
|
|
||||||
if (head) head.setAttribute('aria-expanded', collapsed ? 'false' : 'true');
|
|
||||||
}
|
|
||||||
function saveSettingsFoldState() {
|
|
||||||
var state = {};
|
|
||||||
document.querySelectorAll('[data-settings-fold]').forEach(function (el) {
|
|
||||||
state[el.getAttribute('data-settings-fold')] = el.classList.contains('is-collapsed');
|
|
||||||
});
|
|
||||||
try { localStorage.setItem(SETTINGS_FOLD_KEY, JSON.stringify(state)); } catch (e) { /* ignore */ }
|
|
||||||
}
|
|
||||||
function loadSettingsFoldState() {
|
|
||||||
try {
|
|
||||||
var raw = localStorage.getItem(SETTINGS_FOLD_KEY);
|
|
||||||
if (!raw) return;
|
|
||||||
var state = JSON.parse(raw);
|
|
||||||
document.querySelectorAll('[data-settings-fold]').forEach(function (el) {
|
|
||||||
var key = el.getAttribute('data-settings-fold');
|
|
||||||
if (Object.prototype.hasOwnProperty.call(state, key)) {
|
|
||||||
setSettingsFold(el, !!state[key]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (e) { /* ignore */ }
|
|
||||||
}
|
|
||||||
document.querySelectorAll('.settings-fold-head').forEach(function (btn) {
|
|
||||||
btn.addEventListener('click', function () {
|
|
||||||
var panel = btn.closest('[data-settings-fold]');
|
|
||||||
if (!panel) return;
|
|
||||||
setSettingsFold(panel, !panel.classList.contains('is-collapsed'));
|
|
||||||
saveSettingsFoldState();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
loadSettingsFoldState();
|
|
||||||
|
|
||||||
var CTP_FOLD_KEY = 'qihuo_ctp_fold';
|
|
||||||
function setCtpFold(el, collapsed) {
|
|
||||||
if (!el) return;
|
|
||||||
el.classList.toggle('is-collapsed', collapsed);
|
|
||||||
var head = el.querySelector('.settings-ctp-fold-head');
|
|
||||||
if (head) head.setAttribute('aria-expanded', collapsed ? 'false' : 'true');
|
|
||||||
}
|
|
||||||
function saveCtpFoldState() {
|
|
||||||
var state = {};
|
|
||||||
document.querySelectorAll('[data-ctp-fold]').forEach(function (el) {
|
|
||||||
state[el.getAttribute('data-ctp-fold')] = el.classList.contains('is-collapsed');
|
|
||||||
});
|
|
||||||
try { localStorage.setItem(CTP_FOLD_KEY, JSON.stringify(state)); } catch (e) { /* ignore */ }
|
|
||||||
}
|
|
||||||
function loadCtpFoldState() {
|
|
||||||
try {
|
|
||||||
var raw = localStorage.getItem(CTP_FOLD_KEY);
|
|
||||||
if (!raw) return;
|
|
||||||
var state = JSON.parse(raw);
|
|
||||||
document.querySelectorAll('[data-ctp-fold]').forEach(function (el) {
|
|
||||||
var key = el.getAttribute('data-ctp-fold');
|
|
||||||
if (Object.prototype.hasOwnProperty.call(state, key)) {
|
|
||||||
setCtpFold(el, !!state[key]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (e) { /* ignore */ }
|
|
||||||
}
|
|
||||||
document.querySelectorAll('.settings-ctp-fold-head').forEach(function (btn) {
|
|
||||||
btn.addEventListener('click', function () {
|
|
||||||
var panel = btn.closest('[data-ctp-fold]');
|
|
||||||
if (!panel) return;
|
|
||||||
setCtpFold(panel, !panel.classList.contains('is-collapsed'));
|
|
||||||
saveCtpFoldState();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
loadCtpFoldState();
|
|
||||||
|
|
||||||
var ctpForm = document.getElementById('ctp-settings-form');
|
|
||||||
if (ctpForm) {
|
|
||||||
ctpForm.addEventListener('submit', function (ev) {
|
|
||||||
var ctpCard = document.querySelector('[data-settings-fold="ctp"]');
|
|
||||||
if (ctpCard) setSettingsFold(ctpCard, false);
|
|
||||||
var simnowFold = document.querySelector('[data-ctp-fold="simnow"]');
|
|
||||||
if (simnowFold) setCtpFold(simnowFold, false);
|
|
||||||
var pwd = document.getElementById('simnow_password');
|
|
||||||
var pwdVal = pwd && pwd.value ? pwd.value.trim() : '';
|
|
||||||
var pwdWasSet = {{ 'true' if ctp_cfg.simnow_password_set else 'false' }};
|
|
||||||
if (pwdWasSet && !pwdVal) {
|
|
||||||
var ok = window.confirm(
|
|
||||||
'SimNow 交易密码为空,保存后不会更新密码(仍用旧密码)。\n\n'
|
|
||||||
+ '若快期已改密,请取消后在「交易密码」框手打新密码再保存。\n\n仍要保存其他项?'
|
|
||||||
);
|
|
||||||
if (!ok) ev.preventDefault();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -227,14 +227,14 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block extra_js %}
|
{% block extra_js %}
|
||||||
<script>
|
<script type="application/json" id="trade-page-data">{{ {
|
||||||
window.TRADE_SIZING_MODE = {{ sizing_mode|tojson }};
|
'sizing_mode': sizing_mode,
|
||||||
window.MARKET_NAV_ENABLED = {{ nav_items.market|tojson }};
|
'market_nav_enabled': nav_items.market,
|
||||||
window.TRADE_FIXED_LOTS = {{ fixed_lots|tojson }};
|
'fixed_lots': fixed_lots,
|
||||||
window.TRADE_FIXED_AMOUNT = {{ fixed_amount|tojson }};
|
'fixed_amount': fixed_amount,
|
||||||
window.PRODUCT_CATEGORIES = {{ product_categories | default([]) | tojson }};
|
'product_categories': product_categories | default([]),
|
||||||
window.__RECOMMEND_ROWS__ = {{ recommend_rows | default([]) | tojson }};
|
'recommend_rows': recommend_rows | default([]),
|
||||||
window.CTP_AUTO_CONNECT = {{ ctp_auto_connect | tojson }};
|
'ctp_auto_connect': ctp_auto_connect
|
||||||
</script>
|
} | tojson }}</script>
|
||||||
<script src="{{ url_for('static', filename='js/trade.js') }}?v={{ asset_v }}"></script>
|
<script src="{{ url_for('static', filename='js/trade.js') }}?v={{ asset_v }}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
Reference in New Issue
Block a user