mdas-jsview-sdk 1.0.17-uat.0 → 1.0.21-uat.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/mdas-sdk.esm.js +374 -153
- package/dist/mdas-sdk.esm.js.map +1 -1
- package/dist/mdas-sdk.js +374 -153
- package/dist/mdas-sdk.js.map +1 -1
- package/dist/mdas-sdk.min.js +9 -9
- package/dist/mdas-sdk.min.js.map +1 -1
- package/package.json +1 -1
package/dist/mdas-sdk.js
CHANGED
|
@@ -1283,6 +1283,24 @@
|
|
|
1283
1283
|
<span class="l2-market-name"></span>
|
|
1284
1284
|
</div>
|
|
1285
1285
|
<span class="symbol editable-symbol">--</span>
|
|
1286
|
+
<div class="level1-info">
|
|
1287
|
+
<div class="l1-item">
|
|
1288
|
+
<span class="l1-label">Last:</span>
|
|
1289
|
+
<span class="l1-value l1-last-px">--</span>
|
|
1290
|
+
</div>
|
|
1291
|
+
<div class="l1-item">
|
|
1292
|
+
<span class="l1-label">Low:</span>
|
|
1293
|
+
<span class="l1-value l1-low-px">--</span>
|
|
1294
|
+
</div>
|
|
1295
|
+
<div class="l1-item">
|
|
1296
|
+
<span class="l1-label">High:</span>
|
|
1297
|
+
<span class="l1-value l1-high-px">--</span>
|
|
1298
|
+
</div>
|
|
1299
|
+
<div class="l1-item">
|
|
1300
|
+
<span class="l1-label">Volume:</span>
|
|
1301
|
+
<span class="l1-value l1-volume">--</span>
|
|
1302
|
+
</div>
|
|
1303
|
+
</div>
|
|
1286
1304
|
</div>
|
|
1287
1305
|
</div>
|
|
1288
1306
|
|
|
@@ -1957,6 +1975,38 @@
|
|
|
1957
1975
|
color: #111827;
|
|
1958
1976
|
}
|
|
1959
1977
|
|
|
1978
|
+
/* ========================================
|
|
1979
|
+
LEVEL 1 INFO (INSIDE HEADER)
|
|
1980
|
+
======================================== */
|
|
1981
|
+
|
|
1982
|
+
.onbbo-level2-widget .level1-info {
|
|
1983
|
+
display: grid;
|
|
1984
|
+
grid-template-columns: repeat(4, 1fr);
|
|
1985
|
+
gap: 12px;
|
|
1986
|
+
margin-top: 10px;
|
|
1987
|
+
}
|
|
1988
|
+
|
|
1989
|
+
.onbbo-level2-widget .l1-item {
|
|
1990
|
+
display: flex;
|
|
1991
|
+
flex-direction: column;
|
|
1992
|
+
gap: 3px;
|
|
1993
|
+
}
|
|
1994
|
+
|
|
1995
|
+
.onbbo-level2-widget .l1-label {
|
|
1996
|
+
font-size: 11px;
|
|
1997
|
+
font-weight: 600;
|
|
1998
|
+
color: #6b7280;
|
|
1999
|
+
text-transform: uppercase;
|
|
2000
|
+
letter-spacing: 0.5px;
|
|
2001
|
+
}
|
|
2002
|
+
|
|
2003
|
+
.onbbo-level2-widget .l1-value {
|
|
2004
|
+
font-size: 15px;
|
|
2005
|
+
font-weight: 700;
|
|
2006
|
+
color: #111827;
|
|
2007
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
2008
|
+
}
|
|
2009
|
+
|
|
1960
2010
|
/* ========================================
|
|
1961
2011
|
ORDER BOOK CONTAINER
|
|
1962
2012
|
======================================== */
|
|
@@ -2341,6 +2391,11 @@
|
|
|
2341
2391
|
.onbbo-level2-widget .orderbook-panel:last-child {
|
|
2342
2392
|
border-bottom: none;
|
|
2343
2393
|
}
|
|
2394
|
+
|
|
2395
|
+
.onbbo-level2-widget .level1-info {
|
|
2396
|
+
grid-template-columns: repeat(2, 1fr);
|
|
2397
|
+
gap: 6px;
|
|
2398
|
+
}
|
|
2344
2399
|
}
|
|
2345
2400
|
|
|
2346
2401
|
@media (max-width: 480px) {
|
|
@@ -2359,6 +2414,19 @@
|
|
|
2359
2414
|
text-align: left;
|
|
2360
2415
|
}
|
|
2361
2416
|
|
|
2417
|
+
.onbbo-level2-widget .level1-info {
|
|
2418
|
+
grid-template-columns: repeat(2, 1fr);
|
|
2419
|
+
gap: 4px;
|
|
2420
|
+
}
|
|
2421
|
+
|
|
2422
|
+
.onbbo-level2-widget .l1-label {
|
|
2423
|
+
font-size: 9px;
|
|
2424
|
+
}
|
|
2425
|
+
|
|
2426
|
+
.onbbo-level2-widget .l1-value {
|
|
2427
|
+
font-size: 11px;
|
|
2428
|
+
}
|
|
2429
|
+
|
|
2362
2430
|
.onbbo-level2-widget .panel-header {
|
|
2363
2431
|
font-size: 10px;
|
|
2364
2432
|
padding: 6px 2px;
|
|
@@ -4507,13 +4575,14 @@
|
|
|
4507
4575
|
} */
|
|
4508
4576
|
|
|
4509
4577
|
handleData(message) {
|
|
4578
|
+
console.log('DEBUG', message);
|
|
4510
4579
|
if (this.loadingTimeout) {
|
|
4511
4580
|
clearTimeout(this.loadingTimeout);
|
|
4512
4581
|
this.loadingTimeout = null;
|
|
4513
4582
|
}
|
|
4514
4583
|
|
|
4515
4584
|
// Handle error messages from server (plain text converted to structured format)
|
|
4516
|
-
if (message.type === 'error'
|
|
4585
|
+
if (message.type === 'error') {
|
|
4517
4586
|
if (this.debug) {
|
|
4518
4587
|
console.log('[MarketDataWidget] Received no data message:', message.message);
|
|
4519
4588
|
}
|
|
@@ -5283,13 +5352,16 @@
|
|
|
5283
5352
|
// to avoid duplicate timeouts
|
|
5284
5353
|
}
|
|
5285
5354
|
handleData(message) {
|
|
5355
|
+
console.log('DEBUG NIGHT', message);
|
|
5356
|
+
//message = message.data || message.Data
|
|
5357
|
+
|
|
5286
5358
|
if (this.loadingTimeout) {
|
|
5287
5359
|
clearTimeout(this.loadingTimeout);
|
|
5288
5360
|
this.loadingTimeout = null;
|
|
5289
5361
|
}
|
|
5290
5362
|
|
|
5291
5363
|
// Handle error messages from server (plain text converted to structured format)
|
|
5292
|
-
if (message.type === 'error'
|
|
5364
|
+
if (message.type === 'error' || message.error == true) {
|
|
5293
5365
|
if (this.debug) {
|
|
5294
5366
|
console.log('[NightSessionWidget] Received no data message:', message.message);
|
|
5295
5367
|
}
|
|
@@ -5345,9 +5417,10 @@
|
|
|
5345
5417
|
}
|
|
5346
5418
|
|
|
5347
5419
|
// Filter for night session data
|
|
5348
|
-
|
|
5420
|
+
|
|
5421
|
+
if (Array.isArray(message.data)) {
|
|
5349
5422
|
// First, try to find data matching our symbol regardless of MarketName
|
|
5350
|
-
const symbolData = message.find(item => item.Symbol === this.symbol);
|
|
5423
|
+
const symbolData = message.data.find(item => item.Symbol === this.symbol);
|
|
5351
5424
|
if (symbolData) {
|
|
5352
5425
|
if (this.debug) {
|
|
5353
5426
|
console.log('[NightSessionWidget] Found data for symbol:', symbolData);
|
|
@@ -5387,34 +5460,35 @@
|
|
|
5387
5460
|
}
|
|
5388
5461
|
}
|
|
5389
5462
|
// Handle wrapped format
|
|
5390
|
-
else if (message.type === 'queryblueoceanl1' || message.type === 'querybrucel1' || message.type === 'queryonbbol1') {
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5463
|
+
/* else if (message.type === 'queryblueoceanl1' || message.type === 'querybrucel1' || message.type === 'queryonbbol1') {
|
|
5464
|
+
if (message.data['0']?.Symbol === this.symbol) {
|
|
5465
|
+
// For onbbo source, skip MarketName check
|
|
5466
|
+
const isOnbbo = message.type === 'queryonbbol1';
|
|
5467
|
+
const shouldShowNoData = message['0'].NotFound === true ||
|
|
5468
|
+
(!isOnbbo && (!message['0'].MarketName || message['0'].MarketName !== 'BLUE'));
|
|
5469
|
+
if (shouldShowNoData) {
|
|
5470
|
+
// Only show no data state if we don't have cached data
|
|
5471
|
+
if (!this.data) {
|
|
5472
|
+
this.showNoDataState(message['0']);
|
|
5473
|
+
} else {
|
|
5474
|
+
this.hideLoading();
|
|
5475
|
+
if (this.debug) {
|
|
5476
|
+
console.log('[NightSessionWidget] No new data, keeping cached data visible');
|
|
5477
|
+
}
|
|
5478
|
+
}
|
|
5479
|
+
} else {
|
|
5480
|
+
const model = new NightSessionModel(message['0']);
|
|
5481
|
+
this.data = model; // Store for caching
|
|
5482
|
+
this.updateWidget(model);
|
|
5403
5483
|
}
|
|
5404
|
-
}
|
|
5405
5484
|
} else {
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
// No matching symbol - keep cached data if available
|
|
5412
|
-
if (this.debug) {
|
|
5413
|
-
console.log('[NightSessionWidget] No matching symbol in response, keeping cached data');
|
|
5485
|
+
// No matching symbol - keep cached data if available
|
|
5486
|
+
if (this.debug) {
|
|
5487
|
+
console.log('[NightSessionWidget] No matching symbol in response, keeping cached data');
|
|
5488
|
+
}
|
|
5489
|
+
this.hideLoading();
|
|
5414
5490
|
}
|
|
5415
|
-
|
|
5416
|
-
}
|
|
5417
|
-
}
|
|
5491
|
+
} */
|
|
5418
5492
|
if (message._cached) ;
|
|
5419
5493
|
}
|
|
5420
5494
|
updateWidget(data) {
|
|
@@ -39091,7 +39165,7 @@ ${SharedStyles}
|
|
|
39091
39165
|
let priceData = null;
|
|
39092
39166
|
|
|
39093
39167
|
// Handle array format (standard night session format)
|
|
39094
|
-
if (Array.isArray(message)) {
|
|
39168
|
+
if (Array.isArray(message.data)) {
|
|
39095
39169
|
console.log('[IntradayChartWidget] Processing array format, length:', message.length);
|
|
39096
39170
|
const symbolData = message.find(item => item.Symbol === this.symbol);
|
|
39097
39171
|
console.log('[IntradayChartWidget] Found symbol data:', symbolData);
|
|
@@ -40062,8 +40136,10 @@ ${SharedStyles}
|
|
|
40062
40136
|
this.styled = options.styled !== undefined ? options.styled : true;
|
|
40063
40137
|
this.maxLevels = options.maxLevels || 10; // Number of levels to display
|
|
40064
40138
|
this.data = null;
|
|
40139
|
+
this.level1Data = null; // Store Level 1 data separately
|
|
40065
40140
|
this.isDestroyed = false;
|
|
40066
|
-
this.
|
|
40141
|
+
this.unsubscribeL2 = null;
|
|
40142
|
+
this.unsubscribeL1 = null;
|
|
40067
40143
|
this.symbolEditor = null;
|
|
40068
40144
|
this.loadingTimeout = null;
|
|
40069
40145
|
|
|
@@ -40164,13 +40240,22 @@ ${SharedStyles}
|
|
|
40164
40240
|
this.showError(`No data received for ${upperSymbol}. Please try again.`);
|
|
40165
40241
|
}, 10000);
|
|
40166
40242
|
|
|
40167
|
-
// Unsubscribe from old symbol
|
|
40168
|
-
if (this.
|
|
40243
|
+
// Unsubscribe from old symbol's L2 and L1 data
|
|
40244
|
+
if (this.unsubscribeL2) {
|
|
40169
40245
|
if (this.debug) {
|
|
40170
|
-
console.log(`[ONBBOLevel2Widget] Unsubscribing from ${this.symbol}`);
|
|
40246
|
+
console.log(`[ONBBOLevel2Widget] Unsubscribing from ${this.symbol} L2`);
|
|
40171
40247
|
}
|
|
40172
|
-
this.
|
|
40173
|
-
this.
|
|
40248
|
+
this.wsManager.sendUnsubscribe('queryonbbol2', this.symbol);
|
|
40249
|
+
this.unsubscribeL2();
|
|
40250
|
+
this.unsubscribeL2 = null;
|
|
40251
|
+
}
|
|
40252
|
+
if (this.unsubscribeL1) {
|
|
40253
|
+
if (this.debug) {
|
|
40254
|
+
console.log(`[ONBBOLevel2Widget] Unsubscribing from ${this.symbol} L1`);
|
|
40255
|
+
}
|
|
40256
|
+
this.wsManager.sendUnsubscribe('queryonbbol1', this.symbol);
|
|
40257
|
+
this.unsubscribeL1();
|
|
40258
|
+
this.unsubscribeL1 = null;
|
|
40174
40259
|
}
|
|
40175
40260
|
|
|
40176
40261
|
// Update internal symbol
|
|
@@ -40240,10 +40325,51 @@ ${SharedStyles}
|
|
|
40240
40325
|
}
|
|
40241
40326
|
}
|
|
40242
40327
|
subscribeToData() {
|
|
40243
|
-
// Subscribe to ONBBO Level 2 data
|
|
40244
|
-
|
|
40245
|
-
|
|
40246
|
-
|
|
40328
|
+
// Subscribe to ONBBO Level 2 data (order book)
|
|
40329
|
+
// Use separate widget IDs to avoid "already active" duplicate detection
|
|
40330
|
+
this.unsubscribeL2 = this.wsManager.subscribe(`${this.widgetId}-l2`, ['queryonbbol2'], messageWrapper => {
|
|
40331
|
+
const {
|
|
40332
|
+
event,
|
|
40333
|
+
data
|
|
40334
|
+
} = messageWrapper;
|
|
40335
|
+
|
|
40336
|
+
// Handle connection events
|
|
40337
|
+
if (event === 'connection') {
|
|
40338
|
+
this.handleConnectionStatus(data);
|
|
40339
|
+
return;
|
|
40340
|
+
}
|
|
40341
|
+
|
|
40342
|
+
// For data events, add type context
|
|
40343
|
+
if (event === 'data') {
|
|
40344
|
+
data._dataType = 'level2';
|
|
40345
|
+
this.handleMessage({
|
|
40346
|
+
event,
|
|
40347
|
+
data
|
|
40348
|
+
});
|
|
40349
|
+
}
|
|
40350
|
+
}, this.symbol);
|
|
40351
|
+
|
|
40352
|
+
// Subscribe to ONBBO Level 1 data (statistics: LastPx, LowPx, HighPx, Volume)
|
|
40353
|
+
this.unsubscribeL1 = this.wsManager.subscribe(`${this.widgetId}-l1`, ['queryonbbol1'], messageWrapper => {
|
|
40354
|
+
const {
|
|
40355
|
+
event,
|
|
40356
|
+
data
|
|
40357
|
+
} = messageWrapper;
|
|
40358
|
+
|
|
40359
|
+
// Connection already handled by L2 subscription
|
|
40360
|
+
if (event === 'connection') {
|
|
40361
|
+
return;
|
|
40362
|
+
}
|
|
40363
|
+
|
|
40364
|
+
// For data events, add type context
|
|
40365
|
+
if (event === 'data') {
|
|
40366
|
+
data._dataType = 'level1';
|
|
40367
|
+
this.handleMessage({
|
|
40368
|
+
event,
|
|
40369
|
+
data
|
|
40370
|
+
});
|
|
40371
|
+
}
|
|
40372
|
+
}, this.symbol);
|
|
40247
40373
|
}
|
|
40248
40374
|
handleData(message) {
|
|
40249
40375
|
if (this.loadingTimeout) {
|
|
@@ -40251,8 +40377,14 @@ ${SharedStyles}
|
|
|
40251
40377
|
this.loadingTimeout = null;
|
|
40252
40378
|
}
|
|
40253
40379
|
|
|
40380
|
+
// Extract data type from metadata (added by subscription callback)
|
|
40381
|
+
const dataType = message._dataType;
|
|
40382
|
+
if (this.debug) {
|
|
40383
|
+
console.log(`[ONBBOLevel2Widget] handleData called with type: ${dataType}`, message);
|
|
40384
|
+
}
|
|
40385
|
+
|
|
40254
40386
|
// Handle error messages
|
|
40255
|
-
if (message.type === 'error') {
|
|
40387
|
+
if (message.type === 'error' || message.error == true) {
|
|
40256
40388
|
const errorMsg = message.message || 'Server error';
|
|
40257
40389
|
if (this.debug) {
|
|
40258
40390
|
console.log('[ONBBOLevel2Widget] Error:', errorMsg);
|
|
@@ -40261,16 +40393,54 @@ ${SharedStyles}
|
|
|
40261
40393
|
return;
|
|
40262
40394
|
}
|
|
40263
40395
|
|
|
40396
|
+
// Handle Level 1 data (statistics: LastPx, LowPx, HighPx, Volume)
|
|
40397
|
+
if (message.type === 'queryonbbol1') {
|
|
40398
|
+
if (this.debug) {
|
|
40399
|
+
console.log('[ONBBOLevel2Widget] Processing Level 1 data:', message);
|
|
40400
|
+
}
|
|
40401
|
+
|
|
40402
|
+
// Handle array format (new format with Data wrapper)
|
|
40403
|
+
if (message.data && Array.isArray(message.data)) {
|
|
40404
|
+
const l1Data = message.data.find(d => d.Symbol === this.symbol);
|
|
40405
|
+
if (l1Data) {
|
|
40406
|
+
this.level1Data = {
|
|
40407
|
+
lastPx: l1Data.LastPx || 0,
|
|
40408
|
+
lowPx: l1Data.LowPx || 0,
|
|
40409
|
+
highPx: l1Data.HighPx || 0,
|
|
40410
|
+
volume: l1Data.Volume || 0
|
|
40411
|
+
};
|
|
40412
|
+
this.updateLevel1Display();
|
|
40413
|
+
}
|
|
40414
|
+
}
|
|
40415
|
+
// Handle direct array format (standard format)
|
|
40416
|
+
else if (Array.isArray(message)) {
|
|
40417
|
+
const l1Data = message.find(d => d.Symbol === this.symbol);
|
|
40418
|
+
if (l1Data) {
|
|
40419
|
+
this.level1Data = {
|
|
40420
|
+
lastPx: l1Data.LastPx || 0,
|
|
40421
|
+
lowPx: l1Data.LowPx || 0,
|
|
40422
|
+
highPx: l1Data.HighPx || 0,
|
|
40423
|
+
volume: l1Data.Volume || 0
|
|
40424
|
+
};
|
|
40425
|
+
this.updateLevel1Display();
|
|
40426
|
+
}
|
|
40427
|
+
}
|
|
40428
|
+
|
|
40429
|
+
// Clean up metadata
|
|
40430
|
+
delete message._dataType;
|
|
40431
|
+
return;
|
|
40432
|
+
}
|
|
40433
|
+
|
|
40264
40434
|
// Handle Level 2 data - Array of MMID quotes
|
|
40265
|
-
if (Array.isArray(message)) {
|
|
40435
|
+
if (Array.isArray(message.data)) {
|
|
40266
40436
|
// Check if it's an array of MMID objects (ONBBO format)
|
|
40267
|
-
if (message.length > 0 && message[0].MMID) {
|
|
40437
|
+
if (message.data.length > 0 && message.data[0].MMID) {
|
|
40268
40438
|
if (this.debug) {
|
|
40269
40439
|
console.log('[ONBBOLevel2Widget] Received MMID array:', message);
|
|
40270
40440
|
}
|
|
40271
40441
|
|
|
40272
40442
|
// Create model from MMID array
|
|
40273
|
-
const model = new ONBBOLevel2Model(message);
|
|
40443
|
+
const model = new ONBBOLevel2Model(message.data);
|
|
40274
40444
|
model.symbol = this.symbol; // Set symbol from widget
|
|
40275
40445
|
this.data = model;
|
|
40276
40446
|
this.updateWidget(model);
|
|
@@ -40278,7 +40448,7 @@ ${SharedStyles}
|
|
|
40278
40448
|
}
|
|
40279
40449
|
|
|
40280
40450
|
// Try to find symbol in array (alternative format)
|
|
40281
|
-
const symbolData = message.find(item => item.Symbol === this.symbol);
|
|
40451
|
+
const symbolData = message.data.find(item => item.Symbol === this.symbol);
|
|
40282
40452
|
if (symbolData) {
|
|
40283
40453
|
if (symbolData.NotFound === true) {
|
|
40284
40454
|
this.showError(`No Level 2 data available for ${this.symbol}`);
|
|
@@ -40292,32 +40462,31 @@ ${SharedStyles}
|
|
|
40292
40462
|
this.showError(`No Level 2 data available for ${this.symbol}`);
|
|
40293
40463
|
}
|
|
40294
40464
|
// Handle wrapped format
|
|
40295
|
-
else if (message.type === 'queryonbbol2') {
|
|
40296
|
-
|
|
40297
|
-
|
|
40298
|
-
|
|
40299
|
-
|
|
40465
|
+
/* else if (message.type === 'queryonbbol2') {
|
|
40466
|
+
// Check if wrapped data contains MMID array
|
|
40467
|
+
if (message['0'] && Array.isArray(message['0'])) {
|
|
40468
|
+
if (this.debug) {
|
|
40469
|
+
console.log('[ONBBOLevel2Widget] Received wrapped MMID array:', message['0']);
|
|
40470
|
+
}
|
|
40471
|
+
const model = new ONBBOLevel2Model(message['0']);
|
|
40472
|
+
model.symbol = this.symbol;
|
|
40473
|
+
this.data = model;
|
|
40474
|
+
this.updateWidget(model);
|
|
40475
|
+
return;
|
|
40300
40476
|
}
|
|
40301
|
-
|
|
40302
|
-
|
|
40303
|
-
|
|
40304
|
-
|
|
40305
|
-
|
|
40306
|
-
|
|
40307
|
-
|
|
40308
|
-
|
|
40309
|
-
|
|
40310
|
-
if (message['0'].NotFound === true) {
|
|
40311
|
-
this.showError(`No Level 2 data available for ${this.symbol}`);
|
|
40477
|
+
// Check for symbol match in wrapped format
|
|
40478
|
+
if (message['0']?.Symbol === this.symbol) {
|
|
40479
|
+
if (message['0'].NotFound === true) {
|
|
40480
|
+
this.showError(`No Level 2 data available for ${this.symbol}`);
|
|
40481
|
+
} else {
|
|
40482
|
+
const model = new ONBBOLevel2Model(message['0']);
|
|
40483
|
+
this.data = model;
|
|
40484
|
+
this.updateWidget(model);
|
|
40485
|
+
}
|
|
40312
40486
|
} else {
|
|
40313
|
-
|
|
40314
|
-
this.data = model;
|
|
40315
|
-
this.updateWidget(model);
|
|
40487
|
+
this.showError(`No Level 2 data available for ${this.symbol}`);
|
|
40316
40488
|
}
|
|
40317
|
-
|
|
40318
|
-
this.showError(`No Level 2 data available for ${this.symbol}`);
|
|
40319
|
-
}
|
|
40320
|
-
}
|
|
40489
|
+
} */
|
|
40321
40490
|
}
|
|
40322
40491
|
updateWidget(data) {
|
|
40323
40492
|
if (this.isDestroyed) return;
|
|
@@ -40415,6 +40584,43 @@ ${SharedStyles}
|
|
|
40415
40584
|
askBody.appendChild(row);
|
|
40416
40585
|
});
|
|
40417
40586
|
}
|
|
40587
|
+
updateLevel1Display() {
|
|
40588
|
+
if (!this.level1Data) return;
|
|
40589
|
+
const formatPrice = price => {
|
|
40590
|
+
return price ? price.toFixed(2) : '--';
|
|
40591
|
+
};
|
|
40592
|
+
const formatVolume = volume => {
|
|
40593
|
+
if (!volume) return '--';
|
|
40594
|
+
return volume.toLocaleString();
|
|
40595
|
+
};
|
|
40596
|
+
|
|
40597
|
+
// Update Last Price
|
|
40598
|
+
const lastPxElement = this.container.querySelector('.l1-last-px');
|
|
40599
|
+
if (lastPxElement) {
|
|
40600
|
+
lastPxElement.textContent = formatPrice(this.level1Data.lastPx);
|
|
40601
|
+
}
|
|
40602
|
+
|
|
40603
|
+
// Update Low Price
|
|
40604
|
+
const lowPxElement = this.container.querySelector('.l1-low-px');
|
|
40605
|
+
if (lowPxElement) {
|
|
40606
|
+
lowPxElement.textContent = formatPrice(this.level1Data.lowPx);
|
|
40607
|
+
}
|
|
40608
|
+
|
|
40609
|
+
// Update High Price
|
|
40610
|
+
const highPxElement = this.container.querySelector('.l1-high-px');
|
|
40611
|
+
if (highPxElement) {
|
|
40612
|
+
highPxElement.textContent = formatPrice(this.level1Data.highPx);
|
|
40613
|
+
}
|
|
40614
|
+
|
|
40615
|
+
// Update Volume
|
|
40616
|
+
const volumeElement = this.container.querySelector('.l1-volume');
|
|
40617
|
+
if (volumeElement) {
|
|
40618
|
+
volumeElement.textContent = formatVolume(this.level1Data.volume);
|
|
40619
|
+
}
|
|
40620
|
+
if (this.debug) {
|
|
40621
|
+
console.log('[ONBBOLevel2Widget] Updated Level 1 display:', this.level1Data);
|
|
40622
|
+
}
|
|
40623
|
+
}
|
|
40418
40624
|
showLoading() {
|
|
40419
40625
|
const loadingOverlay = this.container.querySelector('.widget-loading-overlay');
|
|
40420
40626
|
if (loadingOverlay) {
|
|
@@ -40461,9 +40667,17 @@ ${SharedStyles}
|
|
|
40461
40667
|
this.clearTimeout(this.loadingTimeout);
|
|
40462
40668
|
this.loadingTimeout = null;
|
|
40463
40669
|
}
|
|
40464
|
-
|
|
40465
|
-
|
|
40466
|
-
|
|
40670
|
+
|
|
40671
|
+
// Unsubscribe from L2 data
|
|
40672
|
+
if (this.unsubscribeL2) {
|
|
40673
|
+
this.unsubscribeL2();
|
|
40674
|
+
this.unsubscribeL2 = null;
|
|
40675
|
+
}
|
|
40676
|
+
|
|
40677
|
+
// Unsubscribe from L1 data
|
|
40678
|
+
if (this.unsubscribeL1) {
|
|
40679
|
+
this.unsubscribeL1();
|
|
40680
|
+
this.unsubscribeL1 = null;
|
|
40467
40681
|
}
|
|
40468
40682
|
|
|
40469
40683
|
// Destroy the symbol editor
|
|
@@ -41589,6 +41803,7 @@ ${SharedStyles}
|
|
|
41589
41803
|
}
|
|
41590
41804
|
}
|
|
41591
41805
|
handleMessage(event) {
|
|
41806
|
+
//console.log('EVENT', event)
|
|
41592
41807
|
try {
|
|
41593
41808
|
// Update activity tracking - connection is alive!
|
|
41594
41809
|
this.lastMessageReceived = Date.now();
|
|
@@ -41613,22 +41828,20 @@ ${SharedStyles}
|
|
|
41613
41828
|
return;
|
|
41614
41829
|
}
|
|
41615
41830
|
|
|
41616
|
-
// Determine
|
|
41617
|
-
const
|
|
41831
|
+
// Determine type based on error content, default to 'error'
|
|
41832
|
+
const errorType = this._getTargetTypeFromErrorMessage(textMessage) || 'error';
|
|
41618
41833
|
if (textMessage.toLowerCase().includes('no night session') || textMessage.toLowerCase().includes('no data')) {
|
|
41619
41834
|
message = {
|
|
41620
|
-
type:
|
|
41835
|
+
type: errorType,
|
|
41621
41836
|
message: textMessage,
|
|
41622
|
-
error:
|
|
41623
|
-
noData: true
|
|
41624
|
-
targetType: targetType // Will be 'querynightsession' for night session errors
|
|
41837
|
+
error: true,
|
|
41838
|
+
noData: true
|
|
41625
41839
|
};
|
|
41626
41840
|
} else {
|
|
41627
41841
|
message = {
|
|
41628
|
-
type:
|
|
41842
|
+
type: errorType,
|
|
41629
41843
|
message: textMessage,
|
|
41630
|
-
error:
|
|
41631
|
-
targetType: targetType // Could be null for general errors
|
|
41844
|
+
error: true
|
|
41632
41845
|
};
|
|
41633
41846
|
}
|
|
41634
41847
|
}
|
|
@@ -41636,9 +41849,16 @@ ${SharedStyles}
|
|
|
41636
41849
|
console.log('[WebSocketManager] Processed message:', message);
|
|
41637
41850
|
}
|
|
41638
41851
|
|
|
41639
|
-
//
|
|
41640
|
-
|
|
41641
|
-
|
|
41852
|
+
// Extract data field for night session messages to avoid nested structure
|
|
41853
|
+
// Night session format: { type: 'queryonbbol1', error: false, data: [...] }
|
|
41854
|
+
// We want to send just the data array to widgets
|
|
41855
|
+
let dataToRoute = message;
|
|
41856
|
+
/* if (message.data !== undefined && message.type !== undefined) {
|
|
41857
|
+
// This is night session format - extract the data
|
|
41858
|
+
dataToRoute = message.data;
|
|
41859
|
+
} */
|
|
41860
|
+
|
|
41861
|
+
this._routeMessage(dataToRoute);
|
|
41642
41862
|
} catch (error) {
|
|
41643
41863
|
console.error('[WebSocketManager] Error handling message:', error);
|
|
41644
41864
|
this._notifyWidgets('error', {
|
|
@@ -41777,7 +41997,31 @@ ${SharedStyles}
|
|
|
41777
41997
|
}
|
|
41778
41998
|
} else {
|
|
41779
41999
|
if (this.config.debug) {
|
|
41780
|
-
console.log(`[WebSocketManager] Subscription ${subscriptionKey} already active, skipping`);
|
|
42000
|
+
console.log(`[WebSocketManager] Subscription ${subscriptionKey} already active, skipping server subscription`);
|
|
42001
|
+
}
|
|
42002
|
+
|
|
42003
|
+
// Subscription already active, but send cached data to newly subscribing widgets
|
|
42004
|
+
const cachedMessage = this.lastMessageCache.get(subscriptionKey);
|
|
42005
|
+
console.log('LAST', this.lastMessageCache);
|
|
42006
|
+
if (cachedMessage) {
|
|
42007
|
+
if (this.config.debug) {
|
|
42008
|
+
console.log(`[WebSocketManager] Sending cached data to newly subscribing widgets for ${subscriptionKey}`);
|
|
42009
|
+
}
|
|
42010
|
+
|
|
42011
|
+
// Find all widgets subscribed to this type:symbol combination
|
|
42012
|
+
this.subscriptions.forEach((subscription, widgetId) => {
|
|
42013
|
+
if (subscription.types.has(type) && subscription.symbol === symbol) {
|
|
42014
|
+
try {
|
|
42015
|
+
subscription.callback({
|
|
42016
|
+
event: 'data',
|
|
42017
|
+
data: cachedMessage,
|
|
42018
|
+
widgetId
|
|
42019
|
+
});
|
|
42020
|
+
} catch (error) {
|
|
42021
|
+
console.error(`[WebSocketManager] Error sending cached data to widget ${widgetId}:`, error);
|
|
42022
|
+
}
|
|
42023
|
+
}
|
|
42024
|
+
});
|
|
41781
42025
|
}
|
|
41782
42026
|
}
|
|
41783
42027
|
});
|
|
@@ -41829,11 +42073,6 @@ ${SharedStyles}
|
|
|
41829
42073
|
* The data field structure varies based on the type
|
|
41830
42074
|
*/
|
|
41831
42075
|
_normalizeMessage(message) {
|
|
41832
|
-
// If message already has targetType (error messages), return as is
|
|
41833
|
-
if (message.targetType) {
|
|
41834
|
-
return message;
|
|
41835
|
-
}
|
|
41836
|
-
|
|
41837
42076
|
// Check for error field (case-insensitive)
|
|
41838
42077
|
const errorField = message.error || message.Error;
|
|
41839
42078
|
const typeField = message.type || message.Type;
|
|
@@ -41844,13 +42083,12 @@ ${SharedStyles}
|
|
|
41844
42083
|
if (this.config.debug) {
|
|
41845
42084
|
console.log(`[WebSocketManager] Detected error message with type: ${typeField}`);
|
|
41846
42085
|
}
|
|
41847
|
-
|
|
41848
|
-
// Set targetType for routing to specific widget types
|
|
41849
42086
|
return {
|
|
41850
42087
|
...message,
|
|
41851
|
-
|
|
41852
|
-
type
|
|
41853
|
-
|
|
42088
|
+
// Only add type if message doesn't already have one
|
|
42089
|
+
...(!message.type && !message.Type && typeField ? {
|
|
42090
|
+
type: typeField
|
|
42091
|
+
} : {})
|
|
41854
42092
|
};
|
|
41855
42093
|
}
|
|
41856
42094
|
|
|
@@ -41868,10 +42106,11 @@ ${SharedStyles}
|
|
|
41868
42106
|
// Treat as error and route based on type
|
|
41869
42107
|
return {
|
|
41870
42108
|
...message,
|
|
41871
|
-
|
|
41872
|
-
type
|
|
41873
|
-
|
|
41874
|
-
|
|
42109
|
+
// Only add type if message doesn't already have one
|
|
42110
|
+
...(!message.type && !message.Type && typeField ? {
|
|
42111
|
+
type: typeField
|
|
42112
|
+
} : {}),
|
|
42113
|
+
error: true // Mark as error since it was detected as implicit error
|
|
41875
42114
|
};
|
|
41876
42115
|
}
|
|
41877
42116
|
}
|
|
@@ -41905,8 +42144,8 @@ ${SharedStyles}
|
|
|
41905
42144
|
};
|
|
41906
42145
|
}
|
|
41907
42146
|
|
|
41908
|
-
//
|
|
41909
|
-
if (typeof normalizedData === 'object' && !normalizedData.type) {
|
|
42147
|
+
// Only add type field if the normalized data doesn't already have one
|
|
42148
|
+
if (typeof normalizedData === 'object' && !normalizedData.type && !normalizedData.Type) {
|
|
41910
42149
|
normalizedData.type = typeField;
|
|
41911
42150
|
}
|
|
41912
42151
|
return normalizedData;
|
|
@@ -41928,32 +42167,7 @@ ${SharedStyles}
|
|
|
41928
42167
|
// Cache the message for later use by new subscribers
|
|
41929
42168
|
this._cacheMessage(message);
|
|
41930
42169
|
|
|
41931
|
-
//
|
|
41932
|
-
if (message.targetType) {
|
|
41933
|
-
const targetWidgets = this.typeSubscriptions.get(message.targetType);
|
|
41934
|
-
if (targetWidgets && targetWidgets.size > 0) {
|
|
41935
|
-
if (this.config.debug) {
|
|
41936
|
-
console.log(`[WebSocketManager] Routing ${message.targetType} error to specific widgets:`, [...targetWidgets]);
|
|
41937
|
-
}
|
|
41938
|
-
targetWidgets.forEach(widgetId => {
|
|
41939
|
-
const subscription = this.subscriptions.get(widgetId);
|
|
41940
|
-
if (subscription) {
|
|
41941
|
-
try {
|
|
41942
|
-
subscription.callback({
|
|
41943
|
-
event: 'data',
|
|
41944
|
-
data: message,
|
|
41945
|
-
widgetId
|
|
41946
|
-
});
|
|
41947
|
-
} catch (error) {
|
|
41948
|
-
console.error(`[WebSocketManager] Error in widget ${widgetId} callback:`, error);
|
|
41949
|
-
}
|
|
41950
|
-
}
|
|
41951
|
-
});
|
|
41952
|
-
return; // Don't fall through to broadcast
|
|
41953
|
-
}
|
|
41954
|
-
}
|
|
41955
|
-
|
|
41956
|
-
//console.log('here');
|
|
42170
|
+
// Get relevant widgets based on message type and symbol
|
|
41957
42171
|
const relevantWidgets = this._getRelevantWidgets(message);
|
|
41958
42172
|
if (this.config.debug && relevantWidgets.size > 0) {
|
|
41959
42173
|
console.log(`[WebSocketManager] Routing message to ${relevantWidgets.size} relevant widgets`);
|
|
@@ -41996,42 +42210,49 @@ ${SharedStyles}
|
|
|
41996
42210
|
_cacheMessage(message) {
|
|
41997
42211
|
try {
|
|
41998
42212
|
// Extract symbol and message type to create cache key
|
|
41999
|
-
|
|
42000
|
-
|
|
42213
|
+
// This allows new widgets to get instant data when subscribing
|
|
42214
|
+
// check in message.data or message.Data
|
|
42215
|
+
let data;
|
|
42216
|
+
if (message.data) {
|
|
42217
|
+
data = message.data;
|
|
42218
|
+
} else if (message.Data) {
|
|
42219
|
+
data = message.Data;
|
|
42220
|
+
} else {
|
|
42221
|
+
data = message;
|
|
42222
|
+
}
|
|
42223
|
+
const symbol = this._extractSymbol(data);
|
|
42224
|
+
const messageType = message.type;
|
|
42225
|
+
if (this.config.debug) {
|
|
42226
|
+
console.log(`[WebSocketManager] _cacheMessage - extracted symbol: "${symbol}", messageType: "${messageType}"`);
|
|
42227
|
+
}
|
|
42228
|
+
|
|
42229
|
+
// Cache by type:symbol combination
|
|
42001
42230
|
if (messageType && symbol) {
|
|
42002
42231
|
const cacheKey = `${messageType}:${symbol}`;
|
|
42003
42232
|
this.lastMessageCache.set(cacheKey, message);
|
|
42004
42233
|
if (this.config.debug) {
|
|
42005
42234
|
console.log(`[WebSocketManager] Cached message for ${cacheKey}`);
|
|
42006
42235
|
}
|
|
42007
|
-
}
|
|
42008
|
-
|
|
42009
|
-
|
|
42010
|
-
|
|
42011
|
-
const firstItem = message[0];
|
|
42012
|
-
const symbol = firstItem.Symbol;
|
|
42013
|
-
const messageType = this._extractMessageType(message);
|
|
42014
|
-
if (messageType && symbol) {
|
|
42015
|
-
const cacheKey = `${messageType}:${symbol}`;
|
|
42016
|
-
this.lastMessageCache.set(cacheKey, message);
|
|
42236
|
+
} else {
|
|
42237
|
+
// If we can't extract symbol from message, try to cache by type only
|
|
42238
|
+
// This helps with data like ONBBO L2 which doesn't have symbol in the message
|
|
42239
|
+
if (messageType) {
|
|
42017
42240
|
if (this.config.debug) {
|
|
42018
|
-
console.log(`[WebSocketManager]
|
|
42241
|
+
console.log(`[WebSocketManager] No symbol found in message, attempting to infer from subscriptions for type: ${messageType}`);
|
|
42019
42242
|
}
|
|
42020
|
-
}
|
|
42021
|
-
}
|
|
42022
42243
|
|
|
42023
|
-
|
|
42024
|
-
|
|
42025
|
-
|
|
42026
|
-
|
|
42027
|
-
|
|
42028
|
-
|
|
42029
|
-
|
|
42030
|
-
|
|
42031
|
-
|
|
42244
|
+
// Find active subscriptions for this message type and cache for each
|
|
42245
|
+
this.activeSubscriptions.forEach(activeKey => {
|
|
42246
|
+
const [type, sym] = activeKey.split(':');
|
|
42247
|
+
if (type === messageType && sym) {
|
|
42248
|
+
const cacheKey = activeKey;
|
|
42249
|
+
this.lastMessageCache.set(cacheKey, message);
|
|
42250
|
+
if (this.config.debug) {
|
|
42251
|
+
console.log(`[WebSocketManager] Cached message for ${cacheKey} (inferred from active subscription)`);
|
|
42252
|
+
}
|
|
42032
42253
|
}
|
|
42033
|
-
}
|
|
42034
|
-
}
|
|
42254
|
+
});
|
|
42255
|
+
}
|
|
42035
42256
|
}
|
|
42036
42257
|
} catch (error) {
|
|
42037
42258
|
console.error('[WebSocketManager] Error caching message:', error);
|
|
@@ -42198,7 +42419,7 @@ ${SharedStyles}
|
|
|
42198
42419
|
_extractSymbol(item) {
|
|
42199
42420
|
// Handle new format where symbol might be in nested data structure
|
|
42200
42421
|
// Check if this is an array with data that has _messageType (normalized new format)
|
|
42201
|
-
if (Array.isArray(item)
|
|
42422
|
+
if (Array.isArray(item)) {
|
|
42202
42423
|
// The data is an array, check first item for symbol
|
|
42203
42424
|
if (item.length > 0 && item[0]) {
|
|
42204
42425
|
return this._extractSymbolFromItem(item[0]);
|