UNPKG

iobroker.alias-manager

Version:
1,290 lines (1,210 loc) 97.6 kB
//Alias-Manager - Copyright (c) by Sebatian Bormann //Please visit https://github.com/sbormann/ioBroker.adapter-manager for licence-agreement and further information //Settings var defaultDatapointRoles = { string: [ "state", "adapter.messagebox", "adapter.wakeup", "date", "date.end", "date.start", "html", "info.address", "info.display", "info.ip", "info.mac", "info.name", "info.port", "info.standby", "info.status", "json", "text", "text.url", "text.phone", "url", "url.audio", "url.blank", "url.cam", "url.icon", "url.same", "[media]", "media.add", "media.album", "media.artist", "media.bitrate", "media.broadcastDate", "media.clear", "media.content", "media.cover", "media.cover.big", "media.cover.small", "media.date", "media.duration.text", "media.elapsed.text", "media.episode", "media.grenre", "media.input", "media.playid", "media.playlist", "media.season", "media.title", "media.title.next", "media.track", "media.tts", "media.url", "media.url.announcement", "media.browser", "[weather]", "location", "weather.chart.url", "weather.chart.url.forecast", "weather.direction.wind", "weather.direction.wind.forecast.0", "weather.html", "weather.icon", "weather.icon.forecast.1", "weather.icon.name", "weather.icon.wind", "weather.json", "weather.state", "weather.state.forecast.0", "weather.state.forecast.1", "weather.tile", "weather.tile.forecast.0", "weather.tile.short", "weather.type" ], number: [ "state", "date", "[level - to set a number value]", "level", "level.blind", "level.co2", "level.color.blue", "level.color.green", "level.color.hue", "level.color.luminance", "level.color.red", "level.color.rgb", "level.color.saturation", "level.color.temperature", "level.color.white", "level.curtain", "level.dimmer", "level.temperature", "level.tilt", "level.timer", "level.timer.sleep", "level.valve", "level.volume", "level.volume.group", "[value - readonly]", "value", "value.battery", "value.blind", "value.brightness", "value.current", "value.curtain", "value.default", "value.direction", "value.distance", "value.distance.visibility", "value.gps", "value.gps.elevation", "value.gps.latitude", "value.gps.longitude", "value.humidity", "value.interval", "value.lock", "value.max", "value.min", "value.power.consumption", "value.pressure", "value.severity", "value.speed", "value.sun.azimuth", "value.sun.elevation", "value.temperature", "value.tilt", "value.time", "value.valve", "value.voltage", "value.waring", "value.window", "[media]", "level.bass", "level.trebble", "media.duration", "media.elapsed", "media.input", "media.jump", "media.mode.shuffle", "media.playid", "media.seek", "media.state", "[weather]", "date.forecast.1", "date.sunrise", "date.sunset", "dayofweek", "value.clouds", "value.direction.max.wind", "value.direction.min.wind", "value.direction.wind", "value.direction.wind.forecast.0", "value.direction.wind.forecast.1", "value.humidity", "value.humidity.max", "value.humidity.min", "value.precipitation", "value.precipitation.day.forecast.0", "value.precipitation.forecast.0", "value.precipitation.forecast.1", "value.precipitation.hour", "value.precipitation.night.forecast.0", "value.precipitation.today", "value.pressure", "value.pressure.forecast.0", "value.pressure.forecast.1", "value.radiation", "value.rain", "value.rain.hour", "value.rain.today", "value.snow", "value.snow.hour", "value.snow.today", "value.snowline", "value.speed.max.wind", "value.speed.min.wind", "value.speed.wind", "value.speed.wind.forecast.0", "value.speed.wind.forecast.1", "value.temperature", "value.temperature.dewpoint", "value.temperature.feelslike", "value.temperature.max", "value.temperature.max.forecast.0", "value.temperature.max.forecast.1", "value.temperature.min", "value.temperature.min.forecast.0", "value.temperature.min.forecast.1", "value.temperature.windchill", "value.uv" ], boolean: [ "state", "[button]", "button", "button.long", "button.mode", "button.mode.auto", "button.mode.manual", "button.mode.silent", "button.open.door", "button.open.window", "button.start", "button.stop", "[indicator - belongs to a main datapoint]", "indicator", "indicator.alarm", "indicator.alarm.fire", "indicator.alarm.flood", "indicator.alarm.secure", "indicator.connected", "indicator.error", "indicator.lowbat", "indicator.maintenance", "indicator.maintenance.alarm", "indicator.maintenance.lowbat", "indicator.maintenance.unreach", "indicator.reachable", "indicator.working", "[sensor - is a main datapoint]", "sensor.alarm", "sensor.alarm.fire", "sensor.alarm.flood", "sensor.alarm.power", "sensor.alarm.secure", "sensor.door", "sensor.light", "sensor.lock", "sensor.motion", "sensor.noise", "sensor.rain", "sensor.window", "[switch]", "switch", "switch.boost", "switch.comfort", "switch.enable", "switch.light", "switch.lock", "switch.lock.door", "switch.lock.window", "switch.mode", "switch.mode.auto", "switch.mode.color", "switch.mode.manual", "switch.mode.moonlight", "switch.mode.silent", "switch.power", "[media]", "button.fastforward", "button.fastreverse", "button.forward", "button.next", "button.pause", "button.play", "button.prev", "button.reverse", "button.stop", "button.volume.down", "button.volume.up", "media.mode.repeat", "media.mute", "media.mute.group", "switch.pause", "switch.power.zone" ], array: [ "list" ] } var defaultMainRoles = [ "unknown", "airCondition", "blind", "button", "buttonSensor", "camera", "ct", "dimmer", "door", "fireAlarm", "floodAlarm", "gate", "hue", "humidity", "image", "info", "instance", "light", "location", "lock", "media", "motion", "rgb", "rgbSingle", "slider", "socket", "temperature", "thermostat", "url", "vacuumCleaner", "valve", "volume", "volumeGroup", "warning", "weatherCurrent", "weatherForecast", "window", "windowTilt" ] //Declarations const udef = 'undefined'; var iobrokerObjects = {}; var iobrokerObjectsReady = false; var iobrokerObjectsReadyFunctions = []; var modalZIndexCount = 2000; var isReact = false; //++++++++++ GLOBAL FUNCTIONS ++++++++++ function initDialog(id, callback) { var $dialog = $('#' + id); if (!$dialog.data('inited')) { $dialog.data('inited', true); $dialog.modal({ dismissible: false }); $dialog.find('.btn-set').on('click', function () { var $dialog = $('#' + $(this).data('dialogid')); var callback = $dialog.data('callback'); if (typeof callback === 'function') callback(); $dialog.data('callback', null); }); } $dialog.find('.btn-set').data('dialogid', id); $dialog.data('callback', callback); } var selectId; var selectIdImgPath = '../../lib/css/fancytree/'; function initSelectId(callback) { setTimeout(function(){ $('#dialogSelectId').css('z-index', modalZIndexCount++); }, 100); if (selectId) { return callback(selectId); } var options = { noMultiselect: true, imgPath: selectIdImgPath, filter: {type: 'state'}, name: 'scenes-select-state', texts: { select: _('Select'), cancel: _('Cancel'), all: _('All'), id: _('ID'), name: _('Name'), role: _('Role'), room: _('Room'), value: _('Value'), selectid: _('Select ID'), from: _('From'), lc: _('Last changed'), ts: _('Time stamp'), wait: _('Processing...'), ack: _('Acknowledged'), selectAll: _('Select all'), unselectAll: _('Deselect all'), invertSelection: _('Invert selection') }, columns: ['image', 'name', 'role', 'room'] }; var toDo = function(){ options.objects = iobrokerObjects; selectId = $('#dialogSelectId').selectId('init', options); callback(selectId); } if (iobrokerObjectsReady) { toDo(); } else { iobrokerObjectsReadyFunctions.push(toDo); } } function tryParseJSON(jsonString){ //Returns parsed object or false, if jsonString is not valid try { var o = JSON.parse(jsonString); // Handle non-exception-throwing cases: // Neither JSON.parse(false) or JSON.parse(1234) throw errors, hence the type-checking, // but... JSON.parse(null) returns null, and typeof null === "object", // so we must check for that, too. Thankfully, null is falsey, so this suffices: if (o && typeof o === "object") { return o; } } catch (e) { } return false; }; function removeDuplicates(array) { //Removes duplicates from an array var seen = []; return array.filter(function(item) { if(seen.indexOf(JSON.stringify(item)) > -1){ return false; } else { seen.push(JSON.stringify(item)); return true; } }); } function addCustomCSS(customCSS, customID){ customID = customID || "default"; $('head').append('<style class="customCSS_' + customID + '">' + customCSS + '</style>'); } function removeCustomCSS(customID){ customID = customID || "default"; $('.customCSS_' + customID).remove(); } function multiReplace(string, replacementObj){ //Replaces multiple replacements in string. replacementObj = [{searchValue: "", newValue: ""}, ...] replacementObj.forEach(function(replacement){ var regex = new RegExp(replacement.searchValue, "g"); string = string.replace(regex, replacement.newValue); }); return string; } //Combobox var $enhanceTextInputToComboboxActualTarget; function enhanceTextInputToCombobox(targetInput, options, iconsFromOption, onSelect){ //targetInput - string - selector for text-input-field to enhance //options - string - "value1/caption1/icon1;value2/caption2/icon2;[optgroup-caption];value3/caption3/icon3;..." //iconsFromOption - boolean - if true, the values will be used to generate links to icons (\ will be replaced by / an link will be preceded), if no icon is given in options //onSelect - function - function that will be called with the argument (value), if a value is selected $(targetInput).one('blur', function(){ var that = this; setTimeout(function(){var _that = that; _that.scrollLeft = 100000;}, 10); }); $(targetInput).trigger('blur'); var lastTargetInput; $(targetInput).each(function(){ if(!$(this).parent('div').hasClass('combobox')){ $(this).add('label').wrap("<div class='combobox'></div>"); $(this).after("<a class='comboboxDropdownTrigger waves-effect waves-teal btn-small btn-flat' data-target='dropdown_" + encodeURIComponent(targetInput) + "' href='#' onclick='console.log(\"Combobox dropdown clicked\"); $enhanceTextInputToComboboxActualTarget = $(this).prevAll(\"input\"); enhanceTextInputToComboboxScrollDropdownTo($(this).data(\"target\"), $(this).prevAll(\"input\").val());'><i class='material-icons comboboxDropdownTriggerArrow' style='font-size: 25px;'>arrow_drop_down</i></a>"); } $(this).data('combobox-onselect', onSelect); lastTargetInput = this; }); options = options || $(lastTargetInput).data('options') || ""; options = options.split(";"); $("ul[id='dropdown_" + encodeURIComponent(targetInput) + "']").remove(); //If there was an old dropdownlist remove it var comboboxContent = "<ul id='dropdown_" + encodeURIComponent(targetInput) + "' class='dropdown-content'>"; options.forEach(function(option){ if (option.substring(0,1) == "[" && option.substr(-1) == "]"){ //Optgroup var caption = _(option.substring(1, option.length - 1)); comboboxContent += " <li class='divider' style='padding: 14px 4px 30px 4px; color:grey;' tabindex='-1'>"; comboboxContent += " " + caption + "&nbsp;"; comboboxContent += " </li>"; } else { //Normal option var optionParts = option.split("/"); var value = encodeURIComponent(optionParts[0]); var caption = ""; if (optionParts.length > 1){ caption = optionParts[1]; } else { caption = optionParts[0]; } var icon = ""; if (optionParts.length > 2){ icon = optionParts[2]; } else if (iconsFromOption){ icon = option.split("/")[0].replace(/\\/g, "/").substring(1) || ""; if (icon != "") icon = link + icon; } comboboxContent += " <li data-value='" + value + "'>"; comboboxContent += " <a href='#!'>"; if (icon != ""){ comboboxContent += " <img src='" + icon + "' style='display: block; margin-bottom: 5px; min-width: 40px; max-width: 40px; max-height: 40px; width: auto; height: auto;'>"; } comboboxContent += " " + caption + "&nbsp;"; comboboxContent += " </a>"; comboboxContent += " </li>"; } }); comboboxContent += "</ul>"; $(lastTargetInput).after(comboboxContent); $('.comboboxDropdownTrigger').dropdown({alignment: 'right', constrainWidth: false, onItemClick: function(event){ enhanceTextInputToComboboxEntryToInput($(event).data('value')); }}); } function enhanceTextInputToComboboxScrollDropdownTo(dropdownlist, value){ var $dropdownlist = $("ul[id='" + dropdownlist + "']"); setTimeout(function(){ var _$dropdownlist = $dropdownlist; _$dropdownlist.scrollTop(0); }, 15); setTimeout(function(){ var _dropdownlist = dropdownlist; var _$dropdownlist = $dropdownlist; $("ul[id='" + _dropdownlist + "'] li").each(function(){ $(this).removeClass('grey lighten-3'); if ($(this).data('value') == encodeURIComponent((value || "").replace(/\//g, "\\"))){ $(this).addClass('grey lighten-3'); _$dropdownlist.scrollTop(_$dropdownlist.scrollTop() + $(this).position().top); } }); }, 300); } function enhanceTextInputToComboboxEntryToInput(value){ var onSelect = $enhanceTextInputToComboboxActualTarget.data('combobox-onselect'); if(decodeURIComponent(value).substring(0, 10) == "[VARIABLE]"){ var variable = ""; if(decodeURIComponent(decodeURIComponent(value)).indexOf("{}") > -1) { variable = prompt(_("Please enter datapoint id") + ":"); if (variable == "") variable = null; } if(variable !== null){ value = decodeURIComponent(decodeURIComponent(value).replace("[VARIABLE]", "")).replace("{}", "{" + variable + "}"); $enhanceTextInputToComboboxActualTarget.val(value).trigger('change').trigger('blur'); if(onSelect) onSelect(value); } } else { value = decodeURIComponent(value).replace(/\\/g, "/"); $enhanceTextInputToComboboxActualTarget.val(value).trigger('change').trigger('blur'); if(onSelect) onSelect(value); } } //Objects function getCommonName(object){ var name = false; if(object && typeof object.common != udef && typeof object.common.name != udef){ if(typeof object.common.name == "object" && typeof object.common.name[systemLang] != udef){ name = object.common.name[systemLang]; } else if(typeof object.common.name == "object" && typeof object.common.name["en"] != udef){ name = object.common.name["en"]; } else if (typeof object.common.name == "string") { name = object.common.name; } } return name; } //Aliases var aliases = {}; function loadAliases(callback){ console.log("Loading aliases..."); getAliases('', function(error, result){ if(!error && result){ aliases = result; console.log("Aliases ready."); } else { if(error) console.log("Error getting aliases: " + error); else console.log("There are no Aliases"); $('#aliasesSelectedAliasProgress').hide(); } if(callback) callback(); }); } function getAliases(aliasName, callback) { aliasName = aliasName ? aliasName + '.' : ''; var result = {}; socket.emit('getObjectView', 'system', 'device', {startkey: 'alias' + aliasName, endkey: 'alias' + aliasName + '.\u9999'}, function (err, res) { if (!err && res) { for (var i = 0; i < res.rows.length; i++) { if (res.rows[i].id !== 'alias.' + aliasName) { result[res.rows[i].id] = res.rows[i].value; } } socket.emit('getObjectView', 'system', 'channel', {startkey: 'alias' + aliasName, endkey: 'alias' + aliasName + '.\u9999'}, function (err, res) { if (!err && res) { for (var i = 0; i < res.rows.length; i++) { if (res.rows[i].id !== 'alias.' + aliasName) { result[res.rows[i].id] = res.rows[i].value; } } socket.emit('getObjectView', 'system', 'state', {startkey: 'alias' + aliasName, endkey: 'alias' + aliasName + '.\u9999'}, function (err, res) { if (!err && res) { for (var i = 0; i < res.rows.length; i++) { if (res.rows[i].id !== 'alias.' + aliasName) { result[res.rows[i].id] = res.rows[i].value; } } //Augment with missing main-datapoints for(key in result){ if(key.split('.').length > 3 && typeof result[key.substr(0, key.lastIndexOf('.'))] == udef){ result[key.substr(0, key.lastIndexOf('.'))] = { type: "channel", common: { name: "", role: "" }, _id: key }; } } callback && callback(null, result); } else { callback && callback(err, {}); } }); } else { callback && callback(err, {}); } }); } else { callback && callback(err, {}); } }); } function getAliasName(alias){ var name = alias; if(aliases[alias] && typeof aliases[alias].common != udef && typeof aliases[alias].common.name != udef){ if(typeof aliases[alias].common.name == "object" && typeof aliases[alias].common.name[systemLang] != udef){ name = aliases[alias].common.name[systemLang]; } else if(typeof aliases[alias].common.name == "object" && typeof aliases[alias].common.name["en"] != udef){ name = aliases[alias].common.name["en"]; } else if (typeof aliases[alias].common.name == "string") { name = aliases[alias].common.name; } } return name; } function getAliasesMain(){ var aliasesMain = []; Object.keys(aliases).forEach(function(alias){ aliasesMain.push(alias); var parentAlias = alias.substring(0, alias.lastIndexOf('.')); if(parentAlias != "Alias" && parseInt(parentAlias.substr(6)).toString() != parentAlias.substr(6)) aliasesMain.push(parentAlias); }); aliasesMain = removeDuplicates(aliasesMain); aliasesMain = aliasesMain.filter(function(element){ //Filter for main Aliases (that are elements, that have sub-aliases OR that are direct childs of alias.0. [which means, lastIndexOf(".") == 7]) if(element.lastIndexOf(".") == 7 || aliasesMain.filter(function(_element){ return (_element.indexOf(element + ".") == 0); }).length > 0) return true; else return false; }); aliasesMain.sort(); return aliasesMain; } //History-Instances var historyInstances = []; function getHistoryInstances(callback){ (function(){ //Closure--> (everything declared inside keeps its value as ist is at the time the function is created) var _callback = callback; var _toDo = function(){ historyInstances = []; for(id in iobrokerObjects){ if(id.indexOf('system.adapter.') == 0 && !isNaN(id.substr(id.lastIndexOf('.') + 1)) && iobrokerObjects[id] && iobrokerObjects[id].common && iobrokerObjects[id].common.type === 'storage'){ historyInstances.push(id.substring('system.adapter.'.length)); } } _callback && _callback(historyInstances); } if(iobrokerObjectsReady) { _toDo(); } else { iobrokerObjectsReadyFunctions.push(_toDo); } })(); //<--End Closure } //Enumerations var enumerations = {}; function getEnumerations(callback) { (function(){ //Closure--> (everything declared inside keeps its value as ist is at the time the function is created) var _callback = callback; var _toDo = function(){ enumerations = {}; for(id in iobrokerObjects){ if(id.indexOf("enum") == 0) { enumerations[id] = iobrokerObjects[id]; } } _callback && _callback(enumerations); } if(iobrokerObjectsReady) { _toDo(); } else { iobrokerObjectsReadyFunctions.push(_toDo); } })(); //<--End Closure } function getEnumerationName(enumeration){ var name = _(enumeration); if(enumerations[enumeration] && typeof enumerations[enumeration].common != udef && typeof enumerations[enumeration].common.name != udef){ if(typeof enumerations[enumeration].common.name == "object" && typeof enumerations[enumeration].common.name[systemLang] != udef){ name = enumerations[enumeration].common.name[systemLang]; } else if(typeof enumerations[enumeration].common.name == "object" && typeof enumerations[enumeration].common.name["en"] != udef){ name = _(enumerations[enumeration].common.name["en"]); } else if (typeof enumerations[enumeration].common.name == "string") { name = _(enumerations[enumeration].common.name); } } return name; } function getEnumerationsMain(){ var enumerationsMain = []; if(enumerations){ enumerationsMain = Object.keys(enumerations); enumerationsMain = enumerationsMain.filter(function(element){ //Filter for main Enumerations (that are elements, that have sub-enumerations) if(enumerationsMain.filter(function(_element){ return (_element.indexOf(element + ".") == 0); }).length > 0) return true; else return false; }); $('#dialogViewsAutocreateEnumerationMain').empty().append("<option disabled selected value>" + _("Select Enumeration") + "</option>"); enumerationsMain.forEach(function(enumeration, index){ var name = getEnumerationName(enumeration); $('#dialogViewsAutocreateEnumerationMain').append("<option value='" + enumeration + "'>" + name + "</option>"); }); $('#dialogViewsAutocreateEnumerationMain').select(); $('#viewsAutocreateButton').removeClass('disabled'); $('#viewsAutocreateButtonProgress').hide(); console.log("Enumerations ready."); } else { if(error) console.log("Error getting enumerations: " + error); else console.log("There are no Enumerations"); $('#viewsAutocreateButtonProgress').hide(); } return enumerationsMain; } //Helpers function getDatapointConfiguration(id){ if (id && iobrokerObjects[id]) { var r = {}; r.id = id.substr(id.lastIndexOf('.') + 1) || "SET"; r.name = iobrokerObjects[id].common && iobrokerObjects[id].common.name || id; if(typeof r.name == "object") r.name = r.name[systemLang] || r.name["de"] || r.name["en"] || Object.keys(r.name)[0] || ""; r.role = iobrokerObjects[id].common && iobrokerObjects[id].common.role || "value"; r.type = iobrokerObjects[id].common && iobrokerObjects[id].common.type || "string"; r.unit = iobrokerObjects[id].common && iobrokerObjects[id].common.unit || ""; r.min = (iobrokerObjects[id].common && typeof iobrokerObjects[id].common.min != udef ? iobrokerObjects[id].common.min : ""); r.max = (iobrokerObjects[id].common && typeof iobrokerObjects[id].common.max != udef ? iobrokerObjects[id].common.max : ""); r.read = (iobrokerObjects[id].common && typeof iobrokerObjects[id].common.read != udef ? iobrokerObjects[id].common.read : true); r.write = (iobrokerObjects[id].common && typeof iobrokerObjects[id].common.write != udef ? iobrokerObjects[id].common.write : true); r.aliasId = id; r.aliasRead = ""; r.aliasWrite = ""; r.states = (iobrokerObjects[id].common && typeof iobrokerObjects[id].common.states != udef ? iobrokerObjects[id].common.states : null); r.custom = (iobrokerObjects[id].common && typeof iobrokerObjects[id].common.custom != udef ? iobrokerObjects[id].common.custom : null); return r; } else { return false; } } function getNewId(aliasPath, id, askForId, excludeList){ id = id || "SET"; excludeList = excludeList || []; if(aliases[aliasPath + "." + id] || excludeList.indexOf(id) > -1){ var count = 2; while(aliases[aliasPath + "." + id + "_" + count] || excludeList.indexOf(id + "_" + count) > -1){ count++; } id = id + "_" + count; } if(askForId){ id = prompt(_("Please enter ID of datapoint"), id || "SET"); if(!id) return false; while(aliases[aliasPath + "." + id] || excludeList[id]){ alert("Error: This datapoint exists."); id = prompt(_("Please enter ID of datapoint"), id || "SET"); if(!id) return false; } } return id; } /************** LOAD ******************************************************** *** This will be called by the admin adapter when the settings page loads *** ****************************************************************************/ function load(settings, onChange) { //Loading begins var loading = true; //Hide Settings console.log("Loading Alias-Manager Settings"); $('.hideOnLoad').hide(); $('.showOnLoad').show(); //If react, make some css adjustments isReact = (window.parent.adapterName === 'admin'); if(isReact){ var customCSS = ""; customCSS += ".table-values tr:nth-child(2n) { background-color: rgba(0,0,0,0.04) !important; }"; customCSS += ".table-values.highlight > tbody > tr:hover { background-color: rgba(0,0,0,0.08) !important; }"; customCSS += ".table-values.highlight > tbody > tr:nth-child(2n):hover { background-color: rgba(0,0,0,0.08) !important; }"; customCSS += ".table-values th { background-color: rgba(0,0,0,0.1) !important; color: #1d1d1d !important; }"; customCSS += ".title { background-color: #164477; }"; customCSS += ".m .tabs .tab a { color: rgba(0, 0, 0, 0.5); }"; customCSS += ".m .tabs .tab a:hover { color: rgba(0, 0, 0, 0.86); }"; customCSS += ".m .tabs .tab a.active { color: #164477; }"; customCSS += ".m .tabs .active { border-bottom: 2px solid #164477; }"; customCSS += ".m nav { background-color: #3399cc; }"; customCSS += ".m .btn { background-color: #e0e0e0; color: #000000; }"; customCSS += ".m .btn:hover { background-color: #d5d5d5; }"; customCSS += ".m .btn.disabled { background-color: rgba(0, 0, 0, 0.12) !important; color: rgba(0, 0, 0, 0.26) !important; }"; customCSS += ".m .btn.red { background-color: rgba(244,67,54,0.4) !important; }"; customCSS += ".m .btn.red:hover { background-color: rgba(244,67,54,1) !important; color: #ffffff !important; }"; customCSS += ".m .btn.red:hover i { color: #ffffff; transition: color 0.3s; }"; customCSS += ".m .btn-floating { background-color: transparent; box-shadow: none; color: #000000; }"; customCSS += ".m .btn-floating:hover { background-color: rgba(0,0,0,0.08); }"; customCSS += ".m .btn-floating.selectClear { background-color: #ffffff; }"; customCSS += ".m .btn-floating.selectClear:hover { background-color: #ebebeb; }"; customCSS += ".m .btn-floating i { color: #000000; transition: color 0.3s; }"; customCSS += ".m .btn-floating.red { background-color: transparent !important; }"; customCSS += ".m .btn-floating.red:hover { background-color: red !important; }"; customCSS += ".m .btn-floating.red:hover i { color: #ffffff; }"; customCSS += ".dialog-select-object-ids .material .main-toolbar-table .panel-button { background-color: transparent; }"; customCSS += ".dialog-select-object-ids .material .main-toolbar-table .panel-button:hover { background-color: rgba(0,0,0,0.08); }"; customCSS += ".dialog-select-object-ids .material .main-toolbar-table .panel-button i { color: #757575; }"; customCSS += ".dialog-select-object-ids .objects-list-table { background-color: #ffffff; }"; customCSS += ".dialog-select-object-ids .objects-list-table thead { display: none; }"; customCSS += ".dialog-select-object-ids table.objects-list-table tr { border: none !important; }"; customCSS += ".dialog-select-object-ids table.objects-list-table tr:hover { background-color: #3399cc; outline: none; color: #ffffff; }"; customCSS += ".dialog-select-object-ids table.objects-list-table tr:hover .fancytree-title { color: #ffffff; }"; customCSS += ".dialog-select-object-ids table.objects-list-table tr.fancytree-active { background-color: #236b8e !important; outline: none !important; color: #ffffff !important; }"; customCSS += ".dialog-select-object-ids table.objects-list-table tr.fancytree-active .fancytree-title { color: #ffffff; }"; customCSS += ".dialog-select-object-ids table.objects-list-table td { border: none !important; }"; customCSS += ".m .dropdown-content li>span { color: rgba(0, 0, 0, 0.86); }"; customCSS += ".m .dropdown-content li>a { color: rgba(0, 0, 0, 0.86); }"; customCSS += ".m [type=checkbox].filled-in:checked+span:not(.lever):after { border: #164477; background-color: #164477; }"; customCSS += ".m [type=radio].with-gap:checked+span:after, .m [type=radio]:checked+span:after { background-color: #164477; }"; customCSS += ".m [type=radio].with-gap:checked+span:after, .m [type=radio].with-gap:checked+span:before, .m [type=radio]:checked+span:after { border: 2px solid #164477; }"; customCSS += ".m.react-dark .btn, .m.react-dark .btn-small, .m.react-dark button.btn i, .m.react-dark button.btn-small i { background-color: #272727; }"; customCSS += ".m.react-dark .dialog-select-container .main-header-table, .m.react-dark .dialog-select-container .main-header-table tr, .m.react-dark .dialog-select-container .objects-list-table { background: #272727!important; }"; customCSS += ".m.react-dark .dropdown-content li.grey.lighten-3, .m.react-dark .dropdown-content li.selected, .m.react-dark .dropdown-content li:hover { background-color: #4c4c4c !important; }"; customCSS += ".m.react-dark .dropdown-content li.divider { background-color: #626262; }"; addCustomCSS(customCSS, "reactCSS"); $('.table-button-add').addClass('grey lighten-2'); var selectIdImgPath = './fancytree/react/'; $('#fancytreeCSSLink').attr('href', './fancytree/react/ui.fancytree.min.css'); if ($('.m.adapter-container').hasClass('react-dark')) $('.m.material-dialogs').addClass('react-dark'); } //Create a helper for sortable tables with preserved width of cells var fixHelper = function(e, ui){ ui.children().each(function(){ $(this).width($(this).width()).css({"background-color":"rgba(180,180,180,0.75)", "box-shadow":"-5px 5px 5px 0px rgba(180,180,180,0.75)"}); }); return ui; }; //Select elements with id=key and class=value and insert value if (!settings) return; $('.value').each(function () { var $key = $(this); var id = $key.attr('id'); if ($key.attr('type') === 'checkbox') { if(typeof settings[id] != udef) $key.prop('checked', settings[id]); //do not call onChange direct, because onChange could expect some arguments $key.on('change', () => onChange()); } else { if(typeof settings[id] != udef) $key.val(settings[id]); //do not call onChange direct, because onChange could expect some arguments $key.on('change', () => onChange()).on('keyup', () => onChange()); } }); //Signal to admin, that no changes yet onChange(false); //Init ChannelDetector var channelDetector = new ChannelDetector(); //Load Aliases loadAliases(function(){ //Add Aliases to tabMain loadTabMain(); //Show Settings console.log("All settings loaded. Adapter ready."); $('.hideOnLoad').show(); $('.showOnLoad').hide(); loading = false; //Reinitialize all the Materialize labels on the page if you are dynamically adding inputs: if (M) M.updateTextFields(); //Get historyInstances getHistoryInstances(); //Get Enumerations getEnumerations(); //Get iobrokerObjects getIobrokerObjects(); }); function getIobrokerObjects(){ console.log("Getting ioBroker Objects..."); $('.loadingObjects').show(); if(!iobrokerObjectsReady){ var toDo = function(){ console.log("Subscribing to objectChange"); socket.on('objectChange', function(id, obj){ if(obj) iobrokerObjects[id] = obj; else if(obj == null) delete iobrokerObjects[id]; }); } iobrokerObjectsReadyFunctions.push(toDo); } iobrokerObjectsReady = false; if(parent && parent.gMain && typeof parent.gMain.objects == "object"){ console.log("...assigning ioBroker Objects via parent.gMain.objects..."); iobrokerObjects = Object.assign({}, parent.gMain.objects); iobrokerObjectsReady = true; if(iobrokerObjectsReadyFunctions.length) console.log("There are some functions that were buffered while fetching the ioBroker Objects. They will be executed now..."); for(i = 0; i < iobrokerObjectsReadyFunctions.length; i++){ if (typeof iobrokerObjectsReadyFunctions[i] == 'function') iobrokerObjectsReadyFunctions[i](); } iobrokerObjectsReadyFunctions = []; $('.loadingObjects').hide(); console.log("ioBroker Objects ready."); } else { setTimeout(function(){ console.log("...fetching ioBroker Objects via socket..."); $('.loadingObjects').show(); socket.emit('getObjects', function (err, _objs) { iobrokerObjects = _objs; iobrokerObjectsReady = true; if(iobrokerObjectsReadyFunctions.length) console.log("There are some functions that were buffered while fetching the ioBroker Objects. They will be executed now..."); for(i = 0; i < iobrokerObjectsReadyFunctions.length; i++){ if (typeof iobrokerObjectsReadyFunctions[i] == 'function') iobrokerObjectsReadyFunctions[i](); } iobrokerObjectsReadyFunctions = []; $('.loadingObjects').hide(); console.log("ioBroker Objects ready."); }); }, 1000); } } //++++++++++ TABS ++++++++++ //Enhance Tabs with onShow-Function $('ul.tabs li a').on('click', function(){ //Scroll tab to middle $tab = $(this); $parent = $(this).parents('.tabs'); var tabLeft = $tab.offset().left - $parent.offset().left + $parent.scrollLeft(); var tabWidth = $tab.innerWidth(); var parentWidth = $parent.innerWidth(); $parent.animate({ scrollLeft: (tabLeft + (tabWidth / 2) - (parentWidth / 2)) }, 250); //Load onTabShow-Function onTabShow($(this).attr('href')); }); function onTabShow(tabId){ console.log("Open tab: " + tabId); switch(tabId){ case "#tabMain": loadTabMain(); break; case "#tabAliases": loadTabAliases(); break; case "#tabAutocreateAlias": loadTabAutocreateAlias(); break; case "#tabRenameAliases": loadTabRenameAliases(); break; } } //++++++++++ MAIN ++++++++++ function loadTabMain(){ //Get Aliases and add them to Tree var aliasesMain = getAliasesMain(); var aliasesMainTree = aliasesMain.reduce(function(total, current){ current.split('.').reduce(function(currentTotal, currentValue, currentIndex, currentArray){ var id = currentArray.slice(0, currentIndex + 1).join('.'); var label = currentArray.slice(currentIndex, currentIndex + 1).join('.'); var temp = (currentTotal.children = currentTotal.children || []).find(o => o.id === id); if (!temp) currentTotal.children.push(temp = {id: id, label: label}); return temp; }, total); return total; }, {children: []}).children; function mainCreateNestedAliasesMainList(list){ if(list?.length > 0){ var html = "<ul class='collapsible expandable mainAliasTreeCollapsible'>"; list.forEach(function(alias){ console.log("|- " + alias.id + ":"); var name = getAliasName(alias.id); html += " <li" + ((alias.id == "alias" || alias.id == "alias.0") ? " class='active'" : "") + ">"; html += " <div class='collapsible-header'><i class='material-icons collapsible-header-inactive indigo-text text-darken-4' style='margin: -9px 6px -9px 0px;'>folder</i><i class='material-icons collapsible-header-active indigo-text text-darken-4' style='margin: -9px 6px -9px 0px;'>folder_open</i>"; html += alias.label + (name && name != alias.label ? "<br>(" + name + ")" : ""); if(alias.id != "alias" && alias.id != "alias.0"){ html += " <a class='waves-effect waves-light btn-floating btn-flat btn-small mainAliasListEditButton' data-alias='" + alias.id + "' style='margin: -6px; position: absolute; right: 25px;'><i class='material-icons left' style='color: black;'>edit</i></a>"; } html += " </div>"; html += " <div class='collapsible-body'>"; html += mainCreateNestedAliasesMainList(alias.children); var datapoints = Object.keys(aliases).filter(function(element){return (element.indexOf(alias.id) == 0 && element.substr(alias.id.length).lastIndexOf(".") == 0 && aliasesMain.indexOf(element) == -1);}); if(datapoints){ html += " <div style='padding: 10px; overflow-x: auto; cursor: pointer;' class='mainAliasTreeDatapoints' data-alias='" + alias.id + "'><ul>"; html += " <li>" + datapoints.join("</li><li>"); html += " </ul></div>"; html += " </div>"; } html += " </li>"; }); html += "</ul>"; return html; } else { console.log(" has no childs -|"); return ""; } } $('#mainAliasTreeContainer').html(mainCreateNestedAliasesMainList(aliasesMainTree)); $('.mainAliasTreeCollapsible').collapsible({accordion: false}); //Get Aliases and add them to Table $('#mainAliasListTableBody').empty(); aliasesMain.forEach(function(alias, index){ var name = getAliasName(alias); var tableRow = ""; tableRow += "<tr class='mainAliasListTableRow' data-alias='" + alias + "' style='cursor: pointer;'>"; tableRow += " <td>"; tableRow += alias; tableRow += " </td>"; tableRow += " <td>"; tableRow += name; tableRow += " </td>"; tableRow += " <td>"; tableRow += " <a class='waves-effect waves-light btn-floating btn-flat btn-small mainAliasListEditButton' id='mainAliasListTableEditButton_" + index + "' data-alias='" + alias + "'><i class='material-icons left' style='color: black;'>edit</i></a>"; tableRow += " </td>"; tableRow += "</tr>"; $('#mainAliasListTableBody').append(tableRow); }); //Enhance edit-buttons with function $('.mainAliasListEditButton, .mainAliasListTableRow, .mainAliasTreeDatapoints ').off('click').on('click', function(){ M.Tabs.getInstance($('#tabsTop')).select('tabAliases'); var aliasPath = $(this).data('alias'); (function(){ //Closure--> (everything declared inside keeps its value as ist is at the time the function is created) var _aliasPath = aliasPath; setTimeout(function(){ $('#aliasesSelectedAlias').val(_aliasPath).select().trigger('change'); }, 10); })(); //<--End Closure }); } //++++++++++ ALIASES ++++++++++ var aliasesSelectedAlias = false; var aliasesUsedAliasIds = []; //Load Tab Aliases function loadTabAliases(showAlias){ $('#aliasesSelectedAlias').addClass('disabled'); $('#aliasesSelectedAliasProgress').show(); $('.aliasesContentDiv').hide(); $('.aliasesNothingSelectedDiv').show(); //Get Aliases and add them to Selectbox $('#aliasesSelectedAlias').empty().append("<option disabled" + (showAlias ? "" : " selected") + " value>" + _("Select Alias") + "</option>"); getAliasesMain().forEach(function(alias, index){ var name = getAliasName(alias); $('#aliasesSelectedAlias').append("<option value='" + alias + "' data-index='" + index + "'>" + alias + (name != "" && name != alias ? " (" + name + ")" : "&nbsp;") + "</option>"); }); $('#aliasesSelectedAlias').removeClass('disabled'); $('#aliasesSelectedAlias').val(showAlias); $('#aliasesSelectedAlias').select().trigger('change'); $('#aliasesSelectedAliasProgress').hide(); } //Enhance aliasesSelectedAlias-Selectbox with functions $('#aliasesSelectedAlias').on('change', function(){ aliasesLoadAlias($('#aliasesSelectedAlias').val()); }); //Load Alias function aliasesLoadAlias(aliasId){ $('.aliasesDatapointSaveAll').hide(); aliasesSelectedAlias = aliasId; if(aliasesSelectedAlias){ //Fill Datapoint list $('#aliasesAliasMainList').empty(); $('#aliasesDatapointList').empty(); aliasesUsedAliasIds = []; if(aliases[aliasesSelectedAlias]){ aliasesDatapointListAddLine(aliasesSelectedAlias, true); } else { aliases[aliasesSelectedAlias] = { UNSAVED_NEW: true, type: "channel", common: { name: aliasesSelectedAlias.substr(aliasesSelectedAlias.lastIndexOf('.') + 1), role: "" }, _id: aliasesSelectedAlias }; aliasesDatapointListAddLine(aliasesSelectedAlias, true); } var aliasesMain = getAliasesMain(); var datapoints = Object.keys(aliases).filter(function(element){return (element.indexOf(aliasesSelectedAlias) == 0 && element.substr(aliasesSelectedAlias.length).lastIndexOf(".") == 0 && aliasesMain.indexOf(element) == -1);}); datapoints.forEach(function(alias){ aliasesDatapointListAddLine(alias); }) $('.aliasesContentDiv').show(); $('.aliasesNothingSelectedDiv').hide(); } else { $('.aliasesContentDiv').hide(); $('.aliasesNothingSelectedDiv').show(); } } //Add function to Add Alias Button $('#aliasesNewAlias').on('click', function(){ var aliasId = prompt(_("Please enter ID of alias"), "alias.0.MyNewAlias"); if(!aliasId) return; if(aliasId.indexOf("alias.0.") !== 0) aliasId = "alias.0." + aliasId; if(aliasId.length < 9) return; if(aliases[aliasId] && !aliases[aliasId].UNSAVED_NEW){ alert("Error: This alias exists."); return; } $('#aliasesSelectedAlias').append("<option value='" + aliasId + "'>" + aliasId + " [" + _("NOT SAVED") + "]" + "</option>"); $('#aliasesSelectedAlias').val(aliasId); $('#aliasesSelectedAlias').select().trigger('change'); }); //Add function to Add Datapoint Button $('#aliasesNewDatapoint').on('click', function(){ if(aliasesAddDatapoint()){ setTimeout(function(){ $(".adapter-body").scrollTop($(".adapter-body")[0].scrollHeight); }, 500); } }); //Add function to Add Datapoint From Existing Button var aliasesNewDatapointFromExistingLastSelectId = ""; $('#aliasesNewDatapointFromExisting').on('click', function(){ $('#dialogSelectId').data('selectidfor', ''); initSelectId(function (sid) { sid.selectId('show', aliasesNewDatapointFromExistingLastSelectId, {type: 'state'}, function (newId) { if (newId && iobrokerObjects[newId]) { console.log(iobrokerObjects[newId]); var r = getDatapointConfiguration(newId); if(r & aliasesAddDatapoint(r)){ setTimeout(function(){ $(".adapter-body").scrollTop($(".adapter-body")[0].scrollHeight); }, 500); } aliasesNewDatapointFromExistingLastSelectId = newId; } }); }); }); //Add function to Copy Button $('#aliasesCopyAlias').on('click', function(){ aliasesCopyAlias(); }); //Add function to Rename Button $('#aliasesRenameAlias').on('click', function(){ aliasesCopyAlias(true, true); }); //Add function to Delete Button $('#aliasesDeleteAlias').on('click', function(){ if(confirm(_("Really delete this Alias with all its datapoints? This cant't be undone!"))){ var ids = []; $('#aliasesDatapointList > li').each(function(){ ids.push($(this).data('id')); }); ids.push(aliasesSelectedAlias); aliasesDeleteDatapoints(ids, function(){ loadTabAliases(); }); } }); //Add function to Save all Buttons $('.aliasesDatapointSaveAll').on('click', function(){ var ids = []; $('.aliasesDatapoint.save').each(function(){ if($(this).css('display') != "none") ids.push($(this).data('id')); }); aliasesSaveDatapoints(ids); }); //Add function to Expand all Button $('#aliasesDatapointCollapsibleExpandAll').on('click', function(){ $('#aliasesDatapointList li.aliasesDatapointCollapsibleItem').removeClass('active'); $('#aliasesDatapointList').collapsible('open'); $('#aliasesDatapointList li.aliasesDatapointCollapsibleItem').addClass('active'); }); //Add function to Collapse all Button $('#aliasesDatapointCollapsibleCollapseAll').on('click', function(){ $('#aliasesDatapointList li.aliasesDatapointCollapsibleItem').addClass('active'); $('#aliasesDatapointList').collapsible('close'); $('#aliasesDatapointList li.aliasesDatapointCollapsibleItem').removeClass('active'); }); //Add Line to Datapoint List function aliasesDatapointListAddLine(alias, isMain){ var listContent = ""; var name = getAliasName(alias) || alias; var type = aliases[alias].common.type || ""; var role = aliases[alias].common.role || ""; var unit = aliases[alias].common.unit || ""; var min = aliases[alias].common.min || ""; var max = aliases[alias].common.max || ""; var read = aliases[alias].common.read || false; var write = aliases[alias].common.write || false; var states = aliases[alias].common.states || null; var custom = aliases[alias].common.custom || null; var unsavedNew = aliases[alias].UNSAVED_NEW || false; var convertedToNumber = false; if(typeof min != "number" && min != ""){ if(isNaN(min)) min = ""; else min = parseFloat(min); unsavedNew = true; convertedToNumber = true; } if(typeof max != "number" && max != ""){ if(isNaN(max)) max = ""; else max = parseFloat(max); unsavedNew = true; convertedToNumber = true; } var addedNative = false; if(typeof aliases[alias].native != "object"){ unsavedNew = true; addedNative = true; } var aliasObj = aliases[alias].common.alias || {}; var aliasId = aliasObj.id || ""; var aliasRead = aliasObj.read || ""; var aliasWrite = aliasObj.write || ""; if(aliasId) aliasesUsedAliasIds.push(aliasId); listContent += "<li class='aliasesDatapointCollapsibleItem" + (isMain ? " active" : "") + "' style='background-color: rgba(255,255,255,0.5); border-width: 4px;' data-id='" + alias + "' data-main='" + (isMain ? "true" : "false") + "'>"; listContent += "<div class='aliasesDatapointCollapsibleHeader collapsible-header' data-id='" + alias + "' data-main='" + (isMain ? "true" : "false") + "'>"; listContent += "<div class='row aliasesDatapointRow' style='background-color: rgba(0,0,0,0.2);'>"; if(!isMain && aliases[alias].type == "state") listContent += "<i class='aliasesDatapoint copy material-icons' data-id='" + alias + "' data-setting='copy' data-main='" + (isMain ? "true" : "false") + "' style='position:absolute; right:30px; margin-top: 2px; cursor:pointer; color:#000000;'>content_copy</i>"; if(!isMain) listContent += "<i class='aliasesDatapoint delete material-icons' data-id='" + alias + "' data-setting='delete' data-main='" + (isMain ? "true" : "false") + "' style='position:absolute; right:6px; margin-top: 2px; cursor:pointer; color:#ce0000;'>delete</i>"; listContent += "<div class='col s11 m6 l6'>"; listContent += "<h6><i class='material-icons'>keyboard_arrow_down</i><span class='aliasesDatapoint id' data-id='" + alias + "' data-setting='id'>" + alias + "</span>:"; listContent += "</h6>"; listContent += "</div>"; listContent += "<div class='col s12 m5 l5'>"; listContent += "<input class='val aliasesDatapoint' name='aliasesDatapoint_" + alias + "_NAME' id='aliasesDatapoint_" + alias + "_NAME' data-id='" + alias + "' data-setting='name' value='" + name + "' data-main='" + (isMain ? "true" : "false") + "'></input>"; listContent += "<label for='aliasesDatapoint_" + alias + "_NAME' class='translate'></label>"; listContent += "<span class='translate'>Name</span>"; listContent += "</div>"; listContent += "</div>"; listContent += "</div>"; listContent += "<div class='aliasesDatapointCollapsibleBody collapsible-body' data-id='" + alias + "' data-main='" + (isMain ? "true" : "false") + "'>"; listContent += "<div class='row aliasesDatapointRow' style='background-color: rgba(0,0,255,0.1);'>"; listContent += "<div class='col s12 m6 l4'>"; listContent += "<input class='val aliasesDatapoint' name='aliasesDatapoint_" + alias + "_ROLE' id='aliasesDatapoint_" + alias + "_ROLE' data-id='" + alias + "' data-setting='role' value='" + role + "' data-main='" + (isMain ? "true" : "false") + "'></input>"; listContent += "<label for='aliasesDatapoint_" + alias + "_ROLE' class='translate'></label>"; listContent += "<span class='translate'>common.role</span>"; listContent += "</div>"; if(aliases[alias].type == "state"){ //STATE listContent += "<div class='col s12 m6 l4'>"; listContent += "<input class='val aliasesDatapoint' name='aliasesDatapoint_" + alias + "_TYPE' id='aliasesDatapoint_" + alias + "_TYPE' data-id='" + alias + "' data-setting='type' value='" + type + "'></input>"; listContent += "<label for='aliasesDatapoint_" + alias + "_TYPE' class='translate'></label>"; listContent += "<span class='translate'>common.type</span>"; listContent += "</div>"; listContent += "<div class='col s12 m6 l4'>"; listContent += "<input class='val aliasesDatapoint' name='aliasesDatapoint_" + alias + "_UNIT' id='aliasesDatapoint_" + alias + "_UNIT' data-id='" + alias + "' data-setting='unit' value='" + unit + "'></input>"; listContent += "<label for='aliasesDatapoint_" + alias + "_UNIT' class='translate'></label>"; listContent +=