2359 lines
110 KiB
JavaScript
2359 lines
110 KiB
JavaScript
/**
|
||
* 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 = '<span class="mobile-value-units">' + unit + '</span>';
|
||
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:
|
||
' <select class="mobile-control" data-mobile-id="' + obj._id + '" data-role="slider" data-min="' + (obj.common.min !== undefined ? obj.common.min : 0) + '" data-max="' + (obj.common.max !== undefined ? obj.common.max : 100) + '" >\n' +
|
||
' <option value="' + (obj.common.min !== undefined ? obj.common.min : 0) + '">' + _(off) + '</option>\n' +
|
||
' <option value="' + (obj.common.max !== undefined ? obj.common.max : 100) + '">' + _(on) + '</option>\n' +
|
||
' </select>\n'
|
||
});
|
||
}
|
||
|
||
// add slider
|
||
if (roles.indexOf('level') !== -1 || (obj.common.write && obj.common.type === 'number' && obj.common.max !== undefined)) {
|
||
struct.controls.push({
|
||
value: '<div class="mobile-value ' + (obj.common.unit ? 'mobile-value-with-units' : 'mobile-value-alone') + '" data-role="value" data-mobile-id="' + obj._id + '" data-unit="' + (obj.common.unit || '') + '" data-type="' + obj.common.type + '" data-states=' + "'" + states + "'" + '></div>',
|
||
control: '<input class="mobile-control" type="range" data-mobile-id="' + obj._id + '" min="' + (obj.common.min !== undefined ? obj.common.min : 0) + '" max="' + (obj.common.max !== undefined ? obj.common.max : 100) + '" />'
|
||
});
|
||
} else
|
||
// add button
|
||
if (roles.indexOf('button') !== -1 || roles.indexOf('action') !== -1) {
|
||
struct.controls.push({
|
||
value: '',
|
||
control:
|
||
'<input ' +
|
||
'class="mobile-control" ' +
|
||
'type="button" ' +
|
||
'data-mobile-id="' + obj._id + '" ' +
|
||
'data-role="value" ' +
|
||
'data-unit="' + (obj.common.unit || '') + '" ' +
|
||
'data-states=' + "'" + states + "'" + ' ' +
|
||
'data-type="' + obj.common.type + '" ' +
|
||
'value="' + struct.title + '"/>'
|
||
});
|
||
// 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:
|
||
' <select class="mobile-control" data-mobile-id="' + obj._id + '" data-role="slider" data-min="' + min + '" data-max="' + max + '" data-width="' + length + 'px">\n' +
|
||
' <option value="' + min + '">' + _(off) + '</option>\n' +
|
||
' <option value="' + max + '">' + _(on) + '</option>\n' +
|
||
' </select>'
|
||
});
|
||
} else
|
||
// controllable number, but as text
|
||
if (obj.common.write && obj.common.type === 'number' && obj.common.max !== undefined && !states) {
|
||
struct.controls.push({
|
||
value: '<div class="mobile-value ' + (obj.common.unit ? 'mobile-value-with-units' : 'mobile-value-alone') + '" data-mobile-id="' + obj._id + '" data-role="value" data-unit="' + (obj.common.unit || '') + '" data-type="' + obj.common.type + '" data-states=' + "'" + states + "'" + '></div>',
|
||
control: '<input class="mobile-control" type="range" data-type="' + obj.common.type + '" data-mobile-id="' + obj._id + '" min="' + (obj.common.min !== undefined ? obj.common.min : 0) + '" max="' + (obj.common.max !== undefined ? obj.common.max : 100) + '"/>'
|
||
});
|
||
} else if (obj.common.write && !states) {
|
||
struct.controls.push({
|
||
set: true,
|
||
value: '<input class="mobile-value" data-mobile-id="' + obj._id + '" style="width: 100%" data-type="' + obj.common.type + '" data-states=' + "'" + states + "'" + ' data-role="none"/>' + (obj.common.unit ? '<span>' + obj.common.unit + '</span>': ''),
|
||
valueStyle: 'margin-top: 16px',
|
||
control: '<input ' +
|
||
'class="mobile-control" ' +
|
||
'type="button" ' +
|
||
'data-mobile-id="' + obj._id + '" ' +
|
||
'data-type="set" ' +
|
||
'value="' + _('set') + '"/>'
|
||
});
|
||
} else if (obj.common.write && states) {
|
||
var text = '<select ' +
|
||
'class="mobile-control" ' +
|
||
'data-mobile-id="' + obj._id + '" ' +
|
||
'data-role="select" ' +
|
||
'data-type="' + obj.common.type + '">\n';
|
||
for (var v in vStates) {
|
||
text += '<option value="' + v + '">' + _(vStates[v]) + '</option>\n';
|
||
}
|
||
text += '</select>\n';
|
||
|
||
struct.controls.push({
|
||
value: '',
|
||
select: true,
|
||
control: text
|
||
});
|
||
} else {
|
||
// non controllable value
|
||
struct.controls.push({
|
||
value: '<div ' +
|
||
'data-mobile-id="' + obj._id + '" ' +
|
||
'class="mobile-value ' + (obj.common.unit ? 'mobile-value-with-units' : 'mobile-value-alone') + '" ' +
|
||
'data-role="value" ' +
|
||
'data-unit="' + (obj.common.unit || '') + '" ' +
|
||
'data-states=' + "'" + states + "'" + ' ' +
|
||
'data-type="' + obj.common.type + '"></div>',
|
||
lastChange: (obj.common.type === 'boolean') ? '<div class="mobile-last-change" data-role="lastChange" data-mobile-id="' + obj._id + '"></div>' : 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 += '</div>';
|
||
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('<div class="mobile-indicators"></div>');
|
||
$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 =
|
||
'<a href="#' + _id + '" ' +
|
||
'style="display: none" ' +
|
||
'data-mobile-id="' + id + '" ' +
|
||
'data-p="' + _id + '-p" ' +
|
||
'data-states=' + "'" + states + "'" + ' ' +
|
||
'name="' + name + '" ' +
|
||
'data-rel="popup" ' +
|
||
'data-type="' + this.objects[id].common.type + '" ' +
|
||
'data-role="indicator" ' +
|
||
'class="mobile-widget-a mobile-value mobile-' + this.objects[id].common.role.replace(/\./g, '-') + '" ' +
|
||
'data-transition="pop"></a>' +
|
||
'<div data-history="false" data-role="popup" id="' + _id +'" style="background: gray">' +
|
||
'<p id="' + _id + '-p"></p></div>';
|
||
|
||
$indicators.append(text);
|
||
}
|
||
if (this.objects[id].children && this.objects[id].children.length) {
|
||
this.renderIndicators(this.objects[id], $elem, originId);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
|
||
formatLastChange: function (ms) {
|
||
if (ms < 946684800000) ms *= 1000; // if less than 2000.01.01 may be it is seconds
|
||
var now = new Date().getTime();
|
||
var seconds = Math.round((now - ms) / 1000);
|
||
var text = '<img class="mobile-icon-last-change" src="img/lastChange.png"/>';
|
||
// format seconds
|
||
if (seconds < 60) {
|
||
text += _('%s seconds ago', seconds);
|
||
} else if (seconds < 180) { // under 3 minutes
|
||
text += _('ca. %s minutes ago', Math.floor(seconds / 60));
|
||
} else if (seconds < 600) { // under 10 minutes
|
||
text += _('%s minutes ago', Math.round(seconds / 60));
|
||
} else if (seconds < 36000) { // under 10 hours
|
||
text += _('%s h. and %s m. ago', Math.floor(seconds / 3600), Math.round(seconds / 60) % 60);
|
||
} else if (seconds < 86400) { // under one day
|
||
text += _('%s hours ago', Math.floor(seconds / 3600), Math.round(seconds / 60) % 60);
|
||
} else if (seconds < 86400) { // under 3 days
|
||
text += _('%s days and %s h. ago', Math.floor(seconds / 86400), Math.round(seconds / 3600) % 24);
|
||
} else {
|
||
text += _('%s days ago', Math.round(seconds / 86400));
|
||
}
|
||
return text;
|
||
},
|
||
|
||
_renderSingleSubState: function (control, parent, id) {
|
||
var html = '';
|
||
html += '<' + (this.editMode && !control.oneState ? 'li' : 'div') + ' style="width: 100%" class="' + (control.id ? 'mobile-visibility' : '') + '" ' + (control.id ? ' data-edit-id="' + control.id + '"' : '') + '><table class="mobile-widget-table">';
|
||
html += '<tr>\n';
|
||
|
||
var icon = '';
|
||
if (parent.icon) {
|
||
if (typeof parent.icon === 'object') {
|
||
icon = '<img class="mobile-widget-icon mobile-widget-icon-floating" style="padding-right: 10px;" data-mobile-id="' + id + '" data-type="icon" data-icon-type="' + parent.icon.type + '" data-min="' + parent.icon.min + '" data-max="' + parent.icon.max + '"/>';
|
||
} else {
|
||
icon = '<img class="mobile-widget-icon mobile-widget-icon-floating" style="padding-right: 10px;" src="' + parent.icon + '"/>';
|
||
}
|
||
}
|
||
|
||
if (control.set) {
|
||
html += ' <td class="mobile-widget-table-begin mobile-theme-' + this.config.theme + '">' + (control.control || '') + '</td>\n';
|
||
html += ' <td class="mobile-widget-table-end mobile-widget-title mobile-widget-title-normal" data-edit-id="' + id + '">' + (control.value || '') + '</td>\n';
|
||
} else
|
||
if (control.checkbox && !control.value) {
|
||
html += ' <td class="mobile-widget-table-begin mobile-theme-' + this.config.theme + '">' + (control.control || '') + '</td>\n';
|
||
html += ' <td class="mobile-widget-table-end mobile-widget-title mobile-widget-title-normal" data-edit-id="' + id + '">' + (parent.title || '') + '</td>\n';
|
||
// show title only one time
|
||
parent.title = null;
|
||
} else {
|
||
if (parent.title && control.control) {
|
||
html += '<td class="mobile-widget-table-begin mobile-theme-' + this.config.theme + '" style="' + (control.valueStyle || '') + '">' + (control.value || '').replace('mobile-value', 'mobile-value mobile-value-big mobile-value-with-units') + '</td>\n';
|
||
//html += '<td class="mobile-widget-table-control">';
|
||
html += '<td class="mobile-widget-table-end ui-body-b ui-body-inherit">';
|
||
html += ' <table class="mobile-widget-table">';
|
||
html += ' <tr><td><div class="mobile-widget-title mobile-widget-title-small" data-edit-id="' + id + '">' + parent.title + icon + '</div></td></tr>\n';
|
||
html += ' <tr><td><div>' + control.control + '</div></td></tr>\n';
|
||
html += ' </table>';
|
||
html += '</td>';
|
||
parent.title = null;
|
||
} else if (parent.title && !control.control) {
|
||
html += ' <td class="mobile-widget-table-begin mobile-theme-' + this.config.theme + '">' + (control.value || '') + '</td>\n';
|
||
//html += '<td class="mobile-widget-table-control">';
|
||
html += '<td class="mobile-widget-table-end ui-body-b ui-body-inherit">';
|
||
if (control.lastChange) {
|
||
html += ' <table class="mobile-widget-table">';
|
||
html += ' <tr><td><div class="mobile-widget-title mobile-widget-title-small" data-edit-id="' + id + '">' + parent.title + '</div></td></tr>\n';
|
||
html += ' <tr><td><div class="mobile-widget-last-change">' + control.lastChange + '</div></td></tr>\n';
|
||
html += ' </table>';
|
||
} else {
|
||
html += ' <div class="mobile-widget-title mobile-widget-title-normal" data-edit-id="' + id + '">' + parent.title + '</div>\n';
|
||
}
|
||
html += ' </td>';
|
||
parent.title = null;
|
||
} else if (control.control) {
|
||
// just control or just value
|
||
html += ' <td class="mobile-widget-table-begin mobile-theme-' + this.config.theme + '">' + (control.value || '') + '</td>\n';
|
||
//html += ' <td class="mobile-widget-table-control">' + (control.control || '') + '</td>\n';
|
||
html += ' <td class="mobile-widget-table-end ui-body-b ui-body-inherit">' + (control.control || '') + '</td>\n';
|
||
} else {
|
||
|
||
}
|
||
}
|
||
/*if (parent.icon) {
|
||
html += '<td class="mobile-widget-table-icon">';
|
||
html += parent.icon ? '<img class="mobile-widget-icon mobile-widget-icon-floating" src="' + parent.icon + '" />' : '';
|
||
html += '</td>';
|
||
}*/
|
||
|
||
html += '</tr>\n';
|
||
html += '</table></' + (this.editMode && !control.oneState ? 'li' : 'div') + '>\n';
|
||
return html;
|
||
},
|
||
|
||
_renderCombinedSubState : function (control, parent, state, id) {
|
||
// used only in non edit mode
|
||
var html = '';
|
||
html += '<div><table class="mobile-widget-table mobile-widget-b"><tr>\n';
|
||
html += ' <td class="mobile-widget-table-begin mobile-theme-' + this.config.theme + '">' + (control.value || '') + (control.control || '') + '</td>\n';
|
||
html += ' <td class="mobile-widget-table-end" style="position: relative">';
|
||
html += parent.title ? '<div class="mobile-value-group-title">' + parent.title + '</div>\n' : '';
|
||
html += state && state.title ? '<div class="mobile-value-small-title">' + state.title + '</div>\n' : '';
|
||
html += control.lastChange ? '<div class="mobile-widget-last-change">' + control.lastChange + '</div>' : '';
|
||
html += '</td><td class="mobile-widget-table-icon">';
|
||
if (parent.icon) {
|
||
if (typeof parent.icon === 'object') {
|
||
html += '<img class="mobile-widget-icon mobile-widget-icon-floating" data-mobile-id="' + id + '" data-type="icon" data-icon-type="' + parent.icon.type + '" data-min="' + parent.icon.min + '" data-max="' + parent.icon.max + '"/>';
|
||
} else {
|
||
html += '<img class="mobile-widget-icon mobile-widget-icon-floating" src="' + parent.icon + '" />';
|
||
}
|
||
}
|
||
html += '</td></tr></table></div>\n';
|
||
return html;
|
||
},
|
||
|
||
renderChannel: function (obj, $elem, parentName) {
|
||
var _mobile = obj.common && obj.common.mobile ? obj.common.mobile[this.user] : null;
|
||
if (!this.editMode && _mobile && _mobile.visible === false) return;
|
||
|
||
var struct = this.prepareElement(obj, parentName);
|
||
|
||
if (!struct.controls && !struct.children) return;
|
||
|
||
var html = '<li class="mobile-widget" data-edit-id="' + obj._id + '">\n';
|
||
|
||
// show channel description
|
||
html += '<div class="mobile-widget-a mobile-visibility" title="' + (obj.common.role || '') +'" data-edit-id="' + obj._id + '">\n';
|
||
|
||
var count = 0;
|
||
var order;
|
||
var firstChild;
|
||
for (var child in struct.children) {
|
||
if (!firstChild) firstChild = child;
|
||
count++;
|
||
}
|
||
|
||
var c;
|
||
order = _mobile ? _mobile.order || [] : [];
|
||
if (struct.children) {
|
||
for (child in struct.children) {
|
||
if (order.indexOf(child) === -1) order.push(child);
|
||
}
|
||
for (c = order.length - 1; c >= 0; c--) {
|
||
if (!struct.children[order[c]]) order.splice(c, 1);
|
||
}
|
||
} else {
|
||
order = [];
|
||
}
|
||
|
||
// do not show title if only one child
|
||
if (count < 2 && !this.editMode) {
|
||
//struct.title = '';
|
||
}
|
||
|
||
// if only one child and not slider
|
||
if (!this.editMode && count === 1 && (struct.children[firstChild].controls[0].select || struct.children[firstChild].controls[0].checkbox || !struct.children[firstChild].controls[0].control)) {
|
||
// Show all in one line
|
||
// control | text | icon
|
||
struct.children[firstChild].controls[0].id = firstChild; // enable visibility
|
||
html += this._renderCombinedSubState(struct.children[firstChild].controls[0], struct, struct.children[child].controls.length === 1 ? struct.children[firstChild]: null, firstChild);
|
||
|
||
for (c = 1; c < struct.children[child].controls.length; c++) {
|
||
struct.children[child].controls[c].id = child; // enable visibility
|
||
html += this._renderSingleSubState(struct.children[child].controls[c], struct.children[child], child);
|
||
}
|
||
} else {
|
||
// place title
|
||
if (struct.icon) {
|
||
if (typeof struct.icon === 'object') {
|
||
html += '<img class="mobile-widget-icon" data-mobile-id="' + obj._id + '" data-type="icon" data-icon-type="' + struct.icon.type + '" data-min="' + struct.icon.min + '" data-max="' + struct.icon.max + '"/>';
|
||
} else {
|
||
html += '<img class="mobile-widget-icon" src="' + struct.icon + '"/>';
|
||
}
|
||
}
|
||
html += struct.title ? '<div class="mobile-widget-title mobile-value-group-title" data-edit-id="' + obj._id + '">' + struct.title + '</div>\n' : '';
|
||
|
||
html += '<' + (this.editMode ? 'ul' : 'div') + ' class="mobile-widget-b" title="' + (obj.common.role || '') +'" style="padding: 0" data-edit-id="' + obj._id + '">\n';
|
||
|
||
// try to build states
|
||
for (var or = 0; or < order.length; or++) {
|
||
child = order[or];
|
||
if (!struct.children[child].controls) continue;
|
||
for (c = 0; c < struct.children[child].controls.length; c++) {
|
||
struct.children[child].controls[c].id = child; // enable visibility
|
||
html += this._renderSingleSubState(struct.children[child].controls[c], struct.children[child], child);
|
||
}
|
||
}
|
||
html += '</' + (this.editMode ? 'ul' : 'div') + '>\n';
|
||
}
|
||
|
||
html += '</div>\n';
|
||
html += '</li>\n';
|
||
|
||
|
||
var $channel = $(html);
|
||
$elem.append($channel);
|
||
|
||
if ($elem.hasClass('ui-listview')) {
|
||
$elem.listview('refresh');
|
||
}
|
||
|
||
if (!this.editMode) this.renderIndicators(obj, $channel, obj._id);
|
||
},
|
||
|
||
renderState: function (obj, $elem, parentName) {
|
||
if (!this.editMode && obj.common && obj.common.mobile && obj.common.mobile[this.user] && obj.common.mobile[this.user].visible === false) return;
|
||
var struct = this.prepareElement(obj, parentName);
|
||
|
||
if (!struct.controls) return;
|
||
|
||
var html = '<li class="mobile-widget" data-edit-id="' + obj._id + '">\n';
|
||
// show State description
|
||
html += '<div class="mobile-widget-a mobile-visibility" title="' + (obj.common.role || '') +'" data-edit-id="' + obj._id + '">\n';
|
||
|
||
var c;
|
||
if (!this.editMode && (struct.controls[0].select || struct.controls[0].checkbox || !struct.controls[0].control)) {
|
||
// Show all in one line
|
||
// control | text | icon
|
||
html += this._renderCombinedSubState(struct.controls[0], struct, null, obj._id);
|
||
|
||
for (c = 1; c < struct.controls.length; c++) {
|
||
html += this._renderSingleSubState(struct.controls[c], struct, obj._id);
|
||
}
|
||
} else {
|
||
// place title
|
||
if (struct.icon) {
|
||
if (typeof struct.icon === 'object') {
|
||
html += '<img class="mobile-widget-icon" data-mobile-id="' + obj._id + '" data-type="icon" data-icon-type="' + struct.icon.type + '" data-min="' + struct.icon.min + '" data-max="' + struct.icon.max + '"/>';
|
||
} else {
|
||
html += '<img class="mobile-widget-icon" src="' + struct.icon + '"/>';
|
||
}
|
||
}
|
||
html += struct.title ? '<div class="mobile-value-group-title">' + struct.title + '</div>\n' : '';
|
||
|
||
html += '<div class="mobile-widget-b">\n';
|
||
|
||
// try to build state
|
||
for (c = 0; c < struct.controls.length; c++) {
|
||
struct.controls[c].oneState = true;
|
||
html += this._renderSingleSubState(struct.controls[c], struct, obj._id);
|
||
}
|
||
html += '</div>\n';
|
||
}
|
||
|
||
|
||
html += '</div>\n';
|
||
html += '</li>\n';
|
||
|
||
$elem.append(html);
|
||
|
||
if ($elem.hasClass('ui-listview')) $elem.listview('refresh');
|
||
},
|
||
|
||
renderEditButtons: function () {
|
||
if (this.editMode) {
|
||
var that = this;
|
||
$(document).on('pageshow', function (event) {
|
||
// render root pages
|
||
$('.mobile-visibility-root').each(function () {
|
||
if (!$(this).is(':visible')) return;
|
||
if ($(this).parent().find('.mobile-edit-enum').length) return;
|
||
|
||
var id = $(this).data('edit-id');
|
||
var href = $(this).attr('href');
|
||
that.objects[id].common.mobile = that.objects[id].common.mobile || {};
|
||
that.objects[id].common.mobile[that.user] = that.objects[id].common.mobile[that.user] || {};
|
||
var mobile = that.objects[id].common.mobile[that.user];
|
||
|
||
// everything is visible by default
|
||
if (mobile.visible === undefined) {
|
||
mobile.visible = !that.isDefaultInvisible(that.objects[id].common.role, id);
|
||
that.saveSettings(id);
|
||
}
|
||
|
||
var $overlay = $('<div data-href="' + href + '" class="mobile-edit-enum ' + (!mobile.visible ? 'mobile-invisible' : '') + '" ></div>');
|
||
var $checkbox = $('<div data-edit-id="' + (id || '') + '" class="mobile-enum-visibility">' + (mobile.visible ? '✓' : '') + '</div>');
|
||
var $name = $('<a data-edit-id="' + (id || '') + '" class="mobile-edit-name ui-btn ui-shadow ui-corner-all ui-icon-edit ui-btn-icon-notext ui-btn-inline"></a>');
|
||
//var $sort = $('<a class="mobile-edit-sort ui-btn ui-icon-bars ui-btn-icon-notext ui-btn-inline" style="opacity: 0.6;"></a>');
|
||
|
||
$overlay.append($checkbox);
|
||
$overlay.append($name);
|
||
//$overlay.append($sort);
|
||
$(this).parent().prepend($overlay);
|
||
|
||
$overlay.click(onForward);
|
||
$checkbox.click(onEnumVisibility);
|
||
$name.click(onEditName);
|
||
});
|
||
|
||
// render second menu
|
||
$('.mobile-visibility-subroot').each(function () {
|
||
if (!$(this).is(':visible')) return;
|
||
if ($(this).parent().find('.mobile-edit-subenum').length) return;
|
||
|
||
var id = $(this).data('edit-id');
|
||
var href = $(this).attr('href');
|
||
that.objects[id].common.mobile = that.objects[id].common.mobile || {};
|
||
that.objects[id].common.mobile[that.user] = that.objects[id].common.mobile[that.user] || {};
|
||
var mobile = that.objects[id].common.mobile[that.user];
|
||
|
||
// everything is visible by default
|
||
if (mobile.visible === undefined) {
|
||
mobile.visible = !that.isDefaultInvisible(that.objects[id].common.role, id);
|
||
that.saveSettings(id);
|
||
}
|
||
|
||
var $overlay = $('<div data-href="' + href + '" class="mobile-edit-subenum ' + (!mobile.visible ? 'mobile-invisible' : '') + '"></div>');
|
||
var $checkbox = $('<div style="margin-right: 3em;" data-edit-id="' + (id || '') + '" class="mobile-enum-visibility">' + (mobile.visible ? '✓' : '') + '</div>');
|
||
var $name = $('<a data-edit-id="' + (id || '') + '" class="mobile-edit-name ui-btn ui-shadow ui-corner-all ui-icon-edit ui-btn-icon-notext ui-btn-inline" ></a>');
|
||
var $icon = $('<a data-edit-id="' + (id || '') + '" class="mobile-edit-icon ui-btn ui-shadow ui-corner-all ui-icon-video ui-btn-icon-notext ui-btn-inline"></a>');
|
||
var $sort = $('<a class="mobile-edit-sort ui-btn ui-icon-bars ui-btn-icon-notext ui-btn-inline" style="opacity: 0.6;"></a>');
|
||
|
||
$overlay.append($checkbox);
|
||
$overlay.append($name);
|
||
$overlay.append($icon);
|
||
$overlay.append($sort);
|
||
$(this).parent().prepend($overlay);
|
||
|
||
$overlay.click(onForward);
|
||
$checkbox.click(onEnumVisibility);
|
||
$name.click(onEditName);
|
||
});
|
||
|
||
var typeSelect =
|
||
'<option value="none">' + _('none') + '</option>' +
|
||
'<option value="light">' + _('Light') + '</option>' +
|
||
'<option value="socket">' + _('Socket') + '</option>' +
|
||
'<option value="blinds">' + _('Blinds') + '</option>' +
|
||
'<option value="red">' + _('Red') + '</option>' +
|
||
'<option value="blue">' + _('Green') + '</option>' +
|
||
'<option value="green">' + _('Blue') + '</option>' +
|
||
'<option value="white">' + _('White') + '</option>';
|
||
|
||
// render elements
|
||
$('.mobile-visibility').each(function () {
|
||
if (!$(this).is(':visible')) return;
|
||
var id = $(this).data('edit-id');
|
||
|
||
if ($(this).data('processed')) return;
|
||
$(this).data('processed', true);
|
||
|
||
that.objects[id].common.mobile = that.objects[id].common.mobile || {};
|
||
that.objects[id].common.mobile[that.user] = that.objects[id].common.mobile[that.user] || {};
|
||
var mobile = that.objects[id].common.mobile[that.user];
|
||
|
||
// button is invisible by default
|
||
if (mobile.visible === undefined) {
|
||
mobile.visible = !that.isDefaultInvisible(that.objects[id].common.role, id);
|
||
that.saveSettings(id);
|
||
}
|
||
|
||
var $overlay = $('<div class="mobile-edit-element mobile-edit-' + that.objects[id].type + ' ' + (!mobile.visible ? 'mobile-invisible' : '') + '"></div>');
|
||
var $checkbox = $('<div data-edit-id="' + (id || '') + '" class="mobile-enum-visibility" ' + (that.objects[id].type !== 'state' ? ' style="margin: 0"' : '') + '>' + (mobile.visible ? '✓' : '') + '</div>');
|
||
var margin = that.objects[id].type === 'state' ? '1.6em' : '2.3em';
|
||
var $name = $('<a data-edit-id="' + (id || '') + '" class="mobile-edit-name ui-btn ui-shadow ui-corner-all ui-icon-edit ui-btn-icon-notext ui-btn-inline"' + (that.objects[id].type !== 'state' ? ' style="margin-right: ' + margin + '; margin-top: 0"' : '') + '></a>');
|
||
var $type = $('<fieldset class="mobile-edit-field" data-role="controlgroup" data-type="horizontal" data-mini="true"><select class="mobile-edit-type" data-edit-id="' + (id || '') + '">' +
|
||
typeSelect + '</select></fieldset>');
|
||
var $sort = $('<a class="mobile-edit-sort ui-btn ui-icon-bars ui-btn-icon-notext ui-btn-inline" style="opacity: 0.6;' + (that.objects[id].type !== 'state' ? ' margin-right: 1.6em; margin-top: 0' : '') + '"></a>');
|
||
|
||
$overlay.append($checkbox);
|
||
$overlay.append($name);
|
||
$overlay.append($type);
|
||
$overlay.append($sort);
|
||
$type.find('select').change(onTypeChanged);
|
||
$(this).prepend($overlay);
|
||
|
||
$checkbox.click(onStateVisibility);
|
||
$name.click(onEditName);
|
||
});
|
||
|
||
// detect channels, that have all states hidden
|
||
that.detectAllHiddenStates();
|
||
|
||
$('ul').each(function () {
|
||
var $ul = $(this);
|
||
var $li = $ul.find('> li');
|
||
if (!$ul.data('edit-id')) {
|
||
$li.find('.mobile-edit-sort').remove();
|
||
return;
|
||
}
|
||
|
||
if ($li.length > 1) {
|
||
$ul.sortable();
|
||
$ul.disableSelection().bind('sortstop', function(event, ui) {
|
||
// get order
|
||
var $li = $(this).find('> li');
|
||
var order = [];
|
||
var rootId = $(this).data('edit-id');
|
||
$li.each(function () {
|
||
var id = $(this).data('edit-id');
|
||
order.push(id);
|
||
});
|
||
that.objects[rootId].common.mobile = that.objects[rootId].common.mobile || {};
|
||
that.objects[rootId].common.mobile[that.user] = that.objects[rootId].common.mobile[that.user] || {};
|
||
that.objects[rootId].common.mobile[that.user].order = order;
|
||
that.saveSettings(rootId);
|
||
//$(this).listview('refresh');
|
||
});
|
||
} else {
|
||
$li.find('.mobile-edit-sort:first').remove();
|
||
}
|
||
});
|
||
});
|
||
}
|
||
},
|
||
|
||
renderIndicatorSettings: function () {
|
||
var text = '<legend>' + _('Enabled indicators') + ':</legend>';
|
||
for (var ind in this.config.indicators) {
|
||
text += '<input type="checkbox" data-name="' + ind + '" id="chb_' + ind + '" class="mobile-indicator-settings" ' + (this.config.indicators[ind] ? 'checked' : '') + '/><label for="chb_' + ind + '" >' + ind + '</label>';
|
||
}
|
||
$('#enabledIndicators').html(text);
|
||
},
|
||
|
||
renderRootPages: function () {
|
||
// http://demos.jquerymobile.com/1.2.1/docs/toolbars/docs-navbar.html
|
||
var grid;
|
||
var count = 0;
|
||
var name;
|
||
var common;
|
||
for (var i = 0; i < this.root.length; i++) {
|
||
common = this.objects[this.root[i]] ? this.objects[this.root[i]].common : null;
|
||
|
||
// hide if invisible
|
||
if (!this.editMode && common && common.mobile && common.mobile[this.user] && common.mobile[this.user].visible === false) continue;
|
||
|
||
count++;
|
||
}
|
||
|
||
switch (count) {
|
||
case 1:
|
||
grid = '0';
|
||
break;
|
||
case 2:
|
||
grid = 'a';
|
||
break;
|
||
case 3:
|
||
grid = 'b';
|
||
break;
|
||
case 4:
|
||
grid = 'c';
|
||
break;
|
||
case 5:
|
||
grid = 'd';
|
||
break;
|
||
default:
|
||
}
|
||
|
||
for (i = 0; i < this.root.length; i++) {
|
||
var navbar = '';
|
||
var rCommon = this.objects[this.root[i]] ? this.objects[this.root[i]].common : null;
|
||
if (!this.editMode && rCommon && rCommon.mobile && rCommon.mobile[this.user] && rCommon.mobile[this.user].visible === false) continue;
|
||
|
||
|
||
// build footer (root menu)
|
||
for (var j = 0; j < this.root.length; j++) {
|
||
common = this.objects[this.root[j]] ? this.objects[this.root[j]].common : null;
|
||
|
||
if (!common) {
|
||
console.error('Invalid object "' + _id + '" ');
|
||
continue;
|
||
}
|
||
|
||
// hide if invisible
|
||
if (!this.editMode && common && common.mobile && common.mobile[this.user] && common.mobile[this.user].visible === false) continue;
|
||
|
||
name = common.mobile && common.mobile[this.user] ? common.mobile[this.user].name || common.name || this.root[j] : common.name || this.root[j];
|
||
|
||
navbar += '<li style="position: relative"><a class="' + (i === j ? 'ui-btn-active ui-state-persist' : '') + ' mobile-visibility-root mobile-widget-title" data-edit-id="' + this.root[j] + '" data-icon="';
|
||
if (this.root[j] === 'enum.rooms') {
|
||
navbar += 'home';
|
||
} else if (this.root[j] === 'enum.functions') {
|
||
navbar += 'gear';
|
||
} else {
|
||
navbar += 'star';
|
||
}
|
||
navbar += '" href="#' + this.objectId2htmlId(this.root[j]) + '">' + _(name) + '</a></li>\n';
|
||
}
|
||
|
||
var menu = '';
|
||
// build footer (root menu)
|
||
var order = (rCommon.mobile && rCommon.mobile[this.user]) ? rCommon.mobile && rCommon.mobile[this.user].order || [] : [];
|
||
|
||
// check if still actual
|
||
for (var k = order.length - 1; k >= 0; k--) {
|
||
var _id = order[k];
|
||
if (_id.substring(0, this.root[i].length + 1) !== this.root[i] + '.') {
|
||
order.splice(k, 1);
|
||
}
|
||
}
|
||
// fill all missing ids into order
|
||
for (var id in this.enums) {
|
||
var _id = this.enums[id]._id;
|
||
if (_id.substring(0, this.root[i].length + 1) === this.root[i] + '.') {
|
||
if (order.indexOf(_id) === -1) order.push(_id);
|
||
}
|
||
}
|
||
|
||
// build content
|
||
for (var k = 0; k < order.length; k++) {
|
||
var _id = order[k];
|
||
common = this.objects[_id] ? this.objects[_id].common : null;
|
||
|
||
if (!common) {
|
||
console.error('Invalid object "' + _id + '" ');
|
||
continue;
|
||
}
|
||
|
||
// hide if invisible
|
||
if (!this.editMode && common && common.mobile && common.mobile[this.user] && common.mobile[this.user].visible === false) continue;
|
||
|
||
name = common.mobile && common.mobile[this.user] ? common.mobile[this.user].name || common.name || _id : common.name || _id;
|
||
|
||
menu += '<li data-edit-id="' + _id + '"><a href="#' + encodeURIComponent(this.objectId2htmlId(_id)) + '" class="mobile-visibility-subroot mobile-widget-title"" data-edit-id="' + _id + '">' + _(name) + '</a></li>';
|
||
}
|
||
|
||
name = rCommon.mobile && rCommon.mobile[this.user] ? rCommon.mobile[this.user].name || rCommon.name || this.root[i] : rCommon.name || this.root[i];
|
||
|
||
var page =
|
||
'<div id="' + this.objectId2htmlId(this.root[i]) + '" data-role="page" class="responsive-grid" data-theme="a">' +
|
||
// header
|
||
' <div data-role="header" data-position="fixed" data-id="f2" data-theme="a" data-fullscreen="false">' +
|
||
' <h1><span class="mobile-prefix"></span><span>' + _(name) + '</span></h1>' +
|
||
' <a href="#info" data-rel="page" data-role="button" data-inline="true" data-icon="info" data-iconpos="notext" class="mobile-info ui-btn-right mobile-info-button"></a>' +
|
||
' </div>' +
|
||
// content
|
||
' <div data-role="content" data-theme="a">' +
|
||
' <ul id="menu_' + this.objectId2htmlId(this.root[i]) + '" data-role="listview" data-inset="true" class="mobile-sortable" data-edit-id="' + this.root[i] + '">' +
|
||
menu +
|
||
' </ul>' +
|
||
' </div>' +
|
||
// footer
|
||
' <div data-position="fixed" data-tap-toggle="false" data-role="footer" data-id="f1" data-theme="a">' +
|
||
' <div data-role="navbar" data-grid="' + grid + '">' +
|
||
' <ul>' + navbar + '</ul>' +
|
||
' </div>' +
|
||
' </div>' +
|
||
'</div>';
|
||
|
||
$('body').append(page);
|
||
}
|
||
|
||
var url = $.mobile.path.parseUrl(location.href);
|
||
|
||
// this is a bug. If use all together something goes wrong and string will not be decoded
|
||
var pageId = decodeURIComponent(url.hash.toString());
|
||
pageId = pageId.substring(1);
|
||
pageId = decodeURIComponent(pageId);
|
||
pageId = pageId.replace(/&.*$/, '');
|
||
this.activePage = pageId || this.objectId2htmlId(this.root[0]);
|
||
this.renderPage(this.activePage);
|
||
this.renderIndicatorSettings();
|
||
|
||
$.mobile.initializePage();
|
||
var that = this;
|
||
setTimeout(function () {
|
||
$.mobile.navigate((!url.hash || url.hash === '#') ? '#' + that.objectId2htmlId(that.root[0]) : url.hash);
|
||
}, 500);
|
||
$('#nav-panel').panel();
|
||
|
||
// manage enumerations
|
||
this.renderEditButtons();
|
||
|
||
// init all indicator settings
|
||
$('.mobile-indicator-settings').change(function () {
|
||
var ind = $(this).data('name');
|
||
that.config.indicators[ind] = $(this).prop('checked');
|
||
that.saveConfig();
|
||
// destroy all second level pages to re-render the indicators
|
||
$('div[data-role="page"]').each(function () {
|
||
if ($(this).attr('id').split('*').length > 2) {
|
||
$(this).remove();
|
||
}
|
||
});
|
||
});
|
||
},
|
||
|
||
renderInfoPage: function () {
|
||
if (this.editMode) {
|
||
$('.mobile-noedit').hide();
|
||
$('.mobile-edit').show();
|
||
$('.mobile-refresh').hide();
|
||
} else {
|
||
$('.mobile-noedit').show();
|
||
$('.mobile-edit').hide();
|
||
$('.mobile-refresh').show();
|
||
}
|
||
$('#info').show();
|
||
|
||
var theme = this.config.theme || 'light';
|
||
|
||
setTimeout(function () {
|
||
$('.mobile-theme-selector').each(function () {
|
||
if ($(this).data('theme') === theme) {
|
||
$(this).parent().addClass('ui-btn-active');
|
||
} else {
|
||
$(this).parent().removeClass('ui-btn-active');
|
||
}
|
||
});
|
||
}, 500);
|
||
},
|
||
|
||
htmlId2objectId: function(id) {
|
||
return id.replace(/\*/g, '.').replace(/§§/g, ' ');
|
||
},
|
||
|
||
objectId2htmlId: function(id) {
|
||
return id.replace(/\./g, '*').replace(/\s/g, '§§');
|
||
},
|
||
|
||
convertValue: function (id, val) {
|
||
if (typeof val === 'string') {
|
||
if (val === 'true') {
|
||
val = true;
|
||
} else
|
||
if (val === 'false') {
|
||
val = false;
|
||
} else {
|
||
var f = parseFloat(val);
|
||
if (f.toString() === val) val = f;
|
||
}
|
||
}
|
||
|
||
return val;
|
||
},
|
||
|
||
renderPage: function (id) {
|
||
if (!id) {
|
||
console.log('no id given');
|
||
return;
|
||
}
|
||
if (id === 'info') {
|
||
return this.renderInfoPage();
|
||
} else {
|
||
$('#info').hide();
|
||
}
|
||
if ($('div[id="' + id + '"]').html()) {
|
||
console.log(id + ' already rendered');
|
||
$('div[id="' + id + '"]').trigger('create');
|
||
return;
|
||
}
|
||
|
||
var name;
|
||
var parentId;
|
||
var parentName = id.split('*');
|
||
id = this.htmlId2objectId(id);
|
||
parentName.pop();
|
||
parentName = parentName.join('.');
|
||
var common = this.enums[id] ? this.enums[id].common : null;
|
||
|
||
if (this.enums[parentName]) {
|
||
if (!common) debugger;
|
||
|
||
parentId = parentName;
|
||
parentName = (this.enums[parentId].common.mobile && this.enums[parentId].common.mobile[this.user]) ? this.enums[parentId].common.mobile[this.user].name || this.enums[parentId].common.name : this.enums[parentId].common.name;
|
||
name = (common && common.mobile && common.mobile[this.user]) ? common.mobile[this.user].name || common.name || id : common.name || id;
|
||
} else {
|
||
parentId = '';
|
||
name = '';
|
||
}
|
||
|
||
var hrefId = this.objectId2htmlId(id);
|
||
// header
|
||
var page =
|
||
'<div id="' + hrefId + '" data-role="page" class="ui-responsive-panel pages ui-body-a" data-theme="f">' + // responsive-grid
|
||
' <div data-role="header" data-position="" data-id="f2" data-theme="a" data-fullscreen="false">' +
|
||
' <div class="nav-panel-btn ui-btn ui-btn-icon-notext ui-corner-all ui-icon-bars ui-shadow" style="position: absolute;top: -0.1em;" data-href="' + hrefId + '-nav-panel"></div>' +
|
||
' <a href="#' + encodeURIComponent(this.objectId2htmlId(parentId)) + '" data-role="button" data-icon="arrow-l" style="margin-left: 2.3em">' + _(parentName) + '</a>' +
|
||
' <h1><span class="mobile-prefix"></span>' + _(name) + '</h1>' +
|
||
' <a href="#info" data-rel="page" data-role="button" data-inline="true" data-icon="info" data-iconpos="notext" class="mobile-info ui-btn-right mobile-info-button"></a>' +
|
||
' </div>';
|
||
// content
|
||
page +=
|
||
' <div data-role="content" data-theme="a">' +
|
||
' <ul data-edit-id="' + id + '" data-role="listview" data-inset="true" class="mobile-sortable">' +
|
||
' </ul>' +
|
||
' </div>';
|
||
page += '</div>';
|
||
|
||
if (this.panelActive !== parentId) {
|
||
this.panelActive = parentId;
|
||
// build sidebar
|
||
var members = this.enums[parentId] && this.enums[parentId].children ? this.enums[parentId].children : null;
|
||
var panel = '';
|
||
|
||
if (members) {
|
||
var order = (this.enums[parentId].common.mobile && this.enums[parentId].common.mobile[this.user]) ? this.enums[parentId].common.mobile[this.user].order || [] : members;
|
||
// check if all members are still in order
|
||
for (var i = 0; i < members.length; i++) {
|
||
if (order.indexOf(members[i]) === -1) order.push(members[i]);
|
||
}
|
||
|
||
// build content
|
||
for (var k = 0; k < order.length; k++) {
|
||
var _id = order[k];
|
||
var common = this.objects[_id] ? this.objects[_id].common : null;
|
||
|
||
// hide if invisible
|
||
if (!this.editMode && common && common.mobile && common.mobile[this.user] && common.mobile[this.user].visible === false) continue;
|
||
|
||
var name = common.mobile && common.mobile[this.user] ? common.mobile[this.user].name || common.name || _id : common.name || _id;
|
||
|
||
panel +=' <li data-filtertext="wai-aria voiceover accessibility screen reader">';
|
||
panel +=' <a href="#' + encodeURIComponent(this.objectId2htmlId(_id)) + '">' + _(name) + '</a>';
|
||
panel +=' </li>';
|
||
}
|
||
}
|
||
$('#nav-panel-ul').html(panel);
|
||
|
||
try {
|
||
$('#nav-panel-ul').listview('refresh');
|
||
} catch (e) {
|
||
$('#nav-panel-ul').listview();
|
||
}
|
||
}
|
||
|
||
var $page = $(page);
|
||
$('body').append($page);
|
||
var that = this;
|
||
|
||
$page.find('.nav-panel-btn').click(function () {
|
||
$('#nav-panel').show().panel('open');
|
||
});
|
||
|
||
if (!this.enums[id] || !this.enums[id].common) {
|
||
return;
|
||
}
|
||
|
||
var members = this.enums[id].common.members || [];
|
||
var $ul = $('div[id="' + this.objectId2htmlId(id) + '"] ul');
|
||
|
||
$ul.listview();
|
||
|
||
if (members) {
|
||
var order = (this.enums[id].common.mobile && this.enums[id].common.mobile[this.user]) ? this.enums[id].common.mobile[this.user].order || [] : members;
|
||
// check if all members are still in order
|
||
for (var i = 0; i < members.length; i++) {
|
||
if (order.indexOf(members[i]) === -1) order.push(members[i]);
|
||
}
|
||
// check if all orders are still in members
|
||
for (var i = order.length - 1; i >= 0; i--) {
|
||
if (members.indexOf(order[i]) === -1) {
|
||
order.splice(i, 1);
|
||
}
|
||
}
|
||
for (var i = 0; i < order.length; i++) {
|
||
var children = this.objects[order[i]] ? this.objects[order[i]].children : undefined;
|
||
|
||
this.conn.getObject(order[i], !this.refresh, function (err, obj) {
|
||
if (err) console.error(err);
|
||
|
||
if (obj) {
|
||
obj.children = children;
|
||
that.objects[obj._id] = obj;
|
||
that.renderWidget(obj, $ul, that.enums[id].common.name);
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
if (this.updateStates.length) {
|
||
for (var i = 0; i < this.updateStates.length; i++) {
|
||
this.updateState(this.updateStates[i], true);
|
||
}
|
||
|
||
this.updateStates = [];
|
||
}
|
||
|
||
// read states
|
||
if (this.queueStates.length) {
|
||
this.conn.getStates(this.queueStates, function (err, states) {
|
||
for (var id in states) {
|
||
that.states[id] = states[id];
|
||
that.updateState(id, true);
|
||
}
|
||
|
||
that.queueStates = [];
|
||
});
|
||
}
|
||
|
||
// on change
|
||
$('.mobile-control').unbind('change').change(function (e) {
|
||
if ($(this).prop('tagName') !== 'SELECT') return;
|
||
var id = $(this).data('mobile-id');
|
||
var val = that.convertValue(id, $(this).val());
|
||
if (id && that.states[id].val !== val) {
|
||
that.conn.setState(id, val);
|
||
}
|
||
}).unbind('click').click(function (e) {
|
||
if ($(this).prop('tagName') === 'SELECT') return;
|
||
var id = $(this).data('mobile-id');
|
||
if ($(this).attr('type') === 'button') {
|
||
if ($(this).data('type') === 'set') {
|
||
var val = that.convertValue(id, $('.mobile-value[data-mobile-id="' + id + '"]').val());
|
||
if (id) that.conn.setState(id, val);
|
||
} else {
|
||
if (id) that.conn.setState(id, true);
|
||
}
|
||
} else {
|
||
var val = that.convertValue(id, $(this).val());
|
||
if (id && that.states[id].val !== val) {
|
||
that.conn.setState(id, val);
|
||
}
|
||
}
|
||
});
|
||
|
||
setTimeout(function () {
|
||
$('.pages').unbind('swipeleft').on('swipeleft', function(){
|
||
$('#nav-panel').panel('close');
|
||
}).unbind('swiperight').on('swiperight', function(){
|
||
$('#nav-panel').panel('open');
|
||
});
|
||
|
||
// set slider width
|
||
$('select[data-role="slider"]').each(function () {
|
||
$(this).next().css('width', $(this).data('width'));
|
||
});
|
||
|
||
$('select[data-role="select"]').each(function () {
|
||
$(this).prev().removeClass('ui-body-inherit');
|
||
$(this).on('change', function () {
|
||
$(this)
|
||
.prev()
|
||
.removeClass('ui-body-inherit ui-focus')
|
||
.parent()
|
||
.removeClass('ui-body-inherit ui-focus');
|
||
});
|
||
});
|
||
|
||
$('.mobile-control').on('slidestop stop', function () {
|
||
var id = $(this).data('mobile-id');
|
||
if (id) {
|
||
var val = that.convertValue(id, $(this).val());
|
||
if (that.states[id].val != val) {
|
||
that.states[id].lc = (new Date()).getTime();
|
||
that.states[id].val = val;
|
||
}
|
||
that.states[id].ack = false;
|
||
that.states[id].ts = (new Date()).getTime();
|
||
that.conn.setState(id, that.states[id].val);
|
||
}
|
||
});
|
||
}, 500);
|
||
},
|
||
|
||
destroyPage: function (id) {
|
||
var that = this;
|
||
|
||
// do not destroy first level pages
|
||
|
||
if (!this.erasePage[id] && id.split('*').length > 2) {
|
||
console.log('Add to destroy: ' + id);
|
||
this.erasePage[id] = setTimeout(function () {
|
||
delete that.erasePage[id];
|
||
if ($.mobile.activePage.attr('id') !== id) {
|
||
console.log('Destroy page: ' + id);
|
||
$('div[id="' + id + '"]').remove();
|
||
} else {
|
||
console.log('Trying to destroy active page!');
|
||
}
|
||
|
||
}, 15000);
|
||
}
|
||
},
|
||
|
||
detectHiddenStates: function (id) {
|
||
var $elem = $('.mobile-checkbox-visibility[data-edit-id="' + id + '"]');
|
||
|
||
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) {
|
||
var isAllInvisible = true;
|
||
|
||
if (!this.objects[id].children) {
|
||
console.error(id);
|
||
return;
|
||
}
|
||
|
||
for (var i = 0; i < this.objects[id].children.length; i++) {
|
||
var cid = this.objects[id].children[i];
|
||
if (this.objects[cid] &&
|
||
this.objects[cid].common &&
|
||
this.objects[cid].common.mobile &&
|
||
this.objects[cid].common.mobile[this.user] &&
|
||
this.objects[cid].common.mobile[this.user].visible) {
|
||
isAllInvisible = false;
|
||
break;
|
||
}
|
||
}
|
||
if (isAllInvisible) {
|
||
$elem.prop('checked', false);
|
||
this.objects[id].common.mobile[this.user].visible = false;
|
||
$elem.parent().addClass('mobile-invisible');
|
||
this.saveSettings(id);
|
||
}
|
||
}
|
||
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) {
|
||
$elem.parent().parent().find('.mobile-edit-state').hide();
|
||
}
|
||
},
|
||
|
||
detectAllHiddenStates: function () {
|
||
var that = this;
|
||
$('.mobile-edit-channel').each(function () {
|
||
var id = $(this).find('div').data('edit-id');
|
||
that.detectHiddenStates(id, $(this));
|
||
});
|
||
},
|
||
|
||
compareVersion: function (instVersion, availVersion) {
|
||
var instVersionArr = instVersion.replace(/beta/, '.').split('.');
|
||
var availVersionArr = availVersion.replace(/beta/, '.').split('.');
|
||
|
||
var updateAvailable = false;
|
||
|
||
for (var k = 0; k < 3; k++) {
|
||
instVersionArr[k] = parseInt(instVersionArr[k], 10);
|
||
if (isNaN(instVersionArr[k])) instVersionArr[k] = -1;
|
||
availVersionArr[k] = parseInt(availVersionArr[k], 10);
|
||
if (isNaN(availVersionArr[k])) availVersionArr[k] = -1;
|
||
}
|
||
|
||
if (availVersionArr[0] > instVersionArr[0]) {
|
||
updateAvailable = true;
|
||
} else if (availVersionArr[0] == instVersionArr[0]) {
|
||
if (availVersionArr[1] > instVersionArr[1]) {
|
||
updateAvailable = true;
|
||
} else if (availVersionArr[1] == instVersionArr[1]) {
|
||
if (availVersionArr[2] > instVersionArr[2]) {
|
||
updateAvailable = true;
|
||
}
|
||
}
|
||
}
|
||
return updateAvailable;
|
||
},
|
||
|
||
calcChildren: function (objs) {
|
||
var ids = [];
|
||
var indicators = {};
|
||
for (var ob in objs) {
|
||
if (!objs.hasOwnProperty(ob)) continue;
|
||
ids.push(ob);
|
||
if (!objs[ob]) {
|
||
console.log('Please sync project, because object "' + ob + '" does not exist anymore');
|
||
continue;
|
||
}
|
||
if (objs[ob].common && objs[ob].common.role && this.ignoreIndicators.indexOf(objs[ob].common.role) === -1 && objs[ob].common.role.match(/^indicator\./)) {
|
||
var name = ob.split('.').pop();
|
||
if (!indicators[name]) indicators[name] = this.config.indicators[name] === undefined ? true : this.config.indicators[name];
|
||
}
|
||
}
|
||
this.config.indicators = indicators;
|
||
|
||
ids.sort();
|
||
for (var i = 0; i < ids.length; i++) {
|
||
if (!objs[ids[i]]) continue;
|
||
if (objs[ids[i]].type === 'device' || objs[ids[i]].type === 'channel') {
|
||
var _id = ids[i] + '.';
|
||
var parts = ids[i].split('.');
|
||
var j = i + 1;
|
||
var len = _id.length;
|
||
while (j < ids.length && ids[j].substring(0, len) === _id) {
|
||
var ps = ids[j].split('.');
|
||
if (ps.length === parts.length + 1) {
|
||
objs[ids[i]].children = objs[ids[i]].children || [];
|
||
if (objs[ids[i]].children.indexOf(ids[j]) === -1) {
|
||
objs[ids[i]].children.push(ids[j]);
|
||
}
|
||
}
|
||
j++;
|
||
}
|
||
}
|
||
}
|
||
return objs;
|
||
},
|
||
|
||
loadStyle: function (theme) {
|
||
theme = theme || this.config.theme || 'light';
|
||
$('#css-mobile').attr('href', 'lib/css/' + theme + '/jquery.mobile.min.css');
|
||
$('#css-mobile-icons').attr('href', 'lib/css/' + theme + '/jquery.mobile.icons.min.css');
|
||
}
|
||
};
|
||
|
||
function onEditName(e) {
|
||
e.stopPropagation();
|
||
var that = mobile;
|
||
var id = $(this).data('edit-id');
|
||
//$(this).parent().append('<input type="text" style="width: 100%" value="' + that.objects[id].common.name + '"/>');
|
||
var name;
|
||
if (that.objects[id].common.mobile && that.objects[id].common.mobile[that.user] && that.objects[id].common.mobile[that.user].name) {
|
||
name = that.objects[id].common.mobile[that.user].name;
|
||
} else {
|
||
name = that.objects[id].common.name;
|
||
}
|
||
$('#name_edit').val(name).data('id', id);
|
||
|
||
$('#popupEditName').popup('open');
|
||
setTimeout(function () {
|
||
$('#name_edit').focus();
|
||
}, 200);
|
||
}
|
||
|
||
function onStateVisibility(e) {
|
||
e.stopPropagation();
|
||
var that = mobile;
|
||
var id = $(this).data('edit-id');
|
||
var checked = $(this).html();
|
||
checked = !checked;
|
||
$(this).html(checked ? '✓' : '');
|
||
|
||
if (!id || !that.objects[id]) {
|
||
console.error('Cannot find object ' + id);
|
||
return;
|
||
}
|
||
|
||
if (that.objects[id].common && that.objects[id].common.mobile && that.objects[id].common.mobile[that.user] && that.objects[id].common.mobile[that.user].visible !== checked) {
|
||
that.objects[id].common.mobile[that.user].visible = checked;
|
||
that.saveSettings(id);
|
||
}
|
||
if (that.objects[id].common && that.objects[id].common.mobile && that.objects[id].common.mobile[that.user] && that.objects[id].common.mobile[that.user].visible) {
|
||
$(this).parent().removeClass('mobile-invisible');
|
||
var $states;
|
||
if ($(this).parent().hasClass('mobile-edit-channel')) {
|
||
$states = $(this).parent().parent().find('.mobile-edit-state').show();
|
||
}
|
||
// at least one state of the channel must be visible
|
||
if ($states && $states.length) {
|
||
var oneVisible = false;
|
||
$states.each(function () {
|
||
var $input = $(this).find('div');
|
||
var cid = $input.data('edit-id');
|
||
if (that.objects[cid].common.mobile[that.user].visible) {
|
||
oneVisible = true;
|
||
return false;
|
||
}
|
||
});
|
||
|
||
if (!oneVisible) {
|
||
$states = $($states[0]);
|
||
var $input = $states.find('div');
|
||
var cid = $input.data('edit-id');
|
||
if (!that.objects[cid].common.mobile[that.user].visible) {
|
||
// show only one element of channel
|
||
that.objects[cid].common.mobile[that.user].visible = true;
|
||
that.saveSettings(cid);
|
||
$input.html('✓');
|
||
$states.removeClass('mobile-invisible');
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
$(this).parent().addClass('mobile-invisible');
|
||
if ($(this).parent().hasClass('mobile-edit-channel')) {
|
||
$(this).parent().parent().find('.mobile-edit-state').hide();
|
||
}
|
||
// try to find some in device itself
|
||
var parent = id.split('.');
|
||
parent.pop();
|
||
parent = parent.join('.');
|
||
if (that.objects[parent]) that.detectHiddenStates(parent);
|
||
}
|
||
}
|
||
|
||
function onTypeChanged(e) {
|
||
e.stopPropagation();
|
||
var that = mobile;
|
||
var id = $(this).data('edit-id');
|
||
var val = $(this).val();
|
||
|
||
if (!id || !that.objects[id]) {
|
||
console.error('Cannot find object ' + id);
|
||
return;
|
||
}
|
||
|
||
if (that.objects[id].common && that.objects[id].common.mobile && that.objects[id].common.mobile[that.user] && that.objects[id].common.mobile[that.user].type !== val) {
|
||
that.objects[id].common.mobile[that.user].type = val;
|
||
that.saveSettings(id);
|
||
}
|
||
}
|
||
|
||
function onSubEnumVisibility(e) {
|
||
var that = mobile;
|
||
e.stopPropagation();
|
||
var id = $(this).data('edit-id');
|
||
var checked = $(this).html();
|
||
checked = !checked;
|
||
$(this).html(checked ? '✓' : '');
|
||
|
||
if (that.objects[id].common.mobile[that.user].visible !== checked) {
|
||
that.objects[id].common.mobile[that.user].visible = checked;
|
||
that.saveSettings(id);
|
||
}
|
||
if (that.objects[id].common.mobile[that.user].visible) {
|
||
$(this).parent().removeClass('mobile-invisible');
|
||
} else {
|
||
$(this).parent().addClass('mobile-invisible');
|
||
}
|
||
}
|
||
|
||
function onEnumVisibility(e) {
|
||
var that = mobile;
|
||
e.stopPropagation();
|
||
var id = $(this).data('edit-id');
|
||
var checked = $(this).html();
|
||
checked = !checked;
|
||
$(this).html(checked ? '✓' : '');
|
||
|
||
if (that.objects[id].common.mobile[that.user].visible !== checked) {
|
||
that.objects[id].common.mobile[that.user].visible = checked;
|
||
that.saveSettings(id);
|
||
}
|
||
if (that.objects[id].common.mobile[that.user].visible) {
|
||
$(this).parent().removeClass('mobile-invisible');
|
||
} else {
|
||
$(this).parent().addClass('mobile-invisible');
|
||
}
|
||
}
|
||
|
||
function onForward(e) {
|
||
document.location.href = $(this).data('href');
|
||
e.stopPropagation();
|
||
}
|
||
|
||
if ('applicationCache' in window) {
|
||
window.addEventListener('load', function (e) {
|
||
window.applicationCache.addEventListener('updateready', function (e) {
|
||
if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
|
||
try {
|
||
window.applicationCache.swapCache();
|
||
} catch (ex) {
|
||
console.error(ex);
|
||
}
|
||
window.location.reload();
|
||
}
|
||
}, false);
|
||
}, false);
|
||
}
|
||
|
||
// Start of initialisation: main ()
|
||
(function ($) {
|
||
$(document).ready(function () {
|
||
// force loading menu
|
||
$('body').css('visibility', 'visible');
|
||
mobile.init();
|
||
});
|
||
})(jQuery);
|