/** * yunkong2.vis * https://github.com/yunkong2/yunkong2.vis * * Copyright (c) 2013-2018 bluefox https://github.com/GermanBluefox, hobbyquaker https://github.com/hobbyquaker * Creative Common Attribution-NonCommercial (CC BY-NC) * * http://creativecommons.org/licenses/by-nc/4.0/ * * Short content: * Licensees may copy, distribute, display and perform the work and make derivative works based on it only if they give the author or licensor the credits in the manner specified by these. * Licensees may copy, distribute, display, and perform the work and make derivative works based on it only for noncommercial purposes. * (Free for non-commercial use). */ // visEdit - the yunkong2.vis Editor /* jshint browser:true */ /* global document */ /* global console */ /* global session */ /* global window */ /* global location */ /* global setTimeout */ /* global clearTimeout */ /* global io */ /* global $ */ /* global vis:true */ /* global local */ /* global can */ /* global colorSelect */ /* global storage */ /* global html2canvas */ /* global translateAll */ /* global ace */ /* global _ */ /* jshint -W097 */// jshint strict:false // Format: attr_name(start-end)[default_value]/type/onChangeFunc // attr_name can be extended with numbers (1-2) means it will be attr_name1 and attr_name2 created // end number can be other attribute, e.g (1-count) // defaultValue: If defaultValue has ';' it must be replaced by § // defaultValue: If defaultValue has '/' it must be replaced by ~ // defaultValue: If defaultValue has '"' it must be replaced by ^ // defaultValue: If defaultValue has '^' it must be replaced by ^^ // onChangeFunc has following attributes (widgetID, view, newId, attr, isCss) and must return back the array with changed attributes or null // Type format: id - Object ID Dialog // hid // checkbox // image - image // number,min,max,step - non-float number. min,max,step are optional // color - color picker // views - Name of the view // effect - jquery UI show/hide effects // eff_opt - additional option to effect slide (up, down, left, right) // fontname - Font name // slider,min,max,step - Default step is ((max - min) / 100) // select,value1,value2,... - dropdown select // nselect,value1,value2,... - same as select, but without translation of items // auto,value1,value2,... - autocomplete // style,fileFilter,nameFilter,attrFilter // custom,functionName,options,... - custom editor - functionName is starting from vis.binds.[widgetset.funct]. E.g. custom/timeAndWeather.editWeather,short // group.name - define new or old group. All following attributes belongs to new group till new group.xyz // group.name/byindex/icon - like group, but all following attributes will be grouped by ID. Icon is optional. Like group.windows/byindex;slide(1-4)/id;slide_type(1-4)/select,open,closed Following groups will be created Windows1(slide1,slide_type1), Windows2(slide2,slide_type2), Windows3(slide3,slide_type3), Windows4(slide4,slide_type4) // text - dialog box with html editor // html - dialog box with html editor // widget - existing widget selector // history - select history instances 'use strict'; vis = $.extend(true, vis, { fontNames: [ 'Verdana, Geneva, sans-serif', 'Georgia, "Times New Roman", Times, serif', '"Courier New", Courier, monospace', 'Arial, Helvetica, sans-serif', 'Tahoma, Geneva, sans-serif', '"Trebuchet MS", Arial, Helvetica, sans-serif', '"Arial Black", Gadget, sans-serif', '"Times New Roman", Times, serif', '"Palatino Linotype", "Book Antiqua", Palatino, serif', '"Lucida Sans Unicode", "Lucida Grande", sans-serif', '"MS Serif", "New York", serif', '"Comic Sans MS", cursive' ], editObjectID: function (widAttr, widgetFilter, isHistory, onChange) { var that = this; if (typeof isHistory === 'function') { onChange = isHistory; isHistory = false; } // Edit for Object ID var line = [ { input: '' } ]; if (this.objectSelector) { line[0].button = { icon: 'ui-icon-note', text: false, title: _('Select object ID'), click: function () { var wdata = $(this).data('wdata'); $('#dialog-select-member-' + wdata.attr).selectId('show', that.views[wdata.view].widgets[wdata.widgets[0]].data[wdata.attr], function (newId, oldId) { if (oldId !== newId) { $('#inspect_' + wdata.attr).val(newId).trigger('change'); if ($('#inspect_min').length) { if (that.objects[newId] && that.objects[newId].common && that.objects[newId].common.min !== undefined) { $('#inspect_min').val(that.objects[newId].common.min).trigger('change'); } } if ($('#inspect_max').length) { if (that.objects[newId] && that.objects[newId].common && that.objects[newId].common.max !== undefined) { $('#inspect_max').val(that.objects[newId].common.max).trigger('change'); } } if ($('#inspect_oid-working').length) { if (that.objects[newId] && that.objects[newId].common && that.objects[newId].common.workingID) { if (that.objects[newId].common.workingID.indexOf('.') !== -1) { $('#inspect_oid-working').val(that.objects[newId].common.workingID).trigger('change'); } else { var parts = newId.split('.'); parts.pop(); parts.push(that.objects[newId].common.workingID); $('#inspect_oid-working').val(parts.join('.')).trigger('change'); } } } /* if (document.getElementById('inspect_hm_wid')) { if (that.objects[newId]['Type'] !== undefined && that.objects[value]['Parent'] !== undefined && (that.objects[newId]['Type'] === 'STATE' || that.objects[newId]['Type'] === 'LEVEL')) { var parent = that.objects[newId]['Parent']; if (that.objects[parent]['DPs'] !== undefined && that.objects[parent]['DPs']['WORKING'] !== undefined) { $('#inspect_hm_wid').val(that.objects[parent]['DPs']['WORKING']); $('#inspect_hm_wid').trigger('change'); } } } // Try to find Function of the device and fill the Filter field var $filterkey = $('#inspect_filterkey'); if ($filterkey.length) { if ($filterkey.val() === '') { var oid = newId; var func = null; if (that.metaIndex && that.metaIndex['ENUM_FUNCTIONS']) { while (oid && that.objects[oid]) { for (var t = 0; t < that.metaIndex['ENUM_FUNCTIONS'].length; t++) { var list = that.objects[that.metaIndex['ENUM_FUNCTIONS'][t]]; for (var z = 0; z < list['Channels'].length; z++) { if (list['Channels'][z] === oid) { func = list.Name; break; } } if (func) break; } if (func) break; oid = that.objects[oid]['Parent']; } } if (func) $filterkey.val(func).trigger('change'); } }*/ } }); } }; line[0].onchange = function (val, oldValue) { var wdata = $(this).data('wdata'); $('#inspect_' + wdata.attr + '_desc').html(that.getObjDesc(val)); var userOnchange = $(this).data('onchange'); if (userOnchange) { for (var w = 0; w < wdata.widgets.length; w++) { var widgetSet = $('#' + that.views[wdata.view].widgets[wdata.widgets[w]].tpl).attr('data-vis-set'); if (that.binds[widgetSet] && that.binds[widgetSet][userOnchange]) { return that.binds[widgetSet][userOnchange](wdata.widgets[w], wdata.view, that.widgets[wdata.widgets[w]].data[wdata.attr], wdata.attr, false, oldValue); } } } }; line.push({input: '
'}); var $dialog = $('#dialog-select-member-' + widAttr); // Init select dialog if (!$dialog.length) { $('body').append(''); $('#dialog-select-member-' + widAttr).selectId('init', { filter: { common: { history: isHistory ? { enabled: true } : undefined } }, texts: { select: _('Select'), cancel: _('Cancel'), all: _('All'), id: _('ID'), name: _('Name'), role: _('Role'), room: _('Room'), value: _('Value'), selectid: _('Select ID'), enum: _('Members'), from: _('from'), lc: _('lc'), ts: _('ts'), ack: _('ack'), expand: _('expand'), collapse: _('collapse'), refresh: _('refresh'), edit: _('edit'), ok: _('ok'), wait: _('wait'), list: _('list'), tree: _('tree'), copyToClipboard: _('Copy to clipboard') }, filterPresets: {role: widgetFilter}, noMultiselect: true, columns: ['image', 'name', 'type', 'role', 'enum', 'room', 'value'], imgPath: '/lib/css/fancytree/', objects: this.objects, states: this.states, zindex: 1001 }); } else { $dialog.selectId('option', 'filterPresets', {role: widgetFilter}); $dialog.selectId('option', 'filter', { common: { history: isHistory ? { enabled: true } : undefined } }); } } return line; }, editWidgetNames: function (widAttr, options) { // options[0] all views var widgets = ['']; if (options && options[0] === 'all') { for (var w in this.widgets) { widgets.push(w); } } else { for (var w in this.views[this.activeView].widgets) { widgets.push(w); } } return this.editSelect(widAttr, widgets, true); }, editSelect: function (widAttr, values, notTranslate, init, onchange) { if (typeof notTranslate === 'function') { onchange = init; init = notTranslate; notTranslate = false; } // Select var line = { input: ''; return line; }, editStyle: function (widAttr, options) { var that = this; // options[0] fileFilter // options[1] nameFilter // options[2] attrFilter // Effect selector return { input: '', init: function (_wid_attr, data) { if (that.styleSelect) { that.styleSelect.show({ width: '100%', name: 'inspect_' + _wid_attr, filterFile: options[0], filterName: options[1], filterAttrs: options[2], removeName: options[3], style: data, parent: $(this).parent(), onchange: function (newStyle) { $('#inspect_' + widAttr).val(newStyle).trigger('change'); } }); $('#inspect_' + widAttr).hide(); } } }; }, editFontName: function (widAttr) { var that = this; // Auto-complete return { input: '', init: function (_wid_attr, data) { $(this).autocomplete({ minLength: 0, source: function (request, response) { var _data = $.grep(that.fontNames, function (value) { return value.substring(0, request.term.length).toLowerCase() === request.term.toLowerCase(); }); response(_data); }, select: function (event, ui) { $(this).val(ui.item.value); $(this).trigger('change', ui.item.value); } }).focus(function () { // Show dropdown menu $(this).autocomplete('search', ''); }).autocomplete('instance')._renderItem = function (ul, item) { return $('| title: | button | |||||
| ' + (this.groupsIcons[group] ? ' ' + groupName + ' ' : groupName) + ' | '); var gText = ' | |||||
| ' + groupName + ' | '; var isGroupEnabledObj = group === 'common' || group === 'css_common' ? true : this.findCommonValue(view, widgets, 'g_' + group); var isGroupEnabled = false; var isGroupEnabledIndeterminate = false; if (typeof isGroupEnabledObj === 'object' && isGroupEnabledObj.values) { for (var g = 0; g < isGroupEnabledObj.values.length; g++) { if (isGroupEnabledObj.values[g] !== false) { isGroupEnabled = true; isGroupEnabledIndeterminate = true; break; } } } else { isGroupEnabled = isGroupEnabledObj; } isGroupEnabled = isGroupEnabled !== false; this.groups[group].___enabled = isGroupEnabled; if (group === 'common' || group === 'css_common') { gText += ''; } else { gText += ' | '; } if (isGroupEnabled) { gText += ' | '; } else { gText += ' | '; } $widgetAttrs.append(gText); if (isGroupEnabled) { for (widAttr in this.groups[group]) { if (!this.groups[group].hasOwnProperty(widAttr) || widAttr === '___enabled') continue; var line = this.groups[group][widAttr]; if (line === 'delimiter') { $widgetAttrs.append(' | ||
| ' + (icon ? '' : '') + _(line.attrName) + (line.attrIndex !== '' ? ('[' + line.attrIndex + ']') : '') + ':' + (icon ? '' : '') + ' | ' + (line.input || '') + ' | '; if (line.button) { if (!line.button.html) { text += ''; } else { text += ' | ' + line.button.html + ' | '; } } if (line.css) { text += ''; } text += ' | ||
| ' + this.groups[group][widAttr][i].input + ' | '; $widgetAttrs.append(text); } } // Collect list of attribute names on which depends other attributes if (line.depends) { for (var u = 0; u < line.depends.length; u++) { if (depends.indexOf(line.depends[u]) === -1) depends.push(line.depends[u]); } } } // Hide elements if (!this.groupsState[group]) $widgetAttrs.find('.group-' + group).hide(); } } $('.vis-edit-percent-calc').each(function () { var attr = $(this).data('attr'); var val = $('#inspect_css_' + attr).val(); if (val.toString().indexOf('%') === -1) { $(this).html('px'); } else { $(this).html('%'); } $(this).button().css({width: 18, height: 18}).click(function () { var attr = $(this).data('attr'); var $input = $('#inspect_css_' + attr); var val = $input.val(); if (val.toString().indexOf('%') === -1) { // convert to % for (var i = 0; i < that.activeWidgets.length; i++) { var rect = that.editConvertToPercent(viewDiv, view, that.activeWidgets[i], viewDiv !== view ? viewDiv : null); that.views[view].widgets[that.activeWidgets[i]].style[attr] = rect[attr]; $('#' + that.activeWidgets[i]).css(attr, rect[attr]); } that.setAttrValue(view, that.activeWidgets, 'css_' + attr, true, {}); $(this).html('%'); } else { // convert to px for (var j = 0; j < that.activeWidgets.length; j++) { var pRect = that.editConvertToPx(viewDiv, view, that.activeWidgets[j], viewDiv !== view ? viewDiv : null); that.views[view].widgets[that.activeWidgets[j]].style[attr] = pRect[attr]; $('#' + that.activeWidgets[j]).css(attr, pRect[attr]); } that.setAttrValue(view, that.activeWidgets, 'css_' + attr, true, {}); $(this).html('px'); } }); }); // Init all elements together for (group in this.groups) { if (!this.groups.hasOwnProperty(group) || !this.groups[group].___enabled) continue; for (widAttr in this.groups[group]) { var line_ = this.groups[group][widAttr]; var $input_ = $widgetAttrs.find('#inspect_' + widAttr); var wdata_ = $input_.data('wdata'); if (depends.length) $input_.data('depends', depends); if (line_[0]) line_ = line_[0]; if (typeof line_ === 'string') line_ = {input: line_}; if (typeof line_.init === 'function') { if (wdata_.css) { var cwidAttr_ = widAttr.substring(4); if (values[cwidAttr_] === undefined) values[cwidAttr_] = this.findCommonValue(view, widgets, cwidAttr_); line_.init.call($input_[0], cwidAttr_, values[cwidAttr_]); } else { if (values[widAttr] === undefined) values[widAttr] = this.findCommonValue(view, widgets, widAttr); line_.init.call($input_[0], widAttr, values[widAttr]); } } // Call on change if (typeof line_.onchange === 'function') { if (wdata_.css) { var cwidAttr = widAttr.substring(4); if (values[cwidAttr] === undefined) values[cwidAttr] = this.findCommonValue(view, widgets, cwidAttr); line_.onchange.call($input_[0], values[cwidAttr]); } else { if (values[widAttr] === undefined) values[widAttr] = this.findCommonValue(view, widgets, widAttr); line_.onchange.call($input_[0], values[widAttr]); } } } } this.initStealHandlers(); $widgetAttrs.find('.vis-inspect-widget').change(function () { var $this = $(this); var wdata = $this.data('wdata'); var depends = $this.data('depends'); var diff = $this.data('different'); var oldValue = null; // Set flag, that value was modified if (diff) $this.data('different', false).removeClass('vis-edit-different'); var css = wdata.attr.substring(4); var val = ($this.attr('type') === 'checkbox') ? $this.prop('checked') : $this.val(); for (var i = 0; i < wdata.widgets.length; i++) { if (wdata.css) { if (!that.views[wdata.view].widgets[wdata.widgets[i]].style) { that.views[wdata.view].widgets[wdata.widgets[i]].style = {}; } oldValue = that.views[wdata.view].widgets[wdata.widgets[i]].style[css]; that.views[wdata.view].widgets[wdata.widgets[i]].style[css] = val; if (css !== 'transform') { var $widget = $('#' + wdata.widgets[i]); if (val !== '' && (css === 'left' || css === 'top') && (val.indexOf('%') === -1 && val.indexOf('px') === -1 && val.indexOf('em') === -1)) { $widget.css(css, val + 'px'); } else { $widget.css(css, val); } } if (that.activeWidgets.indexOf(wdata.widgets[i]) !== -1) { that.showWidgetHelper(viewDiv, view, wdata.widgets[i], true); } if ($('#' + that.views[wdata.view].widgets[wdata.widgets[i]].tpl).attr('data-vis-update-style')) { that.reRenderWidgetEdit(viewDiv, view, wdata.widgets[i]); } } else { oldValue = that.widgets[wdata.widgets[i]].data[wdata.attr]; that.views[wdata.view].widgets[wdata.widgets[i]].data[wdata.attr] = that.widgets[wdata.widgets[i]].data[wdata.attr] = val; } // Some user adds ui-draggable and ui-resizable as class to widget. // The result is DashUI tries to remove draggable and resizable properties and fails if (wdata.attr === 'class') { var _val_ = that.views[wdata.view].widgets[wdata.widgets[i]].data[wdata.attr]; if (_val_.indexOf('ui-draggable') !== -1 || _val_.indexOf('ui-resizable') !== -1) { var vals = _val_.split(' '); _val_ = ''; for (var j = 0; j < vals.length; j++) { if (vals[j] && vals[j] !== 'ui-draggable' && vals[j] !== 'ui-resizable') { _val_ += ((_val_) ? ' ' : '') + vals[j]; } } that.views[wdata.view].widgets[wdata.widgets[i]].data[wdata.attr] = _val_; $this.val(_val_); } } // Update select widget dropdown if (wdata.attr === 'name') { that.$selectActiveWidgets.find('option[value="' + wdata.widgets[i] + '"]').text(that.getWidgetName(wdata.view, wdata.widgets[i])); that.sortSelectWidget(); that.$selectActiveWidgets.multiselect('refresh'); } var changed = false; if (typeof wdata.onchange === 'function') { if (wdata.css) { var _css = wdata.attr.substring(4); changed = wdata.onchange.call(this, that.views[wdata.view].widgets[wdata.widgets[i]].style[_css], oldValue) || false; } else { changed = wdata.onchange.call(this, that.widgets[wdata.widgets[i]].data[wdata.attr], oldValue) || false; } } if (wdata.onChangeWidget) { var widgetSet = $('#' + that.views[wdata.view].widgets[wdata.widgets[i]].tpl).attr('data-vis-set'); if (that.binds[widgetSet] && that.binds[widgetSet][wdata.onChangeWidget]) { var _changed; if (wdata.css) { var __css = wdata.attr.substring(4); _changed = that.binds[widgetSet][wdata.onChangeWidget](wdata.widgets[i], wdata.view, that.views[wdata.view].widgets[wdata.widgets[i]].style[__css], __css, true, oldValue); } else { _changed = that.binds[widgetSet][wdata.onChangeWidget](wdata.widgets[i], wdata.view, that.widgets[wdata.widgets[i]].data[wdata.attr], wdata.attr, false, oldValue); } if (!changed) changed = _changed; } } that.save(viewDiv, view); if (!wdata.css) that.reRenderWidgetEdit(viewDiv, view, wdata.widgets[i]); // Rebuild attr list if (changed || (depends && depends.indexOf(wdata.attr) !== -1)) that.inspectWidgets(viewDiv, view); } //Update containers if (wdata.type === 'views') { // Set ths views for containers that.updateContainers(wdata.view, wdata.view); } }); $widgetAttrs.find('.group-control').each(function () { var group = $(this).attr('data-group'); $(this).button({ text: false, icons: { primary: that.groupsState[group] ? "ui-icon-triangle-1-n" : "ui-icon-triangle-1-s" } }).css({width: 22, height: 22}).click(function () { var group = $(this).attr('data-group'); that.groupsState[group] = !that.groupsState[group]; $(this).button('option', { icons: {primary: that.groupsState[group] ? "ui-icon-triangle-1-n" : "ui-icon-triangle-1-s"} }); if (that.groupsState[group]) { $('.group-' + group).show(); if (that.widgetAccordeon) { //close others $('.group-control').each(function () { var _group = $(this).attr('data-group'); if (_group !== group && that.groupsState[_group]) { that.groupsState[_group] = false; $('.group-control[data-group="' + _group + '"]').button('option', {icons: {primary: "ui-icon-triangle-1-s"}}); $('.group-' + _group).hide(); } }); } } else { $('.group-' + group).hide(); } that.editSaveConfig('groupsState', that.groupsState); }); }); function deleteAttrs(group, widgets, viewDiv, view, value) { var isCss = group.substring(0, 4) === 'css_'; for (var i = 0; i < widgets.length; i++) { if (!value) { var cssChanged = false; var $style; if (isCss) $style = $('#' + wdata.widgets[i]).prop('style'); for (var attr in that.groups[group]) { if (!that.groups[group].hasOwnProperty(attr)) continue; if (isCss) { if (that.views[view].widgets[widgets[i]].style) { attr = attr.substring(4); delete that.views[view].widgets[widgets[i]].style[attr]; cssChanged = true; $style.removeProperty(attr); } } else { delete that.views[view].widgets[widgets[i]].data[attr]; } } if (cssChanged && $('#' + that.views[view].widgets[widgets[i]].tpl).attr('data-vis-update-style')) { that.reRenderWidgetEdit(viewDiv, view, widgets[i]); } } that.widgets[widgets[i]].data['g_' + group] = value; that.views[view].widgets[widgets[i]].data['g_' + group] = value; } that.save(viewDiv, view); // Rebuild attr list that.inspectWidgets(viewDiv, view); } $widgetAttrs.find('.group-enable').change(function () { var $this = $(this); var group = $this.attr('data-group'); var wdata = $this.data('wdata'); var checked = $this.prop('checked'); // Set flag, that value was modified var isCss = group.substring(0, 4) === 'css_'; var isEmpty = true; if (!checked) { // check all attributes in this group and if some are not empty, ask for (var i = 0; i < wdata.widgets.length; i++) { for (var attr in that.groups[group]) { var val; if (isCss) { val = that.views[wdata.view].widgets[wdata.widgets[i]].style[attr.substring(4)]; } else { val = that.views[wdata.view].widgets[wdata.widgets[i]].data[attr]; } if (val !== undefined && val !== null && val !== '') { isEmpty = false; break; } } if (!isEmpty) break; } if (!isEmpty) { vis.showMessage(_('Some field are not empty. Sure?'), _('Are you sure?'), 450, function (result) { if (result) { deleteAttrs(group, wdata.widgets, wdata.viewDiv, wdata.view, false); } else { $this.prop('checked', true); } }); } else { deleteAttrs(group, wdata.widgets, wdata.viewDiv, wdata.view, false); } } else { deleteAttrs(group, wdata.widgets, wdata.viewDiv, wdata.view, true); } }).each(function() { $(this).data('wdata', { widgets: widgets, view: view, viewDiv: viewDiv }); if ($(this).data('indeterminate')) { $(this).prop('indeterminate', true) } }); }, extractAttributes: function (_wid_attr, widget) { //returns array of all attributes with groups /*var oneAttr = { name: '', type: '', default: '', options: '', notTranslate: false, depends: [] } Result: array of oneAttr */ if (!this.regexAttr) this.regexAttr = /([a-zA-Z0-9._-]+)(\([a-zA-Z.0-9-_]*\))?(\[.*])?(\/[-_,^§~\s:\/\.a-zA-Z0-9]+)?/; var match = this.regexAttr.exec(_wid_attr); var widAttr = match[1]; var wid_repeats = match[2]; var wid_default = match[3]; var wid_type = match[4]; var wid_on_change = null; var wid_type_opt = null; var notTranslate = false; var index = ''; var attrDepends = []; // remove / if (wid_type) { wid_type = wid_type.substring(1); // extract on change function var _parts = wid_type.split('/'); wid_type = _parts[0]; wid_on_change = _parts[1]; wid_type = wid_type.replace(/§/g, ';'); wid_type = wid_type.replace(/~/g, '/'); wid_type = wid_type.replace(/\^/g, '"'); wid_type = wid_type.replace(/\^\^/g, '^'); parts = wid_type.split(','); // extract min,max,step or select values if (parts.length > 1) { wid_type = parts.shift(); wid_type_opt = parts; } } // remove () if (wid_repeats) { wid_repeats = wid_repeats.substring(1, wid_repeats.length - 1); var parts = wid_repeats.split('-', 2); if (parts.length === 2) { wid_repeats = { start: parseInt(parts[0], 10), end: parseInt(parts[1], 10) }; // If end is not number, it can be attribute if (parts[1][0] < '0' || parts[1][0] > '9') { var view = this.getViewOfWidget(widget); var widgetData = this.views[view].widgets[widget].data; wid_repeats.end = (widgetData[parts[1]] !== undefined) ? parseInt(widgetData[parts[1]], 10) : 1; attrDepends.push(parts[1]); } index = wid_repeats.start; } else { throw 'Invalid repeat argument: ' + wid_repeats; } } // remove [] if (wid_default) { wid_default = wid_default.substring(1, wid_default.length - 1); wid_default = wid_default.replace(/§/g, ';'); wid_default = wid_default.replace(/~/g, '/'); wid_default = wid_default.replace(/\^/g, '"'); wid_default = wid_default.replace(/\^\^/g, '^'); } else { wid_default = undefined; } if (widAttr === 'color') { wid_type = 'color'; } else if (widAttr === 'oid' || widAttr.match(/^oid-/)) { wid_type = wid_type || 'id'; } else if (widAttr.match(/nav_view$/)) { wid_type = 'views'; } else /*if (widAttr.match(/src$/)) { wid_type = 'image'; } else*/ if (widAttr === 'sound') { wid_type = 'sound'; } else if (widAttr.indexOf('_effect') !== -1) { wid_type = 'effect'; } else if (widAttr.indexOf('_eff_opt') !== -1) { wid_type = 'effect-options'; } if (wid_type === 'nselect') { wid_type = 'select'; notTranslate = true; } // Extract min, max, step for number and slider if ((wid_type === 'number' || wid_type === 'slider') && wid_type_opt) { var old = wid_type_opt; wid_type_opt = {}; if (old[0] !== undefined) { wid_type_opt.min = parseFloat(old[0]); if (old[1] !== undefined) { wid_type_opt.max = parseFloat(old[1]); if (old[2] !== undefined) { wid_type_opt.step = parseFloat(old[2]); } } } } var result = []; do { result.push({ name: (widAttr + index), type: wid_type, default: wid_default, options: wid_type_opt, onChangeWidget: wid_on_change, notTranslate: notTranslate, depends: attrDepends, clearName: widAttr, index: index }); } while (wid_repeats && ((++index) <= wid_repeats.end)); return result; }, findCommonAttributes: function (view, widgets) { view = view || this.activeView; var allWidgetsAttr = null; for (var i = 0; i < widgets.length; i++) { var widget = this.views[view].widgets[widgets[i]]; if (!widget) { console.log('inspectWidget ' + widgets[i] + ' undefined'); return []; } if (!widget.tpl) return false; var $widgetTpl = $('#' + widget.tpl); if (!$widgetTpl) { console.log(widget.tpl + ' is not included'); return []; } var widgetAttrs = $widgetTpl.attr('data-vis-attrs'); // Combine attributes from data-vis-attrs, data-vis-attrs0, data-vis-attrs1, ... var t = 0; var attr; while ((attr = $widgetTpl.attr('data-vis-attrs' + t))) { widgetAttrs += attr; t++; } if (widgetAttrs) { widgetAttrs = widgetAttrs.split(';'); } else { widgetAttrs = []; } var group = 'common'; var groupMode = 'normal'; var attrs = {}; for (var j = 0; j < widgetAttrs.length; j++) { if (widgetAttrs[j].match(/^group\./)) { group = widgetAttrs[j].substring('group.'.length); // extract group mode if (group.indexOf('/') !== -1) { var parts = group.split('/'); group = parts[0]; groupMode = parts[1] || 'normal'; // if icon if (parts[2]) this.groupsIcons[group] = groupMode; } else { groupMode = 'normal'; } continue; } if (!widgetAttrs[j]) continue; var a = this.extractAttributes(widgetAttrs[j], widgets[i]); if (groupMode === 'byindex') { for (var k = 0; k < a.length; k++) { attrs[group + '_§' + k] = attrs[group + '_§' + k] || {}; attrs[group + '_§' + k][a[k].name] = a[k]; } } else { attrs[group] = attrs[group] || {}; for (var k = 0; k < a.length; k++) { attrs[group][a[k].name] = a[k]; } } } if (!allWidgetsAttr) { allWidgetsAttr = attrs; } else { // Combine these too groups for (group in allWidgetsAttr) { if (!attrs[group]) delete allWidgetsAttr[group]; } for (group in attrs) { if (!allWidgetsAttr[group]) delete attrs[group]; } for (group in allWidgetsAttr) { for (var name in allWidgetsAttr[group]) { if (!attrs[group][name]) delete allWidgetsAttr[group][name]; } for (name in attrs[group]) { if (!allWidgetsAttr[group][name]) delete attrs[group][name]; } for (name in allWidgetsAttr[group]) { var d1 = allWidgetsAttr[group][name].default; delete allWidgetsAttr[group][name].default; delete attrs[group][name].default; if (JSON.stringify(allWidgetsAttr[group][name]) !== JSON.stringify(attrs[group][name])){ delete allWidgetsAttr[group][name]; } else { allWidgetsAttr[group][name].default = d1; } } } } } return allWidgetsAttr; }, // If only one widget, it returns the value // If array of widgets, ot returns object {values, widgetValues}, where values are all found different values and widgetValues is array with values for every widget findCommonValue: function (view, widgets, attr, isStyle) { view = view || this.activeView; var widgetValues = []; var values = []; for (var i = 0; i < widgets.length; i++) { var widget = this.views[view].widgets[widgets[i]]; var obj = isStyle ? widget.style : widget.data; var val = (isStyle && (!obj || obj[attr] === undefined)) ? '' : (obj ? obj[attr] : ''); widgetValues[i] = val; if (values.indexOf(val) === -1) values.push(val); } if (values.length === 1) { return values[0]; } else { return { values: values, widgetValues: widgetValues }; } }, setAttrValue: function (view, widgets, attr, isStyle, values) { var $input = $('#inspect_' + attr); if (isStyle && attr.substring(0, 4) === 'css_') attr = attr.substring(4); if (values[attr] === undefined) values[attr] = this.findCommonValue(view, widgets, attr, isStyle); if ($input.attr('type') === 'checkbox') { if (typeof values[attr] === 'object') { $input.prop('indeterminate', true); } else { $input.prop('checked', values[attr]); } } else { if (typeof values[attr] === 'object') { $input.addClass('vis-edit-different').val(_('--different--')).data('value', values[attr]).data('different', true); $input.autocomplete({ minLength: 0, source: function (request, response) { var data = $.grep(this.element.data('value').values, function (value) { if (value === undefined || value === null) return false; value = value.toString(); return value.substring(0, request.term.length).toLowerCase() === request.term.toLowerCase(); }); response(data); }, select: function (event, ui) { $(this).val(ui.item.value).trigger('change'); }, change: function (event, ui) { //$(this).trigger('change'); } }).focus(function (event, ui) { if ($(this).data('different')) { $(this).val(''); } $(this).autocomplete('search', ''); }).blur(function (event, ui) { if ($(this).data('different')) { $(this).val(_('--different--')).addClass('vis-edit-different'); } }); } else { $input.val(values[attr]); } } $input.unbind('keyup').keyup(function () { var $this = $(this); var timer = $this.data('timer'); if (timer) clearTimeout(timer); $this.data('timer', setTimeout(function () { $this.data('timer', null); $this.trigger('change'); }, 500)); }); }, inspectWidgets: function (viewDiv, view, addWidget, delWidget, onlyUpdate) { if (this.isStealCss) return false; var that = this; if (typeof viewDiv === 'object') { addWidget = viewDiv; viewDiv = this.activeViewDiv; view = this.activeView; } var oldView; $('.vis-widget[data-zmodified="true"]').each(function () { var wid = $(this).attr('id'); $(this).removeAttr('data-zmodified'); oldView = oldView || that.getViewOfWidget(wid); var zIndex = that.views[oldView].widgets[wid] && that.views[oldView].widgets[wid].style && that.views[oldView].widgets[wid].style['z-index']; if (!zIndex && zIndex !== '0' && zIndex !== 0) { $(this).prop('style').removeProperty('z-index'); } else { $(this).css('z-index', zIndex); } }); $('.vis-widget[data-tmodified="true"]').each(function () { var wid = $(this).attr('id'); $(this).removeAttr('data-tmodified'); oldView = oldView || that.getViewOfWidget(wid); var transform = that.views[oldView].widgets[wid] && that.views[oldView].widgets[wid].style && that.views[oldView].widgets[wid].style.transform; if (!transform) { $(this).prop('style').removeProperty('transform'); } else { $(this).css('transform', transform); } }); // Deselect all elements $(':focus').blur(); // Hide context menu $('#context_menu').hide(); if (typeof addWidget === 'boolean') { onlyUpdate = addWidget; addWidget = undefined; delWidget = undefined; } if (addWidget) { if (typeof addWidget === 'object') { this.activeWidgets = addWidget; } else { if (this.activeWidgets.indexOf(addWidget) === -1) this.activeWidgets.push(addWidget); } } if (typeof delWidget === 'string') { var pos = this.activeWidgets.indexOf(delWidget); if (pos !== -1) this.activeWidgets.splice(pos, 1); } var wid = this.activeWidgets[0] || 'none'; this.groups = {}; this.groupsIcons = { fixed: 'icon/groupFixed.png' }; if (view !== viewDiv) { // disable group resize var $group = $('#' + viewDiv); if ($group.hasClass('vis-resize-group')) { $group.resizable('destroy').removeClass('vis-resize-group'); } } if (!onlyUpdate) { this.alignIndex = 0; var s = JSON.stringify(this.activeWidgets); if (this.views[view] && JSON.stringify(this.views[view].activeWidgets) !== s) { this.views[view].activeWidgets = JSON.parse(s); // Store selected widgets this.save(viewDiv, view); } //this.$selectActiveWidgets.find('option[value="' + wid + '"]').prop('selected', true); //this.$selectActiveWidgets.multiselect('refresh'); var $widget; var select = []; var deselect = []; for (var i = 0; i < this.activeWidgets.length; i++) { if (this.oldActiveWidgets.indexOf(this.activeWidgets[i]) === -1) select.push(this.activeWidgets[i]); } for (i = 0; i < this.oldActiveWidgets.length; i++) { if (this.activeWidgets.indexOf(this.oldActiveWidgets[i]) === -1) deselect.push(this.oldActiveWidgets[i]); } // Deselect unselected widgets for (i = 0; i < deselect.length; i++) { this.showWidgetHelper(viewDiv, view, deselect[i], false); $widget = $('#' + deselect[i]); $widget.removeClass('ui-selected'); if ($widget.hasClass('ui-draggable')) { try { $widget.draggable('destroy'); } catch (e) { this.conn.logError('inspectWidgets - Cannot destroy draggable ' + deselect[i] + ' ' + e); } } if ($widget.hasClass('ui-resizable')) { try { $widget.resizable('destroy'); } catch (e) { this.conn.logError('inspectWidgets - Cannot destroy resizable ' + deselect[i] + ' ' + e); } } } // disable resize if widget not more selected alone if (this.oldActiveWidgets.length === 1 && this.activeWidgets.length !== 1) { $widget = $('#' + this.oldActiveWidgets[0]); if ($widget.hasClass('ui-resizable')) { try { $widget.resizable('destroy'); } catch (e) { this.conn.logError('inspectWidgets - Cannot destroy resizable ' + deselect[i] + ' ' + e); } } } // Select selected widgets for (var p = 0; p < select.length; p++) { try { $widget = this.showWidgetHelper(viewDiv, view, select[p], true); if ($widget && !$('#wid_all_lock_d').hasClass('ui-state-active')) { this.draggable(viewDiv, view, $widget); } } catch (e) { console.log(e); } } this.$selectActiveWidgets.val(this.activeWidgets); // Enable disable buttons if (this.activeWidgets.length) { $('#rib_wid_del').button('enable'); $('#rib_wid_copy').button('enable'); $('#rib_wid_doc').button('enable'); $('#export_widgets').button('enable'); } else { $('#rib_wid_del').button('disable'); $('#rib_wid_copy').button('disable'); $('#rib_wid_doc').button('disable'); $('#export_widgets').button('disable'); } if (this.activeWidgets.length === 1) { try { $widget = $('#' + this.activeWidgets[0]); if (!$widget.hasClass('ui-resizable') && this.widgets[wid] && this.widgets[wid].data && !this.widgets[wid].data._no_resize) { this.resizable(viewDiv, view, $widget); } } catch (e) { console.log(e); } } this.oldActiveWidgets = []; for (var k = 0; k < this.activeWidgets.length; k++) { this.oldActiveWidgets.push(this.activeWidgets[k]); } // update selected widgets dropdown this.$selectActiveWidgets.multiselect('refresh'); // Disable copy widget if was active $('#rib_wid_copy_cancel').trigger('click'); this.actualAttrs = this.findCommonAttributes(view, this.activeWidgets); } var $widgetAttrs = $('#widget_attrs').hide(); // Clear Inspector $widgetAttrs[0].innerHTML = ''; //$widgetAttrs.empty(); if (!wid || wid === 'none') { // Switch tabs to View settings $('#pan_attr').tabs('option', 'disabled', [1]).tabs({active: 0}); $('#widget_tab').text(_('Widget')); if (view !== viewDiv) { // enable group resize of nothing selected this.editResizeGroup(viewDiv, view); } return false; } $('#pan_attr').tabs('option', 'disabled', []).tabs({active: 1}); $('#widget_tab').text((this.activeWidgets.length === 1) ? wid : _('Widget') + ': ' + this.activeWidgets.length); if (!this.views[view]) { console.warn('No view "' + view + ' for ' + wid + ' found'); return; } var widget = this.views[view].widgets[wid]; if (!widget) { console.log('inspectWidget ' + wid + ' undefined'); return false; } if (!widget.tpl) return false; var $widgetTpl = $('#' + widget.tpl); if (!$widgetTpl) { console.log(widget.tpl + ' is not included'); return false; } /*var widgetAttrs = $widgetTpl.attr('data-vis-attrs'); // Combine attributes from data-vis-attrs, data-vis-attrs0, data-vis-attrs1, ... var t = 0; var attr; while ((attr = $widgetTpl.attr('data-vis-attrs' + t))) { widgetAttrs += attr; t++; } if (widgetAttrs) { widgetAttrs = widgetAttrs.split(';'); } else { widgetAttrs = []; } var widgetFilter = $widgetTpl.attr('data-vis-filter');*/ $('#inspect_comment_tr').show(); $('#inspect_class_tr').show(); $widgetAttrs.css({width: '100%'}); // Add fixed attributes var group = 'fixed'; this.addToInspect(this.activeWidgets, 'name', group); this.addToInspect(this.activeWidgets, 'comment', group); this.addToInspect(this.activeWidgets, {name: 'class', type: 'class'}, group); this.addToInspect(this.activeWidgets, {name: 'filterkey', type: 'auto', options: this.updateFilter(view)}, group); this.addToInspect(this.activeWidgets, {name: 'views', type: 'select-views'}, group); this.addToInspect(this.activeWidgets, {name: 'locked', type: 'checkbox'}, group); group = 'visibility'; this.addToInspect(this.activeWidgets, {name: 'visibility-oid', type: 'id'}, group); this.addToInspect(this.activeWidgets, {name: 'visibility-cond', type: 'select', options: ['==', '!=', '<=', '>=', '<', '>', 'consist', 'not consist', 'exist', 'not exist'], default: '=='}, group); this.addToInspect(this.activeWidgets, {name: 'visibility-val', default: 1}, group); this.addToInspect(this.activeWidgets, {name: 'visibility-groups', type: 'groups'}, group); this.addToInspect(this.activeWidgets, {name: 'visibility-groups-action', type: 'select', options: ['hide', 'disabled'], default: 'hide'}, group); this.addToInspect('delimiter', group); // special case for group widget group = 'common'; if ($widgetTpl.attr('id') === '_tplGroup' && this.activeWidgets.length === 1) { var _wid = this.activeWidgets[0]; var id = 1; var _data = this.views[view].widgets[_wid].data; var maxCount = parseInt(_data.attrCount, 10); if (maxCount) { for (var a = 1; a <= maxCount; a++) { this.addToInspect(this.activeWidgets, { name: 'groupAttr' + a, type: _data['attrType' + a], clearName: _data['attrName' + a] || ('attrName' + a), title: _('Use inside of group groupAttr%s', a) }, group); } } } // Edit all attributes for (group in this.actualAttrs) { if (!this.actualAttrs.hasOwnProperty(group)) continue; for (var attr in this.actualAttrs[group]) { if (!this.actualAttrs[group].hasOwnProperty(attr)) continue; this.addToInspect(this.activeWidgets, this.actualAttrs[group][attr], group); } } this.addToInspect('delimiter', group); // Add common css this.editCssCommon(); this.editCssFontText(); this.editCssBackground(); this.editCssBorder(); this.editCssShadowPadding(); //this.editCssAnimation(); this.addToInspect('delimiter', 'css_shadow_padding'); if ($widgetTpl.attr('data-vis-no-gestures') !== 'true') { this.editGestures(view); } if ($widgetTpl.attr('data-vis-no-signals') !== 'true') { this.editSignalIcons(view); } if ($widgetTpl.attr('data-vis-no-ls') !== 'true') { this.editLastChange(view); } // Re-render all widgets, where default values applied if (this.reRenderList && this.reRenderList.length) { for (var r = 0; r < this.reRenderList.length; r++) { this.reRenderWidgetEdit(viewDiv, view, this.reRenderList[r]); } this.reRenderList = []; } this.showInspect(viewDiv, view, this.activeWidgets); // snap objects to the grid, elsewise cannot move /*if (this.views[view].settings.snapType == 2) { this.gridWidth = parseInt(this.views[view].settings.gridSize, 10); if (this.gridWidth < 1 || isNaN(this.gridWidth)) this.gridWidth = 10; for (var i = 0; i < this.activeWidgets.length; i++) { var $this = $('#' + this.activeWidgets[i]); var x = parseInt($this.css('left')); var y = parseInt($this.css('top')); x = Math.round(x / this.gridWidth) * this.gridWidth; y = Math.round(y / this.gridWidth) * this.gridWidth; $this.css({'left': x, 'top': y}); this.showWidgetHelper(this.activeWidgets[i], true); } // show grid }*/ // Put all view names in the select element var $inspectViews = $('#inspect_views'); if ($inspectViews.length) { $inspectViews.html(''); var views = this.getViewsOfWidget(this.activeWidgets[0]); for (var v in this.views) { if (v === '___settings') continue; if (v !== this.activeView) { var selected = ''; for (var m = 0; m < views.length; m++) { if (views[m] === v) { selected = 'selected'; break; } } $inspectViews.append(''); } } $inspectViews.multiselect({ maxWidth: 180, height: 260, noneSelectedText: _('Single view'), selectedText: function (numChecked, numTotal, checkedItems) { var text = ''; for (var i = 0; i < checkedItems.length; i++) { text += (!text ? '' : ',') + checkedItems[i].title; } return text; }, multiple: true, checkAllText: _('Check all'), uncheckAllText: _('Uncheck all'), close: function () { if ($inspectViews.data('changed')) { $inspectViews.data('changed', false); that.syncWidgets(that.activeWidgets, $(this).val()); that.save(viewDiv, view); } } //noneSelectedText: _("Select options") }).change(function () { $inspectViews.data('changed', true); }).data('changed', false); $inspectViews.next().css('width', '100%'); } // Put all view names in the select element var $inspectGroups = $('#inspect_visibility-groups'); if ($inspectGroups.length) { $inspectGroups.html(''); var groups = this.getUserGroups(); var widGroups = this.findCommonValue(view, this.activeWidgets, 'visibility-groups'); if (widGroups && !(widGroups instanceof Array)) widGroups = widGroups.values; widGroups = widGroups || []; for (var g in groups) { var val = g.substring('system.group.'.length); $inspectGroups.append(''); } $inspectGroups.multiselect({ maxWidth: 180, height: 260, noneSelectedText: _('All groups'), selectedText: function (numChecked, numTotal, checkedItems) { var text = ''; for (var i = 0; i < checkedItems.length; i++) { text += (!text ? '' : ',') + checkedItems[i].title; } return text; }, multiple: true, checkAllText: _('Check all'), uncheckAllText: _('Uncheck all'), close: function () { if ($inspectGroups.data('changed')) { $inspectGroups.data('changed', false); that.save(viewDiv, view); } } //noneSelectedText: _("Select options") }).change(function () { $inspectGroups.data('changed', true); }).data('changed', false); $inspectGroups.next().css('width', '100%'); } // If tab Widget is not selected => select it var $menu = $('#menu_body'); if ($menu.tabs('option', 'active') === 1) $menu.tabs({'active': 2}); $widgetAttrs.show(); // modify by all selected widgets the z-index if (this.views[view]) { for (var w in this.views[view].widgets) { if (!this.views[view].widgets.hasOwnProperty(w)) continue; if (this.activeWidgets.indexOf(w) !== -1) { $('#' + w) .attr('data-zmodified', 'true') .css('z-index', 700); } else { var wwidget = this.views[view].widgets[w]; $('#' + w) .attr('data-zmodified', 'true') .css('z-index', (wwidget && wwidget.style) ? (wwidget.style['z-index'] || 0) : 0); } } } } });||||||