analogger 1.20.3 → 1.20.4

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/CHANGELOG.md CHANGED
@@ -1,5 +1,7 @@
1
- ## [1.20.3](https://github.com/thimpat/analogger/compare/v1.20.2...v1.20.3) (2022-09-07)
1
+ ## [1.20.4](https://github.com/thimpat/analogger/compare/v1.20.3...v1.20.4) (2022-09-07)
2
2
 
3
+ ## [1.20.3](https://github.com/thimpat/analogger/compare/v1.20.2...v1.20.3) (2022-09-07)
4
+
3
5
  ## [1.20.2](https://github.com/thimpat/analogger/compare/v1.20.1...v1.20.2) (2022-09-07)
4
6
 
5
7
  ## [1.20.1](https://github.com/thimpat/analogger/compare/v1.20.0...v1.20.1) (2022-09-06)
@@ -52,6 +52,22 @@ export const DEFAULT_LOG_LEVELS = {
52
52
  INHERIT: -1,
53
53
  };
54
54
 
55
+ /**
56
+ * @typedef PLUGIN_TYPE
57
+ * @type {{LOCAL: string, GLOBAL: string}}
58
+ */
59
+ const PLUGIN_TYPE = {
60
+ LOCAL : "local",
61
+ GLOBAL: "global"
62
+ };
63
+
64
+ /**
65
+ * @typedef PLUGIN_PROPERTIES_TYPE
66
+ * @property {string} methodName AnaLogger's real method name that is set to the AnaLogger instance *
67
+ * @property {function} callback AnaLogger method that will be called when invoking the plugin
68
+ * @property {PLUGIN_TYPE} type Whether the plugin is accessible to the AnaLogger class or an instance
69
+ */
70
+
55
71
  export const DEFAULT_LOG_CONTEXTS = {
56
72
  // The default context
57
73
  DEFAULT : {contextName: "DEFAULT", logLevel: DEFAULT_LOG_LEVELS.LOG, symbol: "check"},
@@ -185,7 +201,8 @@ function isNode()
185
201
  }
186
202
 
187
203
  /**
188
- *
204
+ * @module ____AnaLogger
205
+ * @class ____AnaLogger
189
206
  */
190
207
  class ____AnaLogger
191
208
  {
@@ -236,7 +253,7 @@ class ____AnaLogger
236
253
 
237
254
  static instanceCount = 0;
238
255
 
239
- static pluginList = [];
256
+ static pluginTable = {};
240
257
 
241
258
  originalFormatFunction;
242
259
 
@@ -1142,6 +1159,12 @@ class ____AnaLogger
1142
1159
  // ------------------------------------------------
1143
1160
  // Logging methods
1144
1161
  // ------------------------------------------------
1162
+ /**
1163
+ * Add many sections (columns) to a given DOM line
1164
+ * @param $line
1165
+ * @param context
1166
+ * @param text
1167
+ */
1145
1168
  setColumns($line, context, text)
1146
1169
  {
1147
1170
  let index = 0;
@@ -1160,10 +1183,18 @@ class ____AnaLogger
1160
1183
  $line.append($col);
1161
1184
  }
1162
1185
 
1163
- const $col = document.createElement("span");
1186
+ let $col = document.createElement("span");
1164
1187
  $col.classList.add("analogger-col", "analogger-col-text", `analogger-col-${index}`);
1165
1188
  $col.textContent = text;
1166
1189
  $line.append($col);
1190
+
1191
+ // Add 3 more columns
1192
+ for (let i = 1; i <= 3; ++i)
1193
+ {
1194
+ $col = document.createElement("span");
1195
+ $col.classList.add("analogger-col", "analogger-col-extra", `analogger-extra-${i}`);
1196
+ $line.append($col);
1197
+ }
1167
1198
  }
1168
1199
 
