123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640 |
-
- var inited = false;
-
- module.exports = function(RED) {
- if (!inited) {
- inited = true;
- init(RED.server, RED.httpNode || RED.httpAdmin, RED.log, RED.settings);
- }
- return {
- add: add,
- addLink: addLink,
- addBaseConfig: addBaseConfig,
- emit: emit,
- emitSocket: emitSocket,
- toNumber: toNumber.bind(null, false),
- toFloat: toNumber.bind(null, true),
- updateUi: updateUi,
- ev: ev,
- getTheme: getTheme,
- getSizes: getSizes,
- isDark: isDark
- };
- };
-
- var fs = require('fs');
- var path = require('path');
- var events = require('events');
- var process = require('process');
- var socketio = require('socket.io');
- var serveStatic = require('serve-static');
- var compression = require('compression');
- var dashboardVersion = require('./package.json').version;
-
- var baseConfiguration = {};
- var io;
- var menu = [];
- var globals = [];
- var settings = {};
- var updateValueEventName = 'update-value';
- var currentValues = {};
- var replayMessages = {};
- var removeStateTimers = {};
- var removeStateTimeout = 1000;
- var ev = new events.EventEmitter();
- var params = {};
- ev.setMaxListeners(0);
-
- // default manifest.json to be returned as required.
- var mani = {
- "name": "Node-RED Dashboard",
- "short_name": "Dashboard",
- "description": "A dashboard for Node-RED",
- "start_url": "./#/0",
- "background_color": "#910000",
- "theme_color": "#910000",
- "display": "standalone",
- "icons": [
- {"src":"icon192x192.png", "sizes":"192x192", "type":"image/png"},
- {"src":"icon120x120.png", "sizes":"120x120", "type":"image/png"},
- {"src":"icon64x64.png", "sizes":"64x64", "type":"image/png"}
- ]
- }
-
- function toNumber(keepDecimals, config, input, old, m, s) {
- if (input === undefined || input === null) { return; }
- if (typeof input !== "number") {
- var inputString = input.toString();
- input = keepDecimals ? parseFloat(inputString) : parseInt(inputString);
- }
- if (s) { input = Math.round(Math.round(input/s)*s*10000)/10000; }
- return isNaN(input) ? config.min : input;
- }
-
- function emit(event, data) {
- io.emit(event, data);
- }
-
- function emitSocket(event, data) {
- if (data.hasOwnProperty("msg") && data.msg.hasOwnProperty("socketid") && (data.msg.socketid !== undefined)) {
- io.to(data.msg.socketid).emit(event, data);
- }
- else if (data.hasOwnProperty("socketid") && (data.socketid !== undefined)) {
- io.to(data.socketid).emit(event, data);
- }
- else {
- io.emit(event, data);
- }
- }
-
- function noConvert(value) {
- return value;
- }
-
- function beforeEmit(msg, value) {
- return { value:value };
- }
-
- function beforeSend(msg) {
- //do nothing
- }
-
- /* This is the handler for inbound msg from previous nodes...
- options:
- node - the node that represents the control on a flow
- control - the control to be added
- tab - tab config node that this control belongs to
- group - group name
- [emitOnlyNewValues] - boolean (default true).
- If true, it checks if the payload changed before sending it
- to the front-end. If the payload is the same no message is sent.
- [forwardInputMessages] - boolean (default true).
- If true, forwards input messages to the output
- [storeFrontEndInputAsState] - boolean (default true).
- If true, any message received from front-end is stored as state
- [persistantFrontEndValue] - boolean (default true).
- If true, last received message is send again when front end reconnect.
-
- [convert] - callback to convert the value before sending it to the front-end
- [beforeEmit] - callback to prepare the message that is emitted to the front-end
-
- [convertBack] - callback to convert the message from front-end before sending it to the next connected node
- [beforeSend] - callback to prepare the message that is sent to the output,
- if the returned msg has a property _dontSend, then it won't get sent.
- */
- function add(opt) {
- clearTimeout(removeStateTimers[opt.node.id]);
- delete removeStateTimers[opt.node.id];
-
- if (typeof opt.emitOnlyNewValues === 'undefined') {
- opt.emitOnlyNewValues = true;
- }
- if (typeof opt.forwardInputMessages === 'undefined') {
- opt.forwardInputMessages = true;
- }
- if (typeof opt.storeFrontEndInputAsState === 'undefined') {
- opt.storeFrontEndInputAsState = true;
- }
- if (typeof opt.persistantFrontEndValue === 'undefined') {
- opt.persistantFrontEndValue = true;
- }
- opt.convert = opt.convert || noConvert;
- opt.beforeEmit = opt.beforeEmit || beforeEmit;
- opt.convertBack = opt.convertBack || noConvert;
- opt.beforeSend = opt.beforeSend || beforeSend;
- opt.control.id = opt.node.id;
- var remove = addControl(opt.tab, opt.group, opt.control);
-
- opt.node.on("input", function(msg) {
- if (typeof msg.enabled === 'boolean') {
- var state = replayMessages[opt.node.id];
- if (!state) { replayMessages[opt.node.id] = state = {id: opt.node.id}; }
- state.disabled = !msg.enabled;
- io.emit(updateValueEventName, state); // dcj mu
- }
-
- // remove res and req as they are often circular
- if (msg.hasOwnProperty("res")) { delete msg.res; }
- if (msg.hasOwnProperty("req")) { delete msg.req; }
-
- // Retrieve the dataset for this node
- var oldValue = currentValues[opt.node.id];
-
- // let any arriving msg.ui_control message mess with control parameters
- if (msg.ui_control && (typeof msg.ui_control === "object") && (!Array.isArray(msg.ui_control)) && (!Buffer.isBuffer(msg.ui_control) )) {
- var changed = {};
- for (var property in msg.ui_control) {
- if (msg.ui_control.hasOwnProperty(property) && opt.control.hasOwnProperty(property)) {
- if ((property !== "id")&&(property !== "type")&&(property !== "order")&&(property !== "name")&&(property !== "value")&&(property !== "width")&&(property !== "height")) {
- opt.control[property] = msg.ui_control[property];
- changed[property] = msg.ui_control[property];
- }
- }
- }
- if (Object.keys(changed).length !== 0) {
- io.emit('ui-control', {control:changed, id:opt.node.id});
- }
- if (!msg.hasOwnProperty("payload")) { return; }
- }
-
- // Call the convert function in the node to get the new value
- // as well as the full dataset.
- var conversion = opt.convert(msg.payload, oldValue, msg, opt.control.step);
-
- // If the update flag is set, emit the newPoint, and store the full dataset
- var fullDataset;
- var newPoint;
- if ((typeof(conversion) === 'object') && (conversion !== null) && (conversion.update !== undefined)) {
- newPoint = conversion.newPoint;
- fullDataset = conversion.updatedValues;
- }
- else if (conversion === undefined) {
- fullDataset = oldValue;
- newPoint = true;
- }
- else {
- // If no update flag is set, this means the conversion contains
- // the full dataset or the new value (e.g. gauges)
- fullDataset = conversion;
- }
- // If we have something new to emit
- if (newPoint !== undefined || !opt.emitOnlyNewValues || oldValue != fullDataset) {
- currentValues[opt.node.id] = fullDataset;
-
- // Determine what to emit over the websocket
- // (the new point or the full dataset).
-
- // Always store the full dataset.
- var toStore = opt.beforeEmit(msg, fullDataset);
- var toEmit;
- if ((newPoint !== undefined) && (typeof newPoint !== "boolean")) { toEmit = opt.beforeEmit(msg, newPoint); }
- else { toEmit = toStore; }
-
- var addField = function(m) {
- if (opt.control.hasOwnProperty(m) && opt.control[m] && opt.control[m].indexOf("{{") !== -1) {
- var a = opt.control[m].split("{{");
- a.shift();
- for (var i = 0; i < a.length; i++) {
- var b = a[i].split("}}")[0].trim();
- b.replace(/\"/g,'').replace(/\'/g,'');
- if (b.indexOf("|") !== -1) { b = b.split("|")[0]; }
- if (b.indexOf(" ") !== -1) { b = b.split(" ")[0]; }
- if (b.indexOf("?") !== -1) { b = b.split("?")[0]; }
- b.replace(/\(/g,'').replace(/\)/g,'');
- if (b.indexOf("msg.") >= 0) {
- b = b.split("msg.")[1];
- if (b.indexOf(".") !== -1) { b = b.split(".")[0]; }
- if (b.indexOf("[") !== -1) { b = b.split("[")[0]; }
- if (!toEmit.hasOwnProperty("msg")) { toEmit.msg = {}; }
- if (!toEmit.msg.hasOwnProperty(b) && msg.hasOwnProperty(b) && (msg[b] !== undefined)) {
- if (Buffer.isBuffer(msg[b])) { toEmit.msg[b] = msg[b].toString("binary"); }
- else { toEmit.msg[b] = JSON.parse(JSON.stringify(msg[b])); }
- }
- //if (Object.keys(toEmit.msg).length === 0) { delete toEmit.msg; }
- }
- else {
- if (b.indexOf(".") !== -1) { b = b.split(".")[0]; }
- if (b.indexOf("[") !== -1) { b = b.split("[")[0]; }
- if (!toEmit.hasOwnProperty(b) && msg.hasOwnProperty(b)) {
- if (Buffer.isBuffer(msg[b])) { toEmit[b] = msg[b].toString("binary"); }
- else { toEmit[b] = JSON.parse(JSON.stringify(msg[b])); }
- }
- }
- }
- }
- }
-
- // if label, format, color, units, tooltip or icon fields are set to a msg property, emit that as well
- addField("className");
- addField("label");
- addField("format");
- addField("color");
- addField("units");
- addField("tooltip");
- addField("icon");
- if (msg.hasOwnProperty("enabled")) { toEmit.disabled = !msg.enabled; }
- if (msg.hasOwnProperty("className")) { toEmit.className = msg.className; }
- toEmit.id = toStore.id = opt.node.id;
- //toEmit.socketid = msg.socketid; // dcj mu
- // Emit and Store the data
- //if (settings.verbose) { console.log("UI-EMIT",JSON.stringify(toEmit)); }
- emitSocket(updateValueEventName, toEmit);
- if (opt.persistantFrontEndValue === true) {
- replayMessages[opt.node.id] = toStore;
- }
-
- // Handle the node output
- if (opt.forwardInputMessages && opt.node._wireCount && fullDataset !== undefined) {
- msg.payload = opt.convertBack(fullDataset);
- msg = opt.beforeSend(msg) || msg;
- //if (settings.verbose) { console.log("UI-SEND",JSON.stringify(msg)); }
- if (!msg._dontSend) { opt.node.send(msg); }
- }
- }
- });
-
- // This is the handler for messages coming back from the UI
- var handler = function (msg) {
- if (msg.id !== opt.node.id) { return; } // ignore if not us
- if (settings.readOnly === true) { return; } // don't accept input if we are in read only mode
- var converted = opt.convertBack(msg.value);
- if (opt.storeFrontEndInputAsState === true) {
- currentValues[msg.id] = converted;
- if (opt.persistantFrontEndValue === true) {
- replayMessages[msg.id] = msg;
- }
- }
- var toSend = {payload:converted};
- toSend = opt.beforeSend(toSend, msg) || toSend;
-
- if (toSend !== undefined) {
- toSend.socketid = toSend.socketid || msg.socketid;
- if (msg.hasOwnProperty("meta")) { toSend.meta = msg.meta; }
- if (toSend.hasOwnProperty("topic") && (toSend.topic === undefined)) { delete toSend.topic; }
- // send to following nodes
- if (!msg.hasOwnProperty("_dontSend")) { opt.node.send(toSend); }
- }
-
- if (opt.storeFrontEndInputAsState === true) {
- //fwd to all UI clients
- io.emit(updateValueEventName, msg);
- }
- };
-
- ev.on(updateValueEventName, handler);
-
- return function() {
- ev.removeListener(updateValueEventName, handler);
- remove();
- removeStateTimers[opt.node.id] = setTimeout(function() {
- delete currentValues[opt.node.id];
- delete replayMessages[opt.node.id];
- }, removeStateTimeout);
- };
- }
-
- //from: https://stackoverflow.com/a/28592528/3016654
- function join() {
- var trimRegex = new RegExp('^\\/|\\/$','g');
- var paths = Array.prototype.slice.call(arguments);
- return '/'+paths.map(function(e) {
- if (e) { return e.replace(trimRegex,""); }
- }).filter(function(e) {return e;}).join('/');
- }
-
- function init(server, app, log, redSettings) {
- var uiSettings = redSettings.ui || {};
- if ((uiSettings.hasOwnProperty("path")) && (typeof uiSettings.path === "string")) {
- settings.path = uiSettings.path;
- }
- else { settings.path = 'ui'; }
- if ((uiSettings.hasOwnProperty("readOnly")) && (typeof uiSettings.readOnly === "boolean")) {
- settings.readOnly = uiSettings.readOnly;
- }
- else { settings.readOnly = false; }
- settings.defaultGroupHeader = uiSettings.defaultGroup || 'Default';
- settings.verbose = redSettings.verbose || false;
-
- var fullPath = join(redSettings.httpNodeRoot, settings.path);
- var socketIoPath = join(fullPath, 'socket.io');
-
- io = socketio(server, {path: socketIoPath});
-
- var dashboardMiddleware = function(req, res, next) { next(); }
-
- if (uiSettings.middleware) {
- if (typeof uiSettings.middleware === "function" || Array.isArray(uiSettings.middleware)) {
- dashboardMiddleware = uiSettings.middleware;
- }
- }
-
- fs.stat(path.join(__dirname, 'dist/index.html'), function(err, stat) {
- app.use(compression());
- if (!err) {
- app.use( join(settings.path, "manifest.json"), function(req, res) { res.send(mani); });
- app.use( join(settings.path), dashboardMiddleware, serveStatic(path.join(__dirname, "dist")) );
- }
- else {
- log.info("[Dashboard] Dashboard using development folder");
- app.use(join(settings.path), dashboardMiddleware, serveStatic(path.join(__dirname, "src")));
- var vendor_packages = [
- 'angular', 'angular-sanitize', 'angular-animate', 'angular-aria', 'angular-material', 'angular-touch',
- 'angular-material-icons', 'svg-morpheus', 'font-awesome', 'weather-icons-lite',
- 'sprintf-js', 'jquery', 'jquery-ui', 'd3', 'raphael', 'justgage', 'angular-chart.js', 'chart.js',
- 'moment', 'angularjs-color-picker', 'tinycolor2', 'less'
- ];
- vendor_packages.forEach(function (packageName) {
- app.use(join(settings.path, 'vendor', packageName), serveStatic(path.join(__dirname, 'node_modules', packageName)));
- });
- }
- });
-
- if ( process.versions.node.split('.')[0] < 12 ) {
- log.error("Dashboard version "+dashboardVersion+" requires Nodejs 12 or more recent");
- }
- else {
- log.info("Dashboard version " + dashboardVersion + " started at " + fullPath);
- }
-
- if (typeof uiSettings.ioMiddleware === "function") {
- io.use(uiSettings.ioMiddleware);
- } else if (Array.isArray(uiSettings.ioMiddleware)) {
- uiSettings.ioMiddleware.forEach(function (ioMiddleware) {
- io.use(ioMiddleware);
- });
- } else {
- io.use(function (socket, next) {
- if (socket.client.conn.request.url.indexOf("transport=websocket") !== -1) {
- // Reject direct websocket requests
- socket.client.conn.close();
- return;
- }
- if (socket.handshake.xdomain === false) {
- return next();
- } else {
- socket.disconnect(true);
- }
- });
- }
-
- io.on('connection', function(socket) {
- ev.emit("newsocket", socket.id, socket.request.headers['x-real-ip'] || socket.request.headers['x-forwarded-for'] || socket.request.connection.remoteAddress);
- updateUi(socket);
-
- socket.on(updateValueEventName, ev.emit.bind(ev, updateValueEventName));
- socket.on('ui-replay-state', function() {
- var ids = Object.getOwnPropertyNames(replayMessages);
- setTimeout(function() {
- ids.forEach(function (id) {
- socket.emit(updateValueEventName, replayMessages[id]);
- });
- }, 50);
- socket.emit('ui-replay-done');
- });
- socket.on('ui-change', function(index) {
- var name = "";
- if ((index != null) && !isNaN(index) && (menu.length > 0) && (index < menu.length) && menu[index]) {
- name = (menu[index].hasOwnProperty("header") && typeof menu[index].header !== 'undefined') ? menu[index].header : menu[index].name;
- ev.emit("changetab", index, name, socket.id, socket.request.headers['x-real-ip'] || socket.request.headers['x-forwarded-for'] || socket.request.connection.remoteAddress, params);
- }
- });
- socket.on('ui-collapse', function(d) {
- ev.emit("collapse", d.group, d.state, socket.id, socket.request.headers['x-real-ip'] || socket.request.headers['x-forwarded-for'] || socket.request.connection.remoteAddress);
- });
- socket.on('ui-refresh', function() {
- updateUi();
- });
- socket.on('disconnect', function() {
- ev.emit("endsocket", socket.id, socket.request.headers['x-real-ip'] || socket.request.headers['x-forwarded-for'] || socket.request.connection.remoteAddress);
- });
- socket.on('ui-audio', function(audioStatus) {
- ev.emit("audiostatus", audioStatus, socket.id, socket.request.headers['x-real-ip'] || socket.request.headers['x-forwarded-for'] || socket.request.connection.remoteAddress);
- });
- socket.on('ui-params', function(p) {
- delete p.socketid;
- params = p;
- });
- });
- }
-
- var updateUiPending = false;
- function updateUi(to) {
- if (!to) {
- if (updateUiPending) { return; }
- updateUiPending = true;
- to = io;
- }
- process.nextTick(function() {
- menu.forEach(function(o) {
- o.theme = baseConfiguration.theme;
- });
- to.emit('ui-controls', {
- site: baseConfiguration.site,
- theme: baseConfiguration.theme,
- menu: menu,
- globals: globals
- });
- updateUiPending = false;
- });
- }
-
- function find(array, predicate) {
- for (var i=0; i<array.length; i++) {
- if (predicate(array[i])) {
- return array[i];
- }
- }
- }
-
- function itemSorter(item1, item2) {
- if (item1.order === 0 && item2.order !== 0) {
- return 1;
- }
- else if (item1.order !== 0 && item2.order === 0) {
- return -1;
- }
- return item1.order - item2.order;
- }
-
- function addControl(tab, groupHeader, control) {
- if (typeof control.type !== 'string') { return function() {}; }
-
- // global template?
- if (control.type === 'template' && control.templateScope === 'global') {
- // add content to globals
- globals.push(control);
- updateUi();
-
- // return remove function
- return function() {
- var index = globals.indexOf(control);
- if (index >= 0) {
- globals.splice(index, 1);
- updateUi();
- }
- }
- }
- else {
- groupHeader = groupHeader || settings.defaultGroupHeader;
- control.order = parseFloat(control.order);
-
- var foundTab = find(menu, function (t) {
- if (tab && tab.hasOwnProperty("id")) { return t.id === tab.id }
- });
- if (!foundTab) {
- if (tab === null) { return; }
- foundTab = {
- id: tab.id,
- header: tab.config.name,
- order: parseFloat(tab.config.order),
- icon: tab.config.icon,
- //icon: tab.config.hidden ? "fa-ban" : tab.config.icon,
- disabled: tab.config.disabled,
- hidden: tab.config.hidden,
- items: []
- };
- menu.push(foundTab);
- menu.sort(itemSorter);
- }
-
- var foundGroup = find(foundTab.items, function (g) {return g.header === groupHeader;});
- if (!foundGroup) {
- foundGroup = {
- header: groupHeader,
- items: []
- };
- foundTab.items.push(foundGroup);
- }
- foundGroup.items.push(control);
- foundGroup.items.sort(itemSorter);
- foundGroup.order = groupHeader.config.order;
- foundTab.items.sort(itemSorter);
-
- updateUi();
-
- // Return the remove function for this control
- return function() {
- var index = foundGroup.items.indexOf(control);
- if (index >= 0) {
- // Remove the item from the group
- foundGroup.items.splice(index, 1);
-
- // If the group is now empty, remove it from the tab
- if (foundGroup.items.length === 0) {
- index = foundTab.items.indexOf(foundGroup);
- if (index >= 0) {
- foundTab.items.splice(index, 1);
-
- // If the tab is now empty, remove it as well
- if (foundTab.items.length === 0) {
- index = menu.indexOf(foundTab);
- if (index >= 0) {
- menu.splice(index, 1);
- }
- }
- }
- }
- updateUi();
- }
- }
- }
- }
-
- function addLink(name, link, icon, order, target, className) {
- var newLink = {
- name: name,
- link: link,
- icon: icon,
- order: order || 1,
- target: target,
- className: className
- };
-
- menu.push(newLink);
- menu.sort(itemSorter);
- updateUi();
-
- return function() {
- var index = menu.indexOf(newLink);
- if (index < 0) { return; }
- menu.splice(index, 1);
- updateUi();
- }
- }
-
- function addBaseConfig(config) {
- if (config) { baseConfiguration = config; }
- mani.name = config.site ? config.site.name : "Node-RED Dashboard";
- mani.short_name = mani.name.replace("Node-RED","").trim();
- mani.background_color = config.theme.themeState["page-titlebar-backgroundColor"].value;
- mani.theme_color = config.theme.themeState["page-titlebar-backgroundColor"].value;
- updateUi();
- }
-
- function angularColorToHex(color) {
- var angColorValues = { red: "#F44336", pink: "#E91E63", purple: "#9C27B0", deeppurple: "#673AB7",
- indigo: "#3F51B5", blue: "#2196F3", lightblue: "#03A9F4", cyan: "#00BCD4", teal: "#009688",
- green: "#4CAF50", lightgreen: "#8BC34A", lime: "#CDDC39", yellow: "#FFEB3B", amber: "#FFC107",
- orange: "#FF9800", deeporange: "#FF5722", brown: "#795548", grey: "#9E9E9E", bluegrey: "#607D8B"};
- return angColorValues[color.replace("-","").toLowerCase()];
- }
-
- function getTheme() {
- if (baseConfiguration && baseConfiguration.site && baseConfiguration.site.allowTempTheme && baseConfiguration.site.allowTempTheme === "none") {
- baseConfiguration.theme.name = "theme-custom";
- baseConfiguration.theme.themeState["widget-backgroundColor"].value = angularColorToHex(baseConfiguration.theme.angularTheme.primary);
- baseConfiguration.theme.themeState["widget-textColor"].value = (baseConfiguration.theme.angularTheme.palette === "dark") ? "#fff" : "#000";
- return baseConfiguration.theme.themeState;
- }
- else if (baseConfiguration && baseConfiguration.hasOwnProperty("theme") && (typeof baseConfiguration.theme !== "undefined") ) {
- return baseConfiguration.theme.themeState;
- }
- else {
- return undefined;
- }
- }
-
- function getSizes() {
- if (baseConfiguration && baseConfiguration.hasOwnProperty("site") && (typeof baseConfiguration.site !== "undefined") && baseConfiguration.site.hasOwnProperty("sizes")) {
- return baseConfiguration.site.sizes;
- }
- else {
- return { sx:48, sy:48, gx:6, gy:6, cx:6, cy:6, px:0, py:0 };
- }
- }
-
- function isDark() {
- if (baseConfiguration && baseConfiguration.site && baseConfiguration.site.allowTempTheme && baseConfiguration.site.allowTempTheme === "none") {
- if (baseConfiguration && baseConfiguration.hasOwnProperty("theme") && baseConfiguration.theme.hasOwnProperty("angularTheme")) {
- if (baseConfiguration.theme.angularTheme && baseConfiguration.theme.angularTheme.palette && baseConfiguration.theme.angularTheme.palette === "dark") { return true;}
- }
- return false;
- }
- else if (baseConfiguration && baseConfiguration.hasOwnProperty("theme") && baseConfiguration.theme.hasOwnProperty("themeState")) {
- var rgb = parseInt(baseConfiguration.theme.themeState["page-backgroundColor"].value.substring(1), 16);
- var luma = 0.2126 * ((rgb >> 16) & 0xff) + 0.7152 * ((rgb >> 8) & 0xff) + 0.0722 * ((rgb >> 0) & 0xff); // per ITU-R BT.709
- if (luma > 128) { return false; }
- else { return true; }
- }
- else { return false; } // if in doubt - let's say it's light.
- }
|