UNPKG

iobroker.vis

Version:

Graphical user interface for iobroker.

616 lines (543 loc) 28.6 kB
"use strict"; // Following classes should be used if variable table_class="tclass" // <table class="tclass"> // <tr class="tclass-th"> // <th class="tclass-th1">Time</th> // <th class="tclass-th2">Event</th> // </tr> // <tr class="tclass-tr tclass-tr-even tclass-tr-selected"> // <td>12:34:34</td> // <td>Door opened</td> // </tr> // <tr class="tclass-tr tclass-tr-odd tclass-tr-red"> // <td>12:34:35</td> // <td>Door closed</td> // </tr> // <tr class="tclass-tr tclass-tr-even"> // <td>12:34:36</td> // <td>Window opened</td> // </tr> // </table> // // following json string or object is expected: // '[\ // {"Time": "12:34:34", "Event": "Door opened", "_data":{"Type": "1", "Event" : "SomeEvent1"}, "_class": "selected"},\ // {"Time": "12:34:35", "Event": "Door closed", "_data":{"Type": "2", "Event" : "SomeEvent2"}, "_class": "red" },\ // {"Time": "12:34:36", "Event": "Window opened", "_data":{"Type": "3", "Event" : "SomeEvent3"}}\ // ]' // // If _detail object found and detailed_wid is defined // following object will be created by selecting of one row: // <table class="tclass-detail"> // <tr class="tclass-detail-tr tclass-detail-tr-even"><td class="tclass-detail-td-name">Type</td><td class="tclass-detail-td-value">1</td></tr> // <tr class="tclass-detail-tr tclass-detail-tr-odd"><td class="tclass-detail-td-name">Event</td><td class="tclass-detail-td-value">SomeEvent1</td></tr> // </table> // // Dialog // Can be opened by writing "open" into trigger_id. // As dialog closed the trigger_id will be written with the text of button // "show" option is active only in edit mode and has no effect // if (vis.editMode) { // Add words for basic widgets $.extend(true, systemDictionary, { "table_oid": {"en": "Table Object ID", "de": "Table Object ID", "ru": "ID таблицы"}, "static_value": {"en": "Static JSON(If no ID)", "de": "Static JSON(If no ID)", "ru": "Значение, если нет ID таблицы"}, "event_oid": {"en": "Event ID", "de": "Ereigniss ID", "ru": "ID события"}, "hide_header": {"en": "Hide header", "de": "Kein Header", "ru": "Скрыть заголовок"}, "show_scroll": {"en": "Show scroll", "de": "Zeige Scrollbar", "ru": "Показать прокрутку"}, "detailed_wid": {"en": "Detailed widget", "de": "Detailed widget", "ru": "Виджет детализации"}, "colCount": {"en": "Column count", "de": "Kolumnanzahl", "ru": "Кол-во колонок"}, "group_header": {"en": "Headers", "de": "Headers", "ru": "Заголовок"}, "colName": {"en": "Name", "de": "Name", "ru": "Имя"}, "colWidth": {"en": "Width", "de": "Width", "ru": "Ширина"}, "colAttr": {"en": "Attribute in JSON", "de": "Attribut in JSON", "ru": "Атрибут в JSON"}, "ack_oid": {"en": "Acknowledge ID", "de": "Bestätigung ID", "ru": "ID для подтверждения"}, "new_on_top": {"en": "New event on top", "de": "Neus Ereignis am Anfang", "ru": "Новые события сначала"} }); } vis.binds.table = { getBrowserScrollSize: function (){ var css = { "border": "none", "height": "200px", "margin": "0", "padding": "0", "width": "200px" }; var inner = $("<div>").css($.extend({}, css)); var outer = $("<div>").css($.extend({ "left": "-1000px", "overflow": "scroll", "position": "absolute", "top": "-1000px" }, css)).append(inner).appendTo("body") .scrollLeft(1000) .scrollTop(1000); var scrollSize = { height: (outer.offset().top - inner.offset().top) || 0, width: (outer.offset().left - inner.offset().left) || 0 }; outer.remove(); return scrollSize; }, // Show detailed information onRowClick: function () { var $this = $(this); var data = $this.data('options'); // Deselect all rows $('#' + data.wid + ' .vis-table-row').removeClass(data.tClass + '-tr-selected'); // Select a new one $this.addClass(data.tClass + '-tr-selected'); // Get container for detailed information var $el = $('#' + data.detailed_wid); if ($el.length) { var text = ''; if (data.content._detail) { text += '<table class="' + data.tClass + '-detail">'; // Show that object var r = 0; var obj = '_detail'; // Go through all attributes if (typeof data.content[obj] == 'object') { for (var odata in data.content[obj]) { if (typeof data.content[obj][odata] === 'function') continue; var val = data.content[obj][odata].toString(); if (odata.length > 1 && odata[0] === '_' && obj !== '_class' && obj.substring(0, 4) !== '_btn' && obj !== '_id') { continue; } text += '<tr class="' + data.tClass + '-detail-tr ' + data.tClass + '-detail-tr-' + ((r % 2) ? 'odd' : 'even') + '"><td class="' + data.tClass + '-detail-td-name">' + odata + '</td>' + '<td class="' + data.tClass + '-detail-td-value">' + val + '</td></tr>'; if (val && val.length > 6 && val.substring(val.length - 6) === '&nbsp;') { text += '<tr class="' + data.tClass + '-detail-tr"><td colspan="2">&nbsp;</td></tr>'; } r++; } } else { var val = data.content[obj].toString(); text += '<tr class="' + data.tClass + '-detail-tr ' + data.tClass + '-detail-tr-' + ((r % 2) ? 'odd' : 'even') + '"><td class="' + data.tClass + '-detail-td-name">' + obj.substring(1) + '</td>' + '<td class="' + data.tClass + '-detail-td-value">' + val + '</td></tr>'; if (val && val.length > 6 && val.substring(val.length - 6) === '&nbsp;') { text += '<tr class="' + data.tClass + '-detail-tr"><td colspan="2">&nbsp;</td></tr>'; } r++; } text += '</table>'; } else { // Try to find special attributes starting with '_' for (var obj in data.content) { if (!data.content.hasOwnProperty(obj) || typeof data.content[obj] === 'function') continue; if (obj.length > 0 && obj[0] === '_' && obj !== '_class' && obj.substring(0, 4) !== '_btn' && obj !== '_id') { text += '<table class="' + data.tClass + '-detail">'; // Show that object var r = 0; // Go through all attributes if (typeof data.content[obj] === 'object') { for (var odata in data.content[obj]) { if (typeof data.content[obj][odata] === 'function') continue; var val = data.content[obj][odata].toString(); if (odata.length > 1 && odata[0] === '_' && obj !== '_class' && obj.substring(0, 4) !== '_btn' && obj !== '_id') { continue; } text += '<tr class="' + data.tClass + '-detail-tr ' + data.tClass + '-detail-tr-' + ((r % 2) ? 'odd' : 'even') + '"><td class="' + data.tClass + '-detail-td-name">' + odata + '</td>' + '<td class="' + data.tClass + '-detail-td-value">' + val + '</td></tr>'; if (val && val.length > 6 && val.substring(val.length - 6) === '&nbsp;') { text += '<tr class="' + data.tClass + '-detail-tr"><td colspan="2">&nbsp;</td></tr>'; } r++; } } else { var val = data.content[obj].toString(); text += '<tr class="' + data.tClass + '-detail-tr ' + data.tClass + '-detail-tr-' + ((r % 2) ? 'odd' : 'even') + '"><td class="' + data.tClass + '-detail-td-name">' + obj.substring(1) + '</td>' + '<td class="' + data.tClass + '-detail-td-value">' + val + '</td></tr>'; if (val && val.length > 6 && val.substring(val.length - 6) === '&nbsp;') { text += '<tr class="' + data.tClass + '-detail-tr"><td colspan="2">&nbsp;</td></tr>'; } r++; } text += '</table>'; } } } // If no special _data object found => show standard elements if (!text) { text = '<table class="' + data.tClass + '-detail">'; // Go through all attributes var row = 0; for (var data_obj in data.content) { // Show that object if (!data.content.hasOwnProperty(data_obj) || (data_obj.length > 1 && data_obj[0] === '_' && data_obj !== '_class' && data_obj.substring(0, 4) !== '_btn' && data_obj !== '_id')) { continue; } var val = data.content[data_obj].toString(); text += '<tr class="' + data.tClass + '-detail-tr ' + data.tClass + '-detail-tr-' + ((row % 2) ? 'odd' : 'even') + '"><td class="' + data.tClass + '-detail-td-name">' + data_obj + '</td>' + '<td class="' + data.tClass + '-detail-td-value">' + data.content[data_obj]+'</td></tr>'; if (val.length > 6 && val.substring(val.length - 6) === '&nbsp;') { text += '<tr class="' + data.tClass + '-detail-tr"><td colspan="2">&nbsp;</td></tr>'; } row++; } text += '</table>'; } $el.html(text); /*if (options.btn_print) { $(el).append ('<button id="print_'+that._parent._wid+'" class="'+data.tClass+'-print-button">' + options.btn_print + '</button>'); var btn = document.getElementById ('print_'+that._parent._wid); btn._parent = that._parent; btn._print_id = that._data._print_id || JSON.stringify(that._data); if (btn && !vis.editMode) { $(btn).bind('click', function () { if (that._parent._options.ack_oid) { vis.setValue(that._parent._options.ack_oid, that._print_id); } if (that._parent._options.view_for_print) { vis.changeView(that._parent._options.view_for_print); } setTimeout(function () { window.print(); window.location.reload() }, 500); }); } }*/ } }, onAckButton: function () { var data = $(this).data('options'); if (data.ack_oid) { vis.setValue(data.ack_oid, data.ack_id); } }, createRow: function (rowData, wid, options, rowNumber, noTR, index, serverID) { var tClass = options['class'] || 'tclass'; var _classes = rowData['_class'] ? rowData['_class'].split(' ') : null; var text; // Create row if (!noTR) { text = '<tr class="vis-table-row ' + tClass + '-tr ' + tClass + ((rowNumber % 2) ? '-tr-even' : '-tr-odd'); if (_classes) { for (var t = 0, len = _classes.length; t < len; t++) { text += ' ' + (tClass + '-tr-' + _classes[t]); } } text += '" data-index="' + index + '" data-server-id="' + serverID + '">'; } else { text = ''; } var k = 1; for (var obj in rowData) { if (!rowData.hasOwnProperty(obj) || obj.match(/^jQuery/) || typeof rowData[obj] === 'function') { continue; } var attr = options['colAttr' + k] || obj; if (attr && attr[0] === '_') { if (attr.match(/^_btn/) || options['colAttr' + k]) { var btnText = ''; var btnClass = ''; text += '<td class="' + tClass + '-th' + k + '" ' + (options['colWidth' + k] ? 'style="width:' + options['colWidth' + k] + '"' : '') + '>'; if (attr.match(/^_btn/)){ if (typeof rowData[attr] === 'string') { btnText = rowData[attr]; } else { btnText = rowData[attr].caption; btnClass = rowData[attr]._class; } if (btnText) { text += '<button data-index="' + index + '" data-server-id="' + serverID + '" class="vis-table-ack-button ' + tClass + '-ack-button ' + (btnClass ? ('-' + btnClass) : '') + '">' + btnText + '</button>'; } } else { text += rowData[attr]; } text += '</td>'; k++; } continue; } if (!options.colCount || k <= options.colCount) { text += '<td class="' + tClass + '-th' + k + '" ' + (options['colWidth' + k] ? 'style="width:' + options['colWidth' + k] + '"' : '') + '>' + rowData[attr] + '</td>'; } k++; } if (!noTR) text += '</tr>'; return text; }, showTable: function (view, wid, options) { var $div = $('#' + wid); if (!$div.length) { setTimeout(function () { vis.binds.table.showTable(view, wid, options); }, 100); return; } //vis.binds.table.initTable(); var tClass = options['class'] || 'tclass'; // read actual table as json string var tableJson = options.table_oid ? vis.states.attr(options.table_oid + '.val') : (options.static_value || ''); var table = []; if (typeof app !== 'undefined' && app.replaceFilePathJson) { tableJson = app.replaceFilePathJson(tableJson); } if (tableJson && typeof tableJson === 'string') { try { table = JSON.parse(tableJson); } catch (e) { console.log ("showTable: Cannot parse json table"); table = []; } } else { table = tableJson; } if (!table) table = []; // Create widget container var $elem = $('#' + wid); // Start creation of table var header = '<table class="vis-table-header ' + tClass + '">'; var text = '<div class="vis-table-div ' + tClass + '-inner' + ((options.show_scroll) ? ' tclass-inner-overflow' : '') + '"><table class="vis-table-body ' + tClass + '">'; var headerDone = false; var j = 0; var selectedId = null; if (options.max_rows) options.max_rows = parseInt(options.max_rows); // Go through all lines for (var ii = 0, ilen = table.length; ii < ilen; ii++) { if (!table[ii]) continue; var _classes = table[ii]['_class'] ? table[ii]['_class'].split(' ') : null; // Create table header if (!headerDone) { header += '<tr class="' + tClass + '-th">'; var k = 1; for (var obj in table[ii]) { if (!table[ii].hasOwnProperty(obj) || obj.match(/^jQuery/) || typeof table[ii][obj] === 'function') { continue; } var attr = options['colAttr' + k] || obj; if (attr && attr[0] === '_') { if (attr.match(/^_btn/) || options['colAttr' + k]) { header += '<th class="' + tClass + '-th' + k + '" ' + (options['colWidth' + k] ? 'style="width:' + options['colWidth' + k] + '"' : '') + '>' + (options['colName' + k] || '') + '</th>'; k++; } continue; } if (!options.colCount || k <= options.colCount) { header += '<th class="' + tClass + '-th' + k + '" ' + (options['colWidth' + k] ? 'style="width:' + options['colWidth' + k] + '"' : '') + '>' + (options['colName' + k] || attr) + '</th>'; } k++; } if (options.show_scroll !== 'false' && options.show_scroll !== false && options.show_scroll !== undefined){ // Get the scroll width once if (!vis.binds.table.scrollSize) vis.binds.table.scrollSize = vis.binds.table.getBrowserScrollSize(); header += '<td style="width:' + (vis.binds.table.scrollSize.width - 6) + 'px"></td></tr>'; } //header += '</tr>'; headerDone = true; } if (_classes &&_classes.indexOf('selected') !== -1) selectedId = ii; text += vis.binds.table.createRow(table[ii], wid, options, j, false, ii, table[ii]._id); j++; if (options.max_rows && j >= options.max_rows) break; } text += '</table></div>\n'; header += '</table>\n'; $elem.find('.vis-table-div').remove(); $elem.find('.vis-table-header').remove(); // Insert table into container $elem.append((options.hide_header ? '' : header) + text); var data = { options: options, wid: wid, view: view }; $elem.find('.vis-table-ack-button').unbind('click touchstart').bind('click touchstart', function (e) { // Protect against two events if (vis.detectBounce(this)) return; vis.binds.table.onAckButton.call(this, e); }); // Set additional data for every row for (var i = 0, len = table.length; i < len; i++) { if (!table[i]) continue; $elem.find('.vis-table-ack-button[data-index="' + i + '"]') .data('options', { ack_id: table[i]._ack_id || JSON.stringify(table[i]), ack_oid: options.ack_oid }); } // If detailed information desired if (options.detailed_wid) { // Bind on click event for every row $elem.find('.vis-table-row').unbind('click touchstart').bind('click touchstart', function (e) { // Protect against two events if (vis.detectBounce(this)) return; vis.binds.table.onRowClick.call(this, e); }); // Set additional data for every row for (i = 0, len = table.length; i < len; i++) { if (!table[i]) continue; $elem.find('.vis-table-row[data-index="' + i + '"]') .data('options', { content: table[i], detailed_wid: options.detailed_wid, tClass: tClass, wid: wid }); } if (selectedId) { setTimeout (function () { $elem.find('.vis-table-row[data-index="' + selectedId + '"]').trigger('click'); }, 200); } } // Remember index to calculate even or odd data.rowNum = options.new_on_top ? 0 : ((j - 1) >= 0 ? j - 1 : 0); function cbNewTable (e, newVal, oldVal) { $elem.trigger('newTable', newVal); } function cbNewEvent (e, newVal, oldVal) { $elem.trigger('newEvent', newVal); } if (!$('#' + wid).data('inited')) { $('#' + wid).data('inited', true); // New event coming $elem.on('newEvent', function (e, newVal) { if (e.handled) return; e.handled = true; var newEvent; var data = $(this).data('options'); // Convert event to json if (newVal) { if (typeof newVal === 'string') { try { newEvent = JSON.parse(newVal); } catch (e) { console.log('elem.triggered: Cannot parse json new event ' + newVal); return; } } else { newEvent = newVal; } } else { return; } // Try to find, if this event yet exists var $row = (newEvent._id !== undefined) ? $(this).find('tr[data-index="' + newEvent._id + '"]') : []; // get next row number for new line if (!$row.length) data.rowNum++; var text = vis.binds.table.createRow(newEvent, data.wid, data.options, data.rowNum, ($row.length > 0), (newEvent._id === undefined) ? data.rowNum : newEvent._id); if ($row.length) { $row.html(text).addClass(newEvent._class || ''); } else { // If add to the top of table if (data.options.new_on_top) { $('#' + this.id).find('.vis-table-body').prepend(text); } else { // Add to the bottom of table $('#' + this.id).find('.vis-table-body').append(text); } } var $el; // If detailed widget desired if (data.options.detailed_wid) { $el = $('#' + this.id).find('.vis-table-row[data-index="' + ((newEvent._id === undefined) ? data.rowNum : newEvent._id) + '"]') .data('options', { content: newEvent, detailed_wid: options.detailed_wid, tClass: tClass, wid: wid }).unbind('click touchstart').bind('click touchstart', function (e) { // Protect against two events if (vis.detectBounce(this)) return; vis.binds.table.onRowClick.call(this, e); }); $el = $(this).find('.tr_' + ((newEvent._id === undefined) ? data.rowNum : newEvent._id)); } $('#' + this.id).find('.ack_button_' + ((newEvent._id === undefined) ? data.rowNum : newEvent._id)) .data('options', {data: newEvent, parent: this, ack_id: newEvent._ack_id || JSON.stringify(newEvent)}) .unbind('click touchstart').bind('click touchstart', function (e) { // Protect against two events if (vis.detectBounce(this)) return; vis.binds.table.onAckButton.call(this, e); }); }) .on('newTable', function (e, newVal) { if (e.handled) return; e.handled = true; var data = $(this).data('options'); // Update whole table _setTimeout(vis.binds.table.showTable, 50, data.view, data.wid, data.options); }); } $('#' + wid).data('options', data); if (options.event_oid) { if ($('#' + wid).data('binded') !== options.event_oid) { $('#' + wid).data('binded', options.event_oid); vis.states.bind(options.event_oid + '.val', cbNewEvent); } } else { if ($('#' + wid).data('binded') !== options.table_oid) { $('#' + wid).data('binded', options.table_oid); vis.states.bind(options.table_oid + '.val', cbNewTable); } } }, showDialog: function (view, wid, options) { var trigger_value = vis.states.attr(options.trigger_id + '.val'); // Register callback in dashUI if (options.trigger_id) vis.binds.table.registerIds(wid, options.trigger_id); // Create widget container $('#' + wid).remove(); $('#visview_' + view).append('<div class="vis-widget ' + (options._class || "") + '" id="' + wid + '" data-oid="' + (options.trigger_id || '') + '" title="'+options.title+'">' + '<table style="margin-left: ' + options.margin_left + 'px;margin-top:' + options.margin_top + 'px"><tr><td>' + (options.image ? '<img src="' + options.image + '"/>': '') + '</td><td>' + options.text + '</td></tr></table>' + '</div>'); var elem = document.getElementById(wid); var buttons = {}; for (var t = 0, len = options.buttons.length; t < len; t++) { if (options.buttons[t]) { buttons[options.buttons[t]] = { text: options.buttons[t], data: {data: options.buttons[t], trigger_id: options.trigger_id}, click: function (evt, ui) { if (1 || !vis.editMode) { if (vis.binds.dialog_trigger_id) { vis.setValue(vis.binds.dialog_trigger_id, evt.currentTarget.textContent); } } $(this).dialog('close'); } } } } elem._options = options; // Disable autofocus in edit mode if (vis.editMode) { $.ui.dialog.prototype._focusTabbable = function () { }; } $(elem).dialog({ resizable: false, height: options.height || 200, width: options.width || 400, autoOpen: false, modal: (options.modal === true || options.modal === 'true'), draggable: false, buttons: buttons }); if ((vis.editMode && options.show) || trigger_value === 'open') { $(elem).dialog('open'); vis.binds.dialog_trigger_id = options.trigger_id; } elem.triggered = function (objId, _newEvent) { if (_newEvent === 'open') { $(this).dialog('open'); vis.binds.dialog_trigger_id = this._options.trigger_id; } } } };