1169
1200
  /**
@@ -1203,6 +1234,23 @@ class ____AnaLogger
1203
1234
  $view.scrollTop = $view.scrollHeight;
1204
1235
  };
1205
1236
 
1237
+ checkOnLoggingToDom(context, param2)
1238
+ {
1239
+ try
1240
+ {
1241
+ let callback = context.onLoggingToDom;
1242
+ if (typeof callback !== "function")
1243
+ {
1244
+ return;
1245
+ }
1246
+
1247
+ return callback.call(this, context, param2);
1248
+ }
1249
+ catch (e)
1250
+ {
1251
+ }
1252
+ }
1253
+
1206
1254
  /**
1207
1255
  * Add a line to the Analogger div.
1208
1256
  * Remove older lines if exceeding limit.
@@ -1210,9 +1258,28 @@ class ____AnaLogger
1210
1258
  * @param $line
1211
1259
  * @param context
1212
1260
  * @param addType
1261
+ * @param message
1262
+ * @param text
1263
+ * @param args
1213
1264
  */
1214
- addLineToDom($view, $line, {context, addType})
1215
- {
1265
+ addLineToDom($view, $line, {context, addType, message, text, args})
1266
+ {
1267
+ let proceedFurther = this.checkOnLoggingToDom(context, {
1268
+ message,
1269
+ text,
1270
+ args,
1271
+ logCounter: this.logCounter,
1272
+ $view,
1273
+ $line,
1274
+ addType
1275
+ });
1276
+
1277
+ // If one of the plugins returns false, no further operation will follow
1278
+ if (proceedFurther === false)
1279
+ {
1280
+ return;
1281
+ }
1282
+
1216
1283
  if (addType === ADD_TYPE.BOTTOM)
1217
1284
  {
1218
1285
  $view.append($line);
@@ -1230,18 +1297,7 @@ class ____AnaLogger
1230
1297
  return;
1231
1298
  }
1232
1299
 
1233
- context.contextName = ANALOGGER_NAME;
1234
- context.symbol = "🗑";
1235
- context.color = "orange";
1236
- context.className = CLASS_REMOVED_NOTIF;
1237
-
1238
- clearTimeout(this.timerAddLineToDomID);
1239
- this.timerAddLineToDomID = setTimeout(() =>
1240
- {
1241
- this.timerAddLineToDomID = null;
1242
- /* istanbul ignore next */
1243
- this.writeLogToDom(context, "", {addType: ADD_TYPE.TOP, message: `Oldest entries removed`});
1244
- }, 500);
1300
+ this.showRemovedNotification(context);
1245
1301
  return;
1246
1302
  }
1247
1303
 
@@ -1249,7 +1305,23 @@ class ____AnaLogger
1249
1305
 
1250
1306
  }
1251
1307
 
1252
- writeLogToDom(context, fullText, {addType = ADD_TYPE.BOTTOM, message = ""} = {})
1308
+ showRemovedNotification(context)
1309
+ {
1310
+ context.contextName = ANALOGGER_NAME;
1311
+ context.symbol = "🗑";
1312
+ context.color = "orange";
1313
+ context.className = CLASS_REMOVED_NOTIF;
1314
+
1315
+ clearTimeout(this.timerAddLineToDomID);
1316
+ this.timerAddLineToDomID = setTimeout(() =>
1317
+ {
1318
+ this.timerAddLineToDomID = null;
1319
+ /* istanbul ignore next */
1320
+ this.writeLogToDom(context, "", {addType: ADD_TYPE.TOP, message: `Oldest entries removed`});
1321
+ }, 500);
1322
+ }
1323
+
1324
+ writeLogToDom(context, fullText, {addType = ADD_TYPE.BOTTOM, message = "", args = null} = {})
1253
1325
  {
1254
1326
  this.$containers = this.$containers || document.querySelectorAll(this.options.logToDom);
1255
1327
  fullText = message || fullText;
@@ -1300,15 +1372,15 @@ class ____AnaLogger
1300
1372
  }
1301
1373
  $line.style.color = context.color;
1302
1374
 
1303
- this.setColumns($line, context, fullText);
1375
+ this.setColumns($line, context, fullText, args);
1304
1376
 
1305
1377
  // Prevent the application to be stuck when many logs are entered at once
1306
1378
  /* istanbul ignore next */
