/** * yunkong2.mobile * https://git.spacen.net/yunkong2/yunkong2.mobile * * Copyright (c) 2015-2016 bluefox https://git.spacen.net/GermanBluefox * MIT * */ /* jshint browser:--undef */ /* jshint browser:true */ /* global document */ /* global console */ /* global session */ /* global window */ /* global location */ /* global setTimeout */ /* global clearTimeout */ /* global io */ /* global systemLang:true */ /* global systemLang */ /* global _ */ /* global can */ /* global storage */ /* global servConn */ /* global systemDictionary:true */ /* global systemDictionary */ /* global $ */ /* global translateAll */ /* global jQuery */ /* global $ */ /* global document */ /* jshint -W097 */// jshint strict:false 'use strict'; systemDictionary = { 'Views': {'en': 'Views', 'cn': '视图'}, 'edit description': { 'en': 'In edit mode you can add, delete or modify the extensions. Additionally the elements can be sorted or styled.' }, "Loading data values...": { "en": "Loading data values...", "cn": "装载数据..." }, "Rooms": {"en": "Rooms", "cn": "场景"}, "Favorites": {"en": "Favorites", "cn": "收藏"}, "Functions": {"en": "Functions", "cn": "功能"}, "off": {"en": "off", "cn": "关"}, "on": {"en": "on", "cn": "开"}, "CLOSED": {"en": "closed", "cn": "已关闭"}, "closed": {"en": "closed", "cn": "已关闭"}, "opened": {"en": "opened", "cn": "已打开"}, /* "OPEN": {"en": "open", "de": "开"},*/ "open": {"en": "open", "cn": "打开"}, "TILTED": {"en": "tilted", "cn": "tilted"}, "tilted": {"en": "tilted", "cn": "tilted"}, "false": {"en": "false", "cn": "false"}, "true": {"en": "true", "cn": "true"}, "No connection to server": { "en": "No connection to server", "cn": "和服务器断开连接" }, "Edit mode": {"en": "Edit mode", "cn": "编辑模式"}, "Info": {"en": "Info", "cn": "信息"}, "License: ": {"en": "License: ", "cn": "授权: "}, "Refresh": {"en": "Refresh", "cn": "刷新"}, "Used icons": { "en": '新空间' }, "Edit name": { "en": "Edit name", "cn": "修改名称"}, "Last synchronized: ": { "en": "Last synchronized: ", "cn": "上次同步: " }, "Edit-Mode": {"en": "Edit-Mode", "cn": "编辑模式"}, "Finish Edit-Mode": {"en": "Finish Edit-Mode", "cn": "完成"}, "Documentation": {"en": "Documentation", "cn": "文档"}, "Reset layout": {"en": "Reset layout", "cn": "复位"}, "%s seconds ago": {"en": "%s days ago", "de": "vor %s Sekunden", "ru": "%s секунд(у) назад"}, "ca. %s minutes ago": {"en": "ca. %s minutes ago", "de": "vor ca. %s Minuten", "ru": "примеро %s минут(у) назад"}, "%s minutes ago": {"en": "%s minutes ago", "de": "vor %s Minuten", "ru": "%s минут(у) назад"}, "%s h. and %s m. ago": {"en": "%s h. and %s m. ago", "de": "vor %s Stunden und %s Minuten", "ru": "%s час(ов) и %s минут(у) назад"}, "%s hours ago": {"en": "%s hours ago", "de": "vor %s Stunden", "ru": "%s час(ов) назад"}, "%s days and %s h. ago": {"en": "%s days and %s h. ago", "de": "vor %s Tagen und %s Stunden", "ru": "%s дней и %s час(ов) назад"}, "%s days ago": {"en": "%s days ago", "de": "vor %s days", "ru": "%s дней назад"}, "Theme": {"en": "Theme", "cn": "样式"}, "none": {"en": "no type", "de": "kein Typ", "ru": "нет типа"}, "Light": {"en": "light", "de": "Licht", "ru": "свет"}, "Socket": {"en": "socket", "de": "Steckdose", "ru": "розетка"}, "Blinds": {"en": "blinds", "de": "Rolladen", "ru": "жалюзи"}, "Red": {"en": "red", "de": "rot", "ru": "красный"}, "Green": {"en": "green", "de": "grün", "ru": "зелёный"}, "Blue": {"en": "blue", "de": "blau", "ru": "синий"}, "White": {"en": "white", "de": "weiß", "ru": "белый"}, "Wohnzimmer": {"en": "Living room", "de": "Wohnzimmer", "ru": "Гостинная"}, "Küche": {"en": "Kitchen", "de": "Küche", "ru": "Кухня"}, "Schlafzimmer": {"en": "Sleeping room", "de": "Schlafzimmer", "ru": "Спальня"}, "Kinderzimmer": {"en": "Kids room", "de": "Kinderzimmer", "ru": "Детская"}, "Kabinet": {"en": "Cabinet", "de": "Kabinet", "ru": "Кабинет"}, "Bad": {"en": "Bath", "de": "Bad", "ru": "Ванная"}, "Balkon": {"en": "Balcony", "de": "Balkon", "ru": "Балкон"}, "Gäste WC": {"en": "Guest WC", "de": "Gäste WC", "ru": "Гостевой туалет"}, "Flur": {"en": "Hall", "de": "Flur", "ru": "Коридор"}, "Admin Favorites": {"en": "Admin Favorites", "de": "Admin Favorites", "ru": "Admin Favorites"}, "Licht": {"en": "Light", "de": "Licht", "ru": "Свет"}, "Heizung": {"en": "Heting", "de": "Heizung", "ru": "Отопление"}, "Rolladen": {"en": "Shutter", "de": "Rolladen", "ru": "Жалюзи"}, "Wetter": {"en": "Weather", "de": "Wetter", "ru": "Погода"}, "Umwelt": {"en": "Environment", "de": "Umwelt", "ru": "Окружающая среда"}, "Taster": {"en": "Button", "de": "Taster", "ru": "Кнопка"}, "Zentrale": {"en": "Central unit", "de": "Zentrale", "ru": "Центральное устройство"}, "Fenster": {"en": "Window", "de": "Fenster", "ru": "Окно"}, "Aktor": {"en": "Actor", "de": "Aktor", "ru": "Выключатель"}, "Beleuchtung": {"en": "Lighting", "de": "Beleuchtung", "ru": "Подсветка"}, "Technikraum": {"en": "Technical room", "de": "Technikraum", "ru": "Комната оборудования"}, "Büro": {"en": "Office", "de": "Büro", "ru": "Бюро"}, "Kellerraum": {"en": "Basement", "de": "Kellerraum", "ru": "Подвал"}, "Vorraum": {"en": "Vestibule", "de": "Vorraum", "ru": "Сени"}, "Gang EG": {"en": "Corridor 1st floor", "de": "Gang EG", "ru": "Коридор 1й этаж"}, "Aussen EG": {"en": "Outside 1st floor", "de": "Aussen EG", "ru": "Снаружи 1й этаж"}, "Carport": {"en": "Carport", "de": "Carport", "ru": "Навес над машиной"}, "WC EG": {"en": "WC 1st floor", "de": "WC EG", "ru": "Туалет 1й этаж"}, "Bad EG": {"en": "Bath 1st floor", "de": "Bad EG", "ru": "Bad 1й этаж"}, "Schrankraum": {"en": "Wardrobe", "de": "Schrankraum", "ru": "Шкаф"}, "Bad OG": {"en": "Bath 2nd floor", "de": "Bad OG", "ru": "Ванная 2й этаж"}, "Kinderzimmer 1": {"en": "Kid's room 1", "de": "Kinderzimmer 1", "ru": "Детская 1"}, "Kinderzimmer 2": {"en": "Kid's room 2", "de": "Kinderzimmer 2", "ru": "Детская 2"}, "Gang OG": {"en": "Corridor 2nd floor", "de": "Gang OG", "ru": "Коридор 2й этаж"}, "WC OG": {"en": "WC 2nd floor", "de": "WC OG", "ru": "Туалет 2й этаж"}, "Speis": {"en": "Speis", "de": "Speis", "ru": "Speis"}, "Terrasse": {"en": "Terrace", "de": "Terrasse", "ru": "Терасса"}, "Garten": {"en": "Garden", "de": "Garten", "ru": "Сад"}, "Aussen OG": {"en": "Outside 2nd floor", "de": "Aussen OG", "ru": "Снаружи 2й этаж"}, "Treppe": {"en": "Stair", "de": "Treppe", "ru": "Лестница"}, "Esszimmer": {"en": "Eating room", "de": "Esszimmer", "ru": "Столовая"}, "Helligkeitswerte": {"en": "Brightness", "de": "Helligkeitswerte", "ru": "Яркость"}, "IPCams": {"en": "IP Cams", "de": "IPCams", "ru": "Веб камеры"}, "Raffstore": {"en": "Raffstore", "de": "Raffstore", "ru": "Raffstore"}, "Klima": {"en": "Air condition", "de": "Klima", "ru": "Кондиционер"}, "Sicherheit": {"en": "Alarm", "de": "Sicherheit", "ru": "Сигнализация"}, "Verschluss": {"en": "Gate", "de": "Verschluss", "ru": "Двери"}, "Energiemanagement": {"en": "Energy management", "de": "Energiemanagement", "ru": "Потребление энергии"}, "VALVE STATE": {"en": "Valve State", "de": "Ventilposition", "ru": "Позиция вентиля"}, "LEVEL": {"en": "Level", "de": "Wert", "ru": "Положение"}, "PRESS LONG": {"en": "Press long", "de": "Lang drucken", "ru": "Длинное нажатие"}, "PRESS SHORT": {"en": "Press short", "de": "Kurz drucken", "ru": "Короткое нажатие"}, "PRESS CONT": {"en": "Press continuous", "de": "Kontinuerlich", "ru": "Продолжительное нажатие"}, "PRESS LONG RELEASE": {"en": "Press long release", "de": "Press Long Release", "ru": "Прекратить длинное нажатие"}, "STATE": {"en": "State", "de": "Zustand", "ru": "Состояние"}, "ADJUSTING COMMAND": {"en": "Adjusting Command", "de": "Justier-Kommando", "ru": "Команда настойки"}, "ADJUSTING DATA": {"en": "Adjusting Data", "de": "Justierungsdaten", "ru": "Данные для настойки"}, "SETPOINT": {"en": "Setpoint", "de": "Sollwert", "ru": "Заданное значение"}, "HUMIDITY": {"en": "Humidity", "de": "Luftfeuchtigkeit", "ru": "Влажность"}, "TEMPERATURE": {"en": "Temperature", "de": "Temperatur", "ru": "Температура"}, "INHIBIT": {"en": "Inhibit", "de": "Sperrung", "ru": "Заперто"}, "OPEN": {"en": "Open", "de": "Aufmachen", "ru": "Открыть"}, "RELOCK DELAY": {"en": "Relock Delay", "de": "Relock Verzögerung", "ru": "Задержка закрытия"}, "STATE UNCERTAIN": {"en": "State Uncertain", "de": "Unbekannter Zustand", "ru": "Неизвестное состояние"}, "BRIGHTNESS": {"en": "Brightness", "de": "Helligkeit", "ru": "Яркость"}, "ON TIME": {"en": "On Time", "de": "Auf-Zeit", "ru": "Время вкл."}, "SUBMIT": {"en": "Submit", "de": "Bestätigen", "ru": "Подтвердить"}, "FILLING LEVEL": {"en": "Filling Level", "de": "Füllniveau ", "ru": "Уровень заполнения"}, "DEFEKT STATE": {"en": "Defect", "de": "Defekt State", "ru": "Поломка"}, "UP": {"en": "up", "de": "Nach oben", "ru": "наверх"}, "DOWN": {"en": "down", "de": "nach unten", "ru": "вниз"}, "STOP": {"en": "Stop", "de": "Stop", "ru": "Стоп"}, "VOLTAGE": {"en": "Voltage", "de": "Spannung", "ru": "Напряжение"}, "POWER": {"en": "Power", "de": "Power", "ru": "Мощность"}, "FREQUENCY": {"en": "Frequency", "de": "Frequenz", "ru": "Частота"}, "ENERGY COUNTER": {"en": "Energy Counter", "de": "Energiezähler", "ru": "Счётчик расхода"}, "CURRENT": {"en": "Current", "de": "Strom", "ru": "Ток"}, "BOOT": {"en": "Boot", "de": "Boot", "ru": "Boot"}, "DECISION VALUE": {"en": "Decision Value", "de": "Entscheidungswert", "ru": "Порог принятия решения"}, "UNDEFINED": {"en": "--", "de": "--", "ru": "--"}, "AIR PRESSURE": {"en": "Air Pressure", "de": "Luftdruck", "ru": "Атмосферное давление"}, "RAINING": {"en": "Raining", "de": "Regen", "ru": "Дождь"}, "RAIN COUNTER": {"en": "Rain counter", "de": "Luftdruck", "ru": "Атмосферное давление"}, "SUNSHINEDURATION": {"en": "Sunshine duration", "de": "Sonnenscheindauer", "ru": "Длительность солнечного сияния"}, "WIND DIRECTION": {"en": "Wind direction", "de": "Windrichtung", "ru": "Направление ветра"}, "WIND DIRECTION RANGE": {"en": "Wind direction range", "de": "Windrichtungumfang", "ru": "Разброс направления ветра"}, "WIND SPEED": {"en": "Wind speed", "de": "Windgeschwindigkeit", "ru": "Скорость ветра"}, "INSTALL TEST": {"en": "Install test", "de": "Installtest", "ru": "INSTALL TEST"}, "VENT_CLOSED": {"en": "Closed", "de": "Ventil Zu", "ru": "Закрыто"} }; var mobile = { version: "0.4.10", requiredServerVersion: '0.0.0', enums: {}, objects: {}, states: {}, root: [], refresh: false, isFirstTime: true, conn: servConn, editMode: false, queueStates: [], updateStates: [], ids: [], user: 'admin', defaultInvisibleRoles: ['inhibit', 'button', 'action', 'timer'], defaultInvisibleNames: ['TIMER_ON', 'RELOCK_DELAY', 'OLD_VALUE', 'STATE_UNCERTAIN', 'DECISION_VALUE', 'ADJUSTING_DATA' , 'ADJUSTING_COMMAND', 'INSTALL_TEST'], ignoreIndicators: ['indicator.updates', 'indicator.state'], lastTimes: [], activePage: null, erasePage: {}, isMobile: null, icons: { temperature: 'temp_temperature.svg', humidity: 'weather_humidity.svg', setpoint: 'temp_control.svg' }, detectMobile: function () { if( navigator.userAgent.match(/Android/i) || navigator.userAgent.match(/webOS/i) || navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i) || navigator.userAgent.match(/iPod/i) || navigator.userAgent.match(/BlackBerry/i) || navigator.userAgent.match(/Windows Phone/i) ){ return true; } else { if(window.innerWidth <= 800 && window.innerHeight <= 600) { return true; } else { return false; } } }, init: function (id) { var that = this; //this.isMobile = this.detectMobile(); this.conn.namespace = 'mobile.0'; this.conn._useStorage = true; var url = $.mobile.path.parseUrl(location.href); this.editMode = (url.search === '?edit'); if (this.editMode) { this.conn.clearCache(); } else if (url.search === '?refresh') { this.conn.clearCache(); location.href = './' + location.hash; } // show edit indicator if (this.editMode) $('#edit_indicator').show(); $('#popupEditName').popup().popup('close'); $('#name_edit').keyup(function (e) { if (e.keyCode === 13) { $('#ok_edit').trigger('click'); } }); $('#ok_edit').click(function (e) { e.stopPropagation(); var $nameEdit = $('#name_edit'); var id = $nameEdit.data('id'); var val = $nameEdit.val(); if (that.objects[id].common) { that.objects[id].common.mobile = that.objects[id].common.mobile || {}; that.objects[id].common.mobile[that.user] = that.objects[id].common.mobile[that.user] || {}; that.objects[id].common.mobile[that.user].name = val || undefined; $('.mobile-widget-title[data-edit-id="' + id + '"]').html(_(val || that.objects[id].common.name || id)); that.saveSettings(id); } $('#popupEditName').popup('close'); }); $(document).bind('pagebeforechange', function (e, data) { if (typeof data.toPage === 'string') { var u = $.mobile.path.parseUrl(data.toPage); var id = decodeURIComponent(u.hash.toString()); id = id.substring(1); id = decodeURIComponent(id); id = id.replace(/&.*$/, ''); that.renderPage(id); if (id && that.activePage !== id && that.activePage && id !== 'info') { // destroy page that.destroyPage(that.activePage); } if (id && that.erasePage[id]) { clearTimeout(that.erasePage[id]); delete that.erasePage[id]; } if (id !== 'info') that.activePage = id; } }); // edit mode is off => switch it on $('.mobile-noedit').click(function () { document.location = '?edit#' + (that.activePage || ''); }); // edit mode is on => switch it off $('.mobile-edit').click(function () { document.location = './?refresh#' + (that.activePage || ''); }); $('#edit_indicator').click(function () { that.objects = that.calcChildren(); document.location = './?refresh' + document.location.hash.replace('&ui-state=dialog', ''); }); $('.mobile-reset').click(function () { that.resetVisibility(function () { document.location = './' + document.location.hash.replace('&ui-state=dialog', ''); }); }); this.conn.init(null, { onConnChange: function (isConnected) { if (isConnected) { //$('#server-disconnect').popup().popup('close'); if (that.isFirstTime) { that.conn.getVersion(function (version) { if (version) { if (that.compareVersion(version, that.requiredServerVersion)) { window.alert(_('Warning: requires Server version %s - found Server version %s - please update Server.', that.requiredServerVersion, version)); } } //else { // Possible not authenticated, wait for request from server //} }); console.log(_('Loading data values...')); } // Get Server language that.conn.getObjects(!that.refresh, function (err, objects) { if (err) console.error(err); that.conn.getConfig(!that.refresh, function (err, config) { if (err) console.error(err); that.conn.getObject('system.adapter.' + that.conn.namespace, !that.refresh, function (err, mobileConfig) { if (err) console.error(err); systemLang = config.language || systemLang; that.language = systemLang; that.dateFormat = config.dateFormat; translateAll(); if (that.isFirstTime) { // Init edit dialog that.isFirstTime = false; } that.config = mobileConfig && mobileConfig.native ? mobileConfig.native : {indicators: {}, theme: 'light'}; that.config.indicators = that.config.indicators || {}; that.config.theme = that.config.theme || 'light'; that.loadStyle(); that.objects = that.calcChildren(objects); // find for every object the children // show last sync time var syncTime = that.conn.getSyncTime(); if (typeof(Storage) === 'undefined') { $('.mobile-refresh').hide(); $('.last-synchronised').html(_('not supported')); } else { $('.last-synchronised').html(!syncTime ? _('never') : syncTime.toLocaleDateString() + ' ' + syncTime.toLocaleTimeString()); } that.conn.getEnums(!that.refresh, function (err, enums) { that.enums = enums; for (var e in that.enums) { var parts = e.split('.'); if (parts.length === 2) that.root.push(e); } that.renderRootPages(); }); }); }); }); } else { //$('#server-disconnect').popup('open'); } }, onRefresh: function () { window.location.reload(); }, onUpdate: function (id, state) { setTimeout(function () { that.states[id] = state; that.updateState(id); }, 0); }, onObjectChange: function (id, obj) { if (!that.objects || !that.editMode) return; if (obj) { obj.children = that.objects[id].children; that.objects[id] = obj; } else { if (that.objects[id]) delete that.objects[id]; } }, onError: function (err) { window.alert(_('Cannot execute %s for %s, because of insufficient permissions', err.command, err.arg)); } }, true/*edit mode */); $('.mobile-version').html('v' + this.version); $('.mobile-theme-selector').click(function () { var oldTheme = that.config.theme; that.config.theme = $(this).data('theme'); that.saveConfig(); that.loadStyle(); $('.mobile-theme-' + oldTheme).removeClass('mobile-theme-' + oldTheme).addClass('mobile-theme-' + that.config.theme); $('.mobile-theme-selector').each(function () { if ($(this).data('theme') === that.config.theme) { $(this).parent().addClass('ui-btn-active'); } else { $(this).parent().removeClass('ui-btn-active'); } }); }); that.monitorSleep(); }, monitorSleep: function () { var that = this; that.lastTimerUpdate = new Date().getTime(); that.sleepTimer = setTimeout(function () { var now = new Date().getTime(); if (now - that.lastTimerUpdate > 31000) { window.location.reload(); } else{ that.monitorSleep(); } }, 10000); }, saveObjects: function (cb) { if (this.idsToSave && this.idsToSave.length) { var id = this.idsToSave.pop(); var that = this; this.conn._socket.emit('getObject', id, function (err, obj) { obj.common.mobile = that.objects[id].common.mobile; if (!err) { that.conn._socket.emit('setObject', id, obj, function (err) { if (!err) { setTimeout(function () { that.saveObjects(); }, 0); } else { console.error(err); cb && cb(err, id); } }); } else { console.error(err); cb && cb(err, id); } }); } else { cb && cb(); } }, saveSettings: function (id) { this.idsToSave = this.idsToSave || []; if (this.saveTimeout) clearTimeout(this.saveTimeout); if (this.idsToSave.indexOf(id) === -1) this.idsToSave.push(id); var that = this; this.saveTimeout = setTimeout(function () { that.saveObjects(); }, 300); }, saveConfig: function (cb) { var that = this; this.conn._socket.emit('getObject', 'system.adapter.' + this.conn.namespace, function (err, obj) { obj.native = that.config; that.conn._socket.emit('setObject', obj._id, obj, function (err) { cb && cb(err); }); }); }, modifyObjects: function (list, cb) { if (!list || !list.length) { cb && cb(); return; } var id = list.pop(); var that = this; this.conn._socket.emit('setObject', id, this.objects[id], function (err) { if (!err) { setTimeout(function () { that.modifyObjects(list, cb); }, 0); } else { console.error(err); cb && cb(err, id); } }); }, resetVisibility: function (cb) { var modified = []; for (var id in this.objects) { if (this.objects[id] && this.objects[id].common && this.objects[id].common.mobile && this.objects[id].common.mobile[this.user] && this.objects[id].common.mobile[this.user].visible !== undefined) { delete this.objects[id].common.mobile[this.user].visible; modified.push(id); } } this.modifyObjects(modified, cb); }, updateLastStates: function (justStartStopTimer) { var that = mobile; if (that.lastTimes.length && !that.lastTimesTimer) { that.lastTimesTimer = setInterval(function () { that.updateLastStates(); }, 30000); } else if (!that.lastTimes.length && that.lastTimesTimer) { clearInterval(that.lastTimesTimer); that.lastTimesTimer = null; } if (!justStartStopTimer) { var actual = JSON.parse(JSON.stringify(that.lastTimes)); $('.mobile-last-change').each(function () { var lc = $(this).data('time'); if (!lc) return; var pos = actual.indexOf($(this).data('edit-id')); if (!pos) { that.lastTimes.push($(this).data('edit-id')); } else { actual.splice(pos, 1); } $(this).html(that.formatLastChange(lc)); }); // remove all ids from that.lastTimes, that are no more exists for (var a = 0; a < actual.length; a++) { var pos = that.lastTimes.indexOf(actual[a]); if (pos) that.lastTimes.splice(pos, 1); } } }, updateState: function (id, force) { var that = this; $('[data-mobile-id="' + id + '"]').each(function () { var _id = $(this).data('mobile-id'); // actually _id and id must be equal var role = $(this).data('role'); if (role === 'lastChange') { var lc = that.states[_id].lc; var pos = that.lastTimes.indexOf(_id); if (!lc) { if (pos !== -1) { that.lastTimes.splice(pos, 1); that.updateLastStates(true); } $(this).data('time', null).hide(); return; } $(this) .data('time', lc) .show() .html(that.formatLastChange(lc)); if (pos === -1) { that.lastTimes.push(_id); that.updateLastStates(true); } } else { var val = $(this).val(); if (that.states[_id].val === undefined || that.states[_id].val === 'undefined' || that.states[_id].val === null || that.states[_id].val === 'null') { console.warn('No data for "' + _id + '".'); that.states[_id].val = ''; } var type = $(this).data('type'); if (type !== 'set' && (force || val !== that.states[_id].val.toString())) { var rawVal = that.states[_id].val; val = that.states[_id].val; if (type === 'range') { $(this).val(val); $(this).slider('refresh'); } else if (type === 'set') { //ignore } else if (type === 'icon') { var img; var _type = $(this).data('icon-type'); switch (_type) { case 'light': if (val === 'true' || val === true) { rawVal = true; } else if (val === 'false' || val === false) { rawVal = false; } else if (val !== null && parseFloat(val).toString() === val.toString()) { rawVal = parseFloat(val); } img = rawVal ? 'img/bulbOn.png' : 'img/bulbOff.png'; break; case 'red': case 'green': case 'blue': case 'white': rawVal = parseFloat(val) || 0; var min = $(this).data('min'); var max = $(this).data('max'); if (min === undefined || min === null || min === '') { min = 0; } else { min = parseFloat(min); } if (max === undefined || max === null || max === '') { max = 100; } else { max = parseFloat(max); } if (rawVal > max) rawVal = max; if (rawVal < min) rawVal = min; rawVal = (rawVal - min) / (max - min); if (rawVal < 0.1) rawVal = 0.1; img = 'img/rgb-' + _type + '.png'; $(this).css('opacity', rawVal); break; case 'socket': if (val === 'true' || val === true) { rawVal = true; } else if (val === 'false' || val === false) { rawVal = false; } else if (val !== null && parseFloat(val).toString() === val.toString()) { rawVal = parseFloat(val); } img = rawVal ? 'img/socketOn.png' : 'img/socketOff.png'; break; case 'blinds': if (val === 'true' || val === true) { rawVal = 100; } else if (val === 'false' || val === false) { rawVal = 0; } else if (val !== null && parseFloat(val).toString() === val.toString()) { rawVal = parseFloat(val); } var min = $(this).data('min'); var max = $(this).data('max'); if (min === undefined || min === null || min === '') { min = 0; } else { min = parseFloat(min); } if (max === undefined || max === null || max === '') { max = 100; } else { max = parseFloat(max); } if (rawVal > max) rawVal = max; if (rawVal < min) rawVal = min; rawVal = Math.round((rawVal - min) * 100 / (max - min)); rawVal = Math.round(rawVal / 10) * 10; var imgVal = 100 - rawVal; // invert values, in HM 100% means: completely open img = 'img/blind' + imgVal + '.png'; break; default: console.warn('Unknown icon type "' + $(this).data('icon-type') + '"'); break; } $(this).val(val); if (img) { $(this).attr('src', img); } } else if (role === 'slider') { var found = false; var sVal = val.toString(); $(this).find('option').each(function () { if ($(this).val() === sVal) { found = true; return false; } }); if (found) { $(this).val(sVal); $(this).slider().slider('refresh'); } } else if (role === 'select') { $(this).val(val); $(this).selectmenu().selectmenu('refresh'); $(this).prev().removeClass('ui-body-inherit'); } else if($(this).prop('tagName') === 'INPUT') { $(this).val(val); } else { if (val === 'true' || val === true) { rawVal = true; val = _('true'); } else if (val === 'false' || val === false) { rawVal = false; val = _('false'); } else if (val !== null && parseFloat(val).toString() === val.toString()) { val = parseFloat(val); rawVal = val; } var states = $(this).data('states'); if (states && ((role !== 'indicator' && role !== 'error') || val)) { // convert JSON if (states[0] === '{') { try { var values = JSON.parse(states); if (values[val] === undefined) { rawVal = val; } else { rawVal = values[val]; val = _(values[val]); } } catch (ex) { console.error('Cannot parse states for ' + _id); } } else if (typeof states === 'object') { if (states[val] === undefined) { rawVal = val; } else { rawVal = states[val]; val = _(states[val]); } } } if (role === 'indicator' || role === 'error') { if (!rawVal) { $(this).hide(); } else { $(this).show().attr('data-value', rawVal); } if (role === 'error') { if (rawVal) { $(this).addClass('mobile-error'); } else { $(this).removeClass('mobile-error'); } } } var unit = $(this).data('unit') || ''; if (unit) unit = '' + unit + ''; if ($(this).data('title')) { $(this).attr('title', $(this).attr('name') + ' - ' + val + unit); } else { var id = $(this).data('p'); if (id) { if (typeof rawVal === 'boolean') { $('#' + id).html($(this).attr('name')); } else { $('#' + id).html($(this).attr('name') + ' - ' + val + unit); } } else { $(this).html(val + unit); } } } } } }); }, renderWidget: function (obj, elem, parentName) { switch (obj.type) { case 'device': this.renderChannel(obj, elem, parentName); break; case 'channel': this.renderChannel(obj, elem, parentName); break; case 'state': this.renderState(obj, elem, parentName); break; default: } }, isDefaultInvisible: function (role, id) { if (id) { var name = id.split('.').pop(); if (this.defaultInvisibleNames.indexOf(name) !== -1) return true; } if (role) { for (var w = 0; w < this.defaultInvisibleRoles.length; w++) { if (role.indexOf(this.defaultInvisibleRoles[w]) !== -1) return true; } } return false; }, prepareGenericState: function (obj, struct) { var states = obj.common.states || ''; var vStates; var stateName = obj._id.split('.').pop(); if (states) { if (typeof states === 'object') { vStates = states; states = JSON.stringify(states); } else if (typeof states === 'string' && states[0] !== '{') { var values = states.split(';'); states = {}; for (var w = 0; w < values.length; w++) { var parts = values[w].split(':'); states[parts[0]] = parts[1]; } vStates = states; states = JSON.stringify(states); } } if (!this.states[obj._id]) { // read states if (this.queueStates.indexOf(obj._id) === -1) this.queueStates.push(obj._id); } else { if (this.updateStates.indexOf(obj._id) === -1) this.updateStates.push(obj._id); } struct.controls = []; var on = 'on'; var off = 'off'; var roles = obj.common.role ? obj.common.role.split('.') : []; if (roles.indexOf('blind') !== -1 || stateName === 'OPEN' || stateName === 'CLOSE') { on = 'opened'; off = 'closed'; } // add for blinds and dimmer on/off switch if (obj.common.role === 'level.dimmer' || obj.common.role === 'level.blind') { struct.controls.push({ checkbox: true, value: '', control: ' \n' }); } // add slider if (roles.indexOf('level') !== -1 || (obj.common.write && obj.common.type === 'number' && obj.common.max !== undefined)) { struct.controls.push({ value: '
', control: '' }); } else // add button if (roles.indexOf('button') !== -1 || roles.indexOf('action') !== -1) { struct.controls.push({ value: '', control: '' }); // title is on the button struct.title = null; } else // generic types // controllable boolean if (obj.common.write && obj.common.type === 'boolean') { var min; var max; // support of boolean states if (vStates) { if (vStates[0] !== undefined) { min = 0; off = vStates[0]; } else if (vStates['false'] !== undefined) { min = false; off = vStates['false']; } else { var count = 0; for (var vv in vStates) { if (count === 0) { min = vv; off = vStates[vv]; } else if (count === 1) { on = vStates[vv]; max = vv; break; } count++; } } if (vStates[1] !== undefined) { max = 1; on = vStates[1]; } else if (vStates['true'] !== undefined) { max = true; on = vStates['true']; } } else { min = (obj.common.min !== undefined ? obj.common.min : false); max = (obj.common.max !== undefined ? obj.common.max : true); } var length = off.length; if (on.length > length) length = on.length; length = 70 + length * 7; if (length < 112) length = 112; struct.controls.push({ checkbox: true, value: '', control: ' ' }); } else // controllable number, but as text if (obj.common.write && obj.common.type === 'number' && obj.common.max !== undefined && !states) { struct.controls.push({ value: '', control: '' }); } else if (obj.common.write && !states) { struct.controls.push({ set: true, value: '' + (obj.common.unit ? '' + obj.common.unit + '': ''), valueStyle: 'margin-top: 16px', control: '' }); } else if (obj.common.write && states) { var text = '\n'; struct.controls.push({ value: '', select: true, control: text }); } else { // non controllable value struct.controls.push({ value: '', lastChange: (obj.common.type === 'boolean') ? '' : undefined }); } return struct; }, prepareElement: function (obj, parentName, struct) { var i; var id; var name = (obj.common.mobile && obj.common.mobile[this.user]) ? obj.common.mobile[this.user].name || obj.common.name || obj._id : obj.common.name || obj._id; struct = struct || {}; // ignore indicators if (obj.common.role && obj.common.role.match(/^indicator\./) && this.ignoreIndicators.indexOf(obj.common.role) === -1) return ''; var name; if (obj.common.mobile && obj.common.mobile[this.user] && obj.common.mobile[this.user].name) { name = obj.common.mobile[this.user].name } else { name = obj.common.name || obj._id; name = decodeURIComponent(name); // remove room or function name from device name if (parentName) { var reg1 = new RegExp('[-.\/]+' + parentName + '[-.\/]+', 'gi'); var reg2 = new RegExp('[-.\/]+' + parentName, 'gi'); var reg3 = new RegExp(parentName + '[-.\/]+', 'gi'); var reg4 = new RegExp(parentName, 'gi'); name = name.replace(reg1, '.'); name = name.replace(reg2, ''); name = name.replace(reg3, ''); name = name.replace(reg4, ''); name = name.replace(/_/g, ' '); name = name.replace(/\./g, ' '); try { name = decodeURIComponent(name); } catch(err) { console.error('Cannot decode: ' + name + '(' + err + ')'); } var words = name.split(/\s+/); for (var w = words.length - 1; w >= 0; w--) { if (!words[w]) { words.splice(w, 1); continue; } if (!words[w].match(/^[A-ZÜÖÄА-Я0-9]+$/)) { words[w] = words[w][0].toUpperCase() + words[w].substring(1).toLowerCase(); } } name = words.join(' '); } } // try to translate the state anme if (obj.type === 'state') name = _(name); struct.title = name; var mobile = obj.common.mobile && obj.common.mobile[this.user]; var type; if (mobile && (type = obj.common.mobile[this.user].type)) { struct.icon = { type: type, min: (obj.common.min === undefined) ? 0 : parseFloat(obj.common.min) || 0, max: (obj.common.max === undefined) ? 100 : parseFloat(obj.common.max) || 0 }; } else if (mobile && obj.common.mobile[this.user].icon) { struct.icon = obj.common.mobile[this.user].icon; } else if (obj.common.icon) { var adapter = obj._id.split('.').shift(); if (obj.common.icon[0] === '/' && obj.common.icon[1] === '/') { struct.icon = obj.common.icon.substring(1); } else { struct.icon = '/adapter/' + adapter + '/' + obj.common.icon; } } if (obj.children && obj.children.length) { //html += ''; struct.children = {}; for (i = 0; i < obj.children.length; i++) { id = obj.children[i]; if (!this.editMode && this.objects[id].common.mobile && this.objects[id].common.mobile[this.user] && this.objects[id].common.mobile[this.user].visible === false) continue; if (this.objects[id] && this.objects[id].type === 'state') { struct.children[id] = struct.children[id] || {}; struct.children[id].parent = obj._id; this.prepareElement(this.objects[id], obj.common.name || obj._id, struct.children[id]); if (!struct.children[id].controls && !struct.children[id].children) delete struct.children[id]; } } // Check if any child is visible var anyChild = false; for (var c in struct.children) { if (struct.children.hasOwnProperty(c)) { anyChild = true; break; } } if (!anyChild) delete struct.children; } else if (this.editMode || !obj.common.mobile || !obj.common.mobile[this.user] || obj.common.mobile[this.user].visible !== false) { // do not show some buttons by default if (!this.editMode && (!obj.common.mobile || !obj.common.mobile[this.user] || obj.common.mobile[this.user].visible === undefined) && this.isDefaultInvisible(obj.common.role, obj._id)) { // ignore it if not explicit enabled } else { this.prepareGenericState(obj, struct); } } return struct; }, renderIndicators: function (obj, $elem, originId) { var id; // try to find some in device itself var parent = obj._id.split('.'); parent.pop(); parent = parent.join('.'); if (this.objects[parent] && this.objects[parent].type === 'device') { this.renderIndicators(this.objects[parent], $elem, originId); } else { var checked = $elem.data('indicators') || []; if (checked.indexOf(obj._id) === -1) { var $indicators = $elem.find('.mobile-indicators'); if (!$indicators.length) { $elem.append(''); $indicators = $elem.find('.mobile-indicators'); } checked.push(obj._id); $elem.data('indicators', checked); if (obj.children) { for (var i = 0; i < obj.children.length; i++) { id = obj.children[i]; if (this.objects[id] && this.objects[id].common) { if (this.objects[id].common.role && this.objects[id].common.role.match(/^indicator\./) && this.ignoreIndicators.indexOf(obj.common.role) === -1) { // do not render WORKING and DIRECTION for other channels than origin if ((this.objects[id].common.role === 'indicator.working' || this.objects[id].common.role === 'indicator.direction') && originId !== id.substring(0, originId.length)) { continue; } var stateName = id.split('.').pop(); if (this.config.indicators[stateName] !== undefined && !this.config.indicators[stateName]) continue; if (!this.states[id]) { // read states if (this.queueStates.indexOf(id) === -1) this.queueStates.push(id); } else { if (this.updateStates.indexOf(id) === -1) this.updateStates.push(id); } var states = this.objects[id].common.states || ''; if (states) { if (typeof states === 'object') { states = JSON.stringify(states); } else if (typeof states === 'string' && states[0] !== '{') { var values = states.split(';'); states = {}; for (var v = 0; v < values.length; v++) { var parts = values.split(':'); states[parts[0]] = parts[1]; } states = JSON.stringify(states); } } var name = (this.objects[id].common.name || id).split('.').pop().replace(/_/g, ' '); var _id = id.replace(/\./g, '-'); var text = '' + '' + (control.control || '') + ' | \n'; html += '' + (control.value || '') + ' | \n'; } else if (control.checkbox && !control.value) { html += '' + (control.control || '') + ' | \n'; html += '' + (parent.title || '') + ' | \n'; // show title only one time parent.title = null; } else { if (parent.title && control.control) { html += '' + (control.value || '').replace('mobile-value', 'mobile-value mobile-value-big mobile-value-with-units') + ' | \n'; //html += ''; html += ' | ';
html += '
| ';
parent.title = null;
} else if (parent.title && !control.control) {
html += ' ' + (control.value || '') + ' | \n'; //html += ''; html += ' | ';
if (control.lastChange) {
html += ' | ';
parent.title = null;
} else if (control.control) {
// just control or just value
html += ' ' + (control.value || '') + ' | \n'; //html += '' + (control.control || '') + ' | \n'; html += '' + (control.control || '') + ' | \n'; } else { } } /*if (parent.icon) { html += ''; html += parent.icon ? '' : ''; html += ' | '; }*/ html += '
' + (control.value || '') + (control.control || '') + ' | \n'; html += '';
html += parent.title ? ' ' + parent.title + ' \n' : '';
html += state && state.title ? '' + state.title + ' \n' : '';
html += control.lastChange ? ' ' : '';
html += ' | '; if (parent.icon) { if (typeof parent.icon === 'object') { html += ''; } else { html += ''; } } html += ' |