From d6cecc5b8ad4d27ba694ea0434d52f6401595acd Mon Sep 17 00:00:00 2001 From: Jan Litzenburger Date: Sat, 10 Apr 2021 09:18:08 +0200 Subject: [PATCH 1/4] option to config decimals --- MMM-Jast.js | 68 +++++++++++++++++++++++++- README.md | 8 +++- node_helper.js | 79 ++++++++++++++++++++++++++++++- src/client/Client.ts | 2 + src/client/Utils.ts | 20 ++++---- src/models/Config.ts | 6 ++- templates/HorizontalStockList.njk | 14 +++--- templates/VerticalStockList.njk | 14 +++--- 8 files changed, 183 insertions(+), 28 deletions(-) diff --git a/MMM-Jast.js b/MMM-Jast.js index 198fc42..fe33291 100644 --- a/MMM-Jast.js +++ b/MMM-Jast.js @@ -1 +1,67 @@ -(()=>{"use strict";var e={429:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.default=class{static getStockChange(e){var t;return Number((null===(t=e.price)||void 0===t?void 0:t.regularMarketChange).toFixed(2))||0}static getStockChangePercent(e){var t;return Number((100*(null===(t=e.price)||void 0===t?void 0:t.regularMarketChangePercent)).toFixed(1))||0}static getCurrentValue(e){var t,n;return Number(null===(n=null===(t=e.price)||void 0===t?void 0:t.regularMarketPrice)||void 0===n?void 0:n.toFixed(2))||0}static getCurrency(e){var t;return(null===(t=e.summaryDetail)||void 0===t?void 0:t.currency)||"?"}static getDepotGrowth(e,t){var n,a;let r=[];for(const o of t)try{const t=null===(n=e.stocks)||void 0===n?void 0:n.find((e=>{var t;return e.symbol===(null===(t=o.meta)||void 0===t?void 0:t.symbol)}));if(null==t?void 0:t.quantity){const e=(null===(a=o.price)||void 0===a?void 0:a.regularMarketChange)*t.quantity,n=r.find((e=>e.currency===o.price.currency));n?n.value=n.value+e:r.push({value:e,currency:o.price.currency})}}catch(e){console.warn("There was a problem calculating the detpot growth",e)}return r.forEach((e=>{e.value=Number(e.value.toFixed(2))})),r}}}},t={};function n(a){var r=t[a];if(void 0!==r)return r.exports;var o=t[a]={exports:{}};return e[a](o,o.exports,n),o.exports}(()=>{const e=n(429);Module.register("MMM-Jast",{defaults:{header:null,updateIntervalInSeconds:600,fadeSpeedInSeconds:3.5,stocks:[{name:"BASF",symbol:"BAS.DE",quantity:100},{name:"SAP",symbol:"SAP.DE",quantity:200},{name:"Henkel",symbol:"HEN3.DE"},{name:"AbbVie",symbol:"4AB.DE"},{name:"Bitcoin",symbol:"BTC-EUR"},{name:"Alibaba",symbol:"BABA"}],scroll:"vertical",maxWidth:"100%",showCurrency:!0,showChangePercent:!0,showChangeValue:!1,showChangeValueCurrency:!1,showDepotGrowth:!1},getStyles:()=>["MMM-Jast.css"],getTranslations:()=>({en:"translations/en.json",de:"translations/de.json"}),getTemplate:()=>"templates/MMM-Jast.njk",getTemplateData(){return{config:this.config,stocks:this.stocks,utils:e.default}},getHeader(){return this.config.header},start(){this.nunjucksEnvironment().loaders[0].async=!1,this.nunjucksEnvironment().loaders[0].useCache=!0,this.stocks=[],this.loadData(),this.scheduleUpdate(),this.updateDom()},scheduleUpdate(){const e=this;this.config.updateIntervalInSeconds=this.config.updateIntervalInSeconds<120?120:this.config.updateIntervalInSeconds,setInterval((()=>{e.loadData()}),1e3*this.config.updateIntervalInSeconds)},loadData(){this.sendSocketNotification("GET_STOCKS",this.config)},socketNotificationReceived(e,t){"STOCKS_RESULT"===e&&(this.stocks=t,this.updateDom(),console.log("Stock results",this.stocks))}})})()})(); \ No newline at end of file +/* + * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development"). + * This devtool is neither made for production nor for readable output files. + * It uses "eval()" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with "devtool: false". + * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ "use strict"; +/******/ var __webpack_modules__ = ({ + +/***/ "./src/client/Client.ts": +/*!******************************!*\ + !*** ./src/client/Client.ts ***! + \******************************/ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nconst Utils_1 = __webpack_require__(/*! ./Utils */ \"./src/client/Utils.ts\");\nModule.register(\"MMM-Jast\", {\n defaults: {\n header: null,\n updateIntervalInSeconds: 600,\n fadeSpeedInSeconds: 3.5,\n stocks: [\n { name: \"BASF\", symbol: \"BAS.DE\", quantity: 100 },\n { name: \"SAP\", symbol: \"SAP.DE\", quantity: 200 },\n { name: \"Henkel\", symbol: \"HEN3.DE\" },\n { name: \"AbbVie\", symbol: \"4AB.DE\" },\n { name: \"Bitcoin\", symbol: \"BTC-EUR\" },\n { name: \"Alibaba\", symbol: \"BABA\" }\n ],\n scroll: \"vertical\",\n maxWidth: \"100%\",\n numberDecimalsValues: 2,\n numberDecimalsPercentages: 1,\n showCurrency: true,\n showChangePercent: true,\n showChangeValue: false,\n showChangeValueCurrency: false,\n showDepotGrowth: false\n },\n getStyles() {\n return [\"MMM-Jast.css\"];\n },\n getTranslations() {\n return {\n en: \"translations/en.json\",\n de: \"translations/de.json\"\n };\n },\n getTemplate() {\n return \"templates/MMM-Jast.njk\";\n },\n getTemplateData() {\n return {\n config: this.config,\n stocks: this.stocks,\n utils: Utils_1.default\n };\n },\n getHeader() {\n return this.config.header;\n },\n start() {\n // Override defaults\n this.nunjucksEnvironment().loaders[0].async = false;\n this.nunjucksEnvironment().loaders[0].useCache = true;\n this.stocks = [];\n this.loadData();\n this.scheduleUpdate();\n this.updateDom();\n },\n scheduleUpdate() {\n const self = this;\n this.config.updateIntervalInSeconds = this.config.updateIntervalInSeconds < 120 ? 120 : this.config.updateIntervalInSeconds;\n setInterval(() => {\n self.loadData();\n }, this.config.updateIntervalInSeconds * 1000);\n },\n loadData() {\n this.sendSocketNotification(\"GET_STOCKS\", this.config);\n },\n socketNotificationReceived(notificationIdentifier, payload) {\n if (notificationIdentifier === \"STOCKS_RESULT\") {\n this.stocks = payload;\n this.updateDom();\n console.log(\"Stock results\", this.stocks);\n }\n }\n});\n\n\n//# sourceURL=webpack://mmm-jast/./src/client/Client.ts?"); + +/***/ }), + +/***/ "./src/client/Utils.ts": +/*!*****************************!*\ + !*** ./src/client/Utils.ts ***! + \*****************************/ +/***/ ((__unused_webpack_module, exports) => { + +eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nclass JastUtils {\n static getStockChange(stock, config) {\n var _a;\n return Number(((_a = stock.price) === null || _a === void 0 ? void 0 : _a.regularMarketChange).toFixed(config.numberDecimalsValues)) || 0;\n }\n static getStockChangePercent(stock, config) {\n var _a;\n return Number((((_a = stock.price) === null || _a === void 0 ? void 0 : _a.regularMarketChangePercent) * 100).toFixed(config.numberDecimalsPercentages)) || 0;\n }\n static getCurrentValue(stock, config) {\n var _a, _b;\n return Number((_b = (_a = stock.price) === null || _a === void 0 ? void 0 : _a.regularMarketPrice) === null || _b === void 0 ? void 0 : _b.toFixed(config.numberDecimalsValues)) || 0;\n }\n static getCurrency(stock) {\n var _a;\n return ((_a = stock.summaryDetail) === null || _a === void 0 ? void 0 : _a.currency) || \"?\";\n }\n static getStockName(stock) {\n return stock.meta.name || stock.price.longName;\n }\n static getDepotGrowth(stocks, config) {\n var _a, _b;\n let depotGrowth = [];\n for (const stock of stocks) {\n try {\n const configStock = (_a = config.stocks) === null || _a === void 0 ? void 0 : _a.find(current => { var _a; return current.symbol === ((_a = stock.meta) === null || _a === void 0 ? void 0 : _a.symbol); });\n if (configStock === null || configStock === void 0 ? void 0 : configStock.quantity) {\n const growthForStock = ((_b = stock.price) === null || _b === void 0 ? void 0 : _b.regularMarketChange) * configStock.quantity;\n const existingCurrency = depotGrowth.find(growth => growth.currency === stock.price.currency);\n if (existingCurrency) {\n existingCurrency.value = existingCurrency.value + growthForStock;\n }\n else {\n depotGrowth.push({ value: growthForStock, currency: stock.price.currency });\n }\n }\n }\n catch (err) {\n console.warn('There was a problem calculating the detpot growth', err);\n }\n }\n depotGrowth.forEach(growth => {\n growth.value = Number(growth.value.toFixed(config.numberDecimalsValues));\n });\n return depotGrowth;\n }\n}\nexports.default = JastUtils;\n\n\n//# sourceURL=webpack://mmm-jast/./src/client/Utils.ts?"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = __webpack_require__("./src/client/Client.ts"); +/******/ +/******/ })() +; \ No newline at end of file diff --git a/README.md b/README.md index 3a277d6..f30e98f 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,9 @@ To use this module, add it to the modules array in the `config/config.js` file: showChangePercent: true, showChangeValue: false, showChangeValueCurrency: false, - showDepotGrowth: false + showDepotGrowth: false, + numberDecimalsValues: 2, + numberDecimalsPercentages: 1, stocks: [ { name: "BASF", symbol: "BAS.DE", quantity: 10 }, { name: "SAP", symbol: "SAP.DE", quantity: 15 }, @@ -51,6 +53,8 @@ To use this module, add it to the modules array in the `config/config.js` file: | stocks | (Array) Array of stocks to be displayed | Sample set | | scroll | (String) Animation direction for ticker. Values: none, vertical or horizontal | "vertical" | | maxWidth | (String) CSS style to limit ticker width for vertical styles | "100%" | +| numberDecimalsValues | (Number) Number of decimals for stock values | 2 | +| numberDecimalsPercentages | (Number) Number of decimals for percentages | 1 | | showCurrency | (Boolean) Show stocks currency | true | | showChangePercent | (Boolean) Show stocks change against last close in percent | true | | showChangeValue | (Boolean) Show stocks change against last close in absolute value | false | @@ -60,6 +64,6 @@ To use this module, add it to the modules array in the `config/config.js` file: ### Stock Object | Field | Description | Example | | -------- | -------- | -------- | -| name | (String) Stock's display name | "Alibaba" | | symbol | (String) Stock's symbol/key | "BABA" | +| name | (String) Optional: Stock's display name | "Alibaba" | | quantity | (Integer) Optional: To calculate depotGrowth | 500 | diff --git a/node_helper.js b/node_helper.js index ff618d9..15f667e 100644 --- a/node_helper.js +++ b/node_helper.js @@ -1 +1,78 @@ -(()=>{"use strict";var e={944:function(e,t,o){var r=this&&this.__awaiter||function(e,t,o,r){return new(o||(o=Promise))((function(n,i){function s(e){try{c(r.next(e))}catch(e){i(e)}}function a(e){try{c(r.throw(e))}catch(e){i(e)}}function c(e){var t;e.done?n(e.value):(t=e.value,t instanceof o?t:new o((function(e){e(t)}))).then(s,a)}c((r=r.apply(e,t||[])).next())}))};Object.defineProperty(t,"__esModule",{value:!0});const n=o(543),i=o(61);e.exports=n.create({start(){console.log(`${this.name} helper method started...`)},requestStocks(e){return r(this,void 0,void 0,(function*(){let t=[];for(const o of e.stocks)try{const{summaryDetail:e,price:r}=yield i.default.quoteSummary(o.symbol);if(e&&r){const n={symbol:o.symbol,name:o.name,quantity:o.quantity};t.push({summaryDetail:e,price:r,meta:n})}}catch(e){console.error("There was an error requesting the API.",e.message)}return t}))},socketNotificationReceived(e,t){return r(this,void 0,void 0,(function*(){if(e){const e=yield this.requestStocks(t);this.sendSocketNotification("STOCKS_RESULT",e)}else console.warn(`${e} is invalid notification`)}))}})},543:e=>{e.exports=require("node_helper")},61:e=>{e.exports=require("yahoo-finance2")}},t={},o=function o(r){var n=t[r];if(void 0!==n)return n.exports;var i=t[r]={exports:{}};return e[r].call(i.exports,i,i.exports,o),i.exports}(944);module.exports=o})(); \ No newline at end of file +/* + * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development"). + * This devtool is neither made for production nor for readable output files. + * It uses "eval()" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with "devtool: false". + * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ "use strict"; +/******/ var __webpack_modules__ = ({ + +/***/ "./src/server/Server.ts": +/*!******************************!*\ + !*** ./src/server/Server.ts ***! + \******************************/ +/***/ (function(module, exports, __webpack_require__) { + +eval("\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nconst NodeHelper = __webpack_require__(/*! node_helper */ \"node_helper\");\nconst yahoo_finance2_1 = __webpack_require__(/*! yahoo-finance2 */ \"yahoo-finance2\");\nmodule.exports = NodeHelper.create({\n start() {\n console.log(`${this.name} helper method started...`);\n },\n requestStocks(config) {\n return __awaiter(this, void 0, void 0, function* () {\n let results = [];\n for (const stock of config.stocks) {\n try {\n const { summaryDetail, price } = yield yahoo_finance2_1.default.quoteSummary(stock.symbol);\n if (summaryDetail && price) {\n const meta = {\n symbol: stock.symbol,\n name: stock.name,\n quantity: stock.quantity\n };\n results.push({ summaryDetail, price, meta });\n }\n }\n catch (err) {\n console.error(\"There was an error requesting the API.\", err.message);\n }\n }\n return results;\n });\n },\n socketNotificationReceived(notification, config) {\n return __awaiter(this, void 0, void 0, function* () {\n if (notification) {\n const stocks = yield this.requestStocks(config);\n this.sendSocketNotification(\"STOCKS_RESULT\", stocks);\n }\n else {\n console.warn(`${notification} is invalid notification`);\n }\n });\n }\n});\n\n\n//# sourceURL=webpack://mmm-jast/./src/server/Server.ts?"); + +/***/ }), + +/***/ "node_helper": +/*!******************************!*\ + !*** external "node_helper" ***! + \******************************/ +/***/ ((module) => { + +module.exports = require("node_helper");; + +/***/ }), + +/***/ "yahoo-finance2": +/*!*********************************!*\ + !*** external "yahoo-finance2" ***! + \*********************************/ +/***/ ((module) => { + +module.exports = require("yahoo-finance2");; + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module is referenced by other modules so it can't be inlined +/******/ var __webpack_exports__ = __webpack_require__("./src/server/Server.ts"); +/******/ module.exports = __webpack_exports__; +/******/ +/******/ })() +; \ No newline at end of file diff --git a/src/client/Client.ts b/src/client/Client.ts index c695864..25d0015 100644 --- a/src/client/Client.ts +++ b/src/client/Client.ts @@ -16,6 +16,8 @@ Module.register("MMM-Jast", { ], scroll: "vertical", maxWidth: "100%", + numberDecimalsValues: 2, + numberDecimalsPercentages: 1, showCurrency: true, showChangePercent: true, showChangeValue: false, diff --git a/src/client/Utils.ts b/src/client/Utils.ts index e8fb531..7b5c100 100644 --- a/src/client/Utils.ts +++ b/src/client/Utils.ts @@ -3,23 +3,27 @@ import { StockResponse } from "../models/StockResponse" import { Config } from "../models/Config" export default class JastUtils { - static getStockChange(stock: StockResponse): number { - return Number((stock.price?.regularMarketChange).toFixed(2)) || 0 + static getStockChange(stock: StockResponse, config: Config): number { + return Number((stock.price?.regularMarketChange).toFixed(config.numberDecimalsValues)) || 0 } - static getStockChangePercent(stock: StockResponse): number { - return Number((stock.price?.regularMarketChangePercent * 100).toFixed(1)) || 0 + static getStockChangePercent(stock: StockResponse, config: Config): number { + return Number((stock.price?.regularMarketChangePercent * 100).toFixed(config.numberDecimalsPercentages)) || 0 } - static getCurrentValue(stock: StockResponse): number { - return Number(stock.price?.regularMarketPrice?.toFixed(2)) || 0 + static getCurrentValue(stock: StockResponse, config: Config): number { + return Number(stock.price?.regularMarketPrice?.toFixed(config.numberDecimalsValues)) || 0 } static getCurrency(stock: StockResponse): string { return stock.summaryDetail?.currency || "?" } - static getDepotGrowth(config: Config, stocks: StockResponse[]): DepotGrowth[] { + static getStockName(stock: StockResponse): string { + return stock.meta.name || stock.price.longName + } + + static getDepotGrowth(stocks: StockResponse[], config: Config): DepotGrowth[] { let depotGrowth: DepotGrowth[] = [] for (const stock of stocks) { try { @@ -40,7 +44,7 @@ export default class JastUtils { } depotGrowth.forEach(growth => { - growth.value = Number(growth.value.toFixed(2)) + growth.value = Number(growth.value.toFixed(config.numberDecimalsValues)) }) return depotGrowth } diff --git a/src/models/Config.ts b/src/models/Config.ts index d5931bb..e454c6f 100644 --- a/src/models/Config.ts +++ b/src/models/Config.ts @@ -5,6 +5,8 @@ export type Config = { stocks: Stock[], scroll: "vertical" | "horizontal" | "none", maxWidth: string, + numberDecimalsValues: number, + numberDecimalsPercentages: number, showCurrency: boolean, showChangePercent: boolean, showChangeValue: boolean, @@ -13,7 +15,7 @@ export type Config = { }; type Stock = { - name: string, symbol: string, - quantity: number + name?: string, + quantity?: number } \ No newline at end of file diff --git a/templates/HorizontalStockList.njk b/templates/HorizontalStockList.njk index f4e4d45..3bdc6c5 100755 --- a/templates/HorizontalStockList.njk +++ b/templates/HorizontalStockList.njk @@ -4,28 +4,28 @@

{% for stock in stocks %} - {{ stock.meta.name }}: - {% if utils.getStockChange(stock) > 0 %} + {{ utils.getStockName(stock) }}: + {% if utils.getStockChange(stock, config) > 0 %} {% set colorClass = "high" %} - {% elif utils.getStockChange(stock) < 0 %} + {% elif utils.getStockChange(stock, config) < 0 %} {% set colorClass = "low " %} {% else %} {% set colorClass = "" %} {% endif %} - {{ utils.getCurrentValue(stock) }} + {{ utils.getCurrentValue(stock, config) }} {% if config.showCurrency %}{{ utils.getCurrency(stock) }}{% endif %} {% if colorClass and (config.showChangeValue or config.showChangePercent) %} - ({% if config.showChangeValue %}{% if colorClass == "high" %}+{%endif%}{{ utils.getStockChange(stock) }}{% if config.showChangeValueCurrency %} {{ utils.getCurrency(stock) }}{% endif %}{% endif %} - {% if config.showChangePercent %}{% if colorClass == "high" %}+{%endif%}{{ utils.getStockChangePercent(stock) }}%{% endif %}) + ({% if config.showChangeValue %}{% if colorClass == "high" %}+{%endif%}{{ utils.getStockChange(stock, config) }}{% if config.showChangeValueCurrency %} {{ utils.getCurrency(stock) }}{% endif %}{% endif %} + {% if config.showChangePercent %}{% if colorClass == "high" %}+{%endif%}{{ utils.getStockChangePercent(stock, config) }}%{% endif %}) {% endif %} {% endfor %} {% if config.showDepotGrowth %} - {% set depotGrowth = utils.getDepotGrowth(config, stocks) %} + {% set depotGrowth = utils.getDepotGrowth(stocks, config) %} {{ "depotGrowth" | translate | safe }} {% for growth in depotGrowth %} {% if growth.value > 0 %} diff --git a/templates/VerticalStockList.njk b/templates/VerticalStockList.njk index aca5fbc..926ccf3 100755 --- a/templates/VerticalStockList.njk +++ b/templates/VerticalStockList.njk @@ -12,28 +12,28 @@ {% endif %}