1307
- setTimeout(/* istanbul ignore next */function ($view, $line, {addType, context})
1379
+ setTimeout(/* istanbul ignore next */function ($view, $line, {addType, context, message, text, args})
1308
1380
  {
1309
1381
  /* istanbul ignore next */
1310
- this.addLineToDom($view, $line, {addType, context});
1311
- }.bind(this, $view, $line, {addType, context}), 0);
1382
+ this.addLineToDom($view, $line, {addType, context, message, text, args});
1383
+ }.bind(this, $view, $line, {addType, context, message, text: fullText, args}), 0);
1312
1384
 
1313
1385
  }
1314
1386
  }
@@ -1356,10 +1428,10 @@ class ____AnaLogger
1356
1428
  /**
1357
1429
  * Send data to the registered remote server
1358
1430
  * @param raw
1359
- * @param info
1360
- * @param lid
1431
+ * @param context
1432
+ * @param done
1361
1433
  */
1362
- uploadDataToRemote(raw, info = null, lid = null)
1434
+ uploadDataToRemote(raw, context = null, done = null)
1363
1435
  {
1364
1436
  try
1365
1437
  {
@@ -1375,16 +1447,17 @@ class ____AnaLogger
1375
1447
  }
1376
1448
 
1377
1449
  let data = raw;
1378
- if (info || lid)
1450
+ if (context)
1379
1451
  {
1380
- data = JSON.stringify({raw, info, lid});
1452
+ data = JSON.stringify({raw, context});
1381
1453
  }
1382
1454
 
1383
1455
  fetch(urlDest, {
1384
1456
  method: "post",
1385
1457
  body : data,
1386
1458
  })
1387
- .then(() => true)
1459
+ .then((response) => response.json())
1460
+ .then((data) => done && done(data))
1388
1461
  .catch(e => e);
1389
1462
  }
1390
1463
  catch (e)
@@ -1441,29 +1514,140 @@ class ____AnaLogger
1441
1514
  }
1442
1515
 
1443
1516
  const contextLevel = context.contextLevel || DEFAULT_LOG_LEVELS.LOG;
1444
- if (contextLevel > DEFAULT_LOG_LEVELS.ERROR)
1517
+ if (contextLevel >= DEFAULT_LOG_LEVELS.ERROR)
1445
1518
  {
1446
1519
  this.#realConsoleError(...res);
1447
1520
  }
1448
- else if (contextLevel > DEFAULT_LOG_LEVELS.WARN)
1521
+ else if (contextLevel >= DEFAULT_LOG_LEVELS.WARN)
1449
1522
  {
1450
1523
  this.#realConsoleWarn(...res);
1451
1524
  }
1452
- else if (contextLevel > DEFAULT_LOG_LEVELS.INFO)
1525
+ else if (contextLevel >= DEFAULT_LOG_LEVELS.INFO)
1453
1526
  {
1454
1527
  this.#realConsoleInfo(...res);
1455
1528
  }
1456
- else if (contextLevel > DEFAULT_LOG_LEVELS.LOG)
1529
+ else if (contextLevel >= DEFAULT_LOG_LEVELS.LOG)
1457
1530
  {
1458
1531
  this.#realConsoleLog(...res);
1459
1532
  }
1460
- else if (contextLevel > DEFAULT_LOG_LEVELS.DEBUG)
1533
+ else if (contextLevel >= DEFAULT_LOG_LEVELS.DEBUG)
1461
1534
  {
1462
1535
  this.#realConsoleDebug(...res);
1463
1536
  }
1464
1537
 
1465
1538
  }
1466
1539
 
1540
+ /**
1541
+ * Parse the context. If one of its keys has the same name as a registered plugin,
1542
+ * the system will invoke the plugin (the value of the key must be anything truthy).
1543
+ * @param context
1544
+ * @param extras
1545
+ * @returns {undefined|boolean}
1546
+ */
1547
+ checkPlugins(context, {message, text, args, logCounter})
1548
+ {
1549
+ try
1550
+ {
1551
+ if (!Object.keys(____AnaLogger.pluginTable).length)
1552
+ {
1553
+ return;
1554
+ }
1555
+
1556
+ let proceedFurther = true;
1557
+ for (let keyName in context)
1558
+ {
1559
+ const pluginArgs = context[keyName];
1560
+
1561
+ /**
1562
+ * The key has been passed in the context, but has a falsy value,
1563
+ * so let's ignore it
1564
+ */
1565
+ if (!pluginArgs)
1566
+ {
1567
+ continue;
1568
+ }
1569
+
1570
+ /**
1571
+ * Extract plugin properties
1572
+ * @type PLUGIN_TYPE
1573
+ */
1574
+ const pluginProperties = ____AnaLogger.pluginTable[keyName];
1575
+
1576
+ /**
1577
+ * Check plugin properties exists
1578
+ * @see addPlugin
1579
+ * @see addGlobalPlugin
1580
+ */
1581
+ if (!pluginProperties)
1582
+ {
1583
+ continue;
1584
+ }
1585
+
1586
+ // Should be an object
1587
+ if (typeof pluginProperties !== "object")
1588
+ {
1589
+ continue;
1590
+ }
1591
+
1592
+ /**
1593
+ * Extract plugin properties
1594
+ */
1595
+ const {callback, methodName, type} = pluginProperties;
1596
+ if (typeof callback !== "function")
1597
+ {
1598
+ continue;
1599
+ }
1600
+
1601
+ /**
1602
+ * If the key given in the context was a function, invoke that function
1603
+ */
1604
+ if (typeof pluginArgs === "function")
1605
+ {
1606
+ context = pluginArgs;
1607
+ }
1608
+
1609
+ /**
1610
+ * Invoke the plugin
1611
+ */
1612
+ let res = callback.call(this, context, {message, text, args, logCounter, methodName, type, pluginArgs});
1613
+
1614
+ // If the plugin returns exactly false, the log entry will be ignored by anaLogger
1615
+ if (res === false)
1616
+ {
1617
+ proceedFurther = false;
1618
+ }
1619
+ }
1620
+ return proceedFurther;
1621
+ }
1622
+ catch (e)
1623
+ {
1624
+ }
1625
+ }
1626
+
1627
+ /**
1628
+ * If the context contain a key onLogging that is a function,
1629
+ * execute
1630
+ * @param context
1631
+ * @param extras
1632
+ * @returns {*}
1633
+ */
1634
+ checkOnLogging(context, extras)
1635
+ {
1636
+ try
1637
+ {
1638
+ let callback = context.onLogging;
1639
+ if (typeof callback !== "function")
1640
+ {
1641
+ return;
1642
+ }
1643
+
1644
+ return callback.call(this, context, extras);
1645
+ }
1646
+ catch (e)
1647
+ {
1648
+ }
1649
+ }
1650
+
1467
1651
  /**
1468
1652
  * Display log following template
1469
1653
  * @param context
@@ -1501,6 +1685,28 @@ class ____AnaLogger
1501
1685
 
1502
1686
  ++this.logCounter;
1503
1687
 
1688
+ let proceedFurther;
1689
+
1690
+ proceedFurther = this.checkOnLogging(context, {message, text, args, logCounter: this.logCounter});
1691
+ // If one of the plugins returns false, no further operation will follow
1692
+ if (proceedFurther === false)
1693
+ {
1694
+ return;
1695
+ }
1696
+
1697
+ proceedFurther = this.checkPlugins(context, {message, text, args, logCounter: this.logCounter});
1698
+
1699
+ // If one of the plugins returns false, no further operation will follow
1700
+ if (proceedFurther === false)
1701
+ {
1702
+ return;
1703
+ }
1704
+
1705
+ if (this.options.logToRemote)
1706
+ {
1707
+ this.writeLogToRemote(context, ...args);
1708
+ }
1709
+
1504
1710
  /* istanbul ignore next */
1505
1711
  if (this.isBrowser())
1506
1712
  {
@@ -1509,7 +1715,7 @@ class ____AnaLogger
1509
1715
  if (this.options.logToDom)
1510
1716
  {
1511
1717
  /* istanbul ignore next */
1512
- this.writeLogToDom(context, text, {message});
1718
+ this.writeLogToDom(context, text, {message, args,});
1513
1719
  }
1514
1720
 
1515
1721
  output = `%c${text}`;
@@ -1650,11 +1856,6 @@ class ____AnaLogger
1650
1856
  */
1651
1857
  log(options, ...args)
1652
1858
  {
1653
- if (this.options.logToRemote)
1654
- {
1655
- this.writeLogToRemote(options, ...args);
1656
- }
1657
-
1658
1859
  options = this.extractContextFromInput(options);
1659
1860
  // If the first parameter is not of context format,
1660
1861
  // We use the default context and display
@@ -1673,11 +1874,6 @@ class ____AnaLogger
1673
1874
 
1674
1875
  error(options, ...args)
1675
1876
  {
1676
- if (this.options.logToRemote)
1677
- {
1678
- this.writeLogToRemote(options, ...args);
1679
- }
1680
-
1681
1877
  if (this.options.hideError)
1682
1878
  {
1683
1879
  return;
@@ -1962,14 +2158,16 @@ class ____AnaLogger
1962
2158
  * @param callback
1963
2159
  * @param pluginName
1964
2160
  */
1965
- addPlugin(methodName, callback, pluginName)
2161
+ addPlugin(methodName, callback, pluginName = "")
1966
2162
  {
2163
+ pluginName = pluginName || methodName;
1967
2164
  this[methodName] = callback;
1968
- ____AnaLogger.pluginList.push({
1969
- pluginName,
1970
- type: "local"
1971
- });
1972
2165
 
2166
+ ____AnaLogger.pluginTable[pluginName] = {
2167
+ type: PLUGIN_TYPE.LOCAL,
2168
+ methodName,
2169
+ callback
2170
+ };
1973
2171
  }
1974
2172
 
1975
2173
  /**
@@ -1982,16 +2180,17 @@ class ____AnaLogger
1982
2180
  {
1983
2181
  ____AnaLogger[methodName] = callback;
1984
2182
 
1985
- ____AnaLogger.pluginList.push({
1986
- pluginName,
1987
- type: "global"
1988
- });
2183
+ ____AnaLogger.pluginTable[pluginName] = {
2184
+ type: PLUGIN_TYPE.GLOBAL,
2185
+ methodName,
2186
+ callback
2187
+ };
1989
2188
 
1990
2189
  }
1991
2190
 
1992
2191
  getPluginList()
1993
2192
  {
1994
- return Object.freeze(____AnaLogger.pluginList);
2193
+ return Object.keys(____AnaLogger.pluginTable);
1995
2194
  }
1996
2195
 
1997
2196
  /**
@@ -2001,18 +2200,15 @@ class ____AnaLogger
2001
2200
  */
2002
2201
  validatePlugin(name)
2003
2202
  {
2004
- for (let i = 0; i < ____AnaLogger.pluginList.length; ++i)
2203
+ if (____AnaLogger.pluginTable[name])
2005
2204
  {
2006
- const pluginProperties = ____AnaLogger.pluginList[i];
2007
- if (pluginProperties.pluginName === name)
2008
- {
2009
- return true;
2010
- }
2205
+ return true;
2011
2206
  }
2012
2207
 
2013
2208
  console.warn(`The plugin ${name} is not registered`);
2014
2209
  return false;
2015
2210
  }
2211
+
2016
2212
  }
2017
2213
 
2018
2214
  export const AnaLogger = ____AnaLogger;
@@ -12,44 +12,92 @@ import {anaLogger} from "./ana-logger.mjs";
12
12
 
13
13
 
14
14
 
15
- export const PLUGIN_NAME = "HTML_TO_IMAGE";
15
+ export const PLUGIN_NAME = "takeScreenshot";
16
16
 
17
17
  /**
18
18
  * Take a screenshot then send to a remote
19
- * @param element
20
- * @param container
19
+ * @see ____AnaLogger.checkPlugins
20
+ * @param context
21
+ * @param {HTMLElement} element Dom element we want to take a screenshot from
22
+ * @param args
23
+ * @param logCounter
24
+ * @param message
25
+ * @param text
26
+ * @param methodName
27
+ * @param type
21
28
  * @returns {boolean}
22
29
  */
23
- const takeScreenshot = ({element = document.body, callback = null, info = null, lid = null} = {}) =>
30
+ const takeScreenshot = (context,
31
+ {
32
+ pluginArgs = {},
33
+ divSource = document.body,
34
+ args = null,
35
+ logCounter = -1,
36
+ message = null,
37
+ text = null,
38
+ methodName = "",
39
+ type = ""
40
+ }) =>
24
41
  {
25
42
  try
26
43
  {
27
44
  htmlToImage
28
- .toPng(element)
29
- .then(function (data)
45
+ .toPng(divSource)
46
+ .then(function (imageData)
30
47
  {
31
- anaLogger.uploadDataToRemote(data, info, lid);
32
- callback && callback(data);
48
+ // ------------------------------------
49
+ // Phase 1: We have the screenshot
50
+ // ------------------------------------
51
+ const onScreenshot = pluginArgs ? pluginArgs.onScreenshot : null;
52
+ onScreenshot && onScreenshot({
53
+ imageData,
54
+ context,
55
+ methodName,
56
+ type,
57
+ message,
58
+ text,
59
+ args,
60
+ logCounter,
61
+ });
62
+
63
+ anaLogger.uploadDataToRemote(imageData, context, (serverResponse) =>
64
+ {
65
+ // ------------------------------------
66
+ // Phase 1: We have the screenshot url from the server
67
+ // ------------------------------------
68
+ const onResponse = pluginArgs ? pluginArgs.onResponse : null;
69
+ // We transfer as much information as we can to the plugin
70
+ onResponse && onResponse({
71
+ imageData,
72
+ pluginCallResult: response,
73
+ serverResponse, // We need the response to know where
74
+ // to find the generated image on the
75
+ // server
76
+ context,
77
+ methodName,
78
+ type,
79
+ message,
80
+ text,
81
+ args,
82
+ logCounter,
83
+ });
84
+ });
33
85
  })
34
86
  .catch(function (error)
35
87
  {
36
88
  console.error("Something went wrong:", error);
37
89
  });
38
-
39
- return true;
40
90
  }
41
91
  catch (e)
42
92
  {
43
93
  console.error({lid: 4321}, e.message);
44
94
  }
45
95
 
46
- return false;
96
+ response = false;
97
+ return response;
47
98
  };
48
99
 
49
- /**
50
- * {@link takeScreenshot}
51
- */
52
- anaLogger.addPlugin("takeScreenshot", takeScreenshot, PLUGIN_NAME);
100
+ anaLogger.addPlugin(PLUGIN_NAME, takeScreenshot);
53
101
 
54
102
 
55
103
 
@@ -1 +1 @@
1
- html,body{height:100%}body{margin:0;overflow:hidden}.analogger{background-color:#ababab;box-shadow:1px 1px 4px 0 rgba(0,0,0,.3);box-sizing:border-box;display:flex;flex-direction:column;height:calc(100% - 12px);overflow:hidden;padding:0;position:relative;width:calc(100% - 8px)}.analogger .analogger-header{box-sizing:border-box;display:flex;flex:auto;height:38px;margin:0;padding:0;top:0;width:100%}.analogger .analogger-header span:nth-child(1){flex:auto;font-family:sans-serif;font-size:14px;width:80%}.analogger .analogger-header span:nth-child(2){flex:auto;font-family:sans-serif;font-size:14px}.analogger .analogger-header span:nth-child(3){flex:auto;font-family:sans-serif;font-size:22px;margin:0;padding:0 6px;text-align:right;width:20px}.analogger .analogger-footer{background:#7ba3cd59;bottom:3px;display:inline-block;height:33px;margin:0 0 0 3px;position:absolute;width:calc(100% - 6px)}.analogger .analogger-footer span:nth-child(1){font-family:sans-serif;font-size:14px}.analogger .analogger-view{background-color:#dddbdb;box-sizing:border-box;color:#faebd7;display:block;flex:auto;font-family:sans-serif;font-size:11px;line-height:30px;height:100%;margin:0 0 3px 3px;padding:0;overflow:auto;position:relative;width:calc(100% - 6px)}.analogger .analogger-view .to-esm-line{align-items:stretch;border-bottom:1px dashed #56499324;display:flex;justify-content:flex-start;height:26px;line-height:26px;overflow:hidden;vertical-align:middle;white-space:nowrap}.analogger .analogger-view .to-esm-line.analogger-removed-notif{background-color:rgba(223,73,73,.51);color:#abb9b7;font-size:9px}.analogger .analogger-view .to-esm-line.analogger-removed-notif .analogger-col-symbol{font-size:18px}.analogger .analogger-view .to-esm-line .analogger-col{overflow:hidden;padding:0 4px;text-overflow:ellipsis;white-space:nowrap}.analogger .analogger-view .to-esm-line .analogger-col-contextName{flex-grow:1;max-width:60px;text-align:right}.analogger .analogger-view .to-esm-line .analogger-col-target{flex-grow:1;max-width:60px;text-align:right}.analogger .analogger-view .to-esm-line .analogger-col-symbol{flex-grow:1;max-width:40px;text-align:center}.analogger .analogger-view .to-esm-line .analogger-col-text{flex-grow:1}.analogger .analogger-view::-webkit-scrollbar-thumb{border:5px solid transparent;border-radius:100px;background-color:#514b6e;background-clip:content-box}.analogger .analogger-view::-webkit-scrollbar{width:14px}.analogger .analogger-view::-webkit-scrollbar-track{background-color:#382525;border-radius:100px}.analogger .analogger-view::-webkit-scrollbar-thumb{border-radius:100px;border:4px solid transparent;background-clip:content-box;background-color:#9f6c53}
1
+ html,body{height:100%}body{margin:0;overflow:hidden}.analogger{background-color:#ababab;box-shadow:1px 1px 4px 0 rgba(0,0,0,.3);box-sizing:border-box;display:flex;flex-direction:column;height:calc(100% - 12px);overflow:hidden;padding:0;position:relative;width:calc(100% - 8px)}.analogger .analogger-header{box-sizing:border-box;display:flex;flex:auto;height:38px;margin:0;padding:0;top:0;width:100%}.analogger .analogger-header span:nth-child(1){flex:auto;font-family:sans-serif;font-size:14px;width:80%}.analogger .analogger-header span:nth-child(2){flex:auto;font-family:sans-serif;font-size:14px}.analogger .analogger-header span:nth-child(3){flex:auto;font-family:sans-serif;font-size:22px;margin:0;padding:0 6px;text-align:right;width:20px}.analogger .analogger-footer{background:#7ba3cd59;bottom:3px;display:inline-block;height:33px;margin:0 0 0 3px;position:absolute;width:calc(100% - 6px)}.analogger .analogger-footer span:nth-child(1){font-family:sans-serif;font-size:14px}.analogger .analogger-view{background-color:#dddbdb;box-sizing:border-box;color:#faebd7;display:block;flex:auto;font-family:sans-serif;font-size:11px;line-height:30px;height:100%;margin:0 0 3px 3px;padding:0;overflow:auto;position:relative;width:calc(100% - 6px)}.analogger .analogger-view .to-esm-line{align-items:stretch;border-bottom:1px dashed #56499324;display:flex;justify-content:flex-start;height:26px;line-height:26px;overflow:hidden;vertical-align:middle;white-space:nowrap}.analogger .analogger-view .to-esm-line.analogger-removed-notif{background-color:rgba(223,73,73,.51);color:#abb9b7;font-size:9px}.analogger .analogger-view .to-esm-line.analogger-removed-notif .analogger-col-symbol{font-size:18px}.analogger .analogger-view .to-esm-line .analogger-col{overflow:hidden;padding:0 4px;text-overflow:ellipsis;white-space:nowrap}.analogger .analogger-view .to-esm-line .analogger-col-contextName{flex-grow:1;max-width:60px;text-align:right}.analogger .analogger-view .to-esm-line .analogger-col-target{flex-grow:1;max-width:60px;text-align:right}.analogger .analogger-view .to-esm-line .analogger-col-symbol{flex-grow:1;max-width:40px;text-align:center}.analogger .analogger-view .to-esm-line .analogger-col-text{flex-grow:1}.analogger .analogger-view .to-esm-line .analogger-col-extra{display:none}.analogger .analogger-view::-webkit-scrollbar-thumb{border:5px solid transparent;border-radius:100px;background-color:#514b6e;background-clip:content-box}.analogger .analogger-view::-webkit-scrollbar{width:14px}.analogger .analogger-view::-webkit-scrollbar-track{background-color:#382525;border-radius:100px}.analogger .analogger-view::-webkit-scrollbar-thumb{border-radius:100px;border:4px solid transparent;background-clip:content-box;background-color:#9f6c53}