UNPKG

iobroker.vis-2

Version:

Next generation graphical user interface for ioBroker.

1,094 lines (1,017 loc) 146 kB
<link rel="stylesheet" type="text/css" href="widgets/basic/css/table.css" /> <script type="text/javascript" src="widgets/basic/js/table.js" ></script> <script type="text/javascript"> 'use strict'; if (vis.editMode) { // Add words for basic widgets $.extend(true, systemDictionary, { // Bars src: { en: 'Source', de: 'Quelle', ru: 'Адрес' }, refreshInterval: { en: 'Refresh interval(ms)', de: 'Updatezeit(ms)', ru: 'Интервал обновления(ms)' }, is_comma: { en: 'Divider comma', de: 'Komme als Trennung', ru: 'Запятая-разделитель' }, is_tdp: { en: 'Use thousands separator', de: 'Tausender Trennzeichen', ru: 'Use thousands separator' }, digits: { en: 'Digits after comma', de: 'Zeichen nach Komma', ru: 'Знаков после запятой' }, oid: { en: 'Object ID', de: 'Object ID', ru: 'ID Объекта' }, html_prepend: { en: 'Prepend value', de: 'Voranstellen HTML', ru: 'Префикс значения' }, html_append: { en: 'Append to value', de: 'HTML anhängen', ru: 'Суффикс значения' }, html_append_singular: { en: 'Append to value (Singular)', de: 'HTML anhängen (Singulär)', ru: 'Суффикс значения(един.ч.)', }, html_append_plural: { en: 'Append to value (Plural)', de: 'HTML anhängen(Plüral)', ru: 'Суффикс значения(множ.ч.)', }, html_prepend_tooltip: { en: 'Write HTML code here that will be placed before,\x0Ae.g. <b> ', de: 'HTML Kod, der wird vom dem Wert platziert,\x0Az.B. <b>', ru: 'HTML код будет помещён перед значением,\x0Aнапример <b>', }, html_append_tooltip: { en: 'Write HTML code here that will be placed before,\x0Ae.g. </b>', de: 'HTML Kod, der wird vom dem Wert platziert,\x0Az.B. </b>', ru: 'HTML код будет помещён после значения,\x0Aнапример </b>', }, stretch: { en: 'Stretch', de: 'Strecken', ru: 'Растянуть' }, factor: { en: 'Multiplex factor', de: 'Multiplikation', ru: 'Множитеть' }, class_true: { en: "Class if quality 'true'", de: "Klasse bei Qualität 'true'", ru: "Класс, если качество 'true'", }, class_false: { en: "Class if quality 'false'", de: "Klasse bei Qualität 'false'", ru: "Класс, если качество 'false'", }, test_html: { en: 'Text for test', de: 'Testtext', ru: 'Тестовый текст' }, test_html_tooltip: { en: 'You can specify the test text if value is now empty to visualise settings.\x0AIt is valid only during edit.', de: 'Man kann noch Testtext setzen um die Einstellungen visuell zu sehen.\x0ADas ist nur während Edit gültig.', ru: 'Можно задать тестовый текст, что бы видеть настройки визуально.\x0AОн действителен только во время редактирования.', }, html: { en: 'HTML', de: 'HTML', ru: 'HTML' }, 'oid-quality': { en: 'Quality ID', de: 'Qualität ID', ru: 'ID-Качество' }, 'oid-quality_tooltip': { en: 'You can set additionally Quality ID to indicate if the value valid or not.', de: 'Man kann noch zusätzlich Qualität ID setzetn um zu zeigen ob das Wert aktuell ist.', ru: 'Можно дополнительно установить ID-Качества, что бы показать актуальное значение или нет.', }, title: { en: 'Title', de: 'Titel', ru: 'Заголовок' }, title_font: { en: 'Title font name', de: 'Titelschriftname', ru: 'Шрифт заголовка' }, title_color: { en: 'Title color', de: 'Titelfarbe', ru: 'Цвет заголовка' }, title_back: { en: 'Title backg. color', de: 'Titelhintergrund', ru: 'Цвет фона текста' }, title_top: { en: 'Title top padding', de: 'Titel-Oben-Abstand', ru: 'Отступ заголовка сверху' }, title_left: { en: 'Title left padding', de: 'Titel-Links-Abstand', ru: 'Отступ заголовка слева' }, header_height: { en: 'Header height', de: 'Kopfhöhe', ru: 'Высота заголовока' }, header_color: { en: 'Header color', de: 'Kopffarbe', ru: 'Цвет фона заголовка' }, refreshOnWakeUp: { en: 'Refresh on wake up', de: 'Update bei Aufwachen', ru: 'Обновлять при выходе из сна', }, refreshOnViewChange: { en: 'Refresh on view change', de: 'Update bei Viewwechsel', ru: 'Обновлять при смене страницы', }, refreshWithNoQuery: { en: 'Do not add anything to URL', de: 'Addiere nichst zu URL', ru: 'Ничего не добавлять к URL', }, src_: { en: 'URL, by value=', de: 'URL falls Wert=', ru: 'Адрес при значении ' }, nav_view: { en: 'View to navigate', de: 'View zum Navigieren', ru: 'Перейти на страницу' }, group_effects: { en: 'Show/Hide Effects', de: 'Anzeige Effekte', ru: 'Эффекты появления/исчезновения' }, group_extended: { en: 'Extended settings', de: 'Erweiterte Eistellungen', ru: 'Расширенные настройки' }, 'body-background': { en: 'Background color by changing', de: 'Hintegrund by Wechsel', ru: 'Фон при смене страниц', }, sync: { en: 'Hide and show together:', de: 'Anzeigen und verbergen gleichzeitig', ru: 'Появления и исчезновение вместе', }, // Effects show: { en: 'show', de: 'show', ru: 'show' }, blind: { en: 'blind', de: 'blind', ru: 'blind' }, bounce: { en: 'bounce', de: 'bounce', ru: 'bounce' }, clip: { en: 'clip', de: 'clip', ru: 'clip' }, drop: { en: 'drop', de: 'drop', ru: 'drop' }, explode: { en: 'explode', de: 'explode', ru: 'explode' }, fade: { en: 'fade', de: 'fade', ru: 'fade' }, fold: { en: 'fold', de: 'fold', ru: 'fold' }, highlight: { en: 'highlight', de: 'highlight', ru: 'highlight' }, puff: { en: 'puff', de: 'puff', ru: 'puff' }, pulsate: { en: 'pulsate', de: 'pulsate', ru: 'pulsate' }, scale: { en: 'scale', de: 'scale', ru: 'scale' }, shake: { en: 'shake', de: 'shake', ru: 'shake' }, size: { en: 'size', de: 'size', ru: 'size' }, slide: { en: 'slide', de: 'slide', ru: 'slide' }, is_milliseconds: { en: 'Milliseconds', de: 'Millisekunden', ru: 'Миллисекунды' }, is_milliseconds_tooltip: { en: 'Is object is milliseconds from 1970.01.01 00:00:00. Normally no.', de: 'Ob das Wert die Milleskunden seit 1970.01.01 00:00:00 ist. Normalerweise nicht.', ru: 'Является ли значение объекта миллисекундами с 1970.01.01 00:00:00. Обычно нет.', }, format_date: { en: 'Dateformat', de: 'Datumformat', ru: 'Формат даты' }, format_date_tooltip: { en: 'Dateformat', de: 'Datumformat', ru: 'Формат даты', }, show_interval: { en: 'As interval', de: 'Als Intervall', ru: 'Как интервал' }, hide_effect: { en: 'Hide effect', de: 'Verbergeneffekt', ru: 'Эффект скрытия' }, hide_duration: { en: 'Hide duration(ms)', de: 'Verbergendauer', ru: 'Длительность скрытия(мс)' }, hide_options: { en: 'Hide options', de: 'Verbergenoptionen', ru: 'Опции скрытия' }, show_effect: { en: 'Show effect', de: 'Anzeigeeffekt', ru: 'Эффект появления' }, show_duration: { en: 'Show duration(ms)', de: 'Anzeigedauer', ru: 'Длительность появления(мс)' }, show_options: { en: 'Show options', de: 'Anzeigeoptionen', ru: 'Опции появления' }, left: { en: 'left', de: 'links', ru: 'лево' }, right: { en: 'right', de: 'rechts', ru: 'право' }, top: { en: 'top', de: 'oben', ru: 'верх' }, bottom: { en: 'bottom', de: 'unten', ru: 'низ' }, contains_view: { en: 'Contains view', de: 'Viewname', ru: 'Имя страницы' }, persistent: { en: 'Persistent', de: 'Bleibend', ru: 'Постоянно' }, persistent_tooltip: { en: 'If persistent the view will not be destroyed when inactive, just hide.\nElsewise the view will be destroyed, if inactive.', de: "Falls 'Bleibend', dann wird die View nicht zerstört, sondern nur versteckt wenn inaktive. Sonst wird die View immer wieder kreiert und zerstört.", ru: "Если выбранно 'Постоянно', то страница не будет уничтожаться, если она не активна. В противном случае страница будет создаваться и разрушаться.", }, notIfInvisible: { en: 'Only if visible', de: 'Nur falls sichtbar', ru: 'Только если видимо' }, notIfInvisible_tooltip: { en: 'View will be used only if this widget is visible', de: 'Die View wird nur benutzt, wenn dieses Widget sichtbar ist', ru: 'Страница будет использоваться только в том случае, если виден этот виджет', }, valuelist: { en: 'Values list', de: 'Wertenliste', ru: 'Список значений' }, valuelist_tooltip: { en: "Divide values with semicolon, like 'ok;warning;alram'. Every text accordingly for value 0,1,2 and so on\nTo have ';' in text use §§ instead.", de: "Die Werte mit Semikolon trennen, wie 'ok;Warnung;Alarm'. Jeder Text ist entsprechend für das Wert 0,1,2 usw.\nUm ';' im Text zu haben, schrein '§§'.", ru: "Разделять значения точкой запятой, например 'ok;Внимание;Тревога'. Каждый текст соответственно для значения 0,1,2 итд.\nДля написания ';' в тексте используй '§§'.", }, html_false: { en: "HTML by 'false'", de: "HTML bei 'false'", ru: 'HTML если 0' }, html_true: { en: "HTML by 'true'", de: "HTML bei 'true'", ru: 'HTML если 1' }, text_false: { en: "Text by 'false'", de: "Text bei 'false'", ru: 'Текст если 0' }, text_true: { en: "Text by 'true'", de: "Text bei 'true'", ru: 'Текст если 1' }, svg_false: { en: "SVG by 'false'", de: "SVG bei 'false'", ru: 'SVG если 0' }, svg_true: { en: "SVG by 'true'", de: "SVG bei 'true'", ru: 'SVG если 1' }, svg_opacity: { en: 'Opacity', de: 'Durchsichtigkeit', ru: 'Прозрачность' }, html_closed: { en: "HTML by 'closed'", de: "HTML bei 'zu'", ru: 'HTML если закрыто' }, html_open: { en: "HTML by 'open'", de: "HTML bei 'auf'", ru: 'HTML если открыто' }, html_tilt: { en: "HTML by 'tilted'", de: "HTML bei 'gekippt'", ru: 'HTML если наклоненно' }, html_tilt_tooltip: { en: '0 - Closed, 1 - tilt, 2 - open', de: '0- Zu, 1 - gekippt, 2 - auf', ru: '0 - закрыто, 1 - откинуто, 2 - открыто', }, color: { en: 'Color', de: 'Farbe', ru: 'Цвет' }, shadow: { en: 'Opacity', de: 'Durchsichtigkeit', ru: 'Тень' }, shadow_tooltip: { en: "CSS Shadow, like '10px 10px 5px #888888'", de: "CSS Shatten, wie '10px 10px 5px #888888'", ru: "CSS Тень, как '10px 10px 5px #888888'", }, reverse: { en: 'Revers value', de: 'Wert umkehren', ru: 'Перевернуть значение' }, border: { en: 'Border', de: 'Rand', ru: 'Окантовка' }, border_tooltip: { en: "CSS border, like 'green 5px solid'", de: "CSS Rand, wie 'green 5px solid'", ru: "CSS бордюр, как 'green 5px solid'", }, test_text: { en: 'Test text', de: 'Testtext', ru: 'Тестовый текст' }, max_width: { en: 'Max. width', de: 'Maximale Breite', ru: 'Максимальная ширина' }, style: { en: 'Style for ', de: 'Stil für ', ru: 'Стиль для ' }, style_tooltip: { en: "Write here css style, like: 'color:red;background:white'", de: "Hier muss CSS Stil stehen, wie 'color:red;background:white'", ru: "CSS Стиль, например: 'color:red;background:white'", }, count: { en: 'Values number to', de: 'Werteanzahl bis', ru: 'Количество значений до' }, test_list: { en: 'Test value', de: 'Testwert', ru: 'Тестовое значение' }, urlValue: { en: 'Call URL on click', de: 'Rufe URL bei click', ru: 'Вызвать URL при нажатии' }, group_ccontrol: { en: 'Advanced control', de: 'Extrasteuerung', ru: 'Продвинутое управление' }, urlFalse: { en: 'URL on false', de: 'URL bei false', ru: 'URL при false' }, urlTrue: { en: 'URL on true', de: 'URL bei true', ru: 'URL при true' }, oidFalse: { en: 'Object ID on false', de: 'Objekt ID bei false', ru: 'ID объекта при false' }, oidTrue: { en: 'Object ID on true', de: 'Objekt ID bei true', ru: 'ID объекта при true' }, oidTrueValue: { en: 'Value for OÍD on true', de: 'Wert für ID bei false', ru: 'Значение для ID при false' }, oidFalseValue: { en: 'Value for OÍD on false', de: 'Wert für ID bei true', ru: 'Значение для ID при true' }, square: { en: 'square', de: 'square', ru: 'квадрат' }, pentagone: { en: 'pentagone', de: 'pentagone', ru: 'Пятиуголник' }, hexagone: { en: 'hexagone', de: 'hexagone', ru: 'Шестиугольник' }, octagone: { en: 'octagone', de: 'octagone', ru: 'Восьмиугольник' }, circle: { en: 'circle', de: 'Kreis', ru: 'Круг' }, svgType: { en: 'Type', de: 'Typ', ru: 'Тип' }, strokeColor: { en: 'Stroke color', de: 'Liniefarbe', ru: 'Цвет линии' }, fill: { en: 'Fill color', de: 'Füllfarbe', ru: 'Цвет заливки' }, strokeWidth: { en: 'Stroke width', de: 'Liniebreite', ru: 'Ширина линии' }, rotate: { en: 'Rotate', de: 'Drehen', ru: 'Повернуть на' }, no_control: { en: 'Read only', de: 'Nur Anzeige', ru: 'Только показывать' }, numeric: { en: 'Number', de: 'Nummer', ru: 'Число' }, autoSet: { en: 'Auto set', de: 'Auto-setzen', ru: 'Авто запись' }, autoSet_tooltip: { en: "Without 'Auto set' you must press ENTER,\x0ato write the value.", de: "Ohne 'Auto-setzen' man muss danach ENTER drucken,\x0A um das Wert zu schreiben.", ru: "Без 'Авто записи' нужно нажать ENTER,\x0Aчто бы записать значение.", }, group_views: { en: 'Views', de: 'Views', ru: 'Страницы' }, group_frames: { en: 'iFrames', de: 'iFrames', ru: 'iFrames' }, horizontal: { en: 'horizontal', de: 'horizontal', ru: 'горизонтально' }, vertical: { en: 'vertical', de: 'senkrecht', ru: 'вертикально' }, orientation: { en: 'Orientation', de: 'Ausrichtung ', ru: 'Направление' }, noSandbox: { en: 'No sandbox', de: 'Kein Sandkasten', ru: 'Не запускать в песочнице' }, scrollX: { en: 'Scroll X', de: 'Scroll X', ru: 'Scroll X' }, scrollY: { en: 'Scroll Y', de: 'Scroll Y', ru: 'Scroll Y' }, seamless: { en: 'Seamless', de: 'Kein Rahmen', ru: 'Без рамки' }, filters: { en: 'Filters', de: 'Filter', ru: 'Фильтры' }, filters_Tooltip: { en: 'Divided by semicolon,\x0Ae.g: light;control', de: 'Geteilt mir Semikolon\x0Az.B.: Licht;Steuerung', ru: 'Разделять точкой запятой\x0Aнапример: Свет;Управление', }, 'Select ID': { en: 'Select ID', de: 'ID auswählen', ru: 'Выбрать ID' }, redirect_url: { en: 'Redirect URL', de: 'Weiterleiten nach Logout', ru: 'Перейти на URL после выхода' }, in_app_close: { en: 'Close mobile APP', de: 'Mobiles APP schliessen', ru: 'Закрыть мобильное приложение' }, line: { en: 'line', de: 'Linie', ru: 'линия' }, triangle: { en: 'triangle', de: 'Dreieck', ru: 'треугольник' }, star: { en: 'star', de: 'Stern', ru: 'звезда' }, arrow: { en: 'arrow', de: 'Pfeil', ru: 'стрела' }, scaleWidth: { en: 'Scale width', de: 'breiten Skala', ru: 'Масштаб по ширине' }, scaleHeight: { en: 'Scale height', de: 'höhen Skala', ru: 'Масштаб по высоте' }, autoFocus: { en: 'Auto focus', de: 'Autofokus', ru: 'Автофокус', pt: 'Auto-foco', nl: 'Autofocus', fr: 'Mise au point automatique', it: 'Messa a fuoco automatica', es: 'Enfoque automático', pl: 'Automatyczne ustawianie ostrości', 'zh-cn': '自动对焦', }, }); } $.extend(true, systemDictionary, { 'Edit note': { en: 'Edit note', de: 'Meldung eingeben', ru: 'Сообщение' }, Clear: { en: 'Clear', de: 'Löschen', ru: 'Очистить' }, Ok: { en: 'Ok', de: 'Ok', ru: 'Ok' }, Cancel: { en: 'Cancel', de: 'Abbrechen', ru: 'Отмена' }, all: { en: 'all', de: 'Alle', ru: 'Все' }, 'just&nbsp;now': { en: 'just&nbsp;now', de: 'gerade&nbsp;jetzt', ru: 'только&nbsp;что' }, 'for&nbsp;%s&nbsp;min.': { en: 'for&nbsp;%s&nbsp;min.', de: 'vor&nbsp;%s&nbsp;Min.', ru: '%s&nbsp;мин. назад' }, 'for&nbsp;%s&nbsp;hr.&nbsp;and&nbsp;%s&nbsp;min.': { en: 'for&nbsp;%s&nbsp;hr.&nbsp;and&nbsp;%s&nbsp;min.', de: 'vor&nbsp;%s&nbsp;St.&nbsp;und&nbsp;%s&nbsp;Min.', ru: '%s&nbsp;часов&nbsp;и&nbsp;%s&nbsp;мин. назад', }, yesterday: { en: 'yesterday', de: 'gestern', ru: 'вчера' }, 'for&nbsp;%s&nbsp;hours': { en: 'for&nbsp;%s&nbsp;hours', de: 'vor&nbsp;%s&nbsp;Stunden', ru: '%s&nbsp;часов назад', }, 'click to create': { en: 'click to create', de: 'klicken um zu erzeugen', ru: 'нажать что бы создать' }, 'This option works only in APP': { en: 'This option works only in APP', de: 'Funktioniert nur im APP', ru: 'Работает только в мобильном приложении', }, }); /*vis.binds.stateful = { view: function (el, viewArr, persistent, notIfInvisible) { const $this = $(el); const oid = $this.attr('data-oid'); let timer = null; function draw(val) { timer = null; const view = viewArr[val]; if (!persistent) { $this.parent().find('div.vis-view').remove(); } else { $this.parent().find('div.vis-view').hide().appendTo($('#vis_container')); } if (vis.views[view]) { vis.renderView(view, view, true, function (_view) { const $view = $('#visview_' + _view); $view.show().data('persistent', persistent); if (!$this.find('#visview_' + _view).length) { $view.appendTo($this); } }); } vis.destroyUnusedViews(); } function onChange(e, newVal) { if (newVal === 'true' || newVal === true) newVal = 1; if (newVal === 'false' || newVal === false) newVal = 0; if (notIfInvisible && !$this.is(':visible')) { return; } if (timer) { clearTimeout(timer) } timer = setTimeout(function () { draw(newVal); }, 50); } if (oid) { vis.states.bind(oid + '.val', onChange); // remember all ids, that bound $this.parent().parent() .data('bound', [oid + '.val']) // remember bind handler .data('bindHandler', onChange); } }, iframe: function (el, srcArr, refreshInterval) { const $this = $(el).parent().find('iframe'); const oid = $this.attr('data-oid'); refreshInterval = parseInt(refreshInterval, 10) || 0; function onChange (e, newVal) { if (newVal === 'true' || newVal === true) newVal = 1; if (newVal === 'false' || newVal === false) newVal = 0; $this.attr('src', srcArr[newVal]); } if (oid) { vis.states.bind(oid + '.val', onChange); // remember all ids, that bound $this.parent().parent() .data('bound', [oid + '.val']) // remember bind handler .data('bindHandler', onChange); if (vis.states[oid + '.val'] !== undefined) { let val = vis.states[oid + '.val']; if (val === 'true' || val === true) val = 1; if (val === 'false' || val === false) val = 0; $this.attr('src', srcArr[val]); } if (refreshInterval > 0) { setInterval(function () { let val = vis.states[oid + '.val'] || 0; if (val === 'true' || val === true) val = 1; if (val === 'false' || val === false) val = 0; const src = srcArr[val]; $this.attr('src', src + (src.match(/\?/) ? '&' : '?') + '_vis_refts=' + Date.now()); }, refreshInterval); } } }, image: function (el, srcArr, refreshInterval) { const $this = $(el).parent().find('img'); const oid = $this.attr('data-oid'); refreshInterval = parseInt(refreshInterval, 10) || 0; function onChange (e, newVal) { if (newVal === 'true' || newVal === true) newVal = 1; if (newVal === 'false' || newVal === false) newVal = 0; $this.attr('src', srcArr[newVal]); } if (oid) { vis.states.bind(oid + '.val', onChange); // remember all ids, that bound $this.parent().parent() .data('bound', [oid + '.val']) // remember bind handler .data('bindHandler', onChange); if (vis.states[oid + '.val'] !== undefined) { let val = vis.states[oid + '.val']; if (val === 'true' || val === true) val = 1; if (val === 'false' || val === false) val = 0; $this.attr('src', srcArr[val]); } if (refreshInterval > 0) { setInterval(function () { let val = vis.states[oid + '.val'] || 0; if (val === 'true' || val === true) val = 1; if (val === 'false' || val === false) val = 0; const src = srcArr[val]; if (src) $this.attr('src', src + ((src.indexOf('?') !== -1) ? '&' : '?') + '_vis_refts=' + Date.now()); }, refreshInterval); } } }, value: function (values, oid) { if (oid !== 'nothing_selected' && vis.states.attr(oid + '.val') !== undefined) { let val = vis.states.attr(oid + '.val'); if (val === 'true' || val === true) val = 1; if (val === 'false' || val === false) val = 0; return values[val]; } else { return values[0]; } } };*/ vis.binds.container = function (el, view) { const $this = $(el); if (vis.views[view]) { vis.renderView(view, view, true, function (_view) { $('#visview_' + _view) .appendTo($this) .show(); }); } }; vis.binds.basic = { isFullScreen: false, /* filterDropdown: function (el, filters, hideEffect, hideDuration, showEffect, showDuration) { const $this = $(el); if (filters) { filters = filters.split(';'); for (let i = 0; i < filters.length; i++) { $this.find('select').append('<option value="' + filters[i] + '">' + filters[i] + '</option>'); } } if (vis.viewsActiveFilter[vis.activeView]) { $this.find('select option[value="' + vis.viewsActiveFilter[vis.activeView] + '"]').attr('selected', true); } $this.find('select').change(function () { vis.changeFilter(null, $this.find('select option:selected').val(), hideEffect, hideDuration, showEffect, showDuration); }); }, */ // used in metro state: function (el, oid) { const $this = $(el); oid = oid || $this.attr('data-oid'); if (oid) { $this.attr('data-ctrl-oid', oid); } if (!vis.editMode) { let moved = false; $this .on('click touchend', function (e) { // Protect against two events if (vis.detectBounce(this)) { return; } if (moved) { return; } const oid = $(this).attr('data-ctrl-oid'); if ($(this).attr('url-value')) { vis.conn.httpGet($(this).attr('url-value')); } if (oid) { let val = $(this).attr('data-val'); if (val === undefined || val === null) { val = false; } if (val === 'true') { val = true; } if (val === 'false') { val = false; } if (parseFloat(val).toString() == val) { val = parseFloat(val); } if (oid) { vis.setValue(oid, val); } } }) .on('touchmove', function () { moved = true; }) .on('touchstart', function () { moved = false; }); } }, pressed: null, pressedNext: null, increment: function (el, minmax, delay, interval) { function fInterval($that) { vis.binds.basic.pressedNext = true; vis.binds.basic.pressed = null; const oid = $that.attr('data-oid'); if (!vis.editMode) { const step = parseFloat($that.attr('data-vis-step')); const tmp = parseFloat(vis.states[oid + '.val']) + step; if (step < 0) { if (tmp >= minmax) { vis.setValue($that.attr('data-oid'), tmp); vis.binds.basic.pressed = _setTimeout(fInterval, interval, $that); } } else { if (tmp <= minmax) { vis.setValue($that.attr('data-oid'), tmp); vis.binds.basic.pressed = _setTimeout(fInterval, interval, $that); } } } } function intervalStart() { vis.binds.basic.pressedNext = false; const $this = $(this); if (vis.binds.basic.pressed) { clearInterval(vis.binds.basic.pressed); vis.binds.basic.pressed = null; } vis.binds.basic.pressed = setTimeout(fInterval, delay, $this); } if (!vis.editMode) { let moved = false; $(el) .on('click touchend', function () { // Protect against two events if (vis.detectBounce(this) || moved) { return; } if (vis.binds.basic.pressed) { clearInterval(vis.binds.basic.pressed); vis.binds.basic.pressed = null; } if (vis.binds.basic.pressedNext) { vis.binds.basic.pressedNext = false; return; } const $this = $(this); const oid = $this.attr('data-oid'); const step = parseFloat($this.attr('data-vis-step')); const tmp = parseFloat(vis.states[oid + '.val']) + step; if (step < 0) { if (minmax === undefined || tmp >= minmax) { vis.setValue($this.attr('data-oid'), tmp); } } else { if (minmax === undefined || tmp <= minmax) { vis.setValue($this.attr('data-oid'), tmp); } } }) .on('touchmove', function () { moved = true; }) .on('touchstart', function () { moved = false; }); } if (interval) { $(el) .on('mousedown', intervalStart) .on('touchstart', intervalStart) .on('touchend', function () { if (vis.binds.basic.pressed) { clearInterval(vis.binds.basic.pressed); vis.binds.basic.pressed = null; } }) .on('mouseup', function () { if (vis.binds.basic.pressed) { clearInterval(vis.binds.basic.pressed); vis.binds.basic.pressed = null; } }) .data('destroy', function (id, $widget) { $widget && $widget.off('mousedown').off('touchstart').off('touchend').off('mouseup'); }); } }, // Used in metro navigation: function (el, options) { if (!vis.editMode && options.nav_view) { const $this = $(el); let moved = false; $this .on('click touchend', function (e) { // Protect against two events if (vis.detectBounce(this) || moved) { return; } if (options.background) { $('body').css({ background: options.background }); } vis.changeView( options.nav_view, options.nav_view, options.hideOptions, options.showOptions, options.sync, ); //e.preventDefault(); //return false; }) .on('touchmove', function () { moved = true; }) .on('touchstart', function () { moved = false; }); } }, /*hideOnTrue: function (el) { const $this = $(el); const oid = $this.attr('data-oid'); vis.states.bind(oid + '.val', function (e, newVal, oldVal) { if (newVal === true || parseFloat(newVal) > 0) { if (!vis.editMode) { $this.hide(); } } else { $this.show(); } }); if (!vis.editMode) { if (parseFloat(vis.states.attr(oid + '.val')) !== 0 && vis.states.attr(oid + '.val') !== false) { $this.hide(); } } }, showOnValue: function (el, val) { const $this = $(el); const oid = $this.attr('data-oid'); vis.states.bind(oid + '.val', function (e, newVal, oldVal) { if (newVal != val) { if (!vis.editMode) { $this.hide(); } } else { $this.show(); } }); if (!vis.editMode) { if (vis.states.attr(oid + '.val') != val) { $this.hide(); } } },*/ _onChange: function (el, oid, wid) { const $this = $(el); // If still working //console.log(oid + ' ' + vis.states.attr(oid + '.val') + ' (' + vis.states.attr(oid + '.ack') + ') - ' + wid + ' ' + vis.states.attr(wid + '.val') + ' (' + vis.states.attr(wid + '.ack') + ')'); if (wid && vis.states.attr(wid + '.val') === true) { return; } let val = vis.states.attr(oid + '.val'); if (val === 'false') { val = false; } else if (val === 'true') { val = true; } else if (typeof val === 'string') { const f = parseFloat(val); if (f == val) { val = f; } else if (val !== '') { val = true; } else { val = false; } } if ($this.data('data-numeric')) { $this.prop('checked', val > ($this.data('data-max') - $this.data('data-min')) / 2); } else { $this.prop('checked', val); } }, // used in metro checkbox: function (el, numeric, min, max) { const $this = $(el); const oid = $this.data('oid'); // Object ID const wid = $this.data('oid-working'); // Work ID function onChange() { vis.binds.basic._onChange(el, oid, wid); } if (oid) { const bound = []; vis.states.bind(oid + '.val', onChange); bound.push(oid + '.val'); if (wid) { vis.states.bind(wid + '.val', onChange); bound.push(wid + '.val'); } // remember all ids, that bound $this .closest('.vis-widget') .data('bound', bound) // remember bind handler .data('bindHandler', onChange); } if (numeric) { if (min !== undefined && min !== null && min !== '') { min = parseFloat(min); } else { min = 0; } if (max !== undefined && max !== null && max !== '') { max = parseFloat(max); } else { max = 1; } } else { min = false; max = true; } $this.data('min', min); $this.data('max', max); $this.data('numeric', numeric); vis.binds.basic._onChange(el, oid, wid); if (!vis.editMode) { $this.change(function () { const $this_ = $(this); if ($this_.prop('checked')) { vis.setValue($this_.data('oid'), $this_.data('max')); } else { vis.setValue($this_.data('oid'), $this_.data('min')); } }); } }, input: function (el, data) { const $this = $(el); const oid = $this.data('oid'); // Object ID const wid = $this.data('oid-working'); // Work ID function onChange(e, val) { $this.val(val); } if (oid) { const bound = [oid + '.val']; vis.states.bind(oid + '.val', onChange); if (wid) { bound.push(wid + '.val'); vis.states.bind(wid + '.val', onChange); } // remember all ids, that bound $this .closest('.vis-widget') .data('bound', bound) // remember bind handler .data('bindHandler', onChange); } if (data.numeric) { $this.attr('type', 'number'); if (data.min !== undefined && data.min !== null && data.min !== '') { data.min = parseFloat(data.min); } else { data.min = null; } if (data.max !== undefined && data.max !== null && data.max !== '') { data.max = parseFloat(data.max); } else { data.max = null; } } $this.val(vis.states[oid + '.val'] === undefined ? '' : vis.states[oid + '.val']); setTimeout(function () { $this.css('text-align', $this.parent().parent().css('text-align')); $this.css('color', $this.parent().parent().css('color')); $this.css('background', $this.parent().parent().css('background')); $this.css('border', '0'); $this.css('text-font', $this.parent().parent().css('text-font')); }, 0); if (!vis.editMode) { $this.change(function () { const $this_ = $(this); if (data.numeric) { let value = parseFloat($this_.val()); if (data.min !== null && value < data.min) { value = data.min; $this_.val(value); } else if (data.max !== null && value > data.max) { value = data.max; $this_.val(value); } vis.setValue($this_.data('oid'), value); } else { vis.setValue($this_.data('oid'), $this_.val()); } }); if (data.autoSet) { $this.keyup(function (e) { const timer = $this.data('timer'); if (timer) { clearTimeout(timer); } $this.data( 'timer', setTimeout(function () { $this.trigger('change'); }), 1000, ); }); } } }, select: function (el, invert) { const $this = $(el).prev(); const oid = $this.attr('data-oid'); let val = vis.states[oid + '.val']; if (val === 'false') { val = false; } else if (val === 'true') { val = true; } else if (typeof val === 'string') { const f = parseFloat(val); if (f == val) { val = f; } else if (val !== '') { val = true; } else { val = false; } } if (invert) val = !val; $this.val(val ? 1 : 0); if (!vis.editMode) { if (oid !== 'nothing_selected') { $this.change(function () { let val = $this.find('option:selected').val(); if (invert) { val = !val; } vis.setValue(oid, val); }); } } if (oid !== 'nothing_selected') { } function onChange(e, newVal, oldVal) { if (newVal === 'false') { newVal = false; } else if (newVal === 'true') { newVal = true; } else if (typeof newVal === 'string') { const f = parseFloat(newVal); if (f == newVal) { newVal = f; } else if (newVal !== '') { newVal = true; } else { newVal = false; } } if (oldVal === 'false') { oldVal = false; } else if (oldVal === 'true') { oldVal = true; } else if (typeof oldVal === 'string') { const f = parseFloat(oldVal); if (f == oldVal) { oldVal = f; } else if (oldVal !== '') { oldVal = true; } else { oldVal = false; } } if (newVal == oldVal) { return; } if (newVal === 'false' || newVal === false || parseFloat(newVal) === 0) { if ($this.find('option[value="1"]').prop('selected')) { $this.find('option[value="1"]').prop('selected', false); $this.find('option[value="0"]').prop('selected', true); $this.trigger('change'); } } else { if ($this.find('option[value="0"]').prop('selected')) { $this.find('option[value="0"]').prop('selected', false); $this.find('option[value="1"]').prop('selected', true); $this.trigger('change'); } } } if (oid) { vis.states.bind(oid + '.val', onChange); // remember all ids, that bound $this .closest('.vis-widget') .data('bound', [oid + '.val']) // remember bind handler .data('bindHandler', onChange); } }, /*pushbutton: function(el, oid) { if (!vis.editMode) { const $this = $(el); oid = oid || $this.data('oid'); $this.on('mousedown touchstart', function (e) { // Protect against two events if (vis.detectBounce(this)) { return; } vis.setValue(oid, true); }); $this.on('mouseup touchend touchcancel', function (e) { // Protect against two events if (vis.detectBounce(this, true)) { return; } vis.setValue(oid, false); }); } },*/ // used in metro toggle: function (el, oid) { const $this = $(el); oid = oid || $this.data('oid'); let min = $this.data('min'); let max = $this.data('max'); const urlTrue = $this.data('url-true'); let urlFalse = $this.data('url-false'); const oidTrue = $this.data('oid-true'); let oidFalse = $this.data('oid-false'); let oidTrueVal = $this.data('oid-true-value'); let oidFalseVal = $this.data('oid-false-value'); const readOnly = $this.data('read-only'); if (min === '') { min = undefined; } if (max === '') { max = undefined; } if ((oid || oidTrue || urlTrue) && !vis.editMode && !readOnly) { let moved = false; $this .on('click touchend', function () { // Protect against two events if (vis.detectBounce(this) || moved) { return; } let val; if (oidTrue || urlTrue) { if (!oidFalse && oidTrue) { oidFalse = oidTrue; } if (!urlFalse && urlTrue) { urlFalse = urlTrue; } if (!oid || oid === 'nothing_selected') { val = !$(this).data('state'); // remember state $(this).data('state', val); } else { val = vis.states[oid + '.val']; if (max !== undefined) { if (max === 'true') max = true; if (max === 'false') max = false; if (val === 'true') val = true; if (val === 'false') val = false; val = val == max; } else { val = val === 1 || val === '1' || val === true || val === 'true'; } val = !val; // invert } if (min === undefined || min === 'false' || min === null) { min = false; } if (max === undefined || max === 'true' || max === null) { max = true; } if (oidTrue) { if (val) { if (oidTrueVal === undefined || oidTrueVal === null) { oidTrueVal = max; } if (oidTrueVal === 'false') { oidTrueVal = false; } if (oidTrueVal === 'true') { oidTrueVal = true; } const f = parseFloat(oidTrueVal); if (f.toString() == oidTrueVal) { oidTrueVal = f; } vis.setValue(oidTrue, oidTrueVal); } else { if (oidFalseVal === undefined || oidFalseVal === null) { oidFalseVal = min; } if (oidFalseVal === 'false') { oidFalseVal = false; } if (oidFalseVal === 'true') { oidFalseVal = true; } const f = parseFloat(oidFalseVal); if (f.toString() == oidFalseVal) { oidFalseVal = f; } vis.setValue(oidFalse, oidFalseVal); } } if (urlTrue) { if (val) { vis.conn.httpGet(urlTrue); } else { vis.conn.httpGet(urlFalse); } } // show new state if (!oid || oid === 'nothing_selected') { const img = $(this).data('img-class'); if (val) {