//


function YamlPaper(yamltext, metadata) {
  var MD = metadata;

  var DATA = [];
  function dataParams() {
    return DATA.filter(function(item) {
      return item.type == 'parameter';
    }) || [];
  }

  function setDataParams(new_params) { DATA = [...new_params]; }

    const
        ADD_LAYOUT_ITEM                        = 100000,   // { parent_id:ID, item_type:STRING }
        DELETE_LAYOUT_ITEM                     = 100010,   // { parent_id:ID, item_id:ID }
        MOVE_LAYOUT_ITEM                       = 100020,   // { parent_id:ID, element_id:ID, sibling_id:ID }
        COPY_LAYOUT_ITEM                       = 100030,   // { parent_id:ID, element_id:ID, sibling_id:ID }
        //
        BLOCK_WIZ_SET_TABLE                    = 101000,   // { blkid:ID, value:STRING }
        BLOCK_WIZ_SET_CAPTION                  = 101010,   // { blkid:ID, value:STRING }
        BLOCK_WIZ_SET_FILTER                   = 101020,   // { blkid:ID, value:STRING }
        BLOCK_WIZ_SET_DESCRIPTION              = 101030,   // { blkid:ID, value:STRING }
        BLOCK_WIZ_SET_STATUS                   = 101040,   // { blkid:ID, value:STRING }
        BLOCK_WIZ_SET_PARALINK                 = 101050,   // { blkid:ID, param, link }
        BLOCK_WIZ_SET_LINKS                    = 101060,   // { blkid:ID, value:STRING }
        BLOCK_WIZ_SET_LIMIT                    = 101070,   // { blkid:ID, value:STRING }
        BLOCK_WIZ_SHOW_ROWS_COUNT              = 101080,   // { blkid:ID, value:STRING }
        BLOCK_WIZ_ALIGNMENT                    = 101090,   // { blkid:ID, value:STRING }
        BLOCK_WIZ_COLUMN_ADD                   = 102010,   // { blkid:ID }
        BLOCK_WIZ_COLUMN_DELETE                = 102020,   // { blkid:ID, colid:ID }
        BLOCK_WIZ_COLUMN_SET_VALUE             = 102030,   // { blkid:ID, colid:ID, name:STRING, value:STRING }
        BLOCK_WIZ_COLUMN_MOVE                  = 102040,   // { blkid:ID, element_id:ID, sibling_id:ID }
        BLOCK_WIZ_SHOW_OPTIONS                 = 103000,   // { blkid:ID, show:BOOL }
        BLOCK_WIZ_SET_IMAGE                    = 103010,   // { blkid:ID, value:STRING }
        BLOCK_WIZ_SET_IMAGE_HREF               = 103020,   // { blkid:ID, value:STRING }
        BLOCK_WIZ_SET_KIND_CHART               = 103030,   // { blkid:ID, value:STRING }
        BLOCK_WIZ_SET_LEGEND_CHART             = 103040,   // { blkid:ID, value:STRING }
        BLOCK_WIZ_LINE_ADD                     = 103050,   // { blkid:ID }
        BLOCK_WIZ_LINE_DELETE                  = 103060,   // { blkid:ID, colid:ID }
        BLOCK_WIZ_LINE_SET_VALUE               = 103070,   // { blkid:ID, colid:ID, name:STRING, value:STRING }
        BLOCK_WIZ_LINE_MOVE                    = 103080,   // { blkid:ID, element_id:ID, sibling_id:ID }
        BLOCK_WIZ_AXIS_SET_VALUE               = 103110,   // { blkid:ID, colid:ID, name:STRING, value:STRING }
        BLOCK_WIZ_SHOW_EMPTY_VALUES            = 103200,
        BLOCK_WIZ_HIDE_MAIN_EMPTY_VALUES       = 103201,
        BLOCK_WIZ_SHOW_EMPTY_GROUPS            = 103210,
        BLOCK_WIZ_KIND_OF_PERIOD               = 103220,
        BLOCK_WIZ_KIND_COLOR_SET               = 103230,
        BLOCK_WIZ_PALETTE_COLOR_SET            = 103240,
        BLOCK_WIZ_SHOW_PHONE                   = 103250,
        BLOCK_WIZ_TITLE_VALUE                  = 103260,
        BLOCK_WIZ_GROUP_VALUE                  = 103270,
        BLOCK_WIZ_SET_COLOR                    = 103280,
        BLOCK_WIZ_ADD_COLOR                    = 103290,
        BLOCK_WIZ_DELETE_COLOR                 = 103300,
        BLOCK_WIZ_ADDITIONAL_ACTIONS           = 103310,
        BLOCK_WIZ_SET_WHAT_PAINT               = 103320,
        BLOCK_WIZ_SET_CUT_TO                   = 103330,
        BLOCK_WIZ_SET_LAST_LINES               = 103350,

        BLOCK_WIZ_SET_WIDTH                    = 103130,   // { blkid:ID, value:STRING }
        BLOCK_WIZ_CHART_VOLUME                 = 103140,
        BLOCK_WIZ_SET_ORIENTATION              = 103150,
        BLOCK_WIZ_SET_SIZE_INNER_CIRCLE        = 103160,
        BLOCK_WIZ_SET_OUTPUT_TOTAL_VALUE       = 103170,
        //
        COLOR_FORMATTING_ADD                   = 103230,   // { blkid:ID, value:STRING }
        COLOR_FORMATTING_DELETE                = 103340,   // { blkid:ID, value:STRING }
        COLOR_FORMATTING_SET_VALUE             = 103450,   // { blkid:ID, value:STRING }
        //
        BLOCK_WIZ_SET_MICROCHART_PERIODS       = 104010,
        BLOCK_WIZ_SET_RELATIVE_VALUE           = 105003,
        //
        CHANGE_ITEM_APPEND                     = 104001,
        CHANGE_CLEAR                           = 104002,
        CHANGE_ITEM_SET_VALUE                  = 104003,
        BLOCK_WIZ_SET_RELATIVE_INDICATOR       = 105001,
        BLOCK_WIZ_SET_RELATIVE_INDICATOR_FIELD = 105002,
        BLOCK_WIZ_SET_PARALINK_RELATIVE        = 105010,   // { blkid:ID, value:STRING }
        BLOCK_WIZ_SET_BLOCK_HEIGHT             = 105020,   // { blkid:ID, value:STRING }
        BLOCK_WIZ_SET_DYNAMICS_COMPARE_PERIOD  = 105030,

        // параметры
        DATA_ITEM_APPEND   /* добавить */      = 600000,   // { item:{type,name,...} }
        DATA_ITEM_DELETE   /* удалить */       = 600010,   // { item_name }
        MOVE_PARAMETER_ROW /* переместить */   = 600020,   // { item_name }
        DATA_ITEM_SET                          = 600030,   // { item_name, name, value }
        APPEND_LAYOUT_ITEM                     = 600100,   // { parent_id:ID, item:{} }

        //
        SET_DETAILS_ITEM                       = 800100,   // { item_id:ID }
        //
        SHOW_DIALOG                            = 900000,   // { title:STRING, body: m() }
        SHOW_MESSAGE                           = 900010,   // message
        SHOW_ALERT                             = 900020,   // message
        CONSOLE_LOG                            = 999998,   // payload
        FINE_FINE                              = 999999;

    const
        AGGR_SQL = [
            {value: '', label: ''},
            {value: 'SUM', label: lang['Sum']},
            {value: 'AVG', label: lang['Avg']},
            {value: 'COUNT', label: lang['Count']},
            {value: 'MIN', label: lang['Minimum']},
            {value: 'MAX', label: lang['Maximum']},
        ],
        AGGR_TOTAL = [
            {value: '', label: ''},
            {value: 'SUM', label: lang['Total_sum']},
            {value: 'AVG', label: lang['Total_avg']},
            {value: 'AVG_WITHOUT_NULL', label: lang['Total_avg_without_zeros']},
            {value: 'COUNT', label: lang['Total_count']},
            {value: 'MIN', label: lang['Total_minimum']},
            {value: 'MAX', label: lang['Total_maximum']},
        ],
        FORMATS = [
            {value: '', label: ''},
            {value: 'd', label: lang['Integer']},
            {value: 'f', label: lang['Fractional']},
        ],
        PARAMETER_DATATYPE = [
            {value:'period', label:lang['Period']},
            {value:'user_field',   label:lang['User']},
            {value:'from_fields',  label:lang['from_field'][0].toUpperCase()+lang['from_field'].slice(1)},
        ],
        PARAMETER_PERIOD = [
            {value:'day',        label:lang['Day']},
            {value:'week',       label:lang['Week']},
            {value:'half_month', label:lang['Half_a_month']},
            {value:'month',      label:lang['Month']},
            {value:'quarter',    label:lang['Quarter']},
            {value:'year',       label:lang['Year']},
        ],
        LINKS_STATUS = [
            {value:'none', label:lang['Not_show']},
            {value:'explicit', label:lang['Show_explicit_links']},
            {value:'implicit', label:lang['Show_hidden_links']},
        ],
        ALIGNMENT = [
            {value:'AsInTheTable', label:lang['AsInTheTable']},
            {value:'center', label:lang['Center']},
            {value:'left', label:lang['Left']},
            {value:'right', label:lang['Right']},
        ],
        COLUMN_HIDDEN = [
            {value:'no',   label:''},
            {value:'yes',  label:lang['Hidden_column']},
        ],
        COLUMN_GROUPBY = [
            {value:'no',   label:''},
            {value:'yes',  label:lang['Grouping_field']},
        ],
        COLUMN_SORTBY = [
            {value:'no',    label:''},
            {value:'asc',   label:lang['Sort_by_asc']},
            {value:'desc',  label:lang['Sort_by_desc']},
        ],
        KIND_OF_CHARTS = [
            {value:'linear',    label:lang['Linear_chart']},
            {value:'column',    label:lang['Column_chart']},
            {value:'pie',       label:lang['Pie_chart']},
            {value:'donut',     label:lang['Donut_chart']},
        ],
        LEGEND_CHARTS = [
            {value:'none',   label:lang['Not_show']},
            {value:'in',     label:lang['Legend_inside']},
            {value:'top',    label:lang['Legend_top']},
            {value:'right',  label:lang['Right']},
            {value:'bottom', label:lang['Legend_bottom']},
        ],
        KIND_OF_WIDTH = [
            {value:'20',    label:'20%'},
            {value:'25',    label:'25%'},
            {value:'33',    label:'33%'},
            {value:'40',    label:'40%'},
            {value:'50',    label:'50%'},
            {value:'60',    label:'60%'},
            {value:'67',    label:'67%'},
            {value:'75',    label:'75%'},
            {value:'80',    label:'80%'},
            {value:'100',   label:'100%'},
        ],
        KIND_OF_ORIENTATION = [
            {value:'vertical',    label:lang['Vertical']},
            {value:'horizontal',  label:lang['Horizontal']},
        ],
        SIZES_OF_INNER_CIRCLE = [
            {value:'small',    label:lang['Small']},
            {value:'medium',   label:lang['Medium']},
            {value:'large',    label:lang['Large']},
        ],
        COLORS_CHOOSE = [
            {value:'default',  label:lang['Default']},
            {value:'palette',  label:lang['Palette']},
        ],
        COLORS = [
            {value:'rgb(150,150,150)',   subvalue:'#fff',             label:lang['grey']},
            {value:'rgb(106, 168, 79)',  subvalue:'#fff',             label:lang['success']},
            {value:'rgb(61, 133, 198)',  subvalue:'#fff',             label:lang['primary']},
            {value:'rgb(69, 129, 142)',  subvalue:'#fff',             label:lang['info']},
            {value:'rgb(230, 145, 56)',  subvalue:'#fff',             label:lang['warning']},
            {value:'rgb(204, 0, 0)',     subvalue:'#fff',             label:lang['danger']},
            {value:'rgb(241, 194, 50)',  subvalue:'#fff',             label:lang['bd_group_yellow']},
            {value:'rgb(166, 28, 0)',    subvalue:'#fff',             label:lang['bd_group_maroon']},
            {value:'rgb(60, 120, 216)',  subvalue:'#fff',             label:lang['bd_group_cyan']},
            {value:'rgb(103, 78, 167)',  subvalue:'#fff',             label:lang['bd_group_violet']},
            {value:'rgb(166, 77, 121)',  subvalue:'#fff',             label:lang['bd_group_purple']},
            {value:'rgb(237,237,237)',   subvalue:'#4B4B4B',          label:lang['light_grey']},
            {value:'rgb(217, 234, 211)', subvalue:'rgb(56, 118, 29)', label:lang['light_green']},
            {value:'rgb(207, 226, 243)', subvalue:'rgb(11, 83, 148)', label:lang['light_blue']},
            {value:'rgb(208, 224, 227)', subvalue:'rgb(19, 79, 92)',  label:lang['light_turquoise']},
            {value:'rgb(252, 229, 205)', subvalue:'rgb(180, 95, 6)',  label:lang['light_orange']},
            {value:'rgb(244, 204, 204)', subvalue:'rgb(153, 0, 0)',   label:lang['light_red']},
            {value:'rgb(230, 184, 175)', subvalue:'rgb(133, 32, 12)', label:lang['light_maroon']},
            {value:'rgb(255, 242, 204)', subvalue:'rgb(191, 144, 0)', label:lang['light_yellow']},
            {value:'rgb(201, 218, 248)', subvalue:'rgb(17, 85, 204)', label:lang['light_cyan']},
            {value:'rgb(217, 210, 233)', subvalue:'rgb(53, 28, 117)', label:lang['light_violet']},
            {value:'rgb(234, 209, 220)', subvalue:'rgb(116, 27, 71)', label:lang['light_purple']},
        ],
        RELATIVE_INDICATOR_TYPES = [
            {value:'none',   label:lang['No']},
            {value:'fixed',  label:lang['fixed'].slice(0, 1).toUpperCase() + lang['fixed'].slice(1)},
            {value:'field',  label:lang['from_field'].slice(0, 1).toUpperCase() + lang['from_field'].slice(1)},
        ],
        DYNAMICS_COMPARE_PERIOD = [
          {value: 'fixed',   label: lang['Fixed']},
          {value: 'dynamic', label: lang['Dynamic']},
        ];

    let MAIN_GROUP;

    /**
     * Обертка вокруг старых функций рендеринга
     * Возващает функцию вызывающую рендеринг с указанным template
     * @param {*} template - функции реализующие шаблоны
     * @returns ({ children, ...props }) => m(template, { ...props}, children)
     */
    const Element = (template) => ({ children, ...props }) => m(template, { ...props}, children);

    const copyObjectData = (data) => {
        if (Array.isArray(data)) {
            return data.map(item => {
                return { ...item };
            });
        } else if (typeof data === 'object' && data !== null) {
            return { ...data };
        }
        return data;
    };

    function buildItemTitle(type, caption, use_table) {
        result = type;
        result += caption!='' ? ': '+caption : '';
        result += use_table!='' ? ' ('+use_table+')' : '';
        return result;
    }

    var Dispatcher = {
        queue: [],
        register: function(callback) { this.queue.push(callback); },
        unregister: function(callback) { this.queue = this.queue.filter(function(item){return item!=callback}); },
        dispatch: function(action,payload) { this.queue.forEach(function(item){item(action,payload)}); },
    }

    function raise(action,payload) {
        switch (action) {
            case SHOW_DIALOG:
                dialog = payload;
                break;
            case SHOW_MESSAGE:
                dialog = { title:'Message', body:payload, };
                break;
            case SHOW_ALERT:
                alert(payload);
                break;
            case CONSOLE_LOG:
                console.log(payload);
                break;
            case FINE_FINE:
                console.log('FINE_FINE');
                break;
            default:
                Dispatcher.dispatch(action, payload);
                break;
        }
    }

    function genid() {
        var dt = new Date().getTime();
        var mask = 'ixxxyxxx';  //'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';
        return mask.replace(/[xy]/g, function(c) {
            var r = (dt + Math.random()*16)%16 | 0;
            dt = Math.floor(dt/16);
            return (c=='x' ? r :(r&0x3|0x8)).toString(36);
        });
    }

    function yamlify(paper) {
         return YAML.dump(paper,42,2)
    }

    var PaperToolbar = function() {
        var barid = genid();
        var block_label = { block:lang['Block'],inline:lang['Text'],unknown:lang['Code'],table:lang['Table2'],};
        var parse_subs = function(item) {
            return item.call ? m('li',{onclick:item.call},item.name)
                             : m('li',{},item.name, m('ul',item.subs.map(parse_subs)))
        }
        return {
            view: function(vnode) {
                return m.fragment( {}, [
                    m('style',
                        '#'+vnode.attrs.blockid+' > .yamlview__block_inner:hover #'+barid+'{display:block;}'+
                        '#'+vnode.attrs.blockid+':hover > .yamlview__block_inner > .yamlview__block_layout{border:1px dotted gray;}'+
                        (vnode.attrs.blocktype=='block'?'#'+barid+'{top:-26px}':'')
                    ),
                    m('div.yamlbuilder-toolbar#'+barid,[
                        m('span',block_label[vnode.attrs.blocktype]+': '),
                        m('ul.yamltoolbar',vnode.attrs.tools.map(parse_subs)),
                    ]),
                ]);
            }
        }
    }

    var dialog = null;
    var PaperDialog = function() {
        return {
            view: function(vnode) {
                return m('div.modal-window',{}, m('div.modal-inner',
                    {
                        style:'min-width:'+vnode.attrs.width+';min-height:'+vnode.attrs.height+';',
                    },
                    [
                        m('div[style=text-align:right]',m('a[href=#modal-close]',{
                            onclick: function(){closeDialog();return false;},
                        },lang['close'])),
                        m('h3', vnode.attrs.title),
                        m('div', vnode.attrs.body),
                    ]
                ))
            }
        }
    }

    function closeDialog() {
        setTimeout(function(){ dialog = null; m.redraw(); }, 100);
    }

    function dragZone() { // className, onmove
        let drake;
        let zoneid = 'zone_' + genid();
        let onmove;
        return {
            oncreate: function(vnode) {
                onmove = vnode.attrs.onmove;
                drake = dragula([document.getElementById(zoneid)],{
                    moves: function (el, container, handle) {
                        return handle.classList.contains('draghandle');
                    }
                });
                drake.on('drop', function(element, target, source, sibling) {
                    // element was dropped before sibling
                    let dat = onmove.payload;
                    dat.blkid = element.getAttribute('blkid') ? element.getAttribute('blkid') : dat.blkid;
                    dat.element_id = element.getAttribute('item_id');
                    dat.sibling_id = sibling ? sibling.getAttribute('item_id') : '';
                    raise(onmove.action,dat);
                    if (dat.blkid != 'parameter') m.redraw();
                });
            },
            onremove: function() {
                drake.destroy();
            },
            view: function(vnode) { //
                return m('div.dragzone',{id:zoneid, className:vnode.attrs.className},[
                    vnode.children
                ])
            },
        }
    }

    function listItem() { return { view: function(vnode) { // parent_id, item_id, caption
        return m('div',{item_id:vnode.attrs.item_id},[
            m('img[src=images/draggable.png].draghandle'),
            m('img.alpiction[src=images/b_drop.png]',{onclick: function(){raise(DELETE_LAYOUT_ITEM,{parent_id:vnode.attrs.parent_id,item_id:vnode.attrs.item_id})}}),
            m('img.alpiction[src=images/b_copy.png]',{onclick: function(){raise(COPY_LAYOUT_ITEM,{parent_id:vnode.attrs.parent_id,item_id:vnode.attrs.item_id})}}),
            m('span.alaction[style=font-size:108%]',{onclick:function(){raise(SET_DETAILS_ITEM,{item_id:vnode.attrs.item_id}); m.redraw();}},vnode.attrs.caption),
    ]) } } }

    function listItemNotActivated() { return { view: function(vnode) { // parent_id, item_id, caption
        return m('div',{item_id:vnode.attrs.item_id},[
            m('img[src=images/draggable.png].draghandle'),
            m('img.alpiction[src=images/b_drop.png]',{onclick: function(){raise(DELETE_LAYOUT_ITEM,{parent_id:vnode.attrs.parent_id,item_id:vnode.attrs.item_id})}}),
            m('span', {style:"margin-left: 1.6em;"}, ' '),
            m('span', {
                title: "To work, you need to buy or activate.",     // TODO: lang[To work, you need to buy or activate.]
                style:'font-size:108%;color:gray;'
            }, lang['Kanban']),
    ]) } } }

    function createHelpBtn() { return {
        view: function(vnode) { // id
            return m('span[class=help_bt]', {h_id:vnode.attrs.helpbtn} );
        },
        oncreate: function() {
            bind_help_bt('edit_form'); // bind help notifications for new row element
        },
        oninit: checkHelpButtonsOnCurrentPage(),
    } }

    function gear() { return { view: function(vnode) { // href, title
        return m('a[style=decoration:none][class=no_print][target=_blank]',{href:vnode.attrs.href,title:vnode.attrs.title},[
            m('img[class=settings_t][style=margin:0 0 0 6px;border:0][src=images/settings_a.gif]')
    ]) } } }
/**
 * @deprecated Используйте "компонент" Row
 * @returns 
 */
    function interfaceRow() { return { view: function(vnode) { // label, children
        return m('tr', [
            m('td[align=right][valign=middle]', vnode.attrs.label,
            [(vnode.attrs.help?m(createHelpBtn, {helpbtn:vnode.attrs.help}):null), (vnode.attrs.label?':':'')]),
            m('td',vnode.children),
    ]) } } }
    const Row = Element(() => ({
        view: (vnode) => m('tr', [
            m('td[align=right][valign=middle]', 
                vnode.attrs.label,
            [(vnode.attrs.help?m(createHelpBtn, {helpbtn:vnode.attrs.help}):null), (vnode.attrs.label?':':'')]),
            m('td',vnode.children),
        ])
    }));
    function interfaceElementsInTable(elements) {  // label, children
        return m('table', elements.map(row => m('tr', row.map(column => m('td', column)))));
    }
    /**
     * @deprecated Используйте "компонент" Select
     * @returns 
     */
    function selectee() {
        return {
            oncreate: function (vnode) {
                if (!vnode.attrs.class || vnode.attrs.class && vnode.attrs.class.match('dont_use_chosen') === null) {
                    $(vnode.dom).find('select').chosen();
                }
            },
            onupdate: function (vnode) {
                $(vnode.dom).find('select').chosen('destroy');
                if (!vnode.attrs.class || vnode.attrs.class && vnode.attrs.class.match('dont_use_chosen') === null) {
                    $(vnode.dom).find('select').chosen();
                }
            },
            onremove: function (vnode) {
                if (!vnode.attrs.class || vnode.attrs.class && vnode.attrs.class.match('dont_use_chosen') === null) {
                    $(vnode.dom).find('select').chosen('destroy');
                }
            },
            view: function (vnode) {
                return m('span',
                    m('select.form-control',
                    {
                        style: { width: (vnode.attrs.width || 100) + 'px', margin: '0 2px' },
                        class: vnode.attrs.class || '',
                        disabled: vnode.attrs.disabled || false,
                        onchange: vnode.attrs.onchange instanceof Function
                            ? vnode.attrs.onchange
                            : function (e) {
                                var res = vnode.attrs.onchange;
                                res.payload.value = e.target.value;
                                raise(res.action, res.payload);
                            }
                    },
                    vnode.children
                ));
            }
        }
    }

    const Select = Element(() => ({
        oncreate: function (vnode) {
            if (!vnode.attrs.class || vnode.attrs.class && vnode.attrs.class.match('dont_use_chosen') === null) {
                $(vnode.dom).find('select').chosen();
            }
        },
        onupdate: function (vnode) {
            $(vnode.dom).find('select').chosen('destroy');
            if (!vnode.attrs.class || vnode.attrs.class && vnode.attrs.class.match('dont_use_chosen') === null) {
                $(vnode.dom).find('select').chosen();
            }
        },
        onremove: function (vnode) {
            if (!vnode.attrs.class || vnode.attrs.class && vnode.attrs.class.match('dont_use_chosen') === null) {
                $(vnode.dom).find('select').chosen('destroy');
            }
        },
        view: (vnode) => 
            m('span',
                m('select.form-control',
                    {
                        style: { 
                            width: `${(vnode.attrs.width || 100)}px`, 
                            margin: '0 2px' 
                        },
                        class: vnode.attrs.class || '',
                        disabled: vnode.attrs.disabled || false,
                        onchange: vnode.attrs.onchange instanceof Function
                            ? vnode.attrs.onchange
                            : function (e) {
                                var res = vnode.attrs.onchange;
                                res.payload.value = e.target.value;
                                raise(res.action, res.payload);
                            }
                    },
                    vnode.children
                )
            )
    }));
    function inputText() { return { view: function(vnode) { // value, width, placeholder, onchange
        return m('input.form-control[type=text]',
            {
                value: vnode.attrs.value,
                style: {width:(vnode.attrs.width || 100)+'px',margin:'0 2px'},
                placeholder: vnode.attrs.placeholder,
                disabled: vnode.attrs.disabled,
                onchange: vnode.attrs.onchange instanceof Function
                    ? vnode.attrs.onchange
                    : function(e) {
                        var res = vnode.attrs.onchange;
                        res.payload.value = e.target.value;
                        raise(res.action,res.payload);
                    },
                onfocus: vnode.attrs.onfocus,
                onblur: vnode.attrs.onblur,
            },
            null)
    } } }

    function toBase64(file) {
        return new Promise((resolve, reject) => {
            const reader = new FileReader();
            reader.readAsDataURL(file);
            reader.onload = () => resolve(reader.result);
            reader.onerror = error => reject(error);
        })
    };

    function getWidth(file) {
        return new Promise((resolve, reject) => {
            const image = new Image();
            const _URL = window.URL || window.webkitURL;
            image.onload = function () { resolve(this.width) };
            image.onerror = error => reject(error);
            image.src = _URL.createObjectURL(file);
        })
    };

    function inputFile() { return { view: function(vnode) { // value, width, placeholder, onchange
        return m.fragment({},
            [
                vnode.attrs.value == "" ? m.fragment({},[
                    m(aee, {
                        onclick: function (e) {
                            const event = new MouseEvent('click', {
                                view: window,
                                bubbles: false,
                                cancelable: true
                            });
                            const file_el = e.target.nextSibling;
                            file_el.dispatchEvent(event);
                        }
                    }, lang['Add']),
                    m('input[type=file][style=display:none;][accept=.jpg, .jpeg, .png, .svg]', {
                        onchange: async function(e) {
                            let res = vnode.attrs.onchange;
                            res.payload.value = await toBase64(e.target.files[0]);
                            let width = await getWidth(e.target.files[0]);
                            res.payload.width = width > 150 ? 150 : width;
                            raise(res.action,res.payload);
                            m.redraw();
                        },
                    }),
                ]) : m.fragment({},[
                    m('img.alpiction[src=images/b_drop.png]',{
                        onclick: function(){
                            var res = vnode.attrs.onchange;
                            res.payload.value = "";
                            raise(res.action,res.payload);
                            m.redraw();
                        },
                    }),
                    m('img', {
                        style: 'max-width:'+vnode.attrs.preview_width+'px;',
                        src: vnode.attrs.value
                    }),
                ])
            ]
        )
    } } }

    function inputRadioLine() { return { view: function(vnode) { // items: [{value, label, onchange}]
        ralid = genid();
        return m.fragment({}, vnode.attrs.items.map(function(item){
            return m('label[style=cursor:pointer;margin-right:13px;vertical-align:middle]',m('input[type=radio][style=margin-right:7px;vertical-align:middle]',{
                name: ralid,
                value: item.value,
                checked: item.checked,
                onchange: item.onchange instanceof Function
                ? () => {
                    item.onchange();
                }
                : function(e) {
                    var res = item.onchange;
                    res.payload.value = e.target.value;
                    raise(res.action,res.payload);
                },
            }), item.label)
        }))
    } } }

    function inputChecker() {
      var checkid = genid();

      return {
        view: function(vnode) { // value, label, onchange
          let attrs = {
            id: checkid,
            checked: vnode.attrs.value == 'yes',
            disabled: vnode.attrs.disabled,
            onchange: vnode.attrs.onchange instanceof Function
              ? vnode.attrs.onchange
              : function(e) {
                var res = vnode.attrs.onchange;
                res.payload.value = e.target.checked ? 'yes' : 'no';
                raise(res.action, res.payload);
              },
          };

          if (vnode.attrs.onclick) {
            attrs.onclick = vnode.attrs.onclick;
          }

          if (vnode.attrs.disabled) {
            attrs.disabled = vnode.attrs.disabled;
          }

          return m.fragment({}, [
            m('input.form-control[type=checkbox][style=width:20px]', attrs),
            m('label[style=vertical-align:center][for=' + checkid + ']', vnode.attrs.label),
          ])
        }
      }
    }

    function statusCheckSet() {
      return {
          view: function(vnode) {
              var blkid, value = {active:'no',archive:'no',deleted:'no'};
              function changer(name,flag) {
                  value[name] = flag ? 'yes' : 'no';
                  var val = [];
                  for(x in value) if (value[x] == 'yes') val.push(x);
                  raise(BLOCK_WIZ_SET_STATUS,{blkid:blkid, value:val.join('+'), index: vnode.attrs.index});
              }
              (vnode.attrs.value || '').split('+').forEach(function(i){if(i!='')value[i]='yes'});
              blkid = vnode.attrs.blkid;
              return m.fragment({},[
                  m('div',m(inputChecker,{value:value.active,label:lang['Active'],onchange:function(e){changer('active',e.target.checked)}})),
                  m('div',m(inputChecker,{value:value.archive,label:lang['Archival'],onchange:function(e){changer('archive',e.target.checked)}})),
                  m('div',m(inputChecker,{value:value.deleted,label:lang['Deleted'],onchange:function(e){changer('deleted',e.target.checked)}})),
              ])
          }
      }
  }

    function aee() { return { view: function(vnode) {
        return m('span.alaction',
            {
                style: vnode.attrs.style,
                onclick: vnode.attrs.onclick instanceof Function
                    ? vnode.attrs.onclick
                    : function() { raise(vnode.attrs.onclick.action,vnode.attrs.onclick.payload); return false; },
            },
            vnode.children)
    } } }

    /**
     * @deprecated Используйте "компонент" Block
     * @returns 
     */
    function detailsBlock() { return { view: function(vnode) {
        return m.fragment({},[
            m(interfaceRow,{},m('h3',vnode.attrs.title)),
            vnode.children,
            m(interfaceRow,{},
                m('input[type=button][value='+ lang['Roll_up'] + '].btn.btn-default.btn-sm',{onclick:function(){raise(SET_DETAILS_ITEM,{item_id:undefined});return false;}}),
            ),
    ]) } } }
    const Block = Element(() => ({ 
        view: (vnode) => 
            m.fragment({},[
                m(interfaceRow,{},m('h3',vnode.attrs.title)),
                vnode.children,
                m(interfaceRow,{},
                    m('input[type=button][value='+ lang['Roll_up'] + '].btn.btn-default.btn-sm',{onclick:function(){raise(SET_DETAILS_ITEM,{item_id:undefined});return false;}}),
                ),
            ]) 
    }));

    /**
     * Строка определения параметра.
     */
    function parameterDefinitionRow() {
      return {
        view: function(vnode) { // item
          /**
           * Определения вида параметра
           * @param {String} type  Тип параметра
           * @param {Object} param Настройки параметра
           * @returns Фрагмент верстки
           */
          function parameterTypeDefinitions(type, param) {
            switch (type) {
              // Параметр 'период'
              case 'period':
                return m.fragment({}, [
                  m(inputText, { // input 'Количество'
                    value: (param.default == 'quarter' ? "" : (param.datatype_details != '' ? param.datatype_details : 1)),
                    width: 110,
                    placeholder: param.default == 'quarter' ? "" : lang['Count'],
                    disabled: param.default == 'quarter',
                    onchange: function() {
                      let value = parseInt(this.value.replace(/^\D*/gi, ''));
                      if (isNaN(value) || value < 1) {
                        value = 1;
                      }
                      raise(DATA_ITEM_SET,{
                        item_name: param.name,
                        name: 'datatype_details',
                        value
                      })
                    },
                  }),

                  m(selectee, { // select 'Временной промежуток'
                    width: 100,
                    class: 'dont_use_chosen',
                    onchange: function() {
                      raise(DATA_ITEM_SET, { item_name: param.name, name: 'default', value: this.value});

                      if (this.value == 'quarter') {
                        raise(DATA_ITEM_SET, { item_name: param.name, name: 'datatype_details', value: 0});
                      }
                    }
                  }, PARAMETER_PERIOD.map(function(i) {
                    return m('option', {
                      value: i.value,
                      selected: (param.default == i.value)
                    }, i.label)}
                  )),
              ]);

              // Параметр 'пользователь'
              case 'user_field':
                return m.fragment({}, [
                  m(selectee, { // select - выбор групп доступа
                    width: 100,
                    class: 'dont_use_chosen',
                    onchange: function() {
                      raise(DATA_ITEM_SET, {
                        item_name: param.name, name: 'default', value: '',
                      });

                      raise(DATA_ITEM_SET, {
                        item_name: param.name, name: 'selected_group', value: `${this.value}`,
                      });
                  }}, [{id: '', name: ''}, ...MD.getGroups()].map(function(i) {
                    return m('option', {
                      value: i.id, selected: (param.selected_group == i.id)
                    }, i.name);
                  })),

                  m(selectee, { // select - множественный выбор
                    width: 100,
                    class: 'dont_use_chosen',
                    onchange: function() {
                      raise(DATA_ITEM_SET, {
                        item_name: param.name, name: 'multiple_choice', value: `${this.value}`,
                      });
                  }}, [
                    {id: 'no', name: ''},
                    {id: 'yes', name: lang['multiple_selection']}
                  ].map(function(i) {
                    return m('option', {
                      value: i.id, selected: (param.multiple_choice == i.id)
                    }, i.name);
                  })),
                ]);

              // Параметр 'из поля'
              case 'list_field':
              case 'link_field':
              case 'from_fields':
                return m.fragment({}, (() => {
                  let cur_table_id = '';

                  if (!param.datatype_details) {
                    raise(DATA_ITEM_SET, {
                      item_name: param.name,
                      name: 'datatype_details',
                      value: ''
                    });
                  }

                  return [
                    m(selectee, { // Выбор таблицы
                      width: 100,
                      class: 'dont_use_chosen',
                      onchange: function() {
                        let value = `${this.value}|`;
                        raise(DATA_ITEM_SET, {
                          item_name: param.name, name: 'datatype_details', value: value
                        });
                        raise(DATA_ITEM_SET, {
                          item_name: param.name, name: 'default', value: ''
                        });
                      }
                    }, MD.getTableList().map(function(i) {
                      if (param.datatype_details.split('|')[0] == i.id) cur_table_id = i.id;
                      return m('option', {
                        value: i.id, selected: (param.datatype_details.split('|')[0] == i.id)
                      }, i.name);
                    })),

                    [ // Выбор поля таблицы
                      cur_table_id != '' ? m(selectee, {
                        width: 100,
                        class: 'dont_use_chosen',
                        onchange: function() {
                          let value = `${cur_table_id}|${this.value}`;
                          let field_info = MD.getFieldInfo(cur_table_id, this.value.slice(1));

                          raise(DATA_ITEM_SET, {
                            item_name: param.name,
                            name: 'datatype',
                            value: (field_info?.type == 4 ? 'list_field': (
                              field_info?.type == 5 ? 'link_field' : 'from_fields'
                            )) || ''
                          });

                          raise(DATA_ITEM_SET, {
                            item_name: param.name,
                            name: 'datatype_details',
                            value: value
                          });
                        }
                      }, [{id: '', name: ''}, ...MD.getFieldList(cur_table_id).filter(
                        (item) => (item.type == 4 || item.type == 5)
                      )].map(function(i) {
                        return m('option', {
                          value: i.id,
                          selected: (param.datatype_details.split('|')[1] == i.id)
                        }, i.name)})
                      ) : m('span[style=display:inline-block;width:136px;]', ' '),
                    ]
                  ];
              })());
            }
          }

          const param = vnode.attrs.item;
          const params_length = vnode.attrs.params_length > 1;

          return m('div', {
            blkid: 'parameter',
            item_id: param.name,
            style: (params_length ? { 'margin-bottom': '4px' } : {}),
          }, [
            m('img[src=images/draggable.png].draghandle'),

            // крестик удаления параметра (если один параметр, то нет крестика)
            !params_length ? null : m('img', {
              class: 'alpiction',
              src: 'images/b_drop.png',
              onclick: function() {
                raise(DATA_ITEM_DELETE, {item_name: param.name});
              },
            }),

            // input 'Название параметра'
            m(inputText, {
              value: param.label ? param.label : null,
              width:75,
              placeholder: lang['Name2'],
              onchange: function() {
                raise(DATA_ITEM_SET, {
                  item_name: param.name,
                  name: 'label',
                  value: this.value
                })
              },
            }),

            // select - выбор 'типа параметра'
            m(selectee, {
              width: 75,
              class: 'dont_use_chosen',
              onchange: function() {
                raise(DATA_ITEM_SET, {
                  item_name: param.name, name: 'datatype', value: this.value
                });
                raise(DATA_ITEM_SET, {
                  item_name: param.name, name: 'datatype_details', value: ''
                });

                if (this.value != 'period') {
                  raise(DATA_ITEM_SET, {
                    item_name: param.name, name: 'default', value: ''
                  });
                }
              }
            }, PARAMETER_DATATYPE.map(function(i) {
              return m('option', {
                value: i.value,
                selected: (
                  param.datatype == i.value ||
                  (
                    ['list_field', 'link_field'].includes(param.datatype) &&
                    i.value == 'from_fields'
                  )
                )
              }, i.label)
            })),

            // Определение вида параметра
            parameterTypeDefinitions(param.datatype, param),

            // отступ с номером параметра
            m('span', {
              style: {display: 'inline-block', color: 'gray', 'font-family': 'monospace'},
              title: param.name
            }, param.name),
          ]);
        }
      }
    }

    /**
     * Вывод всех параметров.
     */
    function parameterLinkRow() {
      return {
        view: function(vnode) { // blkid, item, table, link
          var param = vnode.attrs.item,
            table   = vnode.attrs.table,
            link    = vnode.attrs.link,
            axis    = vnode.attrs.axis,
            width   = vnode.attrs.width;

          let fieldInfo = null;
          if (param.datatype == 'link_field') {
            fieldInfo = MD.getFieldInfo(param.datatype_details.split('|')[0], param.datatype_details.split('|')[1]);
            if ('value' in fieldInfo && !('options' in fieldInfo)) {
              fieldInfo.options = fieldInfo.value.split('|');
            }
          }

          var flds = MD.getFieldList(table).filter(function(i) {
            if (i.mult_value == 1 && vnode.attrs.multiple_choice_disabled) {
              return false;
            }

            switch (param.datatype) {
              case 'period':     return (i.type == '2' || i.type == '12');
              case 'user_field': return (i.type == '7' || i.type == '11');
              case 'list_field': return (i.id == param.datatype_details.split('|')[1]);
              case 'link_field': {
                let field = (i.options || '').split('|');
                return (
                  typeof field[0] !== 'undefined' &&
                  typeof field[1] !== 'undefined' &&
                  field[0] == fieldInfo.options[0] &&
                  field[1] == fieldInfo.options[1]
                );
              }
              default: return false;
            }
          });

          return m('div', {
            style: vnode.attrs.params_length > 1 ? {'margin-bottom': '8px'} : {}
          }, [
            m('span', { style: {
              display: 'inline-block', width: '30px', color: 'gray', 'font-family': 'monospace'
            } }, param.name),
            m(selectee, {
              width: width || 100,
              class: 'dont_use_chosen',
              onchange: {
                action: BLOCK_WIZ_SET_PARALINK,
                payload: {blkid: vnode.attrs.blkid, param: param.name, index: vnode.attrs.index,}
              }
            }, [
              m('option', { value: '' }, ''),
              (
                axis
                  ? flds
                    .filter(item => axis.includes(item.id))
                    .map(function(i) {
                      return m('option', {value: i.id, selected: (link == i.id)}, i.name);
                    })
                  : flds.map(function(i) {
                    return m('option', {value: i.id, selected: (link == i.id)}, i.name);
                  })
              )
            ]),
          ])
        }
      }
    }

    function parameterLinkRowRelative() { return { view: function(vnode) { // blkid, item, table, link
        var param = vnode.attrs.item, table = vnode.attrs.table, link = vnode.attrs.link;
        var flds = MD.getFieldList(table).filter(function(i){
            switch (param.datatype) {
                case 'period': return (i.type=='2' || i.type=='12');
                case 'user_field': return (i.type=='7' || i.type=='11');
                case 'list_field': return (i.id==param.datatype_details.split('|')[1]);
                case 'link_field': return (i.id==param.datatype_details.split('|')[1]);
                default: return false;
            }
        });
        return m('div' + (vnode.attrs.params_length > 1 ? '[style=margin-bottom:8px]':''),[
            m('span[style=display:inline-block;width:30px;color:gray;font-family:monospace]',param.name),
            m(selectee,{width:100,class:'dont_use_chosen',onchange:{action:BLOCK_WIZ_SET_PARALINK_RELATIVE,payload:{blkid:vnode.attrs.blkid,param:param.name}}},[
                m('option',{value:''},''),
                flds.map(function(i){return m('option',{value:i.id,selected:(link==i.id)},i.name)}),
            ]),
    ]) } } }

    // Редактирование строки
    /**
     * Редактирование строки
     *  При наличии параметра is_main_grouping меняет свое поведение
     *  для отображения основного поля группировки мультитаблиц
     *  TODO: Необходимо изменить непредсказуемое поведение
     *  Например, разделить функционал создав отдельный компонент для мультитаблиц
     *  или управлять поведением отдельным явно читаемым параметром showAs...
     */
    function columnRowWizTable() {
      return {
        view: function(vnode) { // blkid, col, table
          var col = vnode.attrs.col;
          var coltype = col.field.split('|',1)[0],
            colempty = col.field == 'field|';

          // необходимо ли вывести доп. настройки поля (по умолчанию = true,да)
          let need_more_fields = (typeof vnode.attrs.need_more_fields == 'undefined') ? true : vnode.attrs.need_more_fields;
          // необходимо ли вывести расширенную группу "вычислений" в опции выбора поля таблицы
          const extended_group = (typeof vnode.attrs.extended_group == 'undefined') ? true : vnode.attrs.extended_group;

          function paysetval(name) {
            return {
              action: BLOCK_WIZ_COLUMN_SET_VALUE,
              payload: {
                blkid: vnode.attrs.blkid, 
                colid: vnode.attrs.col.id, 
                name: name, 
                index: vnode.attrs.index, 
                is_additional_grouping: vnode.attrs.is_additional_grouping, 
                is_main_group_table: vnode.attrs.is_main_group_table,
                is_main_grouping: vnode.attrs.is_main_grouping
              },
            }
          }

          function aggrSetVal() {
            let value = this.value;

            if (value == 'yes') {
              raise(BLOCK_WIZ_COLUMN_SET_VALUE, {
                blkid: vnode.attrs.blkid, 
                colid: vnode.attrs.col.id, 
                name: 'group', value, 
                index: vnode.attrs.index
            });
              raise(BLOCK_WIZ_COLUMN_SET_VALUE, {
                blkid: vnode.attrs.blkid, 
                colid: vnode.attrs.col.id, 
                name: 'expr', 
                value: '', 
                index: vnode.attrs.index
            });
            } else {
              if (value == '' || value == 'no') {
                raise(BLOCK_WIZ_COLUMN_SET_VALUE, {
                    blkid: vnode.attrs.blkid, 
                    colid: vnode.attrs.col.id, 
                    name: 'group', 
                    value: 'no', 
                    index: vnode.attrs.index
                });
              }

              raise(BLOCK_WIZ_COLUMN_SET_VALUE, {
                blkid: vnode.attrs.blkid, 
                colid: vnode.attrs.col.id, 
                name: 'expr', 
                value, 
                index: vnode.attrs.index
            });
            }

            init_chosen();
          }

          function checkAvailablestKindOfPeriod() {
            return (
              MD.getFieldInfo(vnode.attrs.table, col.field.split('|')[1])?.type == 2 ||
              MD.getFieldInfo(vnode.attrs.table, col.field.split('|')[1])?.type == 12
            );
          }

          return m(
            `div[style=${vnode.attrs.is_additional_grouping || vnode.attrs.is_main_grouping ? 'margin-left:35px;' : 'margin-bottom:4px;'}]`, 
            {
                item_id: vnode.attrs.col.id, 
                blkid: vnode.attrs.blkid
            }, [
            // иконка перемещения строки
                vnode.attrs.is_additional_grouping || vnode.attrs.is_main_grouping 
                    ? null 
                    : m('img[src=images/draggable.png].draghandle'),

            // иконка удаления строки
                vnode.attrs.is_additional_grouping || vnode.attrs.is_main_grouping 
                    ? null 
                    : m(
                        'img.alpiction[src=images/b_drop.png]',
                        {
                            onclick: function() {
                                raise(BLOCK_WIZ_COLUMN_DELETE, {blkid: vnode.attrs.blkid, colid: vnode.attrs.col.id, index: vnode.attrs.index})
                            },
                        }
                    ),

            // input "Заголовок"
            m(inputText, {
              value: col.title,
              width:150,
              placeholder: lang['Column_title'],
              onchange:paysetval('title'),
            }),

            // select "Выбор поля"
            m(
                selectee, 
                {
                    width: 150,
                    onchange: paysetval('field'),
                    ...(vnode.attrs.is_main_grouping ? { class: 'main-current-group' } : {})
                }, [
                    m('option', {value: 'field|', selected: (col.field == 'field|')}, ''),

                    // группа "Вычисления"
                    !extended_group || vnode.attrs.is_additional_grouping || vnode.attrs.is_main_grouping 
                        ? null 
                        : m('optgroup', {label: lang['field_calcs']}, (() => {
                            let result = [
                            // Вычисление по строке отчета
                                m('option', {value: 'expr|', selected: (col.field == 'expr|')}, lang['calc_on_report_line'])
                            ];

                            if (vnode.attrs.has_available_aa && !vnode.attrs.is_multitable) { // Дополнительные действия
                            result.push(
                                m('option', {value: 'aa|', selected: (col.field.indexOf('aa|') !== -1)}, lang['Additional_action'])
                            );
                            }

                            return result;
                        })()),

                    // группа "Поля таблицы"
                    vnode.attrs.is_additional_grouping
                        ?   m('optgroup', {label: lang['fields_of_table']}, [
                                MD.getFieldAndLinkList(vnode.attrs.table, vnode.attrs.multiple_choice_disabled)
                                .filter(i => {

                                    const elements = document.querySelector('div.main-current-group');
                                    if (!MAIN_GROUP.name_field && elements) {
                                        MAIN_GROUP.name_field = elements.querySelector('.chosen-single span').textContent.split('.')[0];
                                    }

                                    const iData = MD.getFieldInfo(vnode.attrs.additional_table.use_table, i.id.split('|')[1]);
                                    const iMainData = MD.getFieldInfo(MAIN_GROUP.use_table + '', MAIN_GROUP.field.split('|')[1]);

                                    // Список допустимых соответствий типов
                                    const typePairs = [
                                        [1, 10], // число
                                        [2, 12], // дата
                                        [3],     // текст
                                        [4, 13], // список
                                        [5],     // связь
                                        [7, 11], // пользователь
                                        [14]     // группа
                                    ];

                                    // Проверяем, есть ли пара, включающая оба типа
                                    const isValidType = typePairs.some(pair => pair.includes(MAIN_GROUP.type) && pair.includes(iData.type));

                                    if (MAIN_GROUP.type == 5) { // для поля типа "Связь", должно быть привязанно к одной и той же таблице
                                    return isValidType && iMainData.value.split('|')[1] == iData.value.split('|')[1];
                                    } else if (MAIN_GROUP.type == 13 || MAIN_GROUP.type == 4) { // для поля типа "Список", должно быть одинаковое значение
                                    return isValidType && iMainData.value == iData.value;
                                    } else {
                                    return isValidType;
                                    }
                                })
                                .reduce((uniqueItems, i) => {
                                    const itemId = i.id.split('|').length > 2 ? i.id.split('|').slice(0, 2).join('|') : i.id;
                                    if (!uniqueItems.some(item => item.processedId === itemId)) {
                                    uniqueItems.push({...i, processedId: itemId});
                                    }
                                    if (uniqueItems.length == 1) {
                                    vnode.attrs.autoSelectItem = i; // Сохраняем элемент для авто-выбора
                                    }
                                    return uniqueItems;
                                }, [])
                                .map(function(i) {
                                    return m('option', {value: i.id, selected: (col.field == i.id), 'data-auto-select': vnode.attrs.autoSelectItem ? 'true' : 'false'}, i.name.split('.')[0]);
                                })
                            ])
                        : vnode.attrs.is_additional_column
                            ?   m('optgroup', {label: lang['fields_of_table']}, [
                                    MD.getFieldAndLinkList(vnode.attrs.table, vnode.attrs.multiple_choice_disabled)
                                        .filter(i => {
                                            const iData = MD.getFieldInfo(vnode.attrs.additional_table.use_table, i.id.split('|')[1])
                                            return iData.type == 1 || iData.type == 2
                                        })
                                        .map(function(i) {
                                            return m('option', {value: i.id, selected: (col.field == i.id)}, i.name);
                                        })
                                ])
                            :   vnode.attrs.is_main_grouping
                                ?   m('optgroup', {label: lang['fields_of_table']}, [
                                        MD.getFieldAndLinkList(vnode.attrs.table, vnode.attrs.multiple_choice_disabled)
                                            .filter(i => {
                                                const iData = MD.getFieldInfo(vnode.attrs.table, i.id.split('|')[1]);
                                                // Типы, которые нужно включить
                                                const validTypes = [2, 12, 4, 13, 5, 7, 11, 14];
                                                return validTypes.includes(iData.type);
                                            })
                                            .map(function(i) {
                                                return m('option', {value: i.id, selected: (col.field == i.id)}, i.name);
                                            })
                                    ])
                                :   m('optgroup', {label: lang['fields_of_table']}, [
                                        MD.getFieldAndLinkList(vnode.attrs.table, vnode.attrs.multiple_choice_disabled).map(function(i) {
                                            return m('option', {value: i.id, selected: (col.field == i.id)}, i.name);
                                        })
                                    ]),
                ]
            ),
            // что то
            (vnode.attrs.is_additional_grouping || vnode.attrs.is_main_grouping) && !checkAvailablestKindOfPeriod() 
                ? null 
                : (!colempty && need_more_fields) 
                    ?   m.fragment({},[
                            m.fragment({},[
                                col.field.indexOf('aa|') !== -1
                                    ?   m(
                                            selectee, {
                                                width:150,
                                                onchange:function(e){
                                                    raise(BLOCK_WIZ_COLUMN_SET_VALUE, { blkid: vnode.attrs.blkid, colid: vnode.attrs.col.id, name:'field', value: 'aa|' + e.target.value, index: vnode.attrs.index});
                                                },
                                                id:col.name+'-column-aa'
                                            }, 
                                            MD.getAA(vnode.attrs.table)
                                                .map(item => m('option',{
                                                    value: item.id,
                                                    selected: (col.field.split('|')[1]==item.id)
                                                    },item.name)
                                                )
                                        )
                                    :   vnode.attrs.is_additional_grouping || vnode.attrs.is_main_grouping
                                            ?   null
                                            :   m(selectee, {width:150, onchange:aggrSetVal, id:col.name+'-column-expr'},
                                                    (() => {
                                                        let options = [];

                                                        if(coltype == 'field'){
                                                            options.push(
                                                                AGGR_SQL.slice(vnode.attrs.is_multitable ? 1 : 0).map(function(i){return m('option',{value:i.value,selected:(col.expr==i.value && col.group != 'yes')},i.label)})
                                                            );
                                                        }

                                                        if(
                                                            ['field','link','user'].indexOf(coltype)>=0 && !vnode.attrs.is_multitable
                                                        ){
                                                            let columns_group = options.length == 0 ? COLUMN_GROUPBY : [ COLUMN_GROUPBY[1] ];
                                                            options.push(
                                                                m('optgroup', {}, [
                                                                    columns_group.map(function(i){return m('option',{value:i.value,selected:(col.group==i.value && col.expr == '')},i.label)})
                                                                ])
                                                            );
                                                        }

                                                        return options;
                                                    })()
                                                ),
                                (col.expr!='')
                                    ?   m(
                                            selectee, 
                                            {width:150, onchange:paysetval('filter')},
                                            MD.getFilterList(vnode.attrs.table)
                                                .map(function(i){return m('option',{value:i.id,selected:(col.filter==i.id)},i.parent+i.name)})
                                        )
                                    :   null,
                                ((col.group!='no') && checkAvailablestKindOfPeriod())
                                    ?   m(
                                            selectee,
                                            {width:152,class:'dont_use_chosen',onchange:{action:BLOCK_WIZ_KIND_OF_PERIOD,payload:{blkid:vnode.attrs.blkid}}},
                                            PARAMETER_PERIOD.map(function(i){return m('option',{value:i.value,selected:(vnode.attrs.kind_of_period==i.value)},i.label)})
                                        )
                                    : null,
                                (col.expr == '' && ( col.group == 'no' || col.group == 'yes' && !checkAvailablestKindOfPeriod()))
                                    ?   m('span[style=display:inline-block;width:186px;]',' ')
                                    :   null,
                            ]),
                            (['sql','expr'].indexOf(coltype)>=0) 
                                ?   m(inputText, {
                                        value: col.expr,
                                        width:346,
                                        placeholder: lang['expression'],
                                        onchange:paysetval('expr'),
                                    }) 
                                :   null,
                        ]) 
                    :   m('span[style=display:inline-block;width:372px;]',' '),

            // номер столбца
            m('span[style=display:inline-block;color:gray;font-family:monospace]', {title: col.name}, col.name),
            ]
          )
        },
        oncreate: function(vnode) {
          handleAutoSelect(vnode);
        },
        onupdate: function(vnode) {
          handleAutoSelect(vnode);
        }
      }
    }

    function removeNextSiblingsIfExpr(selectElement) {
      if (selectElement.value == 'expr|') {
        let parent = selectElement.parentElement;

        if (parent.nextElementSibling && parent.nextElementSibling.firstElementChild && parent.nextElementSibling.firstElementChild.tagName === 'SELECT') {
          parent.nextElementSibling.remove();
        }

        if (parent.nextElementSibling && parent.nextElementSibling.tagName === 'SPAN' && parent.nextElementSibling.textContent.trim() === '') {
          parent.nextElementSibling.remove();
        }
        let lastSpan = parent.parentElement.querySelector('span:last-child');
        if (lastSpan && lastSpan.querySelector('select')) {
          lastSpan.remove();
        }
      }
    }

    function handleAutoSelect(vnode) {
      if (vnode.attrs.is_multitable) {
        setTimeout(() => {
          const selectElement = vnode.dom.querySelector('select');

          // если Вычисление по строке, то удаляем селекты с действием и фильтром
          removeNextSiblingsIfExpr(selectElement);

          // Автоматически выбираем первый элемент, если содержит только одно значение
          const optgroup = selectElement.querySelector('optgroup');

          if (vnode.attrs.is_additional_grouping && vnode.attrs.autoSelectItem && optgroup && optgroup.children.length == 1) {
            const firstOption = optgroup.children[0];
            const spanElement = selectElement.parentElement.querySelector('span');

            if (firstOption && spanElement && selectElement.value !== firstOption.value) {
              // Устанавливаем значение первого option
              selectElement.value = firstOption.value;
              spanElement.textContent = firstOption.textContent;
              vnode.attrs.col.field = firstOption.value;

              // Обновляем значение в val
              updateFieldValue(
                vnode.attrs.blkid,
                vnode.attrs.col.id,
                firstOption.value,
                vnode.attrs.index,
                vnode.attrs.is_additional_grouping,
                vnode.attrs.is_main_grouping
              );
            }
          }
        }, 1);
      }
    }

    function updateFieldValue(blkid, colid, value, index, is_additional_grouping, is_main_grouping) {
      raise(BLOCK_WIZ_COLUMN_SET_VALUE, {
        blkid: blkid,
        colid: colid,
        name: 'field',
        value: value,
        index: index,
        is_additional_grouping: is_additional_grouping,
        is_main_grouping: is_main_grouping
      });
    }

    function columnRowWizTableSettings() { 
        return { 
            view: function(vnode) { // blkid, col, table
                var col = vnode.attrs.col;
                var disabled = vnode.attrs.disabled;
                var isColumnEmpty =  col.field=='field|';

                // какие части настроек выводить
                const total  = (typeof vnode.attrs.total == 'undefined') ? true : vnode.attrs.total;
                const format = (typeof vnode.attrs.format == 'undefined') ? true : vnode.attrs.format;
                const hidden = (typeof vnode.attrs.hidden == 'undefined') ? true : vnode.attrs.hidden;
                const sort   = (typeof vnode.attrs.sort == 'undefined') ? true : vnode.attrs.sort;


                function paysetval(name) { 
                    return {
                        action: BLOCK_WIZ_COLUMN_SET_VALUE,
                        payload: { 
                            blkid: vnode.attrs.blkid, 
                            colid: vnode.attrs.col.id, 
                            name:name, 
                            index: vnode.attrs.index, 
                        },
                    } 
                }
                return m(
                    'div[style=margin-bottom:4px]', [
                    m.fragment({},[
                        m('span[style=display:inline-block;width:26px;color:gray;font-family:monospace]',{title:col.name},col.name),
                    ]),
                    m(inputText, {
                        value: col.title!='' ? col.title : null,
                        width:150,
                        disabled: 'disabled',
                        placeholder: lang['Column_title'],
                        onchange:paysetval('title'),
                    }),
                    (!isColumnEmpty && col.field.indexOf('aa|') === -1) ? m.fragment({},[
                        total ? m(selectee, {
                                width:150,
                                onchange:paysetval('total'),
                            },
                            AGGR_TOTAL.map(function(i){return m('option',{value:i.value,selected:(col.total==i.value)},i.label)})
                        ) : null,
                        format ? m(selectee,{
                            width:75,
                            onchange:paysetval('format'),
                        },
                            FORMATS.map(function(i){return m('option',{value:i.value,selected:(col.format==i.value)},i.label)})
                        ) : null,
                        hidden ? Select({ 
                            width:75,
                            onchange: paysetval('hidden'),
                            disabled: disabled?.hidden ?? null,
                            children: COLUMN_HIDDEN.map((i) => 
                                m('option',{value:i.value,selected:(col.hidden==i.value)},i.label))
                        }) : null,
                        sort ? m(selectee,{
                            width:75,
                            onchange:paysetval('sort'),
                        },
                            COLUMN_SORTBY.map(function(i){return m('option',{value:i.value,selected:(col.sort==i.value)},i.label)})
                        ) : null,
                    ]) : null,
                ]) 

            } 
        } 
    }

    function columnRowWizKanbanSettings() { return { view: function(vnode) { // blkid, col, table
        var col = vnode.attrs.col;
        var coltype = col.field.split('|',1)[0], colempty =  col.field=='field|';
        function paysetval(name) { return {
                action: BLOCK_WIZ_COLUMN_SET_VALUE,
                payload: { blkid: vnode.attrs.blkid, colid: vnode.attrs.col.id, name:name },
        } }
        return m('div[style=margin-bottom:4px]', [
            m.fragment({},[
                m('span[style=display:inline-block;width:26px;color:gray;font-family:monospace]',{title:col.name},col.name),
            ]),
            m(inputText, {
                value: col.title!='' ? col.title : null,
                width:150,
                disabled: 'disabled',
                placeholder: lang['Column_title'],
                onchange:paysetval('title'),
            }),
            (!colempty) ? m.fragment({},[
                m(selectee,{width:75,onchange:paysetval('format')},
                    FORMATS.map(function(i){return m('option',{value:i.value,selected:(col.format==i.value)},i.label)})
                ),
                m(selectee,{width:75,onchange:paysetval('hidden')},
                    COLUMN_HIDDEN.map(function(i){return m('option',{value:i.value,selected:(col.hidden==i.value)},i.label)})
                ),
                m(selectee,{width:75,onchange:paysetval('sort')},
                    COLUMN_SORTBY.map(function(i){return m('option',{value:i.value,selected:(col.sort==i.value)},i.label)})
                ),
            ]) : null,
    ]) } } }

    function columnRowWizKanbanColor() {
        return {
            view: function(vnode) { // blkid, col, table
                let col = vnode.attrs.col,
                    all_fields_values = vnode.attrs.all_fields_values.values,
                    use_color_values_ids = vnode.attrs.colors.map(item => item.field_value_id),
                    group_field_values = [];

                if(vnode.attrs.all_fields_values.type == 7){
                    let tech_help_id = null;
                    for(let id of Object.keys(all_fields_values)){
                        if(all_fields_values[id] == 'Техподдержка КБ'){
                            tech_help_id = id;
                            break;
                        }
                    }
                    if(tech_help_id !== null){
                        delete all_fields_values[tech_help_id];
                    }
                }

                for(let key in all_fields_values){
                    if(!use_color_values_ids.includes(key) || col.field_value_id == key){
                        group_field_values.push({id: key, value: all_fields_values[key]});
                    }
                }
                function paysetval(name) { return {
                        action: BLOCK_WIZ_SET_COLOR,
                        payload: { blkid: vnode.attrs.blkid, key: vnode.attrs.key, name:name },
                } }
                return m('div[style=margin-bottom:4px]', [
                    m('img.alpiction[src=images/b_drop.png]',{
                        onclick: function(){raise(BLOCK_WIZ_DELETE_COLOR,{blkid:vnode.attrs.blkid,key:vnode.attrs.key})},
                    }),
                    m(selectee, {
                        width:150,
                        onchange:function (e) {
                            raise(BLOCK_WIZ_SET_COLOR, { blkid: vnode.attrs.blkid, key: vnode.attrs.key, name:'field_value_id', value: e.target.value});
                            raise(BLOCK_WIZ_SET_COLOR, { blkid: vnode.attrs.blkid, key: vnode.attrs.key, name:'field_value_value', value: all_fields_values[e.target.value]});
                        }
                    }, group_field_values.map(item => m('option', {value: item.id, selected: (item.id == col.field_value_id)}, item.value))),
                    m(selectee,{width:75,onchange:paysetval('color')},
                        COLORS.map(function(i){return m('option',{value:i.value,selected:(i.value == col.color)},i.label)})
                    ),
                ]);
            }
        }
    }

    function axisRowWizChart() {
      return {
        view: function(vnode) { // blkid, col, table
          var col = vnode.attrs.col,
            colempty = col.field == 'field|';

          function paysetval(name) {
            return {
              action: BLOCK_WIZ_AXIS_SET_VALUE,
              payload: { blkid: vnode.attrs.blkid, colid: vnode.attrs.col.id, name:name },
            }
          }

          return m('div[class=axis-row]', {item_id: vnode.attrs.col.id}, [
            // вместо крестика пустота
            m('span[style=display:inline-block;width:36px;]',' '),

            // Заголовок столбца
            m(inputText, {
              value: col.title != '' ? col.title : null,
              width: 150,
              placeholder: lang['Column_title'],
              onchange: paysetval('title'),
            }),

            // Поля таблицы
            m(selectee, {width: 150, onchange: paysetval('field')}, [
              m('option', {value: 'field|', selected: (col.field == 'field|')}, ''),
              m('optgroup', {label: lang['fields_of_table']}, [
                MD.getFieldAndLinkList(vnode.attrs.table, true).map(function(i) {
                    return  m('option', {value: i.id, selected: (col.field == i.id)}, i.name)
                })
              ]),
            ]),

            !colempty && (
              MD.getFieldInfo(vnode.attrs.table, col.field.split('|')[1]).type == 2 ||
              MD.getFieldInfo(vnode.attrs.table, col.field.split('|')[1]).type == 12
            )
              ? m(selectee, {
                width: 150,
                class: 'dont_use_chosen',
                onchange: {action: BLOCK_WIZ_KIND_OF_PERIOD, payload: {blkid: vnode.attrs.blkid}}
              }, PARAMETER_PERIOD.map(function(i) {
                return m('option', {value: i.value, selected: (vnode.attrs.kind_of_period == i.value)}, i.label)
              })) : null,

            // отступ
            m('span[style=display:inline-block;color:gray;font-family:monospace]', {}, ''),
          ]);
        }
      }
    }

    function lineRowWizChart() {
      return {
        view: function(vnode) { // blkid, col, table
          var col = vnode.attrs.col;
          if (col.expr == '') {
            raise(BLOCK_WIZ_LINE_SET_VALUE, {
              blkid: vnode.attrs.blkid, colid: vnode.attrs.col.id, name:'expr', value: 'SUM'
            });
          }

          var coltype = col.field.split('|',1)[0],
            colempty = col.field == 'field|';

          function paysetval(name) {
            return {
              action: BLOCK_WIZ_LINE_SET_VALUE,
              payload: {blkid: vnode.attrs.blkid, colid: vnode.attrs.col.id, name: name},
            }
          }

          return m('div[style=margin-bottom:4px]',{item_id:vnode.attrs.col.id}, [
            m('img[src=images/draggable.png].draghandle'),

            m('img.alpiction[src=images/b_drop.png]', {
              onclick: function() {
                raise(BLOCK_WIZ_LINE_DELETE, {blkid: vnode.attrs.blkid, colid: vnode.attrs.col.id})
              },
            }),

            m(inputText, {
              value: col.title != '' ? col.title : null,
              width: 150,
              placeholder: lang['Column_title'],
              onchange: paysetval('title'),
            }),

            m(selectee,{ width: 150, onchange: paysetval('field')},[
              m('option',{value: 'field|', selected: (col.field == 'field|')}, ''),
              m('optgroup', {label: lang['field_calcs']}, [
                m('option', {value: 'expr|', selected: (col.field == 'expr|')}, lang['calc_on_report_line']),
              ]),
              m('optgroup', {label: lang['fields_of_table']}, [
                MD.getFieldAndLinkList(vnode.attrs.table).map(function(i) {
                  if (i.id !== vnode.attrs.axis.field) {
                    return m('option', {value: i.id, selected: (col.field == i.id)}, i.name)
                  }
                })
              ]),
            ]),

            (!colempty) ? m.fragment({},[
                (coltype=='field') ? m.fragment({},[
                    m(selectee, {width:150, onchange:paysetval('expr'), id:col.name+'-column-expr'},
                        AGGR_SQL.filter(i => i.value !== '').map(function(i){ return m('option',{value:i.value,selected:(col.expr==i.value)},i.label); })
                    ),
                    (col.expr!='')
                    ? m(selectee, {width:150, onchange:paysetval('filter')},
                        MD.getFilterList(vnode.attrs.table).map(function(i){return m('option',{value:i.id,selected:(col.filter==i.id)},i.parent+i.name)})
                    )
                    : m('span[style=display:inline-block;width:186px;]',' '),
                ]) : null,

                (['sql','expr'].indexOf(coltype)>=0) ? m(inputText, {
                    value: col.expr,
                    width:346,
                    placeholder: lang['expression'],
                    onchange:paysetval('expr'),
                }) : null,
            ]) : m('span[style=display:inline-block;width:372px;]',' '),

            m('span[style=display:inline-block;color:gray;font-family:monospace]',{title:col.name},col.name),
          ]);
        }
      }
    }

    function lineRowWizKanban() { return { view: function(vnode) { // blkid, col, table
        var col = vnode.attrs.col;
        var coltype = col.field.split('|',1)[0], colempty = col.field=='field|';
        function paysetval(name) { return {
                action: BLOCK_WIZ_LINE_SET_VALUE,
                payload: { blkid: vnode.attrs.blkid, colid: vnode.attrs.col.id, name:name },
        } }
        return m('div[style=margin-bottom:4px]',{item_id:vnode.attrs.col.id}, [
            m('img[src=images/draggable.png].draghandle'),
            m('img.alpiction[src=images/b_drop.png]',{
                onclick: function(){raise(BLOCK_WIZ_COLUMN_DELETE,{blkid:vnode.attrs.blkid,colid:vnode.attrs.col.id})},
            }),
            m(inputText, {
                value: col.title!='' ? col.title : null,
                width:150,
                placeholder: lang['Column_title'],
                onchange:paysetval('title'),
            }),
            m(selectee,{width:150,onchange:paysetval('field')},[
                m('option',{value:'field|',selected:(col.field=='field|')},''),
                m('optgroup',{label:lang['field_calcs']},[
                    m('option',{value:'expr|',selected:(col.field=='expr|')},lang['calc_on_report_line']),
                ]),
                m('optgroup',{label:lang['fields_of_table']},[
                    MD.getFieldAndLinkList(vnode.attrs.table).map(function(i){
                        if(i.id !== vnode.attrs.axis.field){
                            return m('option',{value:i.id,selected:(col.field==i.id)},i.name)
                        }
                    })
                ]),
            ]),
            (!colempty) ? m.fragment({},[
                ((['sql','expr'].indexOf(coltype)<0) ? m('span[style=display:inline-block;width:372px;]',' ') : null),
                (['sql','expr'].indexOf(coltype)>=0) ? m(inputText, {
                    value: col.expr,
                    width:346,
                    placeholder: lang['expression'],
                    onchange:paysetval('expr'),
                    //onfocus: function(){needNames=true; m.redraw(); },
                    //onblur: function(){needNames=false; m.redraw(); },
                }) : null,
            ]) : m('span[style=display:inline-block;width:372px;]',' '),
            m('span[style=display:inline-block;color:gray;font-family:monospace]',{title:col.name},col.name),
    ]) } } }

    function lineRowWizChartSettings() { return { view: function(vnode) { // blkid, col, table
        var col = vnode.attrs.col;
        var coltype = col.field.split('|',1)[0], colempty =  col.field=='field|';
        function paysetval(name) { return {
                action: BLOCK_WIZ_LINE_SET_VALUE,
                payload: { blkid: vnode.attrs.blkid, colid: vnode.attrs.col.id, name:name },
        } }
        return m('div[class=line-rows-settings]', [
            m.fragment({},[
                m('span[style=display:inline-block;width:26px;color:gray;font-family:monospace]',{title:col.name},col.name),
            ]),
            m(inputText, {
                value: col.title!='' ? col.title : null,
                width:150,
                disabled: 'disabled',
                placeholder: lang['Column_title'],
                onchange:paysetval('title'),
            }),
            (!colempty) ? m.fragment({},[
                m(selectee,{width:75,onchange:paysetval('format')},
                    FORMATS.map(function(i){return m('option',{value:i.value,selected:(col.format==i.value)},i.label)})
                ),
                m(selectee,{width:75,onchange:paysetval('hidden')},
                    COLUMN_HIDDEN.map(function(i){return m('option',{value:i.value,selected:(col.hidden==i.value)},i.label)})
                ),
            ]) : null,
    ]) } } }

    function axisRowWizChartSettings() { return { view: function(vnode) { // blkid, col, table
        var col = vnode.attrs.col;
        var colempty = col.field=='field|';
        let formats_data = vnode.attrs.table == '' || col.field == 'field|'
            ? []
            : ((
                MD.getFieldInfo(vnode.attrs.table, col.field.split('|')[1]).type == 2 ||
                MD.getFieldInfo(vnode.attrs.table, col.field.split('|')[1]).type == 12
                )
                    ? [ { value: '', label: '' } ]
                    : FORMATS
            );
        function paysetval(name) { return {
                action: BLOCK_WIZ_AXIS_SET_VALUE,
                payload: { blkid: vnode.attrs.blkid, colid: vnode.attrs.col.id, name:name },
        } }
        return m('div[class=axis-row-settings]', [
            m.fragment({},[
                m('span[style=display:inline-block;width:26px;color:gray;font-family:monospace]',{},''),
            ]),
            m(inputText, {
                value: col.title!='' ? col.title : null,
                width:150,
                disabled: 'disabled',
                placeholder: lang['Column_title'],
                onchange:paysetval('title'),
            }),
            (!colempty) ? m.fragment({},[
                m(selectee,{width:75,onchange:paysetval('format')},
                    formats_data.map(function(i){return m('option',{value:i.value,selected:(col.format==i.value)},i.label)})
                ),
                m(selectee,{width:75,onchange:paysetval('sort')},
                    COLUMN_SORTBY.map(function(i){return m('option',{value:i.value,selected:(col.sort==i.value)},i.label)})
                ),
            ]) : null,
    ]) } } }

    function columnRowWizIndicator() { return { view: function(vnode) { // blkid, col, table
        var col = vnode.attrs.col;
        var coltype = col.field.split('|',1)[0], colempty =  col.field=='field|';
        function paysetval(name) { return {
                action: BLOCK_WIZ_COLUMN_SET_VALUE,
                payload: { blkid: vnode.attrs.blkid, colid: vnode.attrs.col.id, name:name },
        } }
        return m('div[style=margin-bottom:4px]', [
            m(selectee,{width:137,onchange:paysetval('field')},[
                m('option',{value:'field|',selected:(col.field=='field|')},''),
                m('optgroup',{label:lang['fields_of_table']},[
                    MD.getFieldAndLinkList(vnode.attrs.table).map(function(i){
                        return m('option',{value:i.id,selected:(col.field==i.id)},i.name)
                    })
                ]),
            ]),
            (!colempty) ? m.fragment({},[
                (['field'].indexOf(coltype)>=0) ? m(selectee, {width:77, onchange:paysetval('expr')},
                    AGGR_SQL.map(function(i){return m('option',{value:i.value,selected:(col.expr==i.value)},i.label)})
                ) : null,
                (['sql','expr'].indexOf(coltype)>=0) ? m(inputText, {
                    value: col.expr,
                    width:130,
                    placeholder: lang['expression'],
                    onchange:paysetval('expr'),
                }) : null,
                (['field'].indexOf(coltype)>=0) ? m(selectee,{width:77,onchange:paysetval('format')},
                    FORMATS.map(function(i){return m('option',{value:i.value,selected:(col.format==i.value)},i.label)})
                ) : null,
                (false && coltype == 'field' && col.expr!='')
                    ? m(selectee, {width:150, onchange:paysetval('filter')},
                        MD.getFilterList(vnode.attrs.table).map(function(i){return m('option',{value:i.id,selected:(col.filter==i.id)},i.parent+i.name)})
                    )
                    : m('span[style=display:inline-block;width:132px;]',' '),
            ]) : null,
    ]) } } }

    function singleRow(){
        return {
            view: function(vnode) {
                const { TABLE_KEY, FIELD_KEY, EXPR_KEY, FORMAT_KEY, FILTER_KEY } = vnode.attrs.keys;
                let col = vnode.attrs.col;
                let coltype = col[FIELD_KEY].split('|',1)[0],
                    colempty = col[FIELD_KEY]=='field|' || col[FIELD_KEY]=='';
                function paysetval(action, name) {
                    return {
                        action: action,
                        payload: {
                            blkid: vnode.attrs.blkid,
                            prop_name: name
                        },
                    }
                }

                return m('div[style=margin-bottom:4px]', [
                    m(selectee,{width:200,onchange:paysetval(vnode.attrs.action, TABLE_KEY)},
                        MD.getTableList().map(function(i){return m('option',{value:i.id,selected:(col[TABLE_KEY]==i.id)},i.name)})
                    ),
                    col[TABLE_KEY] != ''
                        ? m(selectee,{width:137,onchange:paysetval(vnode.attrs.action, FIELD_KEY)},[
                            m('option',{value:'field|',selected:(col[FIELD_KEY]=='field|')},''),
                            m('optgroup',{label:lang['fields_of_table']},[
                                MD.getFieldAndLinkList(col[TABLE_KEY]).map(function(i){
                                    return m('option',{value:i.id,selected:(col[FIELD_KEY]==i.id)},i.name)
                                })
                            ]),
                        ])
                        : null,
                    (!colempty) ? m.fragment({},[
                        (['field'].indexOf(coltype)>=0)
                            ? m(selectee, {width:77, onchange:paysetval(vnode.attrs.action, EXPR_KEY)},
                                AGGR_SQL.map(function(i){return m('option',{value:i.value,selected:(col[EXPR_KEY]==i.value)},i.label)})
                            )
                            : null,
                        (['sql','expr'].indexOf(coltype)>=0)
                            ? m(inputText, {
                                value: col.expr,
                                width:130,
                                placeholder: lang['expression'],
                                onchange:paysetval(vnode.attrs.action,EXPR_KEY),
                            })
                            : null,
                        (true)
                            ? m(selectee,{width:77,onchange:paysetval(vnode.attrs.action, FORMAT_KEY)},
                                FORMATS.map(i => m('option',{value:i.value,selected:(col[FORMAT_KEY]==i.value)},i.label))
                            )
                            : null,
                        (coltype == 'field' && col[EXPR_KEY]!='')
                            ? m(selectee, {width:150, onchange:paysetval(vnode.attrs.action, FILTER_KEY)},
                                MD.getFilterList(col[TABLE_KEY]).map(function(i){return m('option',{value:i.id,selected:(col[FILTER_KEY]==i.id)},i.parent+i.name)})
                            )
                            : m('span[style=display:inline-block;width:132px;]',' '),
                    ]) : null,
                ]);
            }
        }
    }

    function PaperInline(elem,yaml,prnt) {
        var supra = prnt, id = genid();
        var initval = yaml || 'simple text';
        var inline_content = initval;
        var tag = elem || 'div';
        function getPaper() { return inline_content; }
        return {
            id: function(){ return id; },
            copyObject: function(){ return PaperInline(elem,getPaper(),prnt); },
            canBeDeleted: function() { return true; },
            getPaper: function() { return getPaper() },
            getView: function() {
                return m('div.yamlview__block#'+id, [
                    m('div.yamlview__block_inner[style=position:relative]', [
                        m(PaperToolbar, { blockid:id, blocktype:'inline', tools: [
                            { name:lang['lk_change'], call:function(){
                                var entered = prompt(lang['Enter_value'],inline_content);
                                inline_content = entered || inline_content;
                            }},
                            { name:lang['delete'], call:function(){raise(DELETE_LAYOUT_ITEM,{parent_id:supra.id,item_id:id})} },
                        ]}),
                        m(tag, inline_content),
                    ])
                ]);
            },
            viewAsListItem: function() {
                return m(listItem,{
                    caption: lang['Text_block'],
                    item_id: id,
                    parent_id: supra.id,
                    key: id,
                })
            },
            viewAsDetails: function() {
                return m(detailsBlock,{title:lang['Text_block']},m(interfaceRow,{label:'YAML',help:'rb_yaml'},m('pre',yamlify(getPaper()))))
            },
        }
    }

    function PaperUnknown(yaml,prnt) {
        var supra = prnt, id = genid();
        var unknown_content = yaml;
        function getPaper() { return unknown_content; }
        return {
            id: function(){ return id; },
            copyObject: function(){ return PaperUnknown(getPaper(),prnt); },
            canBeDeleted: function() { return true; },
            getPaper: function() { return getPaper() },
            getView: function() {
                return m('div.yamlview__block#'+id,[
                    m('div.yamlview__block_inner[style=position:relative]',[
                        m(PaperToolbar, { blockid:id, blocktype:'unknown', tools: [
                            { name:lang['delete'], call:function(){raise(DELETE_LAYOUT_ITEM,{parent_id:supra.id,item_id:id})} },
                        ]}),
                        //m('span[style=color:red;border:1px solid red;padding:4px;]','unknown block type'),
                        m('div[style=width:160px;overflow:auto]', m('pre', YAML.dump(unknown_content, 42, 2))),
                        //m('div[style=flex:1;min-width:0]', m('pre[style=overflow:auto;max-width:100%]', YAML.dump(unknown_content, 42, 2))),
                    ])
                ]);
            },
            viewAsListItem: function() {
                return m(listItem,{
                    caption: lang['Unknown_block'],
                    item_id: id,
                    parent_id: supra.id,
                    key: id,
                })
            },
            viewAsDetails: function() {
                return m(detailsBlock,{title:lang['Unknown_block']},m(interfaceRow,{label:'YAML',help:'rb_yaml'},m('pre',yamlify(getPaper()))))
            },
        }
    }

    function PaperBlock(yaml,prnt) {
        var supra = prnt, id = genid();
        var initval = yaml || {type:'block',width:'100%',order:0,layout:[]};
        var type = 'block';
        var width = initval.width || '100%';
        var order = initval.order || 0;
        var layout = (initval.layout instanceof Array) ? initval.layout.map(PaperLayoutItem,{id:id}) : [];
        var widthes = ['20%','30%','33%','34%','40%','50%','60%','66%','70%','80%','100%'];
        function blockStyling() {
            var props = '';
            var w = parseInt(width);
            if (w>0 && w<=100) {
                props += ' flex:0 0 calc(' + w + '% - 10px);';
            }
            var o = parseInt(order);
            if (!isNaN(o)) {
                props += 'order:' + o + ';';
            }
            return props+'';
        }
        function getPaper() {
            return {
                type: type,
                width: width,
                order: order,
                layout: layout.map(function(item){return item.getPaper()}),
            }
        }
        var dispatch = function (action,payload) {
            switch (action) {
                case ADD_LAYOUT_ITEM:
                    if (payload.parent_id==id) layout.push(PaperLayoutItem({type:payload.item_type},{id:id}));
                    break;
                case DELETE_LAYOUT_ITEM:
                    if (payload.parent_id==id) layout = layout.filter(function(item){
                        return (item.id()!=payload.item_id) || !item.canBeDeleted()
                    });
                    if (payload.item_id==id && layout.length==0) Dispatcher.unregister(dispatch);
                    break;
                case COPY_LAYOUT_ITEM:
                    if (payload.parent_id==id) {
                        for(let key in layout){
                            if(layout[key].id()==payload.item_id){
                                layout.push(layout[key].copyObject());
                            }
                        }
                    }
                    if (payload.item_id==id && layout.length==0) Dispatcher.unregister(dispatch);
                    break;
                default:
                    break;
            }
        }
        Dispatcher.register(dispatch);

        return {
            id: function(){ return id; },
            copyObject: function(){ return PaperBlock(getPaper(),prnt); },
            canBeDeleted: function() { return layout.length==0; },
            getPaper: function() { return getPaper() },
            getView: function() {
                return m('div.yamlview__block#'+id+'[style='+blockStyling()+']', [
                    m('div.yamlview__block_inner[style=position:relative]',[
                        m(PaperToolbar, { blockid:id, blocktype:'block', tools: [
                            { name:width, call:null, subs: widthes.map(function(item){return {name:item,call:function(){width=item; return false;}}})},
                            { name:lang['lk_add'],call:null, subs: [
                                { name:lang['text'],call:function(){raise(ADD_LAYOUT_ITEM,{parent_id:id,item_type:'inline'})}},
                                { name:lang['block'],call:function(){raise(ADD_LAYOUT_ITEM,{parent_id:id,item_type:'block'})}},
                            ]},
                            { name:lang['delete'],call:function(){raise(DELETE_LAYOUT_ITEM,{parent_id:supra.id,item_id:id})}},
                        ]}),
                        m('div.yamlview__block_layout', layout.map(function(item){return item.getView()}))
                    ])
                ]);
            },
            viewAsListItem: function() {
                return m(listItem,{
                    caption: lang['Composite_block'],
                    item_id: id,
                    parent_id: supra.id,
                    key: id,
                })
            },
            viewAsDetails: function() {
                return m(detailsBlock,{title:lang['Composite_block']},m(interfaceRow,{label:'YAML',help:'rb_yaml'},m('pre',yamlify(getPaper()))))
            },
        }
    }

    function wizNextName(pfx, arr, val) { // [{name}] generate next name like 'S1'
      if(val) {
        let nameNum = 1;
        val.columns.forEach(column => {
          column.name = pfx + nameNum;
          nameNum++;
        });
        val.tables.forEach(table => {
          table.columns.forEach(column => {
            column.name = pfx + nameNum;
            nameNum++;
          });
        });

        return '' + pfx + (nameNum);
      }
      var maxid = arr.reduce(function(max,item){
          var nameid = parseInt(item.name.substr(1),10);
          return nameid>max ? nameid : max;
      },0);
      return ''+pfx+(maxid+1);
  }

    function wizNewColumn(newname) {
        return {
            id:genid(),
            field:'field|',
            expr: '',
            filter: '',
            name: newname,
            format: '',
            hidden: 'no',
            group: 'no',
            sort: 'no',
            title: '',
            output: 'value',
            total: '',
        }
    }

    function wizNewLine(newname) {
        return {
            id:genid(),
            field:'field|',
            expr: '',
            filter: '',
            name: newname,
            format: '',
            hidden: 'no',
            title: '',
        }
    }

    function wizNewAxis(newname) {
        return {
            id:genid(),
            field:'field|',
            expr: '',
            filter: '',
            name: newname,
            format: '',
            group: 'yes',
            sort: 'asc',
            title: '',
        }
    }
    function wizColumnAdd(table_id, columns, val) {
      columns.push(wizNewColumn(wizNextName('S', columns, val)));
    }

    function wizLineAdd(table_id, columns, axis = []) {
        columns.push(wizNewLine(wizNextName('S', [...columns, ...axis])));
    }

    function wizAxisAdd(table_id,axis) {
        axis.push(wizNewAxis(wizNextName('S',axis)));
    }
    /**
     * Отрефакторенная реализация wizColumnSet
     * возвращает массив новых строк вместо мутации
     * @param {Object} object
     * @param {String} object.tableId - id таблицы
     * @param {Array} object.columns - массив старых колонок
     * @param {Object} object.payload - пейлоад экшена
     * @param {String} object.payload.colid - id изменяемой колонки
     * @param {String} object.payload.name - имя параметра изменяемой колонки
     * @param {String} object.payload.value - новое значение
     * @param {String} template_type - тип представления
     * @returns 
     */
    function wizNewColumnsReturn({
        tableId,
        columns,
        payload: {
            colid: columnId,
            name,
            value,
            is_main_grouping,
            is_additional_grouping
        },
        template_type
    }) {
        const is_multitable = template_type === "block_wiz_multitable";

        if(name === 'group') {
            const newColumns = columns.map(column => {
                if(columnId !== column.id) 
                    return {
                        ...column,
                        group: value
                    };
                return {
                    ...column,
                    group: value === 'yes' ? 'no' : column.group
                }
            })
            return newColumns;
        }
        if(name === 'sort') {
            const newColumns = columns.map(column => {
                if(columnId !== column.id) 
                    return {
                        ...column,
                        sort: value,
                    };
                return {
                    ...column,
                    sort: 'no',
                }
            })
            return newColumns;
        }

        const newColumns = columns.map(column => {
            const { 
                id, 
                field: oldValue, 
                title: oldTitle 
            } = column;
            
            if(columnId !== id) return column;
            const [ oldType, oldValueId ] = oldValue.split('|');
            const [ type, valueId ] = value.split('|');

            const fieldTitle = MD.getFieldList(tableId)
                .find(field => field.id === valueId)?.name;
            const oldFieldTitle = MD.getFieldList(tableId)
                .find(field => field.id === oldValueId)?.name;

            const isValueEmpty = value === 'field|';
            const isTypeField = type === 'field';
            const isOldValueEmpty = oldValue=='field|';
            const isOldTypeField = oldType === 'field';
            const isOldTitleEmpty = !oldTitle;
            const isOldTitleEqualOldFieldTitle = oldFieldTitle === oldTitle;
            const isTypeChanged = type !== oldType;
            const isValueChanged = value !== oldValue;
            
            if(name === 'field') {
                const newTitle = isOldTitleEmpty || isOldTitleEqualOldFieldTitle 
                    ? fieldTitle 
                    : column.title;
                    
                if(isValueEmpty) 
                    return wizNewColumn(wizNextName('S',columns));

                if(isTypeChanged) 
                    return { 
                        ...column,
                        title: newTitle,
                        field: value,
                        expr: '',
                        filter: '',
                        format: '',
                    };

                const fieldId = value.substr(6);
                if(
                    isValueChanged && 
                    isOldValueEmpty && 
                    isTypeField && (
                        MD.fi( tableId, fieldId, 'type') == 1 || 
                        (
                            is_multitable && 
                            !is_main_grouping && 
                            !is_additional_grouping
                        )
                    )
                )
                    return {
                        ...column,
                        title: newTitle,
                        field: value,
                        expr: 'SUM',
                        total: 'SUM',
                        format: 'f',
                    };
                
                return {
                    ...column,
                    title: newTitle,
                    field: value,
                };
            }
            if(name === 'title') {
                if(!isOldValueEmpty) 
                    return { ...column, title: value };

                const invalidTypes = ['5', '7', '11'];
                const isValidType = (type) => !invalidTypes.includes(type);

                const foundField = MD.getFieldList(tableId).find(field => 
                    field.name.toLowerCase() === value.toLowerCase() && 
                    isValidType(field.type)
                );

                if(!foundField) 
                    return { ...column, title: value };

                const { id: foundFieldId } = foundField;
                if (
                    MD.fi(tableId, foundFieldId, 'type') == 1 || 
                    (   
                        is_multitable && 
                        !is_main_grouping && 
                        !is_additional_grouping
                    )
                ) {
                    return {
                        ...column,
                        title: value,
                        field: `field|${foundFieldId}`,
                        expr: 'SUM',
                        total: 'SUM',
                        format: 'f',
                    };
                }
                return {
                    ...column,
                    title: value,
                    field: `field|${foundFieldId}`,
                };
            }
            if(name === 'expr') {
                if(!isOldTypeField) 
                    return { ...column, [name]: value, };
                if(value === 'COUNT') 
                    return {
                        ...column,
                        [name]: value,
                        total: value === 'SUM',
                        format: 'd',
                        group: 'no',
                    };
                return {
                    ...column,
                    [name]: value,
                    total: value,
                    format: 'f',
                    group: !value ? column.group : 'no',
                };
            }
            return {
                ...column,
                [name]: value,
            }
            
        });
        return newColumns;
    }
    /**
     * Мутирует массив строк в обновленный
     * @deprecated
     * Пожалуйста используйте wizNewColumnsReturn и явно изменяйте старый массив данных на новый
     * @param {String} table_id - id таблицы
     * @param {Array} columns  массив старых колонок
     * @param {String} item_id - id изменяемой колонки
     * @param {String} param - имя параметра изменяемой колонк
     * @param {String} value - новое значение
     * @param {String} template_type - тип представления
     */
    function wizColumnSet(table_id,columns,item_id,param,value,template_type) {
      const is_multitable = template_type === "block_wiz_multitable"
        columns.forEach(function(item,index,arr){
            if (item.id==item_id) { switch (param) {
                case 'field':

                    var oldvalue = arr[index]['field'];
                    const { title: oldtitle } = item;
                    const [ oldtype, oldvalue_id ] = oldvalue.split('|');
                    const [ newtype, value_id ] = value.split('|');

                    
            
                    const field_title = MD.getFieldList(table_id)
                        .find(field => field.id === value_id)?.name;
                    const old_field_title = MD.getFieldList(table_id)
                        .find(field => field.id === oldvalue_id)?.name;

                    const is_old_title_empty = !oldtitle;
                    const is_old_title_equal_old_field_title = old_field_title === oldtitle;

                    const new_title = is_old_title_empty || is_old_title_equal_old_field_title 
                        ? field_title 
                        : item.title;
                    
                    if (value=='field|') {
                        arr[index] = wizNewColumn(wizNextName('S',columns));
                    };
                    if (oldtype!=newtype) {
                        arr[index]['expr'] = '';
                        arr[index]['filter'] = '';
                        arr[index]['format'] = '';
                    };
                    if (oldvalue=='field|' && newtype=='field' && value!=oldvalue) {
                        var field_id = value.substr(6);
                        if (MD.fi(table_id,field_id,'type')==1 || (is_multitable && columns[0].name !== 'S1')) {
                            arr[index]['expr'] = 'SUM';
                            arr[index]['total'] = 'SUM';
                            arr[index]['format'] = 'f';
                        }
                    }
                    if (oldvalue=='field|' && newtype=='link' && value!=oldvalue) {
                        var field_id = value.split('|',2)[1];
                    }
                    if (oldvalue=='field|' && newtype=='user' && value!=oldvalue) {
                        var field_id = value.split('|',2)[1];
                    }
                    arr[index]['field'] = value;
                    arr[index]['title'] = new_title;
                    break;
                case 'title':
                    if (arr[index]['field']=='field|') {
                        if (found_field = MD.getFieldList(table_id).find(function(item,index,arr){
                                return ((item.name.toLowerCase()==value.toLowerCase()) && (-1 == ['5','7','11'].indexOf(item.type)));
                                })
                            ) {
                            arr[index]['field'] = 'field|'+found_field.id;
                            if (MD.fi(table_id,found_field.id,'type')==1 ||  (is_multitable && columns[0].name !== 'S1')) {
                              arr[index]['expr'] = 'SUM';
                              arr[index]['total'] = 'SUM';
                              arr[index]['format'] = 'f';
                            }
                        };
                    };
                    arr[index]['title'] = value;
                    break;
                case 'group':
                    if(value == 'yes'){
                        columns.forEach(function(item,index,arr){arr[index]['group']='no';});
                    }
                    arr[index]['group'] = value;
                    break;
                case 'sort':
                    columns.forEach(function(item,index,arr){arr[index]['sort']='no';});
                    arr[index]['sort'] = value;
                    break;
                case 'expr':
                    var valtype = arr[index]['field'].split('|',1)[0];
                    if (valtype=='field') {
                        switch (value) {
                            case '':
                                arr[index]['total'] = '';
                                arr[index]['format'] = '';
                                break;
                            case 'AVG':
                                arr[index]['total'] = 'AVG';
                                arr[index]['format'] = 'f';
                                arr[index]['group'] = 'no';
                                break;
                            case 'MIN':
                                arr[index]['total'] = 'MIN';
                                arr[index]['format'] = 'f';
                                arr[index]['group'] = 'no';
                                break;
                            case 'MAX':
                                arr[index]['total'] = 'MAX';
                                arr[index]['format'] = 'f';
                                arr[index]['group'] = 'no';
                                break;
                            case 'SUM':
                                arr[index]['total'] = 'SUM';
                                arr[index]['format'] = 'f';
                                arr[index]['group'] = 'no';
                                break;
                            case 'COUNT':
                                arr[index]['total'] = 'SUM';
                                arr[index]['format'] = 'd';
                                arr[index]['group'] = 'no';
                                break;
                            case 'SUM':
                                arr[index]['total'] = 'SUM';
                                arr[index]['format'] = 'f';
                                arr[index]['group'] = 'no';
                                break;
                            default:
                                break;
                        }
                    }
                    arr[index][param] = value;
                    break;
                default:
                    arr[index][param] = value;
                    break;
            } }
        });
    }

    function wizKanbanColumnSet(table_id,columns,item_id,param,value) {
        columns.forEach(function(item,index,arr){
            if (item.id==item_id) { switch (param) {
                case 'field':
                    var oldvalue = arr[index]['field'], oldtype = oldvalue.split('|',1)[0], newtype = value.split('|',1)[0];
                    if (value=='field|') {
                        arr[index] = wizNewColumn(wizNextName('S',columns));
                    };
                    if (oldtype!=newtype) {
                        arr[index]['expr'] = '';
                        arr[index]['filter'] = '';
                        arr[index]['format'] = '';
                    };
                    if (oldvalue=='field|' && newtype=='field' && value!=oldvalue) {
                        var field_id = value.substr(6);
                    }
                    if (oldvalue=='field|' && newtype=='link' && value!=oldvalue) {
                        var field_id = value.split('|',2)[1];
                    }
                    if (oldvalue=='field|' && newtype=='user' && value!=oldvalue) {
                        var field_id = value.split('|',2)[1];
                    }
                    arr[index]['field'] = value;
                    break;
                case 'title':
                    if (arr[index]['field']=='field|') {
                        if (found_field = MD.getFieldList(table_id).find(function(item,index,arr){
                                return ((item.name.toLowerCase()==value.toLowerCase()) && (-1 == ['5','7','11'].indexOf(item.type)));
                                })
                            ) {
                            arr[index]['field'] = 'field|'+found_field.id;
                        };
                    };
                    arr[index]['title'] = value;
                    break;
                case 'group':
                    if(value == 'yes'){
                        columns.forEach(function(item,index,arr){arr[index]['group']='no';});
                    }
                    arr[index]['group'] = value;
                    break;
                case 'sort':
                    columns.forEach(function(item,index,arr){arr[index]['sort']='no';});
                    arr[index]['sort'] = value;
                    break;
                case 'expr':
                    var valtype = arr[index]['field'].split('|',1)[0];
                    if (valtype=='field') {
                        switch (value) {
                            case '':
                                arr[index]['total'] = '';
                                arr[index]['format'] = '';
                                break;
                            case 'AVG':
                                arr[index]['total'] = 'AVG';
                                arr[index]['format'] = 'f';
                                arr[index]['group'] = 'no';
                                break;
                            case 'MIN':
                                arr[index]['total'] = 'MIN';
                                arr[index]['format'] = 'f';
                                arr[index]['group'] = 'no';
                                break;
                            case 'MAX':
                                arr[index]['total'] = 'MAX';
                                arr[index]['format'] = 'f';
                                arr[index]['group'] = 'no';
                                break;
                            case 'SUM':
                                arr[index]['total'] = 'SUM';
                                arr[index]['format'] = 'f';
                                arr[index]['group'] = 'no';
                                break;
                            case 'COUNT':
                                arr[index]['total'] = 'SUM';
                                arr[index]['format'] = 'd';
                                arr[index]['group'] = 'no';
                                break;
                            case 'SUM':
                                arr[index]['total'] = 'SUM';
                                arr[index]['format'] = 'f';
                                arr[index]['group'] = 'no';
                                break;
                            default:
                                break;
                        }
                    }
                    arr[index][param] = value;
                    break;
                default:
                    arr[index][param] = value;
                    break;
            } }
        });
    }

    function wizColumnsInitial(table_id,columns) {
        return columns instanceof Array && table_id != '' ? columns.map(function(i){
            i.id=genid();
            var itype = i.field.split('|',1)[0];
            if (itype=='field') {
                var fn = MD.getFieldId(table_id,i.field.substr(6));
                if (fn) {
                    switch (MD.fi(table_id,fn,'type')) {
                        case '7': case '11':
                            i.field = 'user|'+fn+'|fio';
                            break;
                        case '5':
                            var fval = MD.fi(table_id,fn,'value').split('|');
                            i.field = 'link|'+fn+'|f'+fval[1];
                        default:
                            i.field = 'field|'+fn;
                            break;
                        };
                };
            }
            return i;
        }) : [];
    }

    function colorPicker() {
        return {
            oncreate: function(vnode) { // blkid, row
                let cs = colorpickerSetings;
                cs.change = function(color) {
                    $(this).val(color.toRgbString());
                    $(this).trigger('change');
                };
                $(`#lighter_${vnode.attrs.item.name}`).spectrum(cs);
            },
            onbeforeupdate: function(vnode) {
                $(`#lighter_${vnode.attrs.item.name}`).spectrum('destroy');
            },
            onupdate: function(vnode) { // blkid, row
                let cs = colorpickerSetings;
                cs.change = function(color) {
                    $(this).val(color.toRgbString());
                    $(this).trigger('change');
                };
                $(`#lighter_${vnode.attrs.item.name}`).spectrum(cs);
            },
            onremove: function(vnode) {
                $(`#lighter_${vnode.attrs.item.name}`).spectrum('destroy');
            },
            view: function(vnode) { // blkid, row
                return m('input[style=display:none;]',{id:`lighter_${vnode.attrs.item.name}`,width:137, onchange: function() {
                    let onchange_val = vnode.attrs.onchange.val;
                    onchange_val.value = this.value;

                    raise(vnode.attrs.onchange.name,onchange_val);
                }, value: vnode.attrs.item.color}, []);
            }
        }
    }

    function wizColorFormattingInitial() {
        return {
            view: function(vnode) { // blkid, row
                let row = vnode.attrs.row;
                function paysetval(prop_name) { return {
                        action: COLOR_FORMATTING_SET_VALUE,
                        payload: { blkid: vnode.attrs.blkid, name: row.name, prop_name },
                }}
                return m('div[style=margin-bottom:4px;]', [
                    m('img.alpiction[src=images/b_drop.png]',{
                        onclick: function(){raise(COLOR_FORMATTING_DELETE,{blkid:vnode.attrs.blkid,name:row.name})},
                    }),
                    m(inputText, {placeholder:lang['Name2'],value:row.label,onchange: paysetval('label')}),
                    m(inputText, {placeholder:lang['revision_of'],value:row.low,onchange: paysetval('low')}),
                    m(inputText, {placeholder:lang['until'],value:row.high,onchange: paysetval('high')}),
                    m(selectee, {
                        class: 'dont_use_chosen',
                        onchange: function() {
                            console.log(this.value)
                            if(this.value == 'without_bg'){
                                raise(COLOR_FORMATTING_SET_VALUE, {
                                    blkid: vnode.attrs.blkid,
                                    name: row.name,
                                    prop_name: 'color',
                                    value: 'rgb(0, 0, 0)',
                                });
                                raise(COLOR_FORMATTING_SET_VALUE, {
                                    blkid: vnode.attrs.blkid,
                                    name: row.name,
                                    prop_name: 'bg_color',
                                    value: '',
                                });
                            }
                            else {
                                raise(COLOR_FORMATTING_SET_VALUE, {
                                    blkid: vnode.attrs.blkid,
                                    name: row.name,
                                    prop_name: 'color',
                                    value: '#fff',
                                });
                                raise(COLOR_FORMATTING_SET_VALUE, {
                                    blkid: vnode.attrs.blkid,
                                    name: row.name,
                                    prop_name: 'bg_color',
                                    value: '#969696',
                                });
                            }

                        }
                    }, [
                        { value: 'without_bg', label: lang['Without_background'] },
                        { value: 'with_bg',    label: lang['With_background'] },
                    ].map(item => m('option', {
                        value: item.value,
                        selected: (
                            row.bg_color && row.bg_color.length != 0 && item.value == 'with_bg' ||
                            (!row.bg_color || row.bg_color?.length == 0) && item.value == 'without_bg'
                        ),
                    }, item.label))),
                    (row.bg_color && row.bg_color.length != 0)
                        ? m(selectee, {
                            class: 'dont_use_chosen',
                            onchange: function(){
                                raise(COLOR_FORMATTING_SET_VALUE, {
                                    blkid: vnode.attrs.blkid,
                                    name: row.name,
                                    prop_name: 'color',
                                    value: COLORS.find(item => item.value == this.value).subvalue,
                                });
                                raise(COLOR_FORMATTING_SET_VALUE, {
                                    blkid: vnode.attrs.blkid,
                                    name: row.name,
                                    prop_name: 'bg_color',
                                    value: this.value,
                                });
                            }
                        }, COLORS.map(item => m('option', {
                            value: item.value,
                            subvalue: item.subvalue,
                            selected: item.value == row.bg_color && item.subvalue == row.color,
                        }, item.label)))
                        : m(colorPicker,{blkid:vnode.attrs.blkid,item:row,onchange:{
                            name: COLOR_FORMATTING_SET_VALUE,
                            val:{
                                blkid: vnode.attrs.blkid,
                                name: row.name,
                                prop_name: 'color',
                            }
                        }}),
                    m('span[style=display:inline-block;width:5px;]',' '),
                    m('span[style=display:inline-block;color:gray;font-family:monospace]',{title:row.name},row.name),
                ])
            }
        }
    }

    
    
    const InputText = Element(inputText);
    const Checkbox = Element(inputChecker);
    const StatusCheckboxes = Element(statusCheckSet);
    const ColumnRowWizTable = Element(columnRowWizTable);
    const DragZone = Element(dragZone);
    const SelectOption = Element("option");
    const Gear = Element(gear);
    const LinkButton = Element(aee);

    function PaperBlockWizIndicator(yaml,prnt) {
        var supra = prnt, id = genid();
        var initval = yaml || {type:'block_wiz_indicator',width:'33',order:0,columns:[]};
        initval.alignment = 'AsInTheTable';
        var val = {
            type:   'block_wiz_indicator',
            width:  initval.width && KIND_OF_WIDTH.map(i => i.value).includes(initval.width) ? initval.width : '33',
            block_height: initval.block_height || 'stretch',
            order:  initval.order || 0,
            use_table: MD.getTableId(initval.use_table || ''),
            use_filter: initval.use_filter || '',
            use_status: initval.use_status || 'active',
            caption: initval.caption || '',
            description: initval.description || '',
            paralink: initval.paralink || {},
            use_links: initval.use_links || 'implicit',
            alignment: initval.alignment || 'AsInTheTable',
            image: initval.image || '',
            image_href: initval.image_href || '',
            microchart: initval.microchart || 0,
            change: initval.change || [],
            relative_value: initval.relative_value || {
                type: 'none',
                field: {
                    table: initval?.relative_value?.table || '',
                    field: initval?.relative_value?.field || '',
                    expr: initval?.relative_value?.expr || '',
                    format: initval?.relative_value?.format || '',
                    filter: initval?.relative_value?.filter || '',
                },
                paralink: {},
                fixed_value: 0,
                subsequent_text: '',
            },
            preview_width: '150',
            dynamics_compare_period: initval.dynamics_compare_period || 'fixed',
            hideEmptyValues: initval.hideEmptyValues || 0,
        };
        val.columns = wizColumnsInitial(val.use_table,initval.columns);
        val.lighter = initval.lighter || [];
        var showOptions = false;

        function checkAvailabilityParamType(type) {
            for(let param of dataParams()){
                if(param.type == 'parameter' && param.datatype == type && val.paralink[param.name]){
                    return true;
                }
            }

            return false;
        }

        function blockStyling() {
            var props = '';
            var w = parseInt(val.width);
            if (w>0 && w<=100) {
                props += ' flex:0 0 calc(' + w + '% - 10px);';
            }
            var o = parseInt(val.order);
            if (!isNaN(o)) {
                props += 'order:' + o + ';';
            }
            return props+'';
        }
        /** 
         * @fixme Эта функция мутирует объекты, удаляя в них id,
         * это может вызвать неожиданные баги. Необходимо это исправить
        */
        function getPaper() {
            val.columns = val.columns.map(function(i){delete i.id; return i;});
            var cleanlink = {};
            dataParams().forEach(function(i){ if (val.paralink.hasOwnProperty(i.name)) cleanlink[i.name] = val.paralink[i.name]; });
            val.paralink = cleanlink;
            return val;
        }
        /** 
         * @fixme Эта функция использует getPaper который мутирует 
         * копируемые объекты, удаляя в них id,
         * это может вызвать неожиданные баги. Необходимо это исправить
        */
        function getPaperForCopy() {
            let value = getPaper();
            let data = {};

            for(let key in value){
                data[key] = value[key];
            }

            data.columns = copyObjectData(value.columns);
            data.change = copyObjectData(value.change);
            data.lighter = copyObjectData(value.lighter);
            data.relative_value = copyObjectData(value.relative_value);
            data.relative_value.field = copyObjectData(value.relative_value.field);
            var relativelink = {};
            if(value.relative_value.paralink){
                dataParams().forEach(function(i){ if (value.relative_value.paralink.hasOwnProperty(i.name)) relativelink[i.name] = value.relative_value.paralink[i.name]; });
            }
            data.relative_value.paralink = relativelink;

            var cleanlink = {};
            dataParams().forEach(function(i){ if (value.paralink.hasOwnProperty(i.name)) cleanlink[i.name] = value.paralink[i.name]; });
            data.paralink = cleanlink;

            return data;
        }

        function changeDefinitionRow() {
            return {
                view: function(vnode) {
                    var item = vnode.attrs.item;
                    return m.fragment({}, [
                        interfaceElementsInTable([
                            [
                                m(`span[style=display:inline-block;margin-right:4px;`,{}, lang['Increase'] + ':'),
                                m(colorPicker,{blkid:vnode.attrs.blkid,item:{name:`${item.name}_up`, color: item.up}, onchange: {name: CHANGE_ITEM_SET_VALUE, val: {
                                    blkid: vnode.attrs.blkid,
                                    name: item.name,
                                    prop_name: 'up'
                                }}}),
                            ],
                            [
                                m(`span[style=display:inline-block;margin-right:4px;]`,{}, lang['Drop'] + ':'),
                                m(colorPicker,{blkid:vnode.attrs.blkid,item:{name:`${item.name}_down`, color: item.down}, onchange: {name: CHANGE_ITEM_SET_VALUE, val: {
                                    blkid: vnode.attrs.blkid,
                                    name: item.name,
                                    prop_name: 'down'
                                }}})
                            ]
                        ])
                    ]);
                }
            }
        }

        var dispatch = function (action,payload) {
            switch (action) {
                case ADD_LAYOUT_ITEM:
                    if (payload.parent_id==id) layout.push(PaperLayoutItem({type:payload.item_type},{id:id}));
                    break;
                case DELETE_LAYOUT_ITEM:
                    if (payload.item_id==id) Dispatcher.unregister(dispatch);
                    break;
                case BLOCK_WIZ_SET_TABLE:
                    if (payload.blkid!=id) break;
                    if (val.use_table==payload.value) break;
                    val.use_table = payload.value;
                    val.use_filter = '';
                    val.use_status = 'active';
                    val.columns = [];
                    val.change = [];
                    val.lighter = [];
                    wizColumnAdd(val.use_table,val.columns);
                    break;
                case BLOCK_WIZ_SET_FILTER:
                    if (payload.blkid!=id) break;
                    val.use_filter = payload.value;
                    break;
                case BLOCK_WIZ_SET_CAPTION:
                    if (payload.blkid!=id) break;
                    val.caption = payload.value;
                    break;
                case BLOCK_WIZ_SET_IMAGE:
                    if (payload.blkid!=id) break;
                    val.image = payload.value;
                    val.preview_width = payload.width || '150';
                    break;
                case BLOCK_WIZ_SET_IMAGE_HREF:
                    if (payload.blkid!=id) break;
                    val.image_href = payload.value;
                    break;
                case BLOCK_WIZ_SET_DESCRIPTION:
                    if (payload.blkid!=id) break;
                    val.description = payload.value;
                    break;
                case BLOCK_WIZ_SET_STATUS:
                    if (payload.blkid!=id) break;
                    val.use_status = payload.value || 'active';
                    break;
                case BLOCK_WIZ_SHOW_OPTIONS:
                    if (payload.blkid!=id) break;
                    showOptions = payload.show;
                    break;
                case BLOCK_WIZ_SET_PARALINK:
                    if (payload.blkid!=id) break;
                    if (payload.value=='') {
                        delete val.paralink[payload.param];
                        if(!checkAvailabilityParamType('period')){
                            val.microchart = 0;
                        }
                        raise(CHANGE_CLEAR, { blkid: payload.blkid });
                    }
                    else {
                        val.paralink[payload.param] = payload.value;
                    }
                    break;
                case BLOCK_WIZ_SET_LINKS:
                    if (payload.blkid!=id) break;
                    val.use_links = payload.value || 'implicit';
                    break;
                case BLOCK_WIZ_ALIGNMENT:
                    if (payload.blkid!=id) break;
                    val.alignment = payload.value;
                    break;
                case BLOCK_WIZ_COLUMN_ADD:
                    if (payload.blkid==id) wizColumnAdd(val.use_table,val.columns);
                    break;
                case BLOCK_WIZ_COLUMN_DELETE:
                    if (payload.blkid==id) val.columns = val.columns.filter(function(i){return i.id!=payload.colid;})
                    break;
                case BLOCK_WIZ_COLUMN_SET_VALUE:
                    if (payload.blkid==id) wizColumnSet(val.use_table,val.columns,payload.colid,payload.name,payload.value);
                    break;
                case BLOCK_WIZ_SET_MICROCHART_PERIODS:
                    if (payload.blkid==id) {
                        if(payload.value == 'yes'){
                            val.microchart = 1;
                        }
                        else if(payload.value == 'no'){
                            val.microchart = 0;
                        }
                        else {
                            val.microchart = payload.value;
                        }
                    }
                    break;
                case CHANGE_ITEM_APPEND:
                    if (payload.blkid==id) val.change.push(payload.item);
                    break;
                case CHANGE_CLEAR:
                    if (payload.blkid==id) {
                      val.change = [];
                      val.dynamics_compare_period = '';
                    }
                    break;
                case CHANGE_ITEM_SET_VALUE:
                    if (payload.blkid==id) val.change = val.change.map((item) => {
                        if(item.name == payload.name){
                            item[payload.prop_name] = payload.value;
                            return item;
                        }
                        return item;
                    });
                    break;
                case COLOR_FORMATTING_ADD:
                    if (payload.blkid==id) val.lighter.push({name:wizNextName('C',val.lighter),low:'',high:'',color:'rgb(0, 0, 0)'});
                    break;
                case COLOR_FORMATTING_DELETE:
                    if (payload.blkid==id) val.lighter = val.lighter.filter(function(i){return i.name!=payload.name;});
                    break;
                case COLOR_FORMATTING_SET_VALUE:
                    if (payload.blkid==id) val.lighter = val.lighter.map(function(i){
                        if (i.name==payload.name){
                            i[payload.prop_name] = payload.value;
                            return i;
                        }
                        return i;
                    });
                    break;
                case BLOCK_WIZ_SET_WIDTH:
                    if (payload.blkid==id) val.width = payload.value;
                    break;
                case BLOCK_WIZ_SET_RELATIVE_INDICATOR:
                    if (payload.blkid==id) {
                        val.relative_value[payload.prop_name] = payload.prop_name == 'fixed_value'
                            ? ( isNaN(parseFloat(payload.value))
                                ? ( isNaN(parseFloat(payload.value.replace(/\s/g, '').replace(/\D/g, '')))
                                        ? 0
                                        : parseFloat(payload.value.replace(/\s/g, '').replace(/\D/g, ''))
                                )
                                : parseFloat(payload.value.replace(/\s/g, ''))
                            )
                            : payload.value;
                        if(payload.prop_name == 'type'){
                            val.relative_value.field = {
                                table: '',
                                field: '',
                                expr: '',
                                format: '',
                                filter: '',
                            };
                            val.relative_value.paralink = {};
                            val.relative_value.fixed_value = 0;
                            if(payload.value == 'none'){
                                val.relative_value.subsequent_text = '';
                            }
                        }
                    }
                    break;
                case BLOCK_WIZ_SET_RELATIVE_INDICATOR_FIELD:
                    if (payload.blkid==id) val.relative_value.field[payload.prop_name] = payload.value;
                    break;
                case BLOCK_WIZ_SET_PARALINK_RELATIVE:
                    if (payload.blkid!=id) break;
                    if (payload.value=='') {
                        delete val.relative_value.paralink[payload.param];
                    }
                    else {
                        val.relative_value.paralink[payload.param] = payload.value;
                    }
                    break;
                case BLOCK_WIZ_SET_BLOCK_HEIGHT:
                    if (payload.blkid!=id) break;
                    val.block_height = payload.value; break;

                case BLOCK_WIZ_SET_DYNAMICS_COMPARE_PERIOD:
                    if (payload.blkid != id) break;
                    val.dynamics_compare_period = payload.value;
                    break;
                    
                case 'HideEmptyValues':
                    if (payload.blkid != id) break;
                    val.hideEmptyValues = payload.value;
                    break;
                
                default:
                    break;
            }
        }
        Dispatcher.register(dispatch);

        return {
            id: function(){ return id; },
            copyObject: function(){ return PaperBlockWizIndicator(getPaperForCopy(), prnt); },
            canBeDeleted: function() { return true; },
            getPaper: function() { return getPaper() },
            getView: function() {
                return m('div.yamlview__block#'+id+'[style='+blockStyling()+']', [
                    m('div.yamlview__block_inner[style=position:relative]','BLOCK_TABLE')
                ]);
            },
            viewAsListItem: function() {
                return m(listItem,{
                    caption: buildItemTitle(lang['Indicator'],val.caption,MD.getTableName(val.use_table)),
                    item_id: id,
                    parent_id: supra.id,
                    key: id,
                })
            },
            viewAsDetails: function() {
                var prms = dataParams();
                return m(detailsBlock,{title:buildItemTitle(lang['Indicator'],val.caption,MD.getTableName(val.use_table))},
                    m(interfaceRow,{label:lang['Table2'],help:'rb_Table',key:id+'tab'}, [
                        m(selectee,{width:250,onchange:{action:BLOCK_WIZ_SET_TABLE,payload:{blkid:id}}},
                            MD.getTableList().map(function(i){return m('option',{value:i.id,selected:(val.use_table==i.id)},i.name)})
                        ),
                        val.use_table ? m(gear,{href:'edit_field.php?table='+MD.ti(val.use_table,'id'),title:lang['Table_settings']}) : null,
                    ]),
                    val.use_table ? m(interfaceRow,{label:lang['Title'],help:'rb_Table_title',key:id+'cap'}, [
                        m(inputText,{value:val.caption,width:260,onchange:{action:BLOCK_WIZ_SET_CAPTION,payload:{blkid:id}}},null),
                    ]) : null,
                    val.use_table ? m(interfaceRow,{label:lang['Indicator'],help:'rb_Indicator',key:id+'ind'}, [
                        val.columns.map(function(i){return m(columnRowWizIndicator,{col:i,blkid:id,table:val.use_table})}),
                    ]) : null,
                    val.use_table ? m(interfaceRow,{label:lang['Description'],help:'rb_Description',key:id+'dsc'}, [
                        m(inputText,{value:val.description,width:260,onchange:{action:BLOCK_WIZ_SET_DESCRIPTION,payload:{blkid:id}}},null),
                    ]) : null,
                    val.use_table ? m(interfaceRow,{label:''}, [
                        m(aee,{onclick:{action:BLOCK_WIZ_SHOW_OPTIONS,payload:{blkid:id,show:!showOptions}}},showOptions?lang['Hide']:lang['Additional'] + '...'),
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Filter'],help:'rb_Filter',key:id+'flt'}, [
                        m(selectee,{width:250,onchange:{action:BLOCK_WIZ_SET_FILTER,payload:{blkid:id}}},
                            MD.getFilterList(val.use_table).map(function(i){
                                return m('option',{value:i.id,selected:(val.use_filter==i.id)},i.parent+i.name)
                            })
                        ),
                        m(gear,{href:'edit_filter.php?table='+MD.ti(val.use_table,'id'),title:lang['Filter_settings']}),
                    ]) : null,
                    val.use_table && showOptions 
                      ? Row({
                        label: lang["Hide_block_with_empty_values"], 
                        help: "rb_Hide_block_with_empty_values",
                        children: Checkbox({
                          value: val.hideEmptyValues === 1 ? 'yes' : 'no',
                          onchange: function () {},
                          onclick: function (e) {
                            raise('HideEmptyValues', {
                              blkid: id,
                              value: e.target.checked ? 1 : 0,
                            })
                          },
                        }) 
                      }) 
                      : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Width_block'],help:'rb_Table_width',key:id+'cap'}, [
                        m(selectee,{width:250,onchange:{action:BLOCK_WIZ_SET_WIDTH,payload:{blkid:id}}},
                            KIND_OF_WIDTH.map(function(i){
                                return m('option',{value:i.value,selected:(val.width==i.value)},i.label)
                            })
                        ),
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Block_height'],help:'rb_Block_height',key:id+'bh'}, [
                        m(selectee,{width:250,onchange:{action:BLOCK_WIZ_SET_BLOCK_HEIGHT,payload:{blkid:id}}}, [
                            m('option',{value:'stretch',selected:(val.block_height=='stretch')},lang['Stretch']),
                            m('option',{value:'by_content',selected:(val.block_height=='by_content')},lang['By_content']),
                        ]),
                    ]) : null,
                    val.use_table && showOptions && prms.length>0 ? m(interfaceRow,{label:lang['Link_shared_param'],help:'rb_Link_shared_param'}, [
                        prms.map(function(item){
                            return m(parameterLinkRow,{width: 222, blkid:id,table:val.use_table,item:item,link:val.paralink[item.name],params_length:prms.length})
                        })
                    ]) : null,
                    val.use_table && showOptions && val.microchart == 0 ? m(interfaceRow,{label:lang['Image'],help:'rb_Image_Indicator',key:id+'img'}, [
                        m(inputFile,{value:val.image,width:260,preview_width:val.preview_width,onchange:{action:BLOCK_WIZ_SET_IMAGE,payload:{blkid:id}}},null),
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Link'],help:'rb_Image_Link_Indicator',key:id+'img_lnk'}, [
                        m(inputText,{value:val.image_href,width:260,onchange:{action:BLOCK_WIZ_SET_IMAGE_HREF,payload:{blkid:id}}},null),,
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Use_records'],help:'rb_Use_records'},[
                        m(statusCheckSet,{blkid:id,value:val.use_status}),
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Links'],help:'rb_Links'}, [
                        m(selectee,{width:250,onchange:{action:BLOCK_WIZ_SET_LINKS,payload:{blkid:id}}},
                            LINKS_STATUS.map(function(i){return m('option',{value:i.value,selected:(val.use_links==i.value)},i.label)})
                        ),
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Relative_indicator'],help:'rb_Relative_indicator'}, [
                        m(selectee,{width:250,onchange:{action:BLOCK_WIZ_SET_RELATIVE_INDICATOR,payload:{blkid:id,prop_name:'type'}}},
                            RELATIVE_INDICATOR_TYPES.map(function(i){return m('option',{value:i.value,selected:(val.relative_value.type==i.value)},i.label)})
                        ),
                        m('div', {style:val.relative_value.type != 'none' ? 'margin-top: 6px;' : ''}, [
                            val.relative_value.type == 'fixed'
                                ? m('div', {style:'margin-top: 6px;'}, [
                                    m(inputText,{
                                        placeholder:(lang['value'].slice(1, 2).toUpperCase() + lang['value'].slice(2)),
                                        value:val.relative_value.fixed_value,
                                        width:260,
                                        onchange:{
                                            action:BLOCK_WIZ_SET_RELATIVE_INDICATOR,
                                            payload:{
                                                blkid:id,
                                                prop_name:'fixed_value'
                                            }
                                        }
                                    },null)
                                ])
                                : null,
                            val.relative_value.type == 'field'
                                ? m('div', {style:'margin-top: 6px;'}, [
                                    m(singleRow, {
                                        blkid:id,
                                        keys: {
                                            TABLE_KEY: 'table',
                                            FIELD_KEY: 'field',
                                            EXPR_KEY: 'expr',
                                            FORMAT_KEY: 'format',
                                            FILTER_KEY: 'filter',
                                        },
                                        action: BLOCK_WIZ_SET_RELATIVE_INDICATOR_FIELD,
                                        col: val.relative_value.field,
                                    })
                                ])
                                : null,
                            val.relative_value.type == 'field' && val.relative_value.field.table
                                ? prms.map(function(item){
                                    return m(parameterLinkRowRelative,{blkid:id,table:val.relative_value.field.table,item:item,link:val.relative_value.paralink[item.name],params_length:prms.length})
                                })
                                : null,
                            val.relative_value.type == 'fixed' || val.relative_value.type == 'field'
                                ? m('div', {style:'margin-top: 6px;'}, [
                                    m(inputText,{placeholder:lang['Subsequent_text'],value:val.relative_value.subsequent_text,width:250,onchange:{action:BLOCK_WIZ_SET_RELATIVE_INDICATOR,payload:{blkid:id,prop_name:'subsequent_text'}}},null)
                                ])
                                : null,
                        ])
                    ]) : null,
                    val.use_table && showOptions && checkAvailabilityParamType('period') && val.image.length == 0 ? m(interfaceRow,{label:lang['Microchart'],help:'rb_Microchart'}, [
                        m(selectee,{width:250,class:'dont_use_chosen',onchange:{action:BLOCK_WIZ_SET_MICROCHART_PERIODS,payload:{blkid:id}}},
                            [
                                {value: 'yes', label: lang['Yes']},
                                {value: 'no', label:lang['No']}
                            ].map(function(i){return m('option',{value:i.value,selected:(val.microchart > 0 && i.value == 'yes' || val.microchart == 0 && i.value == 'no')},i.label)})
                        ),
                        val.microchart > 0 ? m('span[style=padding:0 3px 0 10px;]', lang['Count_of_periods'] + ":") : null,
                        val.microchart > 0 ?
                            m(inputText,{value:val.microchart,width:250,placeholder: lang['Number_of_periods_displayed'], onchange:{action:BLOCK_WIZ_SET_MICROCHART_PERIODS,payload:{blkid:id}}},null) :
                            null
                    ]) : null,
                    val.use_table && showOptions && checkAvailabilityParamType('period') ? m(interfaceRow,{label:lang['Dynamics'] + ' (%)',help:'rb_Dynamics_percent'}, [
                        m(inputRadioLine,{items:[
                            { value: 'CH1', checked:(val.change.length==0 || val.change.length > 0 && val.change[0].percent == 'no'), label:lang['No'], onchange: function(){
                                if(val.change[0].percent == 'yes'){
                                    raise(CHANGE_CLEAR, { blkid: id });
                                } else {
                                    raise(CHANGE_ITEM_SET_VALUE, {
                                        blkid: id,
                                        name: 'CH1',
                                        prop_name: 'percent',
                                        value: 'no',
                                    });
                                }
                            } },
                            { value: 'CH1', checked:(val.change.length > 0 && val.change[0].percent == 'yes'), label:lang['Yes'], onchange: function() {
                                if(val.change.length == 0){
                                    raise(CHANGE_ITEM_APPEND, {
                                        blkid: id,
                                        item: {
                                            name: 'CH1',
                                            percent: 'yes',
                                            abs: 'no',
                                            up: 'rgb(147, 196, 125)',
                                            down: 'rgb(224, 102, 102)'
                                        }
                                    });
                                }
                                else {
                                    raise(CHANGE_ITEM_SET_VALUE, {
                                        blkid: id,
                                        name: 'CH1',
                                        prop_name: 'percent',
                                        value: 'yes',
                                    });
                                }
                            } },
                        ]}),
                    ]) : null,
                    val.use_table && showOptions && val.change.length > 0 && checkAvailabilityParamType('period') ? m(interfaceRow,{label:lang['Dynamics'] + ` (${lang['digit']})`,help:'rb_Dynamics_digit'}, [
                        m(inputRadioLine,{items:[
                            { value: 'CH1', checked:(val.change.length==0 || val.change.length > 0 && val.change[0].abs == 'no'), label:lang['No'], onchange: function(){
                                if(val.change[0].percent == 'no'){
                                    raise(CHANGE_CLEAR, { blkid: id });
                                }
                                else {
                                    raise(CHANGE_ITEM_SET_VALUE, {
                                        blkid: id,
                                        name: 'CH1',
                                        prop_name: 'abs',
                                        value: 'no',
                                    });
                                }
                            } },
                            { value: 'CH1', checked:(val.change.length > 0 && val.change[0].abs == 'yes'), label:lang['Yes'], onchange: function() {
                                if(val.change.length == 0){
                                    raise(CHANGE_ITEM_APPEND, {
                                        blkid: id,
                                        item: {
                                            name: 'CH1',
                                            percent: 'no',
                                            abs: 'yes',
                                            up: 'rgb(147, 196, 125)',
                                            down: 'rgb(224, 102, 102)'
                                        }
                                    });
                                }
                                else {
                                    raise(CHANGE_ITEM_SET_VALUE, {
                                        blkid: id,
                                        name: 'CH1',
                                        prop_name: 'abs',
                                        value: 'yes',
                                    });
                                }
                            } },
                        ]}),
                    ]) : null,
                    val.use_table && showOptions && checkAvailabilityParamType('period') > 0 ?
                        m(interfaceRow, val.change.map((item) => m(changeDefinitionRow, {blkid: id, item: item, type: val.type}))) :
                        null,

                    // Сравнивать период
                    val.use_table && showOptions && checkAvailabilityParamType('period') ? m(interfaceRow, {
                      label: lang['Compare_period'], help:'ko__dynamics__compare-period'
                    }, [
                      m(selectee, {width: 250, onchange: {action: BLOCK_WIZ_SET_DYNAMICS_COMPARE_PERIOD, payload: {blkid: id}}},
                        DYNAMICS_COMPARE_PERIOD.map(function(i) {
                          return m('option', {value: i.value, selected: (val.dynamics_compare_period == i.value)}, i.label);
                        }
                      )),
                    ]) : null,

                    val.use_table && showOptions ? m(interfaceRow, {label:lang['Color_formatting'], help:'rb_Color_format'}, [
                        val.lighter.map(function(i){return m(wizColorFormattingInitial, {blkid:id,row:i})}),
                        m(aee, { style:'margin-left:.5em', onclick: {action: COLOR_FORMATTING_ADD, payload: {blkid:id}}}, lang['Add']),
                    ]) : null
                )
            },
        }
    }

    function PaperBlockWizTable(yaml,prnt) {
        let supra = prnt, id = genid();
        var initval = yaml || {type:'block_wiz_table',width:'100',order:0,columns:[]};
        var val = {
            type:   'block_wiz_table',
            width:  initval.width && KIND_OF_WIDTH.map(i => i.value).includes(initval.width) ? initval.width : '100',
            order:  initval.order || 0,
            caption: initval.caption || '',
            limit: initval.limit || 50,
            showCount: initval.showCount || 1,
            show_additional_actions: initval.show_additional_actions || 2,
            show_empty_values: initval.show_empty_values || (initval.use_table || initval.caption ? 'no' : 'yes'),
            show_empty_groups: initval.show_empty_groups || (initval.use_table || initval.caption ? 'no' : 'yes'),
            kind_of_period: initval.kind_of_period || 'day',
            use_table: MD.getTableId(initval.use_table || ''),
            use_filter: initval.use_filter || '',
            use_status: initval.use_status || 'active',
            paralink: initval.paralink || {},
            use_links: initval.use_links || 'implicit',
            alignment: initval.alignment || 'center',
          hideEmptyValues: initval.hideEmptyValues || 0,
            alignment: initval.alignment || 'AsInTheTable'
        };
        val.columns = wizColumnsInitial(val.use_table,initval.columns);
        var showOptions = false;
        function blockStyling() {
            var props = '';
            var w = parseInt(val.width);
            if (w>0 && w<=100) {
                props += ' flex:0 0 calc(' + w + '% - 10px);';
            }
            var o = parseInt(val.order);
            if (!isNaN(o)) {
                props += 'order:' + o + ';';
            }
            return props+'';
        }
        const getPaper = () => {
          const {
            paralink, 
            columns,
            ...otherVal
          } = val;
          
          // Что то непонятное, скорее всего зачем-то нужно
          // TODO: выяснить зачем и исправить на читабельное
          const gettedParalink = dataParams()
            .filter(({ name }) => paralink.hasOwnProperty(name))
            .reduce((acc, { name }) => ({
                ...acc,
                [name]: paralink[name],
              })
            , {});
            
          return {
            paralink: gettedParalink,
            columns: columns.map(({ id, ...params }) => params),
            ...otherVal
          };
        }
        function getGroupField() {
            let data = {
                field: val.columns[0].field,
                is_manually: false,
                name: "S1",
                type: MD.getFieldInfo(val.use_table, val.columns[0].field.split('|')[1])?.type,
            };

            for(let column of val.columns){
                if(column.group == 'yes'){
                    data.field = column.field;
                    data.is_manually = true;
                    data.name = column.name;
                    data.type = MD.getFieldInfo(val.use_table, column.field.split('|')[1])?.type;

                    return data;
                }
            }

            return data;
        }
        function checkAvailabilityAA(){
            let group_or_expr = false,
                has_aa = false;

            for(let column of val.columns){
                if(column.group == 'yes' || column.expr.length !== 0){
                    group_or_expr = true;
                }
                if(column.field.indexOf('aa|') !== -1){
                    has_aa = true;
                }
            }

            return !group_or_expr && has_aa;
        }
        /**
         * @fixme Непонятна необходимость данной функции
         * Удалить если этой записи больше 6 месяцев и не обнаружены баги
         * @returns 
         */
        function getPaperForCopy() {
            val.columnsCopy = val.columns.map(({ id, ...params }) => params);
            let copy = { ...val };

            copy.columns = copyObjectData(val.columnsCopy);

            copy.paralink = {};

            dataParams().forEach(({ name }) => {
                if (val.paralink.hasOwnProperty(name)) {
                    copy.paralink[name] = val.paralink[name];
                }
            });

            return copy;
        }
        function columnsWithoutAA(columns){
            let new_columns = [];

            for(let column of columns){
                if(column.field.indexOf('aa|') === -1){
                    new_columns.push(column);
                }
            }

            return new_columns;
        }
        function hasAAAvailable(columns){
            for(let column of columns){
                if(column.group == 'yes' || column.expr != '') return false;
            }
            return true;
        }
        const setShowEmptyValuesFromMainGroupType = (isMainGroupTypeLink) => {
            val.show_empty_values = isMainGroupTypeLink ? "no" : "yes"
        }
        var dispatch = function (action,payload) {
            switch (action) {
                case BLOCK_WIZ_SET_WIDTH:
                    if (payload.blkid==id) val.width = payload.value;
                    break;
                case ADD_LAYOUT_ITEM:
                    if (payload.parent_id==id) layout.push(PaperLayoutItem({type:payload.item_type},{id:id}));
                    break;
                case DELETE_LAYOUT_ITEM:
                    if (payload.item_id==id) Dispatcher.unregister(dispatch);
                    break;
                case BLOCK_WIZ_SET_TABLE:
                    if (payload.blkid!=id) break;
                    if (val.use_table==payload.value) break;
                    val.use_table = payload.value;
                    val.use_filter = '';
                    val.use_status = 'active';
                    val.columns = [];
                    wizColumnAdd(val.use_table,val.columns);
                    break;
                case BLOCK_WIZ_SET_FILTER:
                    if (payload.blkid!=id) break;
                    val.use_filter = payload.value;
                    break;
                case BLOCK_WIZ_SET_CAPTION:
                    if (payload.blkid!=id) break;
                    val.caption = payload.value;
                    break;
                case BLOCK_WIZ_SET_STATUS:
                    if (payload.blkid!=id) break;
                    val.use_status = payload.value || 'active';
                    break;
                case BLOCK_WIZ_SET_PARALINK:
                    if (payload.blkid!=id) break;
                    if (payload.value=='') delete val.paralink[payload.param]; else val.paralink[payload.param] = payload.value;
                    break;
                case BLOCK_WIZ_SET_LINKS:
                    if (payload.blkid!=id) break;
                    val.use_links = payload.value || 'implicit';
                    break;
                case BLOCK_WIZ_ALIGNMENT:
                    if (payload.blkid!=id) break;
                    val.alignment = payload.value;
                    break;
                case BLOCK_WIZ_SET_LIMIT:
                    if (payload.blkid!=id) break;
                    val.limit = payload.value;
                    break;
                case BLOCK_WIZ_SHOW_ROWS_COUNT:
                    if (payload.blkid!=id) break;
                    val.showCount = payload.value;
                    break;
                case BLOCK_WIZ_SHOW_OPTIONS:
                    if (payload.blkid!=id) break;
                    showOptions = payload.show;
                    break;
                case BLOCK_WIZ_COLUMN_ADD:
                    if (payload.blkid==id) wizColumnAdd(val.use_table,val.columns);
                    break;
                case BLOCK_WIZ_COLUMN_DELETE:
                    if (payload.blkid==id) val.columns = val.columns.filter(function(i){return i.id!=payload.colid;})
                    break;
                case BLOCK_WIZ_COLUMN_SET_VALUE:
                    if (payload.blkid==id) {
                        if(payload.name == 'field' && payload.value == 'aa|') 
                            payload.value = 'aa|' + MD.getAA(val.use_table)[0].id;
                        
                        wizColumnSet(val.use_table,val.columns,payload.colid,payload.name,payload.value);
                        // Меняется поле группировки
                        if(['expr', 'group'].includes(payload.name)){
                            const groupColumn = val.columns.find(({group}) => group === 'yes');
                            
                            const isMainGroupTypeLink = groupColumn?.field.includes("link")
                            setShowEmptyValuesFromMainGroupType(isMainGroupTypeLink)
                            
                            val.columns = columnsWithoutAA(val.columns);
                            m.redraw();
                        }
                        if (payload.name == "field" && !val.isShowEmptyValuesChanged && !['expr', 'group'].includes(payload.name)) {
                            const isMainGroup = payload.is_main_group_table;
                            
                            if(isMainGroup){
                                const isMainGroupTypeLink = payload.value.includes("link");
                                setShowEmptyValuesFromMainGroupType(isMainGroupTypeLink);
                            }
                        }
                    }
                    break;
                case BLOCK_WIZ_COLUMN_MOVE:
                    if (payload.blkid==id) {
                        var elem = val.columns.find(function(i){return i.id==payload.element_id});
                        var res = [];
                        val.columns.forEach(function(i){
                            if (i.id==payload.element_id) return;
                            if (i.id==payload.sibling_id) {
                                res.push(elem);
                            }
                            res.push(i);
                        });
                        if (payload.sibling_id=='') {
                            res.push(elem);
                        }
                        val.columns = res;
                    };
                    break;
                case BLOCK_WIZ_SHOW_EMPTY_VALUES:
                    if (payload.blkid!=id) break;
                    val.isShowEmptyValuesChanged = true;
                    val.show_empty_values = payload.value;
                    break;
                case BLOCK_WIZ_SHOW_EMPTY_GROUPS:
                    if (payload.blkid!=id) break;
                    val.show_empty_groups = payload.value;
                    break;
                case BLOCK_WIZ_KIND_OF_PERIOD:
                    if (payload.blkid!=id) break;
                    val.kind_of_period = payload.value;
                    break;
                case BLOCK_WIZ_ADDITIONAL_ACTIONS:
                    if (payload.blkid!=id) break;
                    val.show_additional_actions = payload.value;
                    break;
                case 'HideEmptyValues':
                  if (payload.blkid != id) break;
                  val.hideEmptyValues = payload.value;
                  break;
                default:
                    break;
            }
        }
        Dispatcher.register(dispatch);

        return {
            id: function(){ return id; },
            copyObject: function(){ return PaperBlockWizTable(getPaper(),prnt); },
            canBeDeleted: function() { return true; },
            getPaper: function() { return getPaper() },
            getView: function() {
                return m('div.yamlview__block#'+id+'[style='+blockStyling()+']', [
                    m('div.yamlview__block_inner[style=position:relative]','BLOCK_TABLE')
                ]);
            },
            viewAsListItem: function() {
                return m(listItem,{
                    caption: buildItemTitle(lang['Table2'],val.caption,MD.getTableName(val.use_table)),
                    item_id: id,
                    parent_id: supra.id,
                    key: id,
                })
            },
            viewAsDetails: function() {
              const Table = {};
              Table.HideEmptyBlock = ({ children }) => Row({
                label: lang["Hide_block_with_empty_values"], 
                help: "rb_Hide_block_with_empty_values",
                children
              })
                var prms = dataParams();
                return m(detailsBlock,{title:buildItemTitle(lang['Table2'],val.caption,MD.getTableName(val.use_table))},
                    m(interfaceRow,{label:lang['Table2'],help:'rb_Table'}, [
                        m(selectee,{width:250,onchange:{action:BLOCK_WIZ_SET_TABLE,payload:{blkid:id}}},
                            MD.getTableList().map(function(i){return m('option',{value:i.id,selected:(val.use_table==i.id)},i.name)})
                        ),
                        val.use_table ? m(gear,{href:'edit_field.php?table='+MD.ti(val.use_table,'id'),title:lang['Table_settings']}) : null,
                    ]),
                    val.use_table ? m(interfaceRow,{label:lang['Title'],help:'rb_Table_title'}, [
                        m(inputText,{value:val.caption,width:260,onchange:{action:BLOCK_WIZ_SET_CAPTION,payload:{blkid:id}}},null),
                    ]) : null,
                    val.use_table ? m(interfaceRow,{label:lang['Columns'], help:'rb_Columns'}, [
                        m(dragZone,{onmove:{action:BLOCK_WIZ_COLUMN_MOVE, payload:{blkid:id}}}, [
                            val.columns.map(function(column){return m(columnRowWizTable,{
                                key:column.id,
                                col:column,
                                blkid:id,
                                table:val.use_table,
                                has_available_aa:hasAAAvailable(val.columns),
                                group_field:getGroupField(),
                                kind_of_period:val.kind_of_period,
                                is_main_group_table: getGroupField().name === column.name                            
                            })}),
                        ]),
                        m(aee,{onclick:{action:BLOCK_WIZ_COLUMN_ADD,payload:{blkid:id}}},lang['add_column']),
                    ]) : null,
                    val.use_table ? m(interfaceRow,{label:''}, [
                        m(aee,{onclick:{action:BLOCK_WIZ_SHOW_OPTIONS,payload:{blkid:id,show:!showOptions}}},showOptions?lang['Hide']:lang['Additional'] + '...'),
                    ]) : null,
                    val.use_table && showOptions && prms.length>0 ? m(interfaceRow,{label:lang['Link_shared_param'],help:'rb_Link_shared_param'}, [
                        prms.map(function(item){
                            return m(parameterLinkRow,{blkid:id,table:val.use_table,item:item,link:val.paralink[item.name]})
                        })
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Filter'],help:'rb_Filter'}, [
                        m(selectee,{width:250,onchange:{action:BLOCK_WIZ_SET_FILTER,payload:{blkid:id}}},
                            MD.getFilterList(val.use_table).map(function(i){return m('option',{value:i.id,selected:(val.use_filter==i.id)},i.parent+i.name)})
                        ),
                        m(gear,{href:'edit_filter.php?table='+MD.ti(val.use_table,'id'),title:lang['Filter_settings']}),
                    ]) : null,
                    val.use_table && showOptions ? 
                      Table.HideEmptyBlock({
                        children: [
                          Checkbox({
                            value: val.hideEmptyValues === 1 ? 'yes' : 'no',
                            onchange: function () {},
                            onclick: function (e) {
                              raise('HideEmptyValues', {
                                blkid: id,
                                value: e.target.checked ? 1 : 0,
                              })
                            },
                          })
                        ]
                      })
                    : null,
                    val.use_table && showOptions && getGroupField().type !=  void 0 && (
                        getGroupField().type == 2 ||
                        getGroupField().type == 11 ||
                        getGroupField().type == 12 ||
                        getGroupField().type == 13 ||
                        getGroupField().type == 4 ||
                        getGroupField().type == 7 ||
                        getGroupField().type == 5
                    )
                        ? m(interfaceRow,{label:lang['Show_empty_values'],help:'rb_Show_empty_values'}, [
                            m(inputChecker, {
                                value: val.show_empty_values,
                                disabled: val.show_empty_groups == 'nope',
                                onchange: function(){},
                                onclick: function(e){
                                    if (e.ctrlKey){
                                        raise(BLOCK_WIZ_SHOW_EMPTY_GROUPS, {
                                            blkid: id,
                                            value: 'nope',
                                        });
                                    }
                                    else {
                                        raise(BLOCK_WIZ_SHOW_EMPTY_VALUES, {
                                            blkid: id,
                                            value: e.target.checked ? 'yes' : 'no',
                                        });
                                    }
                                }
                            }),
                            m(`span[style=display:inline-block;color:gray;font-family:monospace;cursor:pointer;vertical-align:middle;visibility:${val.show_empty_groups == 'nope' ? 'visible' : 'hidden'};]`,{
                                title:lang['Quasi_off'],
                                onclick: function(){
                                    raise(BLOCK_WIZ_SHOW_EMPTY_GROUPS, {
                                        blkid: id,
                                        value: 'yes',
                                    });
                                }
                            },lang['Quasi_off']),
                        ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Width_block'],help:'rb_Table_width',key:id+'cap'}, [
                        m(selectee,{width:250,onchange:{action:BLOCK_WIZ_SET_WIDTH,payload:{blkid:id}}},
                            KIND_OF_WIDTH.map(function(i){
                                return m('option',{value:i.value,selected:(val.width==i.value)},i.label)
                            })
                        ),
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Use_records'],help:'rb_Use_records'},[
                        m(statusCheckSet,{blkid:id,value:val.use_status}),
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Column_settings'],help:'rb_Column_settings'}, [
                        val.columns.map(function(i){return m(columnRowWizTableSettings,{key:i.id,col:i,blkid:id,table:val.use_table})}),
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Links'],help:'rb_Links'}, [
                        m(selectee,{width:200,onchange:{action:BLOCK_WIZ_SET_LINKS,payload:{blkid:id}}},
                            LINKS_STATUS.map(function(i){return m('option',{value:i.value,selected:(val.use_links==i.value)},i.label)})
                        ),
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Alignment'],help:'rb_Alignment'}, [
                        m(selectee,{width:200,onchange:{action:BLOCK_WIZ_ALIGNMENT,payload:{blkid:id}}},
                            ALIGNMENT.map(function(i){return m('option',{value:i.value,selected:(val.alignment==i.value)},i.label)})
                        ),
                    ]) : null,
                    val.use_table && showOptions && checkAvailabilityAA() ? m(interfaceRow,{label:lang['Show_additional_actions'],help:'Additional_actions'}, [
                        m(selectee, {width:200,onchange:{action:BLOCK_WIZ_ADDITIONAL_ACTIONS,payload:{blkid:id}}},
                            [
                                m('option',{value:0, selected:(val.show_additional_actions==0)},lang['Hover_over_a_line']),
                                m('option',{value:1, selected:(val.show_additional_actions==1)},lang['Always']),
                                m('option',{value:2, selected:(val.show_additional_actions==2)},lang['In_the_context_menu']),
                            ]
                        )
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Line_limit'],help:'rb_Line_limit'}, [
                        m(inputText, {
                            value: val.limit,
                            width: 35,
                            onchange: {action:BLOCK_WIZ_SET_LIMIT,payload:{blkid:id}},
                        }),
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Show_lines_count'],help:'Show_lines_count'}, [
                        m(inputChecker, {
                            value: val.showCount,
                            onchange: {action:BLOCK_WIZ_SHOW_ROWS_COUNT,payload:{blkid:id}},
                        })
                    ]) : null,
                )
            },
        }
    }

    function PaperBlockWizMultitable(yaml, prnt) {
      let supra = prnt,
          id = genid();
      var initval = yaml || { type: "block_wiz_multitable", width: "100", order: 0, columns: [], tables: [] };
      var val = {
          type: "block_wiz_multitable",
          width: initval.width && KIND_OF_WIDTH.map((i) => i.value).includes(initval.width) ? initval.width : "100",
          order: initval.order || 0,
          caption: initval.caption || "",
          limit: initval.limit || 50,
          showCount: initval.showCount || 1,
          hide_main_empty_values: initval.hide_main_empty_values,
          show_additional_actions: initval.show_additional_actions || 2,
          show_empty_values: initval.show_empty_values || (initval.use_table || initval.caption ? "no" : "yes"),
          show_empty_groups: initval.show_empty_groups || (initval.use_table || initval.caption ? "no" : "yes"),
          kind_of_period: initval.kind_of_period || "day",
          use_table: initval.use_table ? MD.getTableId(initval.use_table) : 0,
          use_filter: initval.use_filter || "",
          use_status: initval.use_status || "active",
          paralink: initval.paralink || {},
          use_links: initval.use_links || "implicit",
          alignment: initval.alignment || "AsInTheTable",
          tables: initval.tables || [],
        hideEmptyValues: initval.hideEmptyValues || 0,
      };
      val.columns = wizColumnsInitial(val.use_table, initval.columns);

      var showOptions = false;

      function blockStyling() {
          var props = "";
          var w = parseInt(val.width);
          if (w > 0 && w <= 100) {
              props += " flex:0 0 calc(" + w + "% - 10px);";
          }
          var o = parseInt(val.order);
          if (!isNaN(o)) {
              props += "order:" + o + ";";
          }
          return props + "";
      }
      /**
       * Функция получения данных
       * @returns 
       */
      const getPaper = () => {
        // Деструктуризация данных
        const { 
          paralink, 
          columns: [
            { id: firstColumnId, 
              group: firstColumnGroup, 
              ...firstColumnParams 
            },
            ...otherColumns
          ],
          tables,
          ...otherVal
        } = val;
        // Столбцы без id
        // первый столбец группировка
        const gettedColumns = [
          { 
            group: 'yes',
            ...firstColumnParams 
          },
          ...otherColumns.map(({ id, ...params }) => params)
        ];
        // Что то непонятное, скорее всего зачем-то нужно
        // TODO: выяснить зачем и исправить на читабельное
        const gettedParalink = dataParams()
          .filter(({ name }) => paralink.hasOwnProperty(name))
          .reduce((acc, { name }) => ({
              ...acc,
              [name]: paralink[name],
            })
          , {});
        // Доп таблицы
        // Тоже самое для доп таблиц, но без исключения id
        const gettedTables = tables
          .map(({ 
            columns: [
              { ...firstColumn}, 
              ...otherColumns
            ], 
            paralink, 
            ...otherTable 
          }) => {
            const gettedTableParalink = dataParams()
              .filter(({ name }) => paralink.hasOwnProperty(name))
              .reduce((acc, { name }) => ({
                  ...acc,
                  [name]: paralink[name],
                })
              , {});
                    
            return {
              columns: [
                { ...firstColumn, group: "yes" }, 
                ...otherColumns
              ],
              paralink: gettedTableParalink,
              ...otherTable,
            };
        });


        return {
          paralink: gettedParalink,
          columns: gettedColumns,
          tables:gettedTables,
          ...otherVal
        };
      }
      
      function getGroupField(table) {
          let data = {
              field: table.columns[0].field,
              is_manually: false,
              name: table.columns[0],
              type: MD.getFieldInfo(table.use_table, table.columns[0].field.split("|")[1])?.type,
          };
          for (let column of table.columns) {
              if (column.group == "yes") {
                  data.field = column.field;
                  data.is_manually = true;
                  data.name = column.name;
                  const fieldId = column.field.split("|")[1];
                  data.type = MD.getFieldInfo(table.use_table, fieldId)?.type;

                  return data;
              }
          }

          return data;
      }
      function checkAvailabilityAA() {
          let group_or_expr = false,
              has_aa = false;

          for (let column of val.columns) {
              if (column.group == "yes" || column.expr.length !== 0) {
                  group_or_expr = true;
              }
              if (column.field.indexOf("aa|") !== -1) {
                  has_aa = true;
              }
          }

          return !group_or_expr && has_aa;
      }
      /**
       * @fixme Непонятна необходимость данной функции
       * Удалить если этой записи больше 6 месяцев и не обнаружены баги
       * @returns 
       */
      function getPaperForCopy() {
          let value = getPaper();
          let data = {};

          for (let key in value) {
              data[key] = value[key];
          }

          data.columns = copyObjectData(value.columns);

          var cleanlink = {};
          dataParams().forEach(function (i) {
              if (value.paralink.hasOwnProperty(i.name)) cleanlink[i.name] = value.paralink[i.name];
          });
          data.paralink = cleanlink;
          
          return data;
      }
      function columnsWithoutAA(columns) {
          let new_columns = [];

          for (let column of columns) {
              if (column.field.indexOf("aa|") === -1) {
                  new_columns.push(column);
              }
          }

          return new_columns;
      }
      function hasAAAvailable(columns) {
          for (let column of columns) {
              if (column.group == "yes" || column.expr != "") return false;
          }
          return true;
      }
      const setShowEmptyValuesFromMainGroupType = (isMainGroupTypeLink) => {
        val.show_empty_values = isMainGroupTypeLink ? "no" : "yes"
      }
      var dispatch = function (action, payload) {
          switch (action) {
              case BLOCK_WIZ_SET_WIDTH:
                  if (payload.blkid == id) val.width = payload.value;
                  break;
              case ADD_LAYOUT_ITEM:
                  if (payload.parent_id == id) layout.push(PaperLayoutItem({ type: payload.item_type }, { id: id }));
                  break;
              case DELETE_LAYOUT_ITEM:
                  if (payload.item_id == id) Dispatcher.unregister(dispatch);
                  break;
              case BLOCK_WIZ_SET_TABLE:
                  if (payload.blkid != id) break;

                  if ("index" in payload) {
                      // Дополнительная таблица
                      val.tables[payload.index].use_table = payload.value;
                      val.tables[payload.index].grouping_field = "";
                      val.tables[payload.index].columns = [wizNewColumn(wizNextName("S", val.columns, val))];
                      val.tables[payload.index].use_filter = "";
                      val.tables[payload.index].use_status = "active";
                  } else {
                      // Главная таблица
                      val.use_table = payload.value;
                      val.use_filter = "";
                      val.use_status = "active";
                      val.main_grouping_field = "";
                      val.columns = [];
                      val.tables = [];
                      wizColumnAdd(val.use_table, val.columns, val);
                  }
                  break;
                  case BLOCK_WIZ_SET_FILTER:
                    if (payload.blkid != id) break;
                    if ("index" in payload && val.tables[payload.index]) {
                        val.tables[payload.index].use_filter = payload.value;
                    } else {
                        val.use_filter = payload.value;
                    }
                    break;
              case BLOCK_WIZ_SET_CAPTION:
                  if (payload.blkid != id) break;
                  val.caption = payload.value;
                  break;
              case BLOCK_WIZ_SET_STATUS:
                  if (payload.blkid != id) break;
                  if ("index" in payload && val.tables[payload.index]) {
                      val.tables[payload.index].use_status = payload.value || "active";
                  } else {
                      val.use_status = payload.value || "active";
                  }
                  break;
                  case BLOCK_WIZ_SET_PARALINK:
                    if (payload.blkid != id) break;
                    if ("index" in payload && val.tables[payload.index]) {
                        if (payload.value == "") delete val.tables[payload.index].paralink[payload.param];
                        else val.tables[payload.index].paralink[payload.param] = payload.value;
                    } else {
                        if (payload.value == "") delete val.paralink[payload.param];
                        else val.paralink[payload.param] = payload.value;
                    }
                    break;
              case BLOCK_WIZ_SET_LINKS:
                  if (payload.blkid != id) break;
                  val.use_links = payload.value || "implicit";
                  break;
              case BLOCK_WIZ_ALIGNMENT:
                  if (payload.blkid != id) break;
                  val.alignment = payload.value;
                  break;
              case BLOCK_WIZ_SET_LIMIT:
                  if (payload.blkid != id) break;
                  val.limit = payload.value;
                  break;
              case BLOCK_WIZ_SHOW_ROWS_COUNT:
                  if (payload.blkid != id) break;
                  val.showCount = payload.value;
                  break;
              case BLOCK_WIZ_SHOW_OPTIONS:
                  if (payload.blkid != id) break;
                  if ("index" in payload) {
                      val.tables[payload.index].showOptions = payload.show;
                  } else {
                      showOptions = payload.show;
                  }
                  break;
              case BLOCK_WIZ_COLUMN_ADD:
                  if (payload.blkid == id) {
                      if ("index" in payload) {
                          wizColumnAdd(val.tables[payload.index].use_table, val.tables[payload.index].columns, val);
                      } else {
                          wizColumnAdd(val.use_table, val.columns, val);
                      }
                  }
                  break;

              case BLOCK_WIZ_COLUMN_DELETE:
                  if (payload.blkid == id) {
                      if ("index" in payload && val.tables[payload.index]) {
                          val.tables[payload.index].columns = val.tables[payload.index].columns.filter(function (i) {
                              return i.id != payload.colid;
                          });
                      } else {
                          val.columns = val.columns.filter(function (i) {
                              return i.id != payload.colid;
                          });
                      }
                  }
                  break;
              case BLOCK_WIZ_COLUMN_SET_VALUE:           
                  if (payload.blkid == id) {
                      if (payload.name == "field" && payload.value == "aa|") {
                          payload.value = "aa|" + MD.getAA(val.use_table)[0].id;
                      }
                      if (payload.name == "field") {
                          if (!val.isShowEmptyValuesChanged && payload.is_main_grouping) {
                            const isMainGroupTypeLink = payload.value.includes("link");
                            setShowEmptyValuesFromMainGroupType(isMainGroupTypeLink);
                          }
                          if (payload.is_additional_grouping) {
                              val.tables[payload.index].grouping_field = payload.value;
                          }
                          if (payload.is_main_grouping) {
                              val.main_grouping_field = payload.value;
                              val.tables = [];
                          }
                      }

                      if ("index" in payload && val.tables[payload.index]) {
                            val.tables[payload.index].columns = wizNewColumnsReturn({
                                tableId: val.tables[payload.index].use_table, 
                                columns: val.tables[payload.index].columns, 
                                payload: payload, 
                                template_type: val.type
                            });
                          if (["expr", "group"].includes(payload.name)) {
                              val.tables[payload.index].columns = columnsWithoutAA(val.tables[payload.index].columns);
                          }
                      } else {
                            val.columns = wizNewColumnsReturn({
                                tableId : val.use_table, 
                                columns : val.columns, 
                                payload : payload, 
                                template_type : val.type
                            });
                          if (["expr", "group"].includes(payload.name)) {
                              val.columns = columnsWithoutAA(val.columns);
                          }
                      }
                      m.redraw();
                  }
                  break;
              case BLOCK_WIZ_COLUMN_MOVE:
                  if (payload.blkid == id) {
                      if ("index" in payload) {
                          var elem = val.tables[payload.index].columns.find(function (i) {
                              return i.id == payload.element_id;
                          });
                          var res = [];
                          val.tables[payload.index].columns.forEach(function (i) {
                              if (i.id == payload.element_id) return;
                              if (i.id == payload.sibling_id) {
                                  res.push(elem);
                              }
                              res.push(i);
                          });
                          if (payload.sibling_id == "") {
                              res.push(elem);
                          }
                          val.tables[payload.index].columns = res;
                      } else {
                          var elem = val.columns.find(function (i) {
                              return i.id == payload.element_id;
                          });
                          var res = [];
                          val.columns.forEach(function (i) {
                              if (i.id == payload.element_id) return;
                              if (i.id == payload.sibling_id) {
                                  res.push(elem);
                              }
                              res.push(i);
                          });
                          if (payload.sibling_id == "") {
                              res.push(elem);
                          }
                          val.columns = res;
                      }
                  }
                  break;
              case BLOCK_WIZ_SHOW_EMPTY_VALUES:
                  if (payload.blkid != id) break;
                  val.isShowEmptyValuesChanged = true;
                  val.show_empty_values = payload.value;
                  break;
              case BLOCK_WIZ_HIDE_MAIN_EMPTY_VALUES:
                  if (payload.blkid != id) break;
                  
                  val.hide_main_empty_values = payload.value;
                  break;
              case BLOCK_WIZ_SHOW_EMPTY_GROUPS:
                  if (payload.blkid != id) break;
                  val.show_empty_groups = payload.value;
                  break;
              case BLOCK_WIZ_KIND_OF_PERIOD:
                  if (payload.blkid != id) break;
                  val.kind_of_period = payload.value;
                  break;
              case BLOCK_WIZ_ADDITIONAL_ACTIONS:
                  if (payload.blkid != id) break;
                  val.show_additional_actions = payload.value;
                  break;
              case 'HideEmptyValues':
                if (payload.blkid != id) break;
                val.hideEmptyValues = payload.value;
                break;
                
              default:
                  break;
          }
      };
      Dispatcher.register(dispatch);

      return {
          id: function () {
              return id;
          },
          copyObject: function () {
              return PaperBlockWizMultitable(getPaper(), prnt);
          },
          canBeDeleted: function () {
              return true;
          },
          getPaper: function () {
              return getPaper();
          },
          getView: function () {
              return m("div.yamlview__block#" + id + "[style=" + blockStyling() + "]", [m("div.yamlview__block_inner[style=position:relative]", "BLOCK_TABLE")]);
          },
          viewAsListItem: function () {
              return m(listItem, {
                  caption: buildItemTitle(lang["Multitable"], val.caption, MD.getTableName(val.use_table)),
                  item_id: id,
                  parent_id: supra.id,
                  key: id,
              });
          },
          viewAsDetails: function () {
              var prms = dataParams();
              val.main_grouping_field = MAIN_GROUP ? MAIN_GROUP.field : '';
            const Multitable = {};
            

            Multitable.Block = ({ children }) => Block({
                title: buildItemTitle(lang["Multitable"], val.caption, MD.getTableName(val.use_table)),
                children
            });
            Multitable.TitleRow = ({ children }) => Row({
                label: lang["Title"], 
                help: "rb_Table_title", 
                children
            });
            // Выбор основной таблицы
            Multitable.MainTableRow = ({ children }) => Row({
                label: lang["Main_table"],
                help: "rb_Table", 
                children
            });
            Multitable.MainTableSelect = ({ options }) => Select({
                width: 250,
                onchange: {
                    action: BLOCK_WIZ_SET_TABLE,
                    payload: { blkid: id },
                },
                children: options
            });
            Multitable.MainTableSelect.Options = (val) => MD.getUpdatedTableList(val, MD)
                .filter((item) => !val.tables.some((table) => table.use_table === item.id))
                .map((item) => SelectOption({
                    value: item.id, 
                    selected: val.use_table == item.id,
                    children: item.name
                })
            );
            // Ссылка на настройку основной таблицы
            Multitable.MainTableGear = ({ href }) => Gear({
                href, title: lang["Table_settings"]
            });
            // Основное поле группировки
            Multitable.MainGroupingField = ({ children }) => Row({
                label: lang["Main_grouping_field"], 
                help: "rb_Main_grouping_field",
                children
            });
            // Настройка столбцов для основной таблицы
            Multitable.Columns = ({ children }) => Row({
                label: lang["Columns"], 
                help: "rb_Columns",
                children
            });
            // Кнопка добавить столбец
            Multitable.AddColumnButton = ({ ...props }) => LinkButton({
                ...props,
                children: lang["add_column"],
            });
            // Кнопка дополнительно
            Multitable.AdditionalButton = ({ ...props }) => LinkButton({
                ...props,
                children: showOptions ? lang["Hide"] : lang["Additional"] + "...",
            });
            // Фильтр
            Multitable.FilterRow = ({ children }) => Row({
                label: lang["Filter"], 
                help: "rb_Filter",
                children
            });
            Multitable.FilterSelect = ({ options }) => Select({
                width: 250, 
                onchange: { 
                    action: BLOCK_WIZ_SET_FILTER, 
                    payload: { blkid: id } 
                },
                children: options
            });
            Multitable.FilterSelect.Options = (val) => MD.getFilterList(val.use_table)
                .map((option) => SelectOption({
                    value: option.id, 
                    selected: val.use_filter == option.id, 
                    children: option.parent + option.name,
                })
            );
            // Ссылка на настройку фильтров
            Multitable.FilterGear = ({ href }) => Gear({
                title: lang["Filter_settings"],
                href,
            });
            // Выводить пустые значения
            Multitable.ShowEmptyValuesRow = ({ children }) => Row({
                label: lang["Show_empty_values"], 
                help: "rb_Show_empty_values",
                children,
            });
            // Скрывать строки с нулевым значением в основной таблице
            Multitable.HideMainEmptyValues = ({ children }) => Row({
                label: lang["Hide_main_empty_values"], 
                help: "rb_Hide_main_empty_values",
                children,
            });
            // Ширина блока
            Multitable.WidthRow = ({ children }) => Row({
                label: lang["Width_block"], 
                help: "rb_Table_width", 
                key: id + "cap",
                children,
            });
            Multitable.WidthSelect = ({ options }) => Select({
                width: 250, 
                onchange: { 
                    action: BLOCK_WIZ_SET_WIDTH, 
                    payload: { blkid: id } 
                },
                children: options
            });
            Multitable.WidthSelect.Options = (val) => KIND_OF_WIDTH
                .map((size) => SelectOption({ 
                    value: size.value, 
                    selected: val.width == size.value, 
                    children: size.label
                })
            );
            // Использовать записи
            Multitable.UseRecordsRow = ({ children }) => Row({
                label: lang["Use_records"], 
                help: "rb_Use_records",
                children,
            });
            // Настройка столбцов
            Multitable.ColumnSettingsRow = ({ children }) => Row({
                label: lang["Column_settings"], 
                help: "rb_Column_settings",
                children,
            });
            // Ссылки
            Multitable.LinksRow = ({ children }) => Row({
                label: lang["Links"], 
                help: "rb_Links",
                children,
            });
            // Выравнивание
            Multitable.AlignmentRow = ({ children }) => Row({
                label: lang["Alignment"], 
                help: "rb_Alignment",
                children,
            });
            // Выводить дополнительные действия
            Multitable.ShowAdditionalActionsRow = ({ children }) => Row({
                label: lang["Show_additional_actions"], 
                help: "Additional_actions",
                children,
            });
            // Лимит строк
            Multitable.LineLimitRow = ({ children }) => Row({
                label: lang["Line_limit"], 
                help: "rb_Line_limit",
                children,
            });
            // Выводить количество строк
            Multitable.ShowLinesCountRow = ({ children }) => Row({
                label: lang["Show_lines_count"], 
                help: "Show_lines_count",
                children,
            });

            Multitable.HideEmptyBlock = ({ children }) => Row({
              label: lang["Hide_block_with_empty_values"], 
              help: "rb_Hide_block_with_empty_values",
              children
            })

            const checkShowConditionsFromVal = (val, showOptions) => ({
                'Заголовок': !!val.use_table, 
                'Настройки основной таблицы': !!val.use_table, 
                'Основное поле группировки': !!val.use_table, 
                'Настройка столбцов для основной таблицы': !!val.use_table, 
                'Кнопка дополнительно': !!val.use_table, 
                'Фильтр': !!val.use_table && showOptions,
                'Скрывать блок с нулевыми значениями': !!val.use_table && showOptions,
                'Выводить пустые значения': !!val.use_table && showOptions && getGroupField(val).type != void 0 && (
                    getGroupField(val).type == 2 || 
                    getGroupField(val).type == 11 || 
                    getGroupField(val).type == 12 || 
                    getGroupField(val).type == 13 || 
                    getGroupField(val).type == 4 || 
                    getGroupField(val).type == 7 || 
                    getGroupField(val).type == 5
                ),
                'Скрывать строки с нулевым значением в основной таблице': val.show_empty_values === "no" && val.use_table && showOptions && getGroupField(val).type != void 0 && (
                    getGroupField(val).type == 2 || 
                    getGroupField(val).type == 11 || 
                    getGroupField(val).type == 12 || 
                    getGroupField(val).type == 13 || 
                    getGroupField(val).type == 4 || 
                    getGroupField(val).type == 7 || 
                    getGroupField(val).type == 5
                ),
                'Ширина блока': !!val.use_table && showOptions,
                'Использовать записи': !!val.use_table && showOptions,
                'Настройка столбцов': !!val.use_table && showOptions,
                'Ссылки': !!val.use_table && showOptions,
                'Выравнивание': !!val.use_table && showOptions,
                'Выводить дополнительные действия': !!val.use_table && showOptions && checkAvailabilityAA(),
                'Лимит строк': !!val.use_table && showOptions,
                'Выводить количество строк': !!val.use_table && showOptions
            });
            
            return Multitable.Block({
                children: [
                    checkShowConditionsFromVal(val, showOptions)['Заголовок'] ? (
                        Multitable.TitleRow({ 
                            children: InputText({
                                value: val.caption, 
                                width: 260,
                                onchange: { 
                                    action: BLOCK_WIZ_SET_CAPTION, 
                                    payload: { blkid: id } 
                                }
                            }) 
                        })
                    ): null,
                  // Выбор основной таблицы
                    Multitable.MainTableRow({ 
                        children: [
                            Multitable.MainTableSelect({
                                options: Multitable.MainTableSelect.Options(val)
                            }),
                            checkShowConditionsFromVal(val, showOptions)['Настройки основной таблицы'] && (
                                Multitable.MainTableGear({ href: "edit_field.php?table=" + MD.ti(val.use_table, "id") }) 
                            )
                        ]
                    }
                    ),
                  // Основное поле группировки
                    checkShowConditionsFromVal(val, showOptions)['Основное поле группировки']  ? Multitable.MainGroupingField({
                        children: [
                            ColumnRowWizTable({
                                key: val.columns[0].id,
                                col: {
                                    id: val.columns[0].id,
                                    field: val.columns[0].field,
                                    expr: '',
                                    filter: val.columns[0].filter,
                                    name: val.columns[0].name,
                                    format: val.columns[0].format,
                                    // Данный параметр управляет
                                    // будут ли отображаться столбцы доп. полей группировки
                                    // TODO: Необходимо исправить. Это должно быть либо св-во
                                    // мультитаблицы, либо свойство доп.поля группировки.
                                    hidden: "yes",
                                    group: "yes",
                                    sort: val.columns[0].sort,
                                    title: val.columns[0].title,
                                    output: val.columns[0].output,
                                    total: val.columns[0].total,
                                },
                                blkid: id,
                                table: val.use_table,
                                has_available_aa: hasAAAvailable(val.columns),
                                group_field: getGroupField(val),
                                kind_of_period: val.kind_of_period,
                                main_group: (MAIN_GROUP = { ...getGroupField(val), use_table: val.use_table }),
                                is_main_grouping: true,
                                is_multitable: true,
                            }),
                        ]}): null,

                  // Настройка столбцов для основной таблицы
                    checkShowConditionsFromVal(val, showOptions)['Настройка столбцов для основной таблицы'] ? (
                        Multitable.Columns({
                            children: [
                                DragZone({ 
                                    onmove: { action: BLOCK_WIZ_COLUMN_MOVE, payload: { blkid: id } }, 
                                    children: [
                                        val.columns.slice(1).map((column) => 
                                            ColumnRowWizTable({
                                                key: column.id,
                                                col: column,
                                                blkid: id,
                                                table: val.use_table,
                                                has_available_aa: hasAAAvailable(val.columns),
                                                group_field: getGroupField(val),
                                                kind_of_period: val.kind_of_period,
                                                is_multitable: true,
                                            })
                                        ),
                                    ]
                                }),
                                Multitable.AddColumnButton({ 
                                    onclick: { 
                                        action: BLOCK_WIZ_COLUMN_ADD, 
                                        payload: { blkid: id } 
                                    } 
                                }),
                            ]
                        })
                    ): null,
                  // 	Дополнительно...
                    checkShowConditionsFromVal(val, showOptions)['Кнопка дополнительно']  ? (
                        Row({ 
                            children: [
                                Multitable.AdditionalButton({ 
                                    onclick: { action: BLOCK_WIZ_SHOW_OPTIONS, payload: { blkid: id, show: !showOptions } } 
                                })
                            ]
                        }) 
                    ): null,
                    (val.use_table && showOptions && prms.length > 0) ? (
                        m(interfaceRow, { label: lang["Link_shared_param"], help: "rb_Link_shared_param" }, [
                            prms.map(function (item) {
                                return m(parameterLinkRow, { blkid: id, table: val.use_table, item: item, link: val.paralink[item.name] });
                            }),
                        ])
                    ): null,
                    checkShowConditionsFromVal(val, showOptions)['Фильтр'] ? (
                        Multitable.FilterRow({
                            children: [
                                Multitable.FilterSelect({
                                    options: Multitable.FilterSelect.Options(val)
                                }),
                                Multitable.FilterGear({ href: "edit_filter.php?table=" + MD.ti(val.use_table, "id") }),
                            ]
                        })
                    ): null,
                    checkShowConditionsFromVal(val, showOptions)['Скрывать блок с нулевыми значениями'] ? (
                      Multitable.HideEmptyBlock({
                        children: [
                          Checkbox({
                            value: val.hideEmptyValues === 1 ? 'yes' : 'no',
                            onchange: function () {},
                            onclick: function (e) {
                              raise('HideEmptyValues', {
                                blkid: id,
                                value: e.target.checked ? 1 : 0,
                              })
                            },
                          })
                        ]
                      })
                    ): null,
                    checkShowConditionsFromVal(val, showOptions)['Выводить пустые значения'] ? (
                        Multitable.ShowEmptyValuesRow({
                            children:[
                                Checkbox({
                                    value: val.show_empty_values,
                                    disabled: val.show_empty_groups == "nope",
                                    onchange: function () {},
                                    onclick: function (e) {
                                        if (e.ctrlKey) {
                                            raise(BLOCK_WIZ_SHOW_EMPTY_GROUPS, {
                                                blkid: id,
                                                value: "nope",
                                            });
                                        } else {
                                            raise(BLOCK_WIZ_SHOW_EMPTY_VALUES, {
                                                blkid: id,
                                                value: e.target.checked ? "yes" : "no",
                                            });
                                        }
                                    },
                                }),
                                m(
                                    `span[style=display:inline-block;color:gray;font-family:monospace;cursor:pointer;vertical-align:middle;visibility:${val.show_empty_groups == "nope" ? "visible" : "hidden"};]`,
                                    {
                                        title: lang["Quasi_off"],
                                        onclick: function () {
                                            raise(BLOCK_WIZ_SHOW_EMPTY_GROUPS, {
                                                blkid: id,
                                                value: "yes",
                                            });
                                        },
                                    },
                                    lang["Quasi_off"]
                                ),
                            ]
                        })
                    ): null,
                    checkShowConditionsFromVal(val, showOptions)['Скрывать строки с нулевым значением в основной таблице'] ? (
                        Multitable.HideMainEmptyValues({
                            children: [
                                Checkbox({
                                    value: val.hide_main_empty_values,
                                    onchange: function () {},
                                    onclick: function (e) {
                                        raise(BLOCK_WIZ_HIDE_MAIN_EMPTY_VALUES, {
                                            blkid: id,
                                            value: e.target.checked ? "yes" : "no",
                                        });
                                    },
                                }),
                            ]
                        })
                    ): null,
                    checkShowConditionsFromVal(val, showOptions)['Ширина блока'] ? (
                        Multitable.WidthRow({
                            children: [
                                Multitable.WidthSelect({
                                    options: Multitable.WidthSelect.Options(val)
                                })
                            ]
                        })
                    ): null,
                    checkShowConditionsFromVal(val, showOptions)['Использовать записи'] ? (
                        Multitable.UseRecordsRow({
                            children: StatusCheckboxes({ 
                                blkid: id, 
                                value: val.use_status 
                            })
                        })
                    ): null,
                    checkShowConditionsFromVal(val, showOptions)['Настройка столбцов'] ? (
                        Multitable.ColumnSettingsRow({
                            children: [
                                val.columns.map((column, index) => 
                                    m(columnRowWizTableSettings, { 
                                        key: column.id, 
                                        col: column, 
                                        blkid: id, 
                                        table: val.use_table,
                                        disabled: {
                                            hidden: index === 0
                                        },
                                    })
                                ),
                            ]
                        })
                    ): null,
                    checkShowConditionsFromVal(val, showOptions)['Ссылки'] ? (
                        Multitable.LinksRow({
                            children: [
                                Select({ 
                                    width: 200, 
                                    onchange: { 
                                        action: BLOCK_WIZ_SET_LINKS, 
                                        payload: { blkid: id } 
                                    },
                                    children: LINKS_STATUS.map((linkStatus) => 
                                        SelectOption({ 
                                            value: linkStatus.value, 
                                            selected: val.use_links == linkStatus.value, 
                                            children: linkStatus.label
                                        })
                                    )
                                }),
                            ]
                        })
                    ): null,
                    checkShowConditionsFromVal(val, showOptions)['Выравнивание'] ? (
                        Multitable.AlignmentRow({
                            children: [
                                Select({ 
                                    width: 200, 
                                    onchange: { action: BLOCK_WIZ_ALIGNMENT, payload: { blkid: id } },
                                    children: ALIGNMENT.map((align) => 
                                        SelectOption({ 
                                            value: align.value, 
                                            selected: val.alignment == align.value, 
                                            children: align.label})
                                    )
                                }),
                            ]
                        })
                    ): null,
                    checkShowConditionsFromVal(val, showOptions)['Выводить дополнительные действия'] ? (
                        Multitable.ShowAdditionalActionsRow({
                            children: [
                                Select({ 
                                    width: 200, 
                                    onchange: { action: BLOCK_WIZ_ADDITIONAL_ACTIONS, payload: { blkid: id } },
                                    children: [
                                        SelectOption({ 
                                            value: 0, 
                                            selected: val.show_additional_actions == 0, 
                                            children: lang["Hover_over_a_line"],
                                        }),
                                        SelectOption({ 
                                            value: 1, 
                                            selected: val.show_additional_actions == 1,
                                            children: lang["Always"]
                                        }),
                                        SelectOption({  
                                            value: 2, 
                                            selected: val.show_additional_actions == 2,
                                            children: lang["In_the_context_menu"],
                                        }),
                                    ]
                                }),
                            ]
                        })
                    ): null,
                    checkShowConditionsFromVal(val, showOptions)['Лимит строк'] ? (
                        Multitable.LineLimitRow({
                            children: [
                                InputText({
                                    value: val.limit,
                                    width: 35,
                                    onchange: { action: BLOCK_WIZ_SET_LIMIT, payload: { blkid: id } },
                                }),
                            ]
                        })
                    ): null,
                    checkShowConditionsFromVal(val, showOptions)['Выводить количество строк'] ? (
                        Multitable.ShowLinesCountRow({
                            children: [
                                Checkbox({
                                    value: val.showCount,
                                    onchange: { 
                                        action: BLOCK_WIZ_SHOW_ROWS_COUNT, 
                                        payload: { blkid: id } 
                                    },
                                }),
                            ]
                        })
                    ): null,

                  // Настройка дополнительных таблиц
                  val.tables.map((table, index) => {
                      return m.fragment({}, [
                          m("br"),
                          // Выбор доп таблиц
                          m(interfaceRow, { label: lang["Additional_table"], help: "rb_Table" }, [
                              // Кнопка удаления дополнительной таблицы
                              m('img.alpiction[src=images/b_drop.png]', {
                                  onclick: function() {
                                      val.tables.splice(index, 1);
                                      m.redraw();
                                  },
                                  style: 'margin-right: 10px; cursor: pointer;'
                              }),
                              m(
                                  selectee,
                                  {
                                      width: 250,
                                      onchange: {
                                          action: BLOCK_WIZ_SET_TABLE,
                                          payload: { blkid: id, index },
                                      },
                                  },
                                  MD.getUpdatedTableList(val, MD)
                                      .filter((i) =>
                                        i.id !== val.use_table /* Закомментировал, так как возникает проблема - не выводится выбранная в настройках таблица (так как она исключается)
                                        && // исключаем основную таблицу
                                        !val.tables.some((table) => table.use_table === i.id) // исключаем уже выбранные дополнительные таблицы
                                        */
                                      )
                                      .map(function (i) {
                                          return m("option", { value: i.id, selected: table.use_table == i.id }, i.name);
                                      })
                              ),
                              table.use_table ? m(gear, { href: "edit_field.php?table=" + MD.ti(table.use_table, "id"), title: lang["Table_settings"] }) : null,
                          ]),
                          // Выбор поля группировки
                          table.use_table
                              ? m(interfaceRow, { label: lang["Additional_grouping_field"], help: "rb_Additional_grouping_field", style: "margin-bottom: 20px !important;" }, [
                                    m(columnRowWizTable, {
                                        key: table.columns[0].id,
                                        col: {
                                            id: table.columns[0].id,
                                            field: table.columns[0].field,
                                            expr: table.columns[0].expr,
                                            filter: table.columns[0].filter,
                                            name: table.columns[0].name,
                                            format: table.columns[0].format,
                                            hidden: table.columns[0].hidden,
                                            group: "yes",
                                            sort: table.columns[0].sort,
                                            title: table.columns[0].title,
                                            output: table.columns[0].output,
                                            total: table.columns[0].total,
                                        },
                                        blkid: id,
                                        additional_table: table,
                                        table: table.use_table,
                                        has_available_aa: false, // отключить AA для поля группировки
                                        group_field: getGroupField(table),
                                        kind_of_period: val.kind_of_period,
                                        is_additional_grouping: true,
                                        is_multitable: true,
                                        index,
                                    }),
                                ])
                              : null,

                          // Настройка столбцов для дополнительной таблицы
                          table.use_table
                              ? m(interfaceRow, { label: lang["Columns"], help: "rb_Columns" }, [
                                    m(dragZone, { onmove: { action: BLOCK_WIZ_COLUMN_MOVE, payload: { blkid: id, index } } }, [
                                        table.columns.slice(1).map(function (i) {
                                            return m(columnRowWizTable, {
                                                key: i.id,
                                                col: i,
                                                blkid: id,
                                                additional_table: table,
                                                table: table.use_table,
                                                has_available_aa: hasAAAvailable(table.columns),
                                                group_field: getGroupField(table),
                                                kind_of_period: val.kind_of_period,
                                                is_additional_column: true,
                                                is_multitable: true,
                                                index,
                                            });
                                        }),
                                    ]),
                                    m(aee, { onclick: { action: BLOCK_WIZ_COLUMN_ADD, payload: { blkid: id, index } } }, lang["add_column"]),
                                ])
                              : null,

                          // Кнопка "Показать/скрыть параметры" для дополнительной таблицы
                          table.use_table
                              ? m(interfaceRow, { label: "" }, [
                                    m(
                                        aee,
                                        {
                                            onclick: function () {
                                                table.showOptions = !table.showOptions;
                                            },
                                        },
                                        table.showOptions ? lang["Hide"] : lang["Additional"] + "..."
                                    ),
                                ])
                              : null,

                          // Связанные общие параметры для дополнительной таблицы
                          table.use_table && table.showOptions && prms.length > 0
                              ? m(interfaceRow, { label: lang["Link_shared_param"], help: "rb_Link_shared_param" }, [
                                    prms.map(function (item) {
                                        return m(parameterLinkRow, {
                                            blkid: id,
                                            table: table.use_table,
                                            item: item,
                                            link: table.paralink[item.name],
                                            index,
                                        });
                                    }),
                                ])
                              : null,

                          // Фильтр для дополнительной таблицы
                          table.use_table && table.showOptions
                              ? m(interfaceRow, { label: lang["Filter"], help: "rb_Filter" }, [
                                    m(
                                        selectee,
                                        {
                                            width: 250,
                                            onchange: {
                                                action: BLOCK_WIZ_SET_FILTER,
                                                payload: { blkid: id, index },
                                            },
                                        },
                                        MD.getFilterList(table.use_table).map(function (i) {
                                            return m("option", { value: i.id, selected: table.use_filter == i.id }, i.parent + i.name);
                                        })
                                    ),
                                    m(gear, { href: "edit_filter.php?table=" + MD.ti(table.use_table, "id"), title: lang["Filter_settings"] }),
                                ])
                              : null,

                          // Используйте параметры записей для дополнительной таблицы
                          table.use_table && table.showOptions
                              ? m(interfaceRow, { label: lang["Use_records"], help: "rb_Use_records" }, [
                                    m(statusCheckSet, {
                                        blkid: id,
                                        value: table.use_status,
                                        index,
                                    }),
                                ])
                              : null,
                          // Настройки столбцов для дополнительной таблицы
                          table.use_table && table.showOptions
                              ? m(interfaceRow, { label: lang["Column_settings"], help: "rb_Column_settings" }, [
                                    table.columns.map(function (column, tableIndex) {
                                        return m(columnRowWizTableSettings, {
                                            key: column.id,
                                            col: column,
                                            blkid: id,
                                            table: table.use_table,
                                            index,
                                            disabled: {
                                                hidden: tableIndex === 0
                                            },
                                        });
                                    }),
                                ])
                              : null,
                        ]);
                  }),
                  // Кнопка "Добавить таблицу"
                  val.use_table
                      ? m(interfaceRow, { label: "" }, [
                            m("br"),
                            m(
                                aee,
                                {
                                    onclick: function () {
                                        val.tables.push({
                                            use_table: "",
                                            grouping_field: "",
                                            columns: [wizNewColumn(wizNextName("S", val.columns, val))],
                                            use_filter: "",
                                            use_status: "active",
                                            paralink: {},
                                            showOptions: false,
                                        });
                                    },
                                },
                                lang["Add_table"]
                            ),
                        ])
                      : null
              ]});
          },
          /**
          * @deprecated старая реализация viewAsDetails()
          */
          old_viewAsDetails: function () {
              var prms = dataParams();
              val.main_grouping_field = MAIN_GROUP ? MAIN_GROUP.field : '';
              return m(
                  detailsBlock,
                  { title: buildItemTitle(lang["Multitable"], val.caption, MD.getTableName(val.use_table)) },
                  val.use_table ? m(interfaceRow, { label: lang["Title"], help: "rb_Table_title" }, [m(inputText, { value: val.caption, width: 260, onchange: { action: BLOCK_WIZ_SET_CAPTION, payload: { blkid: id } } }, null)]) : null,
                  // Выбор основной таблицы
                  m(interfaceRow, { label: lang["Main_table"], help: "rb_Table" }, [
                      m(
                          selectee,
                          {
                              width: 250,
                              onchange: {
                                  action: BLOCK_WIZ_SET_TABLE,
                                  payload: { blkid: id },
                              },
                          },
                          MD.getUpdatedTableList(val, MD)
                          .filter((i) =>
                            !val.tables.some((table) => table.use_table === i.id)
                          )
                          .map(function (i) {
                              return m("option", { value: i.id, selected: val.use_table == i.id }, i.name);
                          })
                      ),
                      val.use_table ? m(gear, { href: "edit_field.php?table=" + MD.ti(val.use_table, "id"), title: lang["Table_settings"] }) : null,
                  ]),
                  // Основное поле группировки
                  val.use_table
                      ? m(interfaceRow, { label: lang["Main_grouping_field"], help: "rb_Main_grouping_field" }, [
                            m(columnRowWizTable, {
                                key: val.columns[0].id,
                                col: {
                                    id: val.columns[0].id,
                                    field: val.columns[0].field,
                                    expr: val.columns[0].expr,
                                    filter: val.columns[0].filter,
                                    name: val.columns[0].name,
                                    format: val.columns[0].format,
                                    hidden: "yes",
                                    group: "yes",
                                    sort: val.columns[0].sort,
                                    title: val.columns[0].title,
                                    output: val.columns[0].output,
                                    total: val.columns[0].total,
                                },
                                blkid: id,
                                table: val.use_table,
                                has_available_aa: hasAAAvailable(val.columns),
                                group_field: getGroupField(val),
                                kind_of_period: val.kind_of_period,
                                main_group: (MAIN_GROUP = { ...getGroupField(val), use_table: val.use_table }),
                                is_main_grouping: true,
                                is_multitable: true,
                            }),
                        ])
                      : null,

                  // Настройка столбцов для основной таблицы
                  val.use_table
                      ? m(interfaceRow, { label: lang["Columns"], help: "rb_Columns" }, [
                            m(dragZone, { onmove: { action: BLOCK_WIZ_COLUMN_MOVE, payload: { blkid: id } } }, [
                                val.columns.slice(1).map(function (i) {
                                    return m(columnRowWizTable, {
                                        key: i.id,
                                        col: i,
                                        blkid: id,
                                        table: val.use_table,
                                        has_available_aa: hasAAAvailable(val.columns),
                                        group_field: getGroupField(val),
                                        kind_of_period: val.kind_of_period,
                                        is_multitable: true,
                                    });
                                }),
                            ]),
                            m(aee, { onclick: { action: BLOCK_WIZ_COLUMN_ADD, payload: { blkid: id } } }, lang["add_column"]),
                        ])
                      : null,
                  // 	Дополнительно...
                  val.use_table ? m(interfaceRow, { label: "" }, [m(aee, { onclick: { action: BLOCK_WIZ_SHOW_OPTIONS, payload: { blkid: id, show: !showOptions } } }, showOptions ? lang["Hide"] : lang["Additional"] + "...")]) : null,
                  val.use_table && showOptions && prms.length > 0
                      ? m(interfaceRow, { label: lang["Link_shared_param"], help: "rb_Link_shared_param" }, [
                            prms.map(function (item) {
                                return m(parameterLinkRow, { blkid: id, table: val.use_table, item: item, link: val.paralink[item.name] });
                            }),
                        ])
                      : null,
                  val.use_table && showOptions
                      ? m(interfaceRow, { label: lang["Filter"], help: "rb_Filter" }, [
                            m(
                                selectee,
                                { width: 250, onchange: { action: BLOCK_WIZ_SET_FILTER, payload: { blkid: id } } },
                                MD.getFilterList(val.use_table).map(function (i) {
                                    return m("option", { value: i.id, selected: val.use_filter == i.id }, i.parent + i.name);
                                })
                            ),
                            m(gear, { href: "edit_filter.php?table=" + MD.ti(val.use_table, "id"), title: lang["Filter_settings"] }),
                        ])
                      : null,
                    val.use_table && showOptions && getGroupField(val).type != void 0 && (
                        getGroupField(val).type == 2 || 
                        getGroupField(val).type == 11 || 
                        getGroupField(val).type == 12 || 
                        getGroupField(val).type == 13 || 
                        getGroupField(val).type == 4 || 
                        getGroupField(val).type == 7 || 
                        getGroupField(val).type == 5
                    )
                      ? m(interfaceRow, { label: lang["Show_empty_values"], help: "rb_Show_empty_values" }, [
                            m(inputChecker, {
                                value: val.show_empty_values,
                                disabled: val.show_empty_groups == "nope",
                                onchange: function () {},
                                onclick: function (e) {
                                    if (e.ctrlKey) {
                                        raise(BLOCK_WIZ_SHOW_EMPTY_GROUPS, {
                                            blkid: id,
                                            value: "nope",
                                        });
                                    } else {
                                        raise(BLOCK_WIZ_SHOW_EMPTY_VALUES, {
                                            blkid: id,
                                            value: e.target.checked ? "yes" : "no",
                                        });
                                    }
                                },
                            }),
                            m(
                                `span[style=display:inline-block;color:gray;font-family:monospace;cursor:pointer;vertical-align:middle;visibility:${val.show_empty_groups == "nope" ? "visible" : "hidden"};]`,
                                {
                                    title: lang["Quasi_off"],
                                    onclick: function () {
                                        raise(BLOCK_WIZ_SHOW_EMPTY_GROUPS, {
                                            blkid: id,
                                            value: "yes",
                                        });
                                    },
                                },
                                lang["Quasi_off"]
                            ),
                        ])
                      : null,
                    val.show_empty_values === "no" && val.use_table && showOptions && getGroupField(val).type != void 0 && (
                        getGroupField(val).type == 2 || 
                        getGroupField(val).type == 11 || 
                        getGroupField(val).type == 12 || 
                        getGroupField(val).type == 13 || 
                        getGroupField(val).type == 4 || 
                        getGroupField(val).type == 7 || 
                        getGroupField(val).type == 5
                    )
                      ? m(interfaceRow, { label: lang["Hide_main_empty_values"], help: "rb_Hide_main_empty_values" }, [
                            m(inputChecker, {
                                value: val.hide_main_empty_values,
                                onchange: function () {},
                                onclick: function (e) {
                                    raise(BLOCK_WIZ_HIDE_MAIN_EMPTY_VALUES, {
                                        blkid: id,
                                        value: e.target.checked ? "yes" : "no",
                                    });
                                },
                            }),
                        ])
                      : null,
                  val.use_table && showOptions
                      ? m(interfaceRow, { label: lang["Width_block"], help: "rb_Table_width", key: id + "cap" }, [
                            m(
                                selectee,
                                { width: 250, onchange: { action: BLOCK_WIZ_SET_WIDTH, payload: { blkid: id } } },
                                KIND_OF_WIDTH.map(function (i) {
                                    return m("option", { value: i.value, selected: val.width == i.value }, i.label);
                                })
                            ),
                        ])
                      : null,
                  val.use_table && showOptions ? m(interfaceRow, { label: lang["Use_records"], help: "rb_Use_records" }, [m(statusCheckSet, { blkid: id, value: val.use_status })]) : null,
                  val.use_table && showOptions
                      ? m(interfaceRow, { label: lang["Column_settings"], help: "rb_Column_settings" }, [
                            val.columns.map(function (i) {
                                return m(columnRowWizTableSettings, { key: i.id, col: i, blkid: id, table: val.use_table });
                            }),
                        ])
                      : null,
                  val.use_table && showOptions
                      ? m(interfaceRow, { label: lang["Links"], help: "rb_Links" }, [
                            m(
                                selectee,
                                { width: 200, onchange: { action: BLOCK_WIZ_SET_LINKS, payload: { blkid: id } } },
                                LINKS_STATUS.map(function (i) {
                                    return m("option", { value: i.value, selected: val.use_links == i.value }, i.label);
                                })
                            ),
                        ])
                      : null,
                  val.use_table && showOptions
                      ? m(interfaceRow, { label: lang["Alignment"], help: "rb_Alignment" }, [
                            m(
                                selectee,
                                { width: 200, onchange: { action: BLOCK_WIZ_ALIGNMENT, payload: { blkid: id } } },
                                ALIGNMENT.map(function (i) {
                                    return m("option", { value: i.value, selected: val.alignment == i.value }, i.label);
                                })
                            ),
                        ])
                      : null,
                  val.use_table && showOptions && checkAvailabilityAA()
                      ? m(interfaceRow, { label: lang["Show_additional_actions"], help: "Additional_actions" }, [
                            m(selectee, { width: 200, onchange: { action: BLOCK_WIZ_ADDITIONAL_ACTIONS, payload: { blkid: id } } }, [
                                m("option", { value: 0, selected: val.show_additional_actions == 0 }, lang["Hover_over_a_line"]),
                                m("option", { value: 1, selected: val.show_additional_actions == 1 }, lang["Always"]),
                                m("option", { value: 2, selected: val.show_additional_actions == 2 }, lang["In_the_context_menu"]),
                            ]),
                        ])
                      : null,
                  val.use_table && showOptions
                      ? m(interfaceRow, { label: lang["Line_limit"], help: "rb_Line_limit" }, [
                            m(inputText, {
                                value: val.limit,
                                width: 35,
                                onchange: { action: BLOCK_WIZ_SET_LIMIT, payload: { blkid: id } },
                            }),
                        ])
                      : null,
                  val.use_table && showOptions
                      ? m(interfaceRow, { label: lang["Show_lines_count"], help: "Show_lines_count" }, [
                            m(inputChecker, {
                                value: val.showCount,
                                onchange: { action: BLOCK_WIZ_SHOW_ROWS_COUNT, payload: { blkid: id } },
                            }),
                        ])
                      : null,

                  // Настройка дополнительных таблиц
                  val.tables.map((table, index) => {
                      return m.fragment({}, [
                          m("br"),
                          // Выбор доп таблиц
                          m(interfaceRow, { label: lang["Additional_table"], help: "rb_Table" }, [
                              // Кнопка удаления дополнительной таблицы
                              m('img.alpiction[src=images/b_drop.png]', {
                                  onclick: function() {
                                      val.tables.splice(index, 1);
                                      m.redraw();
                                  },
                                  style: 'margin-right: 10px; cursor: pointer;'
                              }),
                              m(
                                  selectee,
                                  {
                                      width: 250,
                                      onchange: {
                                          action: BLOCK_WIZ_SET_TABLE,
                                          payload: { blkid: id, index },
                                      },
                                  },
                                  MD.getUpdatedTableList(val, MD)
                                      .filter((i) =>
                                        i.id !== val.use_table && // исключаем основную таблицу
                                        !val.tables.some((table) => table.use_table === i.id) // исключаем уже выбранные дополнительные таблицы
                                      )
                                      .map(function (i) {
                                          return m("option", { value: i.id, selected: table.use_table == i.id }, i.name);
                                      })
                              ),
                              table.use_table ? m(gear, { href: "edit_field.php?table=" + MD.ti(table.use_table, "id"), title: lang["Table_settings"] }) : null,
                          ]),
                          // Выбор поля группировки
                          table.use_table
                              ? m(interfaceRow, { label: lang["Additional_grouping_field"], help: "rb_Additional_grouping_field", style: "margin-bottom: 20px !important;" }, [
                                    m(columnRowWizTable, {
                                        key: table.columns[0].id,
                                        col: {
                                            id: table.columns[0].id,
                                            field: table.columns[0].field,
                                            expr: table.columns[0].expr,
                                            filter: table.columns[0].filter,
                                            name: table.columns[0].name,
                                            format: table.columns[0].format,
                                            hidden: table.columns[0].hidden,
                                            group: "yes",
                                            sort: table.columns[0].sort,
                                            title: table.columns[0].title,
                                            output: table.columns[0].output,
                                            total: table.columns[0].total,
                                        },
                                        blkid: id,
                                        additional_table: table,
                                        table: table.use_table,
                                        has_available_aa: false, // отключить AA для поля группировки
                                        group_field: getGroupField(table),
                                        kind_of_period: val.kind_of_period,
                                        is_additional_grouping: true,
                                        is_multitable: true,
                                        index,
                                    }),
                                ])
                              : null,

                          // Настройка столбцов для дополнительной таблицы
                          table.use_table
                              ? m(interfaceRow, { label: lang["Columns"], help: "rb_Columns" }, [
                                    m(dragZone, { onmove: { action: BLOCK_WIZ_COLUMN_MOVE, payload: { blkid: id, index } } }, [
                                        table.columns.slice(1).map(function (i) {
                                            return m(columnRowWizTable, {
                                                key: i.id,
                                                col: i,
                                                blkid: id,
                                                additional_table: table,
                                                table: table.use_table,
                                                has_available_aa: hasAAAvailable(table.columns),
                                                group_field: getGroupField(table),
                                                kind_of_period: val.kind_of_period,
                                                is_additional_column: true,
                                                is_multitable: true,
                                                index,
                                            });
                                        }),
                                    ]),
                                    m(aee, { onclick: { action: BLOCK_WIZ_COLUMN_ADD, payload: { blkid: id, index } } }, lang["add_column"]),
                                ])
                              : null,

                          // Кнопка "Показать/скрыть параметры" для дополнительной таблицы
                          table.use_table
                              ? m(interfaceRow, { label: "" }, [
                                    m(
                                        aee,
                                        {
                                            onclick: function () {
                                                table.showOptions = !table.showOptions;
                                            },
                                        },
                                        table.showOptions ? lang["Hide"] : lang["Additional"] + "..."
                                    ),
                                ])
                              : null,

                          // Связанные общие параметры для дополнительной таблицы
                          table.use_table && table.showOptions && prms.length > 0
                              ? m(interfaceRow, { label: lang["Link_shared_param"], help: "rb_Link_shared_param" }, [
                                    prms.map(function (item) {
                                        return m(parameterLinkRow, {
                                            blkid: id,
                                            table: table.use_table,
                                            item: item,
                                            link: table.paralink[item.name],
                                            index,
                                        });
                                    }),
                                ])
                              : null,

                          // Фильтр для дополнительной таблицы
                          table.use_table && table.showOptions
                              ? m(interfaceRow, { label: lang["Filter"], help: "rb_Filter" }, [
                                    m(
                                        selectee,
                                        {
                                            width: 250,
                                            onchange: {
                                                action: BLOCK_WIZ_SET_FILTER,
                                                payload: { blkid: id, index },
                                            },
                                        },
                                        MD.getFilterList(table.use_table).map(function (i) {
                                            return m("option", { value: i.id, selected: table.use_filter == i.id }, i.parent + i.name);
                                        })
                                    ),
                                    m(gear, { href: "edit_filter.php?table=" + MD.ti(table.use_table, "id"), title: lang["Filter_settings"] }),
                                ])
                              : null,

                          // Используйте параметры записей для дополнительной таблицы
                          table.use_table && table.showOptions
                              ? m(interfaceRow, { label: lang["Use_records"], help: "rb_Use_records" }, [
                                    m(statusCheckSet, {
                                        blkid: id,
                                        value: table.use_status,
                                        index,
                                    }),
                                ])
                              : null,
                          // Настройки столбцов для дополнительной таблицы
                          table.use_table && table.showOptions
                              ? m(interfaceRow, { label: lang["Column_settings"], help: "rb_Column_settings" }, [
                                    table.columns.map(function (i) {
                                        return m(columnRowWizTableSettings, {
                                            key: i.id,
                                            col: i,
                                            blkid: id,
                                            table: table.use_table,
                                            index,
                                        });
                                    }),
                                ])
                              : null,
                        ]);
                  }),
                  // Кнопка "Добавить таблицу"
                  val.use_table
                      ? m(interfaceRow, { label: "" }, [
                            m("br"),
                            m(
                                aee,
                                {
                                    onclick: function () {
                                        val.tables.push({
                                            use_table: "",
                                            grouping_field: "",
                                            columns: [wizNewColumn(wizNextName("S", val.columns, val))],
                                            use_filter: "",
                                            use_status: "active",
                                            paralink: {},
                                            showOptions: false,
                                        });
                                    },
                                },
                                lang["Add_table"]
                            ),
                        ])
                      : null
              );
          },
      };
  }


    function PaperBlockWizText(yaml,prnt) {
        var supra = prnt, id = genid();
        var initval = yaml || {type:'block_wiz_text',caption:'',width:'33',description:'',image:'',image_href:''};
        var val = {
            type:   'block_wiz_text',
            caption: initval.caption || '',
            width: initval.width && KIND_OF_WIDTH.map(i => i.value).includes(initval.width) ? initval.width : '33',
            //block_height: initval.block_height || 'stretch',
            image: initval.image || '',
            image_href: initval.image_href || '',
            description: initval.description || '',
            preview_width: '150',
        };
        function blockStyling() {
            var props = '';
            var w = parseInt(val.width);
            if (w>0 && w<=100) {
                props += ' flex:0 0 calc(' + w + '% - 10px);';
            }
            var o = parseInt(val.order);
            if (!isNaN(o)) {
                props += 'order:' + o + ';';
            }
            return props+'';
        }
        function getPaper() { return val; }
        var dispatch = function (action,payload) {
            switch (action) {
                case ADD_LAYOUT_ITEM:
                    if (payload.parent_id==id) layout.push(PaperLayoutItem({type:payload.item_type},{id:id}));
                    break;
                case DELETE_LAYOUT_ITEM:
                    if (payload.item_id==id) Dispatcher.unregister(dispatch);
                    break;
                case BLOCK_WIZ_SET_CAPTION:
                    if (payload.blkid!=id) break;
                    val.caption = payload.value;
                    break;
                case BLOCK_WIZ_SET_DESCRIPTION:
                    if (payload.blkid!=id) break;
                    val.description = payload.value;
                    break;
                case BLOCK_WIZ_SET_IMAGE:
                    if (payload.blkid!=id) break;
                    val.image = payload.value;
                    val.preview_width = payload.width || '150';
                    break;
                case BLOCK_WIZ_SET_IMAGE_HREF:
                    if (payload.blkid!=id) break;
                    val.image_href = payload.value;
                    break;
                case BLOCK_WIZ_SET_WIDTH:
                    if (payload.blkid==id) val.width = payload.value;
                    break;
                // case BLOCK_WIZ_SET_BLOCK_HEIGHT:
                //     if (payload.blkid!=id) break;
                //     val.block_height = payload.value; break;
                default:
                    break;
            }
        }
        Dispatcher.register(dispatch);

        return {
            id: function(){ return id; },
            copyObject: function(){ return PaperBlockWizText(getPaper(),prnt); },
            canBeDeleted: function() { return true; },
            getPaper: function() { return getPaper() },
            getView: function() {
                return m('div.yamlview__block#'+id+'[style='+blockStyling()+']', [
                    m('div.yamlview__block_inner[style=position:relative]','BLOCK_TABLE')
                ]);
            },
            viewAsListItem: function() {
                return m(listItem,{
                    caption: buildItemTitle(lang['text-block'],val.caption,""),
                    item_id: id,
                    parent_id: supra.id,
                    key: id,
                })
            },
            viewAsDetails: function() {
                var prms = dataParams();
                return m(detailsBlock,{title:buildItemTitle(lang['text-block'],val.caption,"")},/*FIXME*/
                    m(interfaceRow,{label:lang['Title'],help:'rb_Table_title',key:id+'cap'}, [
                        m(inputText,{value:val.caption,width:260,onchange:{action:BLOCK_WIZ_SET_CAPTION,payload:{blkid:id}}},null),
                    ]),
                    m(interfaceRow,{label:lang['Image'],help:'rb_Image_TextBlock',key:id+'img'}, [
                        m(inputFile,{value:val.image,width:260,preview_width:val.preview_width,onchange:{action:BLOCK_WIZ_SET_IMAGE,payload:{blkid:id}}},null),
                    ]),
                    m(interfaceRow,{label:lang['Link'],help:'rb_Image_Link_TextBlock',key:id+'img_lnk'}, [
                        m(inputText,{value:val.image_href,width:260,onchange:{action:BLOCK_WIZ_SET_IMAGE_HREF,payload:{blkid:id}}},null),
                    ]),
                    m(interfaceRow,{label:lang['Description'],help:'rb_Description',key:id+'dsc'}, [
                        m(inputText,{value:val.description,width:260,onchange:{action:BLOCK_WIZ_SET_DESCRIPTION,payload:{blkid:id}}},null),
                    ]),
                    m(interfaceRow,{label:lang['Width_block'],help:'rb_Table_width',key:id+'cap'}, [
                        m(selectee,{width:250,onchange:{action:BLOCK_WIZ_SET_WIDTH,payload:{blkid:id}}},
                            KIND_OF_WIDTH.map(function(i){
                                return m('option',{value:i.value,selected:(val.width==i.value)},i.label)
                            })
                        ),
                    ]),
                );
            },
        }
    }

    function PaperBlockWizCharts(yaml,prnt) {
        var supra = prnt, id = genid();
        var initval = yaml || {type:'block_wiz_chart',width:'100%',order:0,axis:[],lines:[]};
        var val = {
            type:   'block_wiz_chart',
            width:  initval.width && KIND_OF_WIDTH.map(i => i.value).includes(initval.width) ? initval.width : '100',
            order:  initval.order || 0,
            caption: initval.caption || '',
            limit: initval.limit || 365,
            chart_type: initval.chart_type || 'linear',
            chart_legend: initval.chart_legend || 'none',
            show_chart_3d: initval.show_chart_3d || 'no',
            orientation: initval.orientation || 'vertical',
            inner_circle_size: initval.inner_circle_size || 'medium',
            show_total_value: initval.show_total_value || 'no',
            show_empty_values: initval.show_empty_values || 'yes',
            show_empty_groups: initval.show_empty_groups || 'yes',
            kind_of_period: initval.kind_of_period || 'day',
            use_table: MD.getTableId(initval.use_table || ''),
            use_filter: initval.use_filter || '',
            use_status: initval.use_status || 'active',
            paralink: initval.paralink || {},
            color: initval.color || '',
            use_links: initval.use_links || 'yes',  
          hideEmptyValues: initval.hideEmptyValues || 0,
        };
        val.axis = wizColumnsInitial(val.use_table, initval.axis);
        if(val.axis.length == 0) wizAxisAdd(val.use_table, val.axis);
        val.lines = wizColumnsInitial(val.use_table, initval.lines, val.axis);
        var showOptions = false;
        function blockStyling() {
            var props = '';
            var w = parseInt(val.width);
            if (w>0 && w<=100) {
                props += ' flex:0 0 calc(' + w + '% - 10px);';
            }
            var o = parseInt(val.order);
            if (!isNaN(o)) {
                props += 'order:' + o + ';';
            }
            return props+'';
        }
        /** 
         * @fixme Эта функция мутирует объекты, удаляя в них id,
         * это может вызвать неожиданные баги. Необходимо это исправить
        */
        function getPaper() {
            val.lines = val.lines.map(function(i){delete i.id; return i;});
            var cleanlink = {};
            dataParams().forEach(function(i){ if (val.paralink.hasOwnProperty(i.name)) cleanlink[i.name] = val.paralink[i.name]; });
            val.paralink = cleanlink;
            return val;
        }
        /** 
         * @fixme Эта функция использует getPaper который мутирует 
         * копируемые объекты, удаляя в них id,
         * это может вызвать неожиданные баги. Необходимо это исправить
        */
        function getPaperForCopy() {
            let value = getPaper();
            let data = {};

            for(let key in value){
                data[key] = value[key];
            }

            data.axis = copyObjectData(value.axis);
            data.lines = copyObjectData(value.lines);

            var cleanlink = {};
            dataParams().forEach(function(i){ if (value.paralink.hasOwnProperty(i.name)) cleanlink[i.name] = value.paralink[i.name]; });
            data.paralink = cleanlink;

            return data;
        }
        function checkAvailablestKindOfPeriod() {
            let type = MD.getFieldInfo(val.use_table, val.axis[0].field.split('|')[1]).type;
            return val.axis[0].field == 'field|' || val.axis[0].field == 'expr|' ? false : (type == 2 || type == 12);
        }
        function checkAllowLimit() {
            if(val.axis[0].field == 'field|') return false;

            let type_axis_field = MD.getFieldInfo(val.use_table, val.axis[0].field.split('|')[1]).type,
                field = val.axis[0].field.split('|')[1],
                is_parametr_bound = false;

            for(let param in val.paralink){
                if(val.paralink[param] == field){
                    is_parametr_bound = true;
                    break;
                }
            }


            if(
                (!is_parametr_bound && val.show_empty_groups == 'nope') ||
                (
                    (type_axis_field == 2 || type_axis_field == 12) &&
                    (val.show_empty_groups == 'yes' || val.show_empty_groups == 'no') &&
                    !is_parametr_bound
                )
            ){
                if(val.limit == "") raise(BLOCK_WIZ_SET_LIMIT, {blkid: id, value: "5"});
                return true;
            }

            raise(BLOCK_WIZ_SET_LIMIT, {blkid: id, value: ""});

            return false;

        }
        function checkAllowLimit() {
            if(val.axis[0].field == 'field|') return false;

            let type_axis_field = MD.getFieldInfo(val.use_table, val.axis[0].field.split('|')[1]).type,
                field = val.axis[0].field.split('|')[1],
                is_parametr_bound = false;

            for(let param in val.paralink){
                if(val.paralink[param] == field){
                    is_parametr_bound = true;
                    break;
                }
            }


            if(
                (!is_parametr_bound && val.show_empty_groups == 'nope') ||
                (
                    (type_axis_field == 2 || type_axis_field == 12) &&
                    (val.show_empty_groups == 'yes' || val.show_empty_groups == 'no') &&
                    !is_parametr_bound
                )
            ){
                if(val.limit == "") raise(BLOCK_WIZ_SET_LIMIT, {blkid: id, value: "5"});
                return true;
            }

            raise(BLOCK_WIZ_SET_LIMIT, {blkid: id, value: ""});

            return false;

        }
        var dispatch = function (action,payload) {
            switch (action) {
                case BLOCK_WIZ_SET_WIDTH:
                    if (payload.blkid==id) val.width = payload.value;
                    break;
                case ADD_LAYOUT_ITEM:
                    if (payload.parent_id==id) layout.push(PaperLayoutItem({type:payload.item_type},{id:id}));
                    break;
                case DELETE_LAYOUT_ITEM:
                    if (payload.item_id==id) Dispatcher.unregister(dispatch);
                    break;
                case BLOCK_WIZ_SET_TABLE:
                    if (payload.blkid!=id) break;
                    if (val.use_table==payload.value) break;
                    val.use_table = payload.value;
                    val.use_filter = '';
                    val.use_status = 'active';
                    val.axis = [];
                    val.lines = [];
                    wizAxisAdd(val.use_table, val.axis);
                    wizLineAdd(val.use_table, val.lines, val.axis);
                    break;
                case BLOCK_WIZ_SET_FILTER:
                    if (payload.blkid!=id) break;
                    val.use_filter = payload.value;
                    break;
                case BLOCK_WIZ_SET_CAPTION:
                    if (payload.blkid!=id) break;
                    val.caption = payload.value;
                    break;
                case BLOCK_WIZ_SET_STATUS:
                    if (payload.blkid!=id) break;
                    val.use_status = payload.value || 'active';
                    break;
                case BLOCK_WIZ_SET_PARALINK:
                    if (payload.blkid!=id) break;
                    if (payload.value=='') delete val.paralink[payload.param]; else val.paralink[payload.param] = payload.value;
                    break;
                case BLOCK_WIZ_SET_LIMIT:
                    if (payload.blkid!=id) break;
                    val.limit = payload.value;
                    break;
                case BLOCK_WIZ_SHOW_OPTIONS:
                    if (payload.blkid!=id) break;
                    showOptions = payload.show;
                    break;
                case BLOCK_WIZ_LINE_ADD:
                    if (payload.blkid==id) wizLineAdd(val.use_table,val.lines,val.axis);
                    break;
                case BLOCK_WIZ_LINE_DELETE:
                    if (payload.blkid==id) val.lines = val.lines.filter(function(i){return i.id!=payload.colid;})
                    break;
                case BLOCK_WIZ_LINE_SET_VALUE:
                    if (payload.blkid==id) wizColumnSet(val.use_table,val.lines,payload.colid,payload.name,payload.value);
                    break;
                case BLOCK_WIZ_AXIS_SET_VALUE:
                    if (payload.blkid==id) {
                        if(payload.name == 'field' && (
                            MD.getFieldInfo(val.use_table, payload.value.split('|')[1]).type == 2 ||
                            MD.getFieldInfo(val.use_table, payload.value.split('|')[1]).type == 12
                        )) {
                            wizColumnSet(val.use_table,val.axis,payload.colid,'format','');
                            wizColumnSet(val.use_table,val.axis,payload.colid,'expr','');
                            val.paralink = {};
                        }
                        wizColumnSet(val.use_table,val.axis,payload.colid,payload.name,payload.value);
                        if(!checkAvailablestKindOfPeriod()){
                            val.kind_of_period = 'day';
                        }
                    };
                    break;
                case BLOCK_WIZ_LINE_MOVE:
                    if (payload.blkid==id) {
                        var elem = val.lines.find(function(i){return i.id==payload.element_id});
                        var res = [];
                        val.lines.forEach(function(i){
                            if (i.id==payload.element_id) return;
                            if (i.id==payload.sibling_id) {
                                res.push(elem);
                            }
                            res.push(i);
                        });
                        if (payload.sibling_id=='') {
                            res.push(elem);
                        }
                        val.lines = res;
                    };
                    break;
                case BLOCK_WIZ_SET_KIND_CHART:
                    if (payload.blkid!=id) break;
                    val.chart_type = payload.value;
                    val.orientation = 'vertical';
                    val.show_chart_3d = 'no';
                    val.inner_circle_size = 'medium';
                    val.show_total_value = 'no';
                    break;
                case BLOCK_WIZ_SET_LEGEND_CHART:
                    if (payload.blkid!=id) break;
                    val.chart_legend = payload.value;
                    break;
                case BLOCK_WIZ_SHOW_EMPTY_VALUES:
                    if (payload.blkid!=id) break;
                    val.show_empty_values = payload.value;
                    break;
                case BLOCK_WIZ_SHOW_EMPTY_GROUPS:
                    if (payload.blkid!=id) break;
                    val.show_empty_groups = payload.value;
                    break;
                case BLOCK_WIZ_KIND_OF_PERIOD:
                    if (payload.blkid!=id) break;
                    val.kind_of_period = payload.value;
                    break;
                case BLOCK_WIZ_CHART_VOLUME:
                    if (payload.blkid!=id) break;
                    val.show_chart_3d = payload.value;
                    break;
                case BLOCK_WIZ_SET_ORIENTATION:
                    if (payload.blkid!=id) break;
                    val.orientation = payload.value;
                    break;
                case BLOCK_WIZ_SET_SIZE_INNER_CIRCLE:
                    if (payload.blkid!=id) break;
                    val.inner_circle_size = payload.value;
                    break;
                case BLOCK_WIZ_SET_OUTPUT_TOTAL_VALUE:
                    if (payload.blkid!=id) break;
                    val.show_total_value = payload.value;
                    break;
                case BLOCK_WIZ_KIND_COLOR_SET:
                    if (payload.blkid!=id) break;
                    if(payload.value == 'default'){
                        val.color = '';
                    }
                    else {
                        val.color = '#969696';
                    }
                    break;
                case BLOCK_WIZ_PALETTE_COLOR_SET:
                    if (payload.blkid!=id) break;
                    val.color = payload.value;
                    break;
                case BLOCK_WIZ_SET_LINKS:
                    if (payload.blkid!=id) break;
                    val.use_links = payload.value;
                    break;
                case 'HideEmptyValues':
                  if (payload.blkid != id) break;
                  val.hideEmptyValues = payload.value;
                  break;
                  
                default:
                    break;
            }
        }
        Dispatcher.register(dispatch);

        return {
            id: function(){ return id; },
            canBeDeleted: function() { return true; },
            copyObject: function(){ return PaperBlockWizCharts(getPaperForCopy(),prnt); },
            getPaper: function() { return getPaper() },
            getView: function() {
                return m('div.yamlview__block#'+id+'[style='+blockStyling()+']', [
                    m('div.yamlview__block_inner[style=position:relative]','BLOCK_TABLE')
                ]);
            },
            viewAsListItem: function() {
                return m(listItem,{
                    caption: buildItemTitle('График',val.caption,''),
                    item_id: id,
                    parent_id: supra.id,
                    key: id,
                })
            },
            viewAsDetails: function() {
                var prms = dataParams();
                const Charts = {};
                Charts.HideEmptyBlock = ({ children }) => Row({
                  label: lang["Hide_block_with_empty_values"], 
                  help: "rb_Hide_block_with_empty_values",
                  children
                })
                
                return m(detailsBlock,{title:buildItemTitle(lang['Chart'],val.caption, '')},

                    m(interfaceRow,{label:lang['Kind_of_chart'],help:'rb_Kind_of_chart'}, [
                        m(selectee,{width:250,class:'',onchange:{action:BLOCK_WIZ_SET_KIND_CHART,payload:{blkid:id}}},
                            KIND_OF_CHARTS.map(function(i){return m('option',{value:i.value,selected:(val.chart_type==i.value)},i.label)})
                        ),
                    ]),
                    m(interfaceRow,{label:lang['Table2'],help:'rb_Table'}, [
                        m(selectee,{width:250,onchange:{action:BLOCK_WIZ_SET_TABLE,payload:{blkid:id}}},
                            MD.getTableList().map(function(i){return m('option',{value:i.id,selected:(val.use_table==i.id)},i.name)})
                        ),
                        val.use_table ? m(gear,{href:'edit_field.php?table='+MD.ti(val.use_table,'id'),title:lang['Table_settings']}) : null,
                    ]),
                    m(interfaceRow,{label:lang['Title'],help:'rb_Table_title'}, [
                        m(inputText,{value:val.caption,width:260,onchange:{action:BLOCK_WIZ_SET_CAPTION,payload:{blkid:id}}},null),
                    ]),
                    val.use_table ? m(interfaceRow,{label:lang['Grouping_field'], help:'rb_Axis'}, [
                        m(axisRowWizChart,{key:val.axis[0].id,col:val.axis[0],blkid:id,table:val.use_table,show_empty_groups:val.show_empty_groups,kind_of_period:val.kind_of_period}),
                    ]) : null,

                    val.use_table ? m(interfaceRow, {label: lang['Fields'], help: 'rb_Chart_lines'}, [
                      m(dragZone, {
                        onmove: {action: BLOCK_WIZ_LINE_MOVE, payload: {blkid: id}}
                      }, [
                        val.lines.map(function(i) {
                          return m(lineRowWizChart, {
                            key: i.id, col: i, blkid: id, table: val.use_table, axis: val.axis[0]
                          })
                        }),
                      ]),

                      // если круговая диаграмма, то только одно поле можно добавить
                      !(val.lines.length >= 1 && val.chart_type == 'pie')
                        ? m(aee, {
                          onclick: {action: BLOCK_WIZ_LINE_ADD, payload: {blkid: id}}
                        }, lang['add_column']) : null,
                    ]) : null,

                    val.use_table ? m(interfaceRow,{label:''}, [
                        m(aee,{onclick:{action:BLOCK_WIZ_SHOW_OPTIONS,payload:{blkid:id,show:!showOptions}}},showOptions?lang['Hide']:lang['Additional'] + '...'),
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Legend'],help:'rb_Legend_chart'}, [
                        m(selectee,{width:250,onchange:{action:BLOCK_WIZ_SET_LEGEND_CHART,payload:{blkid:id}}},
                            LEGEND_CHARTS.filter(item => !(['pie', 'donut'].includes(val.chart_type) && item.value == 'in')).map(function(i){return m('option',{value:i.value,selected:(val.chart_legend==i.value)},i.label)})
                        ),
                    ]) : null,
                    val.use_table && showOptions && prms.length>0 ? m(interfaceRow,{label:lang['Link_shared_param'],help:'rb_Link_shared_param'}, [
                        prms.map(function(item){
                            return m(parameterLinkRow,{blkid:id,table:val.use_table,item:item,link:val.paralink[item.name]})
                        })
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Filter'],help:'rb_Filter'}, [
                        m(selectee,{width:250,onchange:{action:BLOCK_WIZ_SET_FILTER,payload:{blkid:id}}},
                            MD.getFilterList(val.use_table).map(function(i){return m('option',{value:i.id,selected:(val.use_filter==i.id)},i.parent+i.name)})
                        ),
                        m(gear,{href:'edit_filter.php?table='+MD.ti(val.use_table,'id'),title:lang['Filter_settings']}),
                    ]) : null,
                    val.use_table && showOptions  ? m(interfaceRow,{label:lang['Width_block'],help:'rb_Table_width',key:id+'cap'}, [
                        m(selectee,{width:250,onchange:{action:BLOCK_WIZ_SET_WIDTH,payload:{blkid:id}}},
                            KIND_OF_WIDTH.map(function(i){
                                return m('option',{value:i.value,selected:(val.width==i.value)},i.label)
                            })
                        ),
                    ]) : null,
                    val.use_table && showOptions
                    ? Charts.HideEmptyBlock({
                        children: [
                          Checkbox({
                            value: val.hideEmptyValues === 1 ? 'yes' : 'no',
                            onchange: function () {},
                            onclick: function (e) {
                              raise('HideEmptyValues', {
                                blkid: id,
                                value: e.target.checked ? 1 : 0,
                              })
                            },
                          })
                        ]
                      })
                    : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Show_empty_values'],help:'rb_Show_empty_values'}, [
                        m(inputChecker, {
                            value: val.show_empty_values,
                            disabled: val.show_empty_groups == 'nope',
                            onchange: function(){},
                            onclick: function(e){
                                if (e.ctrlKey){
                                    raise(BLOCK_WIZ_SHOW_EMPTY_GROUPS, {
                                        blkid: id,
                                        value: 'nope',
                                    });
                                }
                                else {
                                    raise(BLOCK_WIZ_SHOW_EMPTY_VALUES, {
                                        blkid: id,
                                        value: e.target.checked ? 'yes' : 'no',
                                    });
                                }
                            }
                        }),
                        m(`span[style=display:inline-block;color:gray;font-family:monospace;cursor:pointer;vertical-align:middle;visibility:${val.show_empty_groups == 'nope' ? 'visible' : 'hidden'};]`,{
                            title:lang['Quasi_off'],
                            onclick: function(){
                                raise(BLOCK_WIZ_SHOW_EMPTY_GROUPS, {
                                    blkid: id,
                                    value: 'yes',
                                });
                            }
                        },lang['Quasi_off']),
                    ]) : null,
                    val.use_table && showOptions && val.chart_type == 'pie' ? m(interfaceRow,{label:lang['Show_volume_chart'],help:'rb_Show_volume_chart'},[
                        m(inputChecker, {
                            value: val.show_chart_3d,
                            onchange: {action:BLOCK_WIZ_CHART_VOLUME,payload:{blkid:id}},
                        })
                    ]) : null,
                    val.use_table && showOptions && val.chart_type == 'column' ? m(interfaceRow,{label:lang['Orientation'],help:'rb_Orientation'},[
                        m(selectee,{width:250,class:'dont_use_chosen',onchange:{action:BLOCK_WIZ_SET_ORIENTATION,payload:{blkid:id}}},
                            KIND_OF_ORIENTATION.map(function(i){
                                return m('option',{value:i.value,selected:(val.orientation==i.value)},i.label)
                            })
                        ),
                    ]) : null,
                    val.use_table && showOptions && val.chart_type == 'donut' ? m(interfaceRow,{label:lang['Size_inner_circle'],help:'rb_Size_inner_circle'},[
                        m(selectee,{width:250,class:'dont_use_chosen',onchange:{action:BLOCK_WIZ_SET_SIZE_INNER_CIRCLE,payload:{blkid:id}}},
                            SIZES_OF_INNER_CIRCLE.map(function(i){
                                return m('option',{value:i.value,selected:(val.inner_circle_size==i.value)},i.label)
                            })
                        ),
                    ]) : null,
                    val.use_table && showOptions && val.chart_type == 'donut' ? m(interfaceRow,{label:lang['Show_total_value'],help:'rb_Show_total_value'},[
                        m(inputChecker, {
                            value: val.show_total_value,
                            onchange: {action:BLOCK_WIZ_SET_OUTPUT_TOTAL_VALUE,payload:{blkid:id}},
                        })
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Use_records'],help:'rb_Use_records'},[
                        m(statusCheckSet,{blkid:id,value:val.use_status}),
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Colors'],help:'rb_Colors'},[
                        m(selectee, {onchange:{action:BLOCK_WIZ_KIND_COLOR_SET,payload:{blkid:id}}}, [
                            COLORS_CHOOSE.map(item => m('option', {value:item.value,selected:(
                                val.color != '' && item.value == 'palette' ||
                                val.color == '' && item.value == 'default'
                            )}, item.label))
                        ]),
                        val.color != '' ? m(selectee,{onchange:{action:BLOCK_WIZ_PALETTE_COLOR_SET,payload:{blkid:id}}},[
                            COLORS.map(item => m('option', {value:item.value,selected:(val.color == item.value)}, item.label))
                        ]) : null,
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Axis_setting'],help:'rb_Axis_setting'}, [
                        val.axis.map(function(i){return m(axisRowWizChartSettings,{key:i.id,col:i,blkid:id,table:val.use_table})}),
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Chart_lines_setting'],help:'rb_Chart_lines_setting'}, [
                        val.lines.map(function(i){return m(lineRowWizChartSettings,{key:i.id,col:i,blkid:id,table:val.use_table})}),
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Links'],help:'rb_Chart_links'}, [
                        m(inputChecker, {
                            value: val.use_links,
                            onchange: {action:BLOCK_WIZ_SET_LINKS,payload:{blkid:id}},
                        }),
                    ]) : null,
                    val.use_table && showOptions && checkAllowLimit() ? m(interfaceRow,{label:lang['Line_limit'],help:'rb_Line_limit'}, [
                        m(inputText, {
                            value: val.limit,
                            width: 35,
                            onchange: {action:BLOCK_WIZ_SET_LIMIT,payload:{blkid:id}},
                        }),
                    ]) : null,
                )
            },
        }
    }

    function PaperBlockWizProgressBar(yaml,prnt) {
        var supra = prnt, id = genid();
        var initval = yaml || {type:'block_wiz_progress_bar',width:'33',order:0,columns:[]};
        var val = {
            type:   'block_wiz_progress_bar',
            width:  initval.width && KIND_OF_WIDTH.map(i => i.value).includes(initval.width) ? initval.width : '33',
            block_height: initval.block_height || 'stretch',
            use_table: MD.getTableId(initval.use_table || ''),
            use_filter: initval.use_filter || '',
            use_status: initval.use_status || 'active',
            caption: initval.caption || '',
            relative_value: typeof initval.relative_value == 'object' ? initval.relative_value : {
                type: 'fixed',
                field: {
                    table: initval?.relative_value?.table || '',
                    field: initval?.relative_value?.field || '',
                    expr: initval?.relative_value?.expr || '',
                    format: initval?.relative_value?.format || '',
                    filter: initval?.relative_value?.filter || '',
                },
                fixed_value: 0,
                paralink: {},
            },
            description: initval.description || '',
            animation_on: initval.animation_on || 'no',
            paralink: initval.paralink || {},
            use_links: initval.use_links || 'implicit',
            color: initval.color || '',
        };
        val.columns = wizColumnsInitial(val.use_table,initval.columns);
        var showOptions = false;
        function checkAvailabilityParamType(type) {
            for(let param of dataParams()){
                if(param.type == 'parameter' && param.datatype == type && val.paralink[param.name]){
                    return true;
                }
            }

            return false;
        }
        function blockStyling() {
            var props = '';
            var w = parseInt(val.width);
            if (w>0 && w<=100) {
                props += ' flex:0 0 calc(' + w + '% - 10px);';
            }
            var o = parseInt(val.order);
            if (!isNaN(o)) {
                props += 'order:' + o + ';';
            }
            return props+'';
        }
        /** 
        * @fixme Эта функция мутирует объекты, удаляя в них id,
        * это может вызвать неожиданные баги. Необходимо это исправить
        */
        function getPaper() {
            val.columns = val.columns.map(function(i){delete i.id; return i;});
            var cleanlink = {};
            dataParams().forEach(function(i){ if (val.paralink.hasOwnProperty(i.name)) cleanlink[i.name] = val.paralink[i.name]; });
            val.paralink = cleanlink;
            return val;
        }
        /** 
        * @fixme Эта функция использует getPaper который мутирует 
        * копируемые объекты, удаляя в них id,
        * это может вызвать неожиданные баги. Необходимо это исправить
        */
        function getPaperForCopy() {
            let value = getPaper();
            let data = {};

            for(let key in value){
                data[key] = value[key];
            }

            data.columns = copyObjectData(value.columns);

            var cleanlink = {};
            dataParams().forEach(function(i){ if (value.paralink.hasOwnProperty(i.name)) cleanlink[i.name] = value.paralink[i.name]; });
            data.paralink = cleanlink;

            data.relative_value = copyObjectData(value.relative_value);
            data.relative_value.field = copyObjectData(value.relative_value.field);
            var relativelink = {};
            dataParams().forEach(function(i){ if (value.relative_value.paralink.hasOwnProperty(i.name)) relativelink[i.name] = value.relative_value.paralink[i.name]; });
            data.relative_value.paralink = relativelink;

            return data;
        }
        var dispatch = function (action,payload) {
            switch (action) {
                case ADD_LAYOUT_ITEM:
                    if (payload.parent_id==id) layout.push(PaperLayoutItem({type:payload.item_type},{id:id}));
                    break;
                case DELETE_LAYOUT_ITEM:
                    if (payload.item_id==id) Dispatcher.unregister(dispatch);
                    break;
                case BLOCK_WIZ_SET_TABLE:
                    if (payload.blkid!=id) break;
                    if (val.use_table==payload.value) break;
                    val.use_table = payload.value;
                    val.use_filter = '';
                    val.use_status = 'active';
                    val.columns = [];
                    wizColumnAdd(val.use_table,val.columns);
                    break;
                case BLOCK_WIZ_SET_FILTER:
                    if (payload.blkid!=id) break;
                    val.use_filter = payload.value;
                    break;
                case BLOCK_WIZ_SET_CAPTION:
                    if (payload.blkid!=id) break;
                    val.caption = payload.value;
                    break;
                case BLOCK_WIZ_SET_STATUS:
                    if (payload.blkid!=id) break;
                    val.use_status = payload.value || 'active';
                    break;
                case BLOCK_WIZ_SHOW_OPTIONS:
                    if (payload.blkid!=id) break;
                    showOptions = payload.show;
                    break;
                case BLOCK_WIZ_SET_PARALINK:
                    if (payload.blkid!=id) break;
                    if (payload.value=='') {
                        delete val.paralink[payload.param];
                    }
                    else {
                        val.paralink[payload.param] = payload.value;
                    }
                    break;
                case BLOCK_WIZ_SET_LINKS:
                    if (payload.blkid!=id) break;
                    val.use_links = payload.value || 'implicit';
                    break;
                case BLOCK_WIZ_COLUMN_ADD:
                    if (payload.blkid==id) wizColumnAdd(val.use_table,val.columns);
                    break;
                case BLOCK_WIZ_COLUMN_DELETE:
                    if (payload.blkid==id) val.columns = val.columns.filter(function(i){return i.id!=payload.colid;})
                    break;
                case BLOCK_WIZ_COLUMN_SET_VALUE:
                    if (payload.blkid==id) wizColumnSet(val.use_table,val.columns,payload.colid,payload.name,payload.value);
                    break;
                case BLOCK_WIZ_SET_WIDTH:
                    if (payload.blkid==id) val.width = payload.value;
                    break;
                case BLOCK_WIZ_SET_RELATIVE_VALUE:
                    if (payload.blkid==id) val.relative_value = payload.value.replace(/\s/g, '');
                    break;
                case BLOCK_WIZ_SET_DESCRIPTION:
                    if (payload.blkid!=id) break;
                    val.description = payload.value;
                    break;
                case BLOCK_WIZ_SET_RELATIVE_INDICATOR:
                    if (payload.blkid==id) {
                        val.relative_value[payload.prop_name] = payload.prop_name == 'fixed_value'
                            ? ( isNaN(parseFloat(payload.value))
                                ? ( isNaN(parseFloat(payload.value.replace(/\D/g, '')))
                                        ? 0
                                        : parseFloat(payload.value.replace(/\D/g, ''))
                                )
                                : parseFloat(payload.value)
                            )
                            : payload.value;
                        if(payload.prop_name == 'type'){
                            val.relative_value.field = {
                                table: '',
                                field: '',
                                expr: '',
                                format: '',
                                filter: '',
                            };
                            val.relative_value.paralink = {};
                            val.relative_value.fixed_value = 0;
                        }
                    }

                    break;
                case BLOCK_WIZ_SET_RELATIVE_INDICATOR_FIELD:
                    if (payload.blkid==id) val.relative_value.field[payload.prop_name] = payload.value;
                    break;
                case BLOCK_WIZ_KIND_COLOR_SET:
                    if (payload.blkid!=id) break;
                    if(payload.value == 'default'){
                        val.color = '';
                    }
                    else {
                        val.color = '#969696';
                    }
                    break;
                case BLOCK_WIZ_PALETTE_COLOR_SET:
                    if (payload.blkid!=id) break;
                    val.color = payload.value; break;
                case BLOCK_WIZ_SET_PARALINK_RELATIVE:
                    if (payload.blkid!=id) break;
                    if (payload.value=='') {
                        delete val.relative_value.paralink[payload.param];
                    }
                    else {
                        val.relative_value.paralink[payload.param] = payload.value;
                    }
                    break;
                case BLOCK_WIZ_SET_BLOCK_HEIGHT:
                    if (payload.blkid!=id) break;
                    val.block_height = payload.value; break;
                default:
                    break;
            }
        }
        Dispatcher.register(dispatch);

        return {
            id: function(){ return id; },
            copyObject: function(){ return PaperBlockWizProgressBar(getPaperForCopy(), prnt); },
            canBeDeleted: function() { return true; },
            getPaper: function() { return getPaper() },
            getView: function() {
                return m('div.yamlview__block#'+id+'[style='+blockStyling()+']', [
                    m('div.yamlview__block_inner[style=position:relative]','BLOCK_TABLE')
                ]);
            },
            viewAsListItem: function() {
                return m(listItem,{
                    caption: buildItemTitle(lang['Progress_bar'],val.caption,MD.getTableName(val.use_table)),
                    item_id: id,
                    parent_id: supra.id,
                    key: id,
                })
            },
            viewAsDetails: function() {
                var prms = dataParams();
                return m(detailsBlock,{title:buildItemTitle(lang['Progress_bar'],val.caption,MD.getTableName(val.use_table))},
                    m(interfaceRow,{label:lang['Table2'],help:'rb_Table',key:id+'tab'}, [
                        m(selectee,{width:250,onchange:{action:BLOCK_WIZ_SET_TABLE,payload:{blkid:id}}},
                            MD.getTableList().map(function(i){return m('option',{value:i.id,selected:(val.use_table==i.id)},i.name)})
                        ),
                        val.use_table ? m(gear,{href:'edit_field.php?table='+MD.ti(val.use_table,'id'),title:lang['Table_settings']}) : null,
                    ]),
                    val.use_table ? m(interfaceRow,{label:lang['Title'],help:'rb_Table_title',key:id+'cap'}, [
                        m(inputText,{value:val.caption,width:260,onchange:{action:BLOCK_WIZ_SET_CAPTION,payload:{blkid:id}}},null),
                    ]) : null,
                    val.use_table ? m(interfaceRow,{label:lang['Indicator'],help:'rb_Indicator',key:id+'ind'}, [
                        val.columns.map(function(i){return m(columnRowWizIndicator,{col:i,blkid:id,table:val.use_table})}),
                    ]) : null,
                    val.use_table ? m(interfaceRow,{label:lang['Relative_indicator'],help:'rb_Relative_indicator'}, [
                        m(selectee,{width:120,onchange:{action:BLOCK_WIZ_SET_RELATIVE_INDICATOR,payload:{blkid:id,prop_name:'type'}}},
                            RELATIVE_INDICATOR_TYPES.filter(item => item.value != 'none').map(function(i){return m('option',{value:i.value,selected:(val.relative_value.type==i.value)},i.label)})
                        ),
                        m('div', {style:'margin-top: 6px;'}, [
                            val.relative_value.type == 'fixed'
                                ? m('div', {style:'margin-top: 6px;'}, [
                                    m(inputText,{
                                        placeholder:(lang['value'].slice(1, 2).toUpperCase() + lang['value'].slice(2)),
                                        value:val.relative_value.fixed_value,
                                        width:260,
                                        onchange:{
                                            action:BLOCK_WIZ_SET_RELATIVE_INDICATOR,
                                            payload:{
                                                blkid:id,
                                                prop_name:'fixed_value'
                                            }
                                        }
                                    },null)
                                ])
                                : null,
                            val.relative_value.type == 'field'
                                ? m('div', {style:'margin-top: 6px;'}, [
                                    m(singleRow, {
                                        blkid:id,
                                        keys: {
                                            TABLE_KEY: 'table',
                                            FIELD_KEY: 'field',
                                            EXPR_KEY: 'expr',
                                            FORMAT_KEY: 'format',
                                            FILTER_KEY: 'filter',
                                        },
                                        action: BLOCK_WIZ_SET_RELATIVE_INDICATOR_FIELD,
                                        col: val.relative_value.field,
                                    })
                                ])
                                : null,
                            val.relative_value.type == 'field' && val.relative_value.field.table
                                ? prms.map(function(item){
                                    return m(parameterLinkRowRelative,{blkid:id,table:val.relative_value.field.table,item:item,link:val.relative_value.paralink[item.name],params_length:prms.length})
                                })
                                : null,
                        ])
                    ]) : null,
                    val.use_table ? m(interfaceRow,{label:lang['Description'],help:'rb_Description_progress_bar',key:id+'dsc'}, [
                        m(inputText,{value:val.description,width:260,onchange:{action:BLOCK_WIZ_SET_DESCRIPTION,payload:{blkid:id}}},null),
                    ]) : null,
                    val.use_table ? m(interfaceRow,{label:''}, [
                        m(aee,{onclick:{action:BLOCK_WIZ_SHOW_OPTIONS,payload:{blkid:id,show:!showOptions}}},showOptions?lang['Hide']:lang['Additional'] + '...'),
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Filter'],help:'rb_Filter',key:id+'flt'}, [
                        m(selectee,{width:250,onchange:{action:BLOCK_WIZ_SET_FILTER,payload:{blkid:id}}},
                            MD.getFilterList(val.use_table).map(function(i){
                                return m('option',{value:i.id,selected:(val.use_filter==i.id)},i.parent+i.name)
                            })
                        ),
                        m(gear,{href:'edit_filter.php?table='+MD.ti(val.use_table,'id'),title:lang['Filter_settings']}),
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Width_block'],help:'rb_Table_width',key:id+'cap'}, [
                        m(selectee,{width:250,onchange:{action:BLOCK_WIZ_SET_WIDTH,payload:{blkid:id}}},
                            KIND_OF_WIDTH.map(function(i){
                                return m('option',{value:i.value,selected:(val.width==i.value)},i.label)
                            })
                        ),
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Block_height'],help:'rb_Block_height',key:id+'bh'}, [
                        m(selectee,{width:250,onchange:{action:BLOCK_WIZ_SET_BLOCK_HEIGHT,payload:{blkid:id}}}, [
                            m('option',{value:'stretch',selected:(val.block_height=='stretch')},lang['Stretch']),
                            m('option',{value:'by_content',selected:(val.block_height=='by_content')},lang['By_content']),
                        ]),
                    ]) : null,
                    val.use_table && showOptions && prms.length>0 ? m(interfaceRow,{label:lang['Link_shared_param'],help:'rb_Link_shared_param'}, [
                        prms.map(function(item){
                            return m(parameterLinkRow,{blkid:id,table:val.use_table,item:item,link:val.paralink[item.name],params_length:prms.length})
                        })
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Use_records'],help:'rb_Use_records'},[
                        m(statusCheckSet,{blkid:id,value:val.use_status}),
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Colors'],help:'rb_Colors'},[
                        m(selectee, {onchange:{action:BLOCK_WIZ_KIND_COLOR_SET,payload:{blkid:id}}}, [
                            COLORS_CHOOSE.map(item => m('option', {value:item.value,selected:(
                                val.color != '' && item.value == 'palette' ||
                                val.color == '' && item.value == 'default'
                            )}, item.label))
                        ]),
                        val.color != '' ? m(selectee,{onchange:{action:BLOCK_WIZ_PALETTE_COLOR_SET,payload:{blkid:id}}},[
                            COLORS.map(item => m('option', {value:item.value,selected:(val.color == item.value)}, item.label))
                        ]) : null,
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Links'],help:'rb_Links'}, [
                        m(selectee,{width:200,onchange:{action:BLOCK_WIZ_SET_LINKS,payload:{blkid:id}}},
                            LINKS_STATUS.map(function(i){return m('option',{value:i.value,selected:(val.use_links==i.value)},i.label)})
                        ),
                    ]) : null,
                )
            },
        }
    }

    function PaperBlockWizKanban(yaml,prnt) {
        var allowed = MD.getShowBlock("ko_kanban");
        var supra = prnt,
            id = genid();
        var initval = yaml || {type:'block_wiz_kanban',width:'100%',order:0,columns:[]};
        var val = {
            type:   'block_wiz_kanban',
            width:  initval.width && KIND_OF_WIDTH.map(i => i.value).includes(initval.width) ? initval.width : '100',
            order:  initval.order || 0,
            caption: initval.caption || '',
            limit: initval.limit || 365,
            use_table: MD.getTableId(initval.use_table || ''),
            use_filter: initval.use_filter || '',
            use_status: initval.use_status || 'active',
            paralink: initval.paralink || {},
            use_links: initval.use_links || 'true',
            colors: initval.colors || [],
            whatPaint: initval.whatPaint || 'without_color',
            showCount: initval.showCount || 1,
            showPhone: initval.showPhone || 0,
            group_field: initval.group_field || '',
            title_field: initval.title_field || ''
        };
        let colors__index_kanban = [
            'rgb(150,150,150)',
            'rgb(106, 168, 79)',
            'rgb(61, 133, 198)',
            'rgb(69, 129, 142)',
            'rgb(230, 145, 56)',
            'rgb(204, 0, 0)',
            'rgb(241, 194, 50)',
            'rgb(166, 28, 0)',
            'rgb(60, 120, 216)',
            'rgb(103, 78, 167)',
            'rgb(166, 77, 121)'
        ];
        let values_group_field = {};
        getGroupValues(val.use_table, val.group_field?.field?.split('|')[1].replace('f', ''), function(result){
            values_group_field = result;
            // console.log(values_group_field)
            if(Object.keys(values_group_field).length > 0 && values_group_field.values.length <= 5){
                let cur_vals = val.colors.map(item => item.field_value_value);
                let cur_colors = val.colors.map(item => item.color);
                let dis_colors = colors__index_kanban.filter(item => !cur_colors.includes(item));
                let dis_vals = [];
                if(Array.isArray(values_group_field.values)){
                    dis_vals = values_group_field.values.map((item, key) => ({ value: item, id: key }));
                }
                else {
                    dis_vals = Object.keys(values_group_field.values).map(key => ({ value: values_group_field.values[key], id: key }));
                }
                dis_vals = dis_vals.filter(item => !cur_vals.includes(item.value));
                let i = 0;
                dis_vals.forEach(item => {
                    val.colors.push({
                        field_value_id: item.id,
                        field_value_value: item.value,
                        color: dis_colors[i],
                    });
                    i++;
                });
            }

            m.redraw();
        });

        val.columns = wizColumnsInitial(val.use_table,initval.columns);
        if(val.columns.length == 0) wizColumnAdd(val.use_table, val.columns);
        var showOptions = false;
        function blockStyling() {
            var props = '';
            var w = parseInt(val.width);
            if (w>0 && w<=100) {
                props += ' flex:0 0 calc(' + w + '% - 10px);';
            }
            var o = parseInt(val.order);
            if (!isNaN(o)) {
                props += 'order:' + o + ';';
            }
            return props+'';
        }
        /** 
         * @fixme Эта функция мутирует объекты, удаляя в них id,
         * это может вызвать неожиданные баги. Необходимо это исправить
        */
        function getPaper() {
          
          val.columns = val.columns.map(function(i){delete i.id; return i;});
            var cleanlink = {};
            dataParams().forEach(function(i){ if (val.paralink.hasOwnProperty(i.name)) cleanlink[i.name] = val.paralink[i.name]; });
            val.paralink = cleanlink;
            return val;
        }
        /** 
         * @fixme Эта функция использует getPaper который мутирует 
         * копируемые объекты, удаляя в них id,
         * это может вызвать неожиданные баги. Необходимо это исправить
        */
        function getPaperForCopy() {
            let value = getPaper();
            let data = {};

            for(let key in value){
                data[key] = value[key];
            }

            var cleanlink = {};
            dataParams().forEach(function(i){ if (value.paralink.hasOwnProperty(i.name)) cleanlink[i.name] = value.paralink[i.name]; });
            data.paralink = cleanlink;

            return data;
        }
        var dispatch = function (action,payload) {
            switch (action) {
                case ADD_LAYOUT_ITEM:
                    if (payload.parent_id==id) layout.push(PaperLayoutItem({type:payload.item_type},{id:id}));
                    break;
                case DELETE_LAYOUT_ITEM:
                    if (payload.item_id==id) Dispatcher.unregister(dispatch);
                    break;
                case BLOCK_WIZ_SET_TABLE:
                    if (payload.blkid!=id) break;
                    if (val.use_table==payload.value) break;
                    val.use_table = payload.value;
                    val.use_filter = '';
                    val.use_status = 'active';
                    val.columns = [];
                    val.colors = [];
                    values_group_field = {};
                    wizColumnAdd(val.use_table,val.columns);
                    break;
                case BLOCK_WIZ_SET_CAPTION:
                    if (payload.blkid!=id) break;
                    val.caption = payload.value;
                    break;
                case BLOCK_WIZ_SHOW_OPTIONS:
                    if (payload.blkid!=id) break;
                    showOptions = payload.show;
                    break;
                case BLOCK_WIZ_GROUP_VALUE:
                    if (payload.blkid==id) {
                        let field_id = payload.value.substr(6);
                        val.group_field = wizNewColumn(wizNextName('S',val.columns));
                        val.group_field['field'] = payload.value;
                        val.group_field['name'] = 'SG';
                        val.colors = [];
                        val.whatPaint = 'without_color'

                        getGroupValues(val.use_table, val.group_field?.field?.split('|')[1].replace('f', ''), function(result){
                            values_group_field = result;

                            m.redraw();
                        });
                    }
                    break;
                case BLOCK_WIZ_TITLE_VALUE:
                    if (payload.blkid==id) {
                        let field_id = payload.value.substr(6);
                        val.title_field = wizNewColumn(wizNextName('S',val.columns));
                        val.title_field['field'] = payload.value;
                        val.title_field['name'] = 'ST';
                    }
                    break;
                case BLOCK_WIZ_LINE_SET_VALUE:
                    if (payload.blkid==id) wizKanbanColumnSet(val.use_table,val.columns,payload.colid,payload.name,payload.value);
                    break;
                case BLOCK_WIZ_COLUMN_MOVE:
                    if (payload.blkid==id) {
                        let elem = val.columns.find(function(i){return i.id==payload.element_id});
                        let res = [];
                        val.columns.forEach(function(i){
                            if (i.id==payload.element_id) return;
                            if (i.id==payload.sibling_id) {
                                res.push(elem);
                            }
                            res.push(i);
                        });
                        if (payload.sibling_id=='') {
                            res.push(elem);
                        }
                        val.columns = res;
                    };
                    break;
                case BLOCK_WIZ_SET_FILTER:
                    if (payload.blkid!=id) break;
                    val.use_filter = payload.value;
                    break;
                case BLOCK_WIZ_SET_WIDTH:
                    if (payload.blkid==id) val.width = payload.value;
                    break;
                case BLOCK_WIZ_SET_STATUS:
                    if (payload.blkid!=id) break;
                    val.use_status = payload.value || 'active';
                    break;
                case BLOCK_WIZ_COLUMN_ADD:
                    if (payload.blkid==id) wizColumnAdd(val.use_table,val.columns);
                    break;
                case BLOCK_WIZ_COLUMN_DELETE:
                    if (payload.blkid==id) val.columns = val.columns.filter(function(i){return i.id!=payload.colid;})
                    break;
                case BLOCK_WIZ_COLUMN_SET_VALUE:
                    if (payload.blkid==id) wizKanbanColumnSet(val.use_table,val.columns,payload.colid,payload.name,payload.value);
                    break;
                case BLOCK_WIZ_SET_LINKS:
                    if (payload.blkid!=id) break;
                    val.use_links = payload.value;
                    break;
                case BLOCK_WIZ_ADD_COLOR:
                    if (payload.blkid!=id) break;
                    val.colors.push({
                        field_value_id: payload.field_value_id,
                        field_value_value: payload.field_value_value,
                        color: payload.color,
                    });
                    break;
                case BLOCK_WIZ_DELETE_COLOR:
                    if (payload.blkid!=id) break;
                    if(payload.field_id === -1){
                        val.colors = [];
                        colors__index_kanban = [
                            'rgb(150,150,150)',
                            'rgb(106, 168, 79)',
                            'rgb(61, 133, 198)',
                            'rgb(69, 129, 142)',
                            'rgb(230, 145, 56)',
                            'rgb(204, 0, 0)',
                            'rgb(241, 194, 50)',
                            'rgb(166, 28, 0)',
                            'rgb(60, 120, 216)',
                            'rgb(103, 78, 167)',
                            'rgb(166, 77, 121)'
                        ];
                    }
                    else {
                        val.colors = val.colors.filter((item, index) => index != payload.key);
                    }
                    break;
                case BLOCK_WIZ_SET_COLOR:
                    if (payload.blkid!=id) break;
                    val.colors[payload.key][payload.name] = payload.value;
                    break;
                case BLOCK_WIZ_SET_WHAT_PAINT:
                    if (payload.blkid!=id) break;

                    if(payload.value == 'without_color'){
                        val.colors = [];
                    }

                    if(values_group_field.values.length <= 5){
                        let cur_vals = val.colors.map(item => item.field_value_value);
                        let cur_colors = val.colors.map(item => item.color);
                        let dis_colors = colors__index_kanban.filter(item => !cur_colors.includes(item));
                        let dis_vals = [];
                        if(Array.isArray(values_group_field.values)){
                            dis_vals = values_group_field.values.map((item, key) => ({ value: item, id: key }));
                        }
                        else {
                            dis_vals = Object.keys(values_group_field.values).map(key => ({ value: values_group_field.values[key], id: key }));
                        }
                        dis_vals = dis_vals.filter(item => !cur_vals.includes(item.value));
                        let i = 0;
                        dis_vals.forEach(item => {
                            val.colors.push({
                                field_value_id: item.id,
                                field_value_value: item.value,
                                color: dis_colors[i],
                            });
                            i++;
                        });
                    }

                    val.whatPaint = payload.value;
                    break;
                case BLOCK_WIZ_SET_LIMIT:
                    if (payload.blkid!=id) break;
                    val.limit = payload.value;
                    break;
                case BLOCK_WIZ_SHOW_ROWS_COUNT:
                    if (payload.blkid!=id) break;
                    val.showCount = payload.value;
                    break;
                case BLOCK_WIZ_SHOW_PHONE:
                    if (payload.blkid!=id) break;
                    val.showPhone = payload.value;
                    break;
                case BLOCK_WIZ_SET_PARALINK:
                    if (payload.blkid!=id) break;
                    if (payload.value=='') delete val.paralink[payload.param]; else val.paralink[payload.param] = payload.value;
                    break;
                default:
                    break;
            }
        }
        Dispatcher.register(dispatch);

        return {
            id: function(){ return id; },
            canBeDeleted: function() { return true; },
            copyObject: function(){ return PaperBlockWizKanban(getPaperForCopy(),prnt); },
            getPaper: function() { return getPaper() },
            getView: function() {
                return m('div.yamlview__block#'+id+'[style='+blockStyling()+']', [
                    m('div.yamlview__block_inner[style=position:relative]','BLOCK_TABLE')
                ]);
            },
            viewAsListItem: function() {        // TODO: lang[To work, you need to buy or activate.]
                return allowed ?
                    m(listItem,{
                        caption: buildItemTitle(lang['Kanban'],val.caption,''),
                        item_id: id,
                        parent_id: supra.id,
                        key: id,
                    }) :
                    m(listItemNotActivated, {
                        caption: buildItemTitle(lang['Kanban'],val.caption,''),
                        item_id: id,
                        parent_id: supra.id,
                        key: id,
                    })
            },
            viewAsDetails: function() {
                var prms = dataParams();
                return m(detailsBlock,{title:buildItemTitle(lang['Kanban'],val.caption, '')},
                    m(interfaceRow,{label:lang['Table2'],help:'rb_Table'}, [
                        m(selectee,{width:250,onchange:{action:BLOCK_WIZ_SET_TABLE,payload:{blkid:id}}},
                            MD.getTableList().map(function(i){return m('option',{value:i.id,selected:(val.use_table==i.id)},i.name)})
                        ),
                        val.use_table ? m(gear,{href:'edit_field.php?table='+MD.ti(val.use_table,'id'),title:lang['Table_settings']}) : null,
                    ]),
                    m(interfaceRow,{label:lang['Title'],help:'rb_Table_title'}, [
                        m(inputText,{value:val.caption,width:260,onchange:{action:BLOCK_WIZ_SET_CAPTION,payload:{blkid:id}}},null),
                    ]),
                    val.use_table ? m(interfaceRow,{label:lang['Grouping_field'], help:'rb_Kanban_group_field'}, [
                        m(selectee,{width:200,onchange:{action:BLOCK_WIZ_GROUP_VALUE,payload:{blkid:id}}},
                            m('option',{value:'',selected:(val.title=='')},''),
                            MD.getFieldForKanbanList(val.use_table).map(function(i){return m('option',{value:i.id,selected:(val.group_field.field==i.id)},i.name)})
                        ),
                        m('span[style=display:inline-block;width:534px;]',' '),
                        m('span[style=display:inline-block;color:gray;font-family:monospace]',{title: 'SG'},'SG'),
                    ]) : null,
                    val.use_table ? m(interfaceRow,{label:lang['Title_field'], help:'rb_Kanban_title_field'}, [
                        m(selectee,{width:200,onchange:{action:BLOCK_WIZ_TITLE_VALUE,payload:{blkid:id}}},
                            m('option',{value:'',selected:(val.title=='')},''),
                            MD.getFieldAndLinkList(val.use_table).map(function(i){return m('option',{value:i.id,selected:(val.title_field.field==i.id)},i.name)})
                        ),
                        m('span[style=display:inline-block;width:534px;]',' '),
                        m('span[style=display:inline-block;color:gray;font-family:monospace]',{title: 'ST'},'ST'),
                    ]) : null,
                    val.use_table ? m(interfaceRow,{label:lang['Fields'], help:'rb_Chart_lines'}, [
                        m(dragZone,{onmove:{action:BLOCK_WIZ_COLUMN_MOVE, payload:{blkid:id}}}, [
                            val.columns.map(function(i){return m(lineRowWizKanban,{key:i.id,col:i,blkid:id,table:val.use_table,axis:{field: val.group_field}})}),
                        ]),
                        (val.columns.length >= 0) ? m(aee,{onclick:{action:BLOCK_WIZ_COLUMN_ADD,payload:{blkid:id}}},lang['add_column']) : null,
                    ]) : null,
                    val.use_table ? m(interfaceRow,{label:''}, [
                        m(aee,{onclick:{action:BLOCK_WIZ_SHOW_OPTIONS,payload:{blkid:id,show:!showOptions}}},showOptions?lang['Hide']:lang['Additional'] + '...'),
                    ]) : null,
                    val.use_table && showOptions && prms.length>0 ? m(interfaceRow,{label:lang['Link_shared_param'],help:'rb_Link_shared_param'}, [
                        prms.map(function(item){
                            return m(parameterLinkRow,{blkid:id,table:val.use_table,item:item,link:val.paralink[item.name]})
                        })
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Filter'],help:'rb_Filter'}, [
                        m(selectee,{width:250,onchange:{action:BLOCK_WIZ_SET_FILTER,payload:{blkid:id}}},
                            MD.getFilterList(val.use_table).map(function(i){return m('option',{value:i.id,selected:(val.use_filter==i.id)},i.parent+i.name)})
                        ),
                        m(gear,{href:'edit_filter.php?table='+MD.ti(val.use_table,'id'),title:lang['Filter_settings']}),
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Width_block'],help:'rb_Table_width',key:id+'cap'}, [
                        m(selectee,{width:250,onchange:{action:BLOCK_WIZ_SET_WIDTH,payload:{blkid:id}}},
                            KIND_OF_WIDTH.map(function(i){
                                return m('option',{value:i.value,selected:(val.width==i.value)},i.label)
                            })
                        ),
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Use_records'],help:'rb_Use_records'},[
                        m(statusCheckSet,{blkid:id,value:val.use_status}),
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Column_settings'],help:'rb_Column_settings'}, [
                        val.columns.map(function(i){return m(columnRowWizKanbanSettings,{key:i.id,col:i,blkid:id,table:val.use_table})}),
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Links'],help:'rb_Links'}, [
                        m(selectee,{width:200,onchange:{action:BLOCK_WIZ_SET_LINKS,payload:{blkid:id}}},
                            m('option',{value:'true',selected:(val.use_links=='true')},lang['Go_to_card']),
                            m('option',{value:'false',selected:(val.use_links=='false')},lang['Dont_go_to_the_card'])
                        ),
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Color_scheme_rep'],help:'rb_Color_scheme_rep_kanban'}, [
                        m(selectee,{width:200,onchange:async function(){
                            if(this.value == 'with_color_all' || this.value == 'with_color_header'){
                                let field_values = values_group_field.values || {};
                                let field_value_id = Object.keys(field_values)[0];
                                let field_value_value = field_values[field_value_id];
                                raise(BLOCK_WIZ_SET_WHAT_PAINT, {blkid: id, value: this.value});
                                if (val.colors.length == 0) {
                                    raise(BLOCK_WIZ_ADD_COLOR, {blkid: id, field_value_id, field_value_value, color: (function(){
                                        let random_index = (Math.floor(Math.random() * 10) > colors__index_kanban.length - 1) ? 0 : Math.floor(Math.random() * 10),
                                            color_random;
                                        if (colors__index_kanban.length == 0) {
                                            colors__index_kanban = [
                                                'rgb(150,150,150)',
                                                'rgb(106, 168, 79)',
                                                'rgb(61, 133, 198)',
                                                'rgb(69, 129, 142)',
                                                'rgb(230, 145, 56)',
                                                'rgb(204, 0, 0)',
                                                'rgb(241, 194, 50)',
                                                'rgb(166, 28, 0)',
                                                'rgb(60, 120, 216)',
                                                'rgb(103, 78, 167)',
                                                'rgb(166, 77, 121)'
                                            ]
                                        } else {
                                            color_random = colors__index_kanban[random_index]
                                            colors__index_kanban.splice(random_index, 1)
                                        }
                                        return color_random
                                    })()});
                                }
                            }
                            else {
                                raise(BLOCK_WIZ_SET_WHAT_PAINT, {blkid: id, payload: this.value});
                                raise(BLOCK_WIZ_DELETE_COLOR, {blkid: id, field_id: -1});
                            }
                            m.redraw();
                        }}, [
                            m('option',{value: 'without_color', selected: (val.whatPaint == 'without_color') }, lang['Without_color']),
                            m('option',{value: 'with_color_header', selected: (val.whatPaint == 'with_color_header') }, lang['With_color_header']),
                            m('option',{value: 'with_color_all', selected: (val.whatPaint == 'with_color_all') }, lang['With_color_all'])
                        ]),
                        val.colors.length > 0 && val.whatPaint != 'without_color'
                        ? [
                            m("div",{style: "margin-top:4px;"}, [
                                val.colors.map(function(item,index){
                                    return m(columnRowWizKanbanColor,{
                                        key:index,
                                        col:item,
                                        blkid:id,
                                        table:val.use_table,
                                        all_fields_values: values_group_field,
                                        colors:val.colors,
                                    });
                                }),
                            ]),
                            Object.keys(values_group_field.values).length > val.colors.length
                                ? m(aee, {
                                    onclick: async () => {
                                        let field_values = values_group_field.values,
                                            use_color_values_ids = val.colors.map(item => item.field_value_id),
                                            group_field_values = [];

                                        for(let key in field_values){
                                            if(!use_color_values_ids.includes(key)){
                                                group_field_values.push({id: key, value: field_values[key]});
                                            }
                                        }
                                        raise(BLOCK_WIZ_ADD_COLOR, {blkid: id, field_value_id: group_field_values[0].id, field_value_value: group_field_values[0].value, color: (function(){
                                            let random = Math.floor(Math.random() * 10),
                                                random_index = (random > colors__index_kanban.length - 1) ? 0 : random,
                                                color_random;
                                            if (colors__index_kanban.length == 0) {
                                                colors__index_kanban = [
                                                    '#969696',
                                                    'rgb(106, 168, 79)',
                                                    'rgb(61, 133, 198)',
                                                    'rgb(69, 129, 142)',
                                                    'rgb(230, 145, 56)',
                                                    'rgb(204, 0, 0)',
                                                    'rgb(241, 194, 50)',
                                                    'rgb(166, 28, 0)',
                                                    'rgb(60, 120, 216)',
                                                    'rgb(103, 78, 167)',
                                                    'rgb(166, 77, 121)'
                                                ]
                                            } else {
                                                color_random = colors__index_kanban[random_index]
                                                colors__index_kanban.splice(random_index, 1)
                                            }
                                            return color_random
                                        })()});
                                        m.redraw();
                                    }
                                }, lang['Add'])
                                : null,
                        ]
                        : null
                    ]) : null,
                    val.use_table && showOptions ? m(interfaceRow,{label:lang['Line_limit'],help:'rb_Line_limit'}, [
                        m(inputText, {
                            value: val.limit,
                            width: 35,
                            onchange: {action:BLOCK_WIZ_SET_LIMIT,payload:{blkid:id}},
                        }),
                    ]) : null,
                )
            },
        }
    }

    /**
     * Блок поиска,
     * выполнение операций по отображению и взаимодействию клиента с настройками блока
     * @param {*} yaml    настройки/спецификация блока
     * @param {*} prnt
     * @returns
     */
    function PaperBlockWizSearchBlock(yaml, prnt) {
      const supra = prnt,
        id      = genid(),
        initval = yaml || {
          type:    'block_wiz_search',
          width:   '100',
          order:   0,
          columns: []
        };

      var showOptions = false, val = {
        /* тип блока */     type: 'block_wiz_search',
        /* Таблица */       use_table:  MD.getTableId(initval.use_table || '') || '',
        /* Заголовок */     caption:    initval.caption || '',
        /* Статус записи */ use_status: initval.use_status || 'active',
        /* Параметры */     paralink:   initval.paralink || {},
        /* фильтр */        use_filter: initval.use_filter || '',
        /* Ширина блока */  width:      (
          initval.width && KIND_OF_WIDTH.map(i => i.value).includes(initval.width) ? initval.width : '100'
        ),
        /* Ссылки */        use_links: initval.use_links || 'implicit',
        /* Выравнивание */  alignment: initval.alignment || 'AsInTheTable',
        /* Лимит записей */ limit:     initval.limit || '50',
        /* Обрезать до X символов */ cut_to: initval.cut_to || 0,
        /* Выводить Х последних строк */ last_lines: initval.last_lines || 0,
      };

      val.columns = wizColumnsInitial(val.use_table, initval.columns);
      // console.log(val);

      // Получить содержание блока
      /** 
       * @fixme Эта функция мутирует объекты, удаляя в них id,
       * это может вызвать неожиданные баги. Необходимо это исправить
      */
      function getPaper() {
        val.columns = val.columns.map(function(i) { delete i.id; return i; });
        var cleanlink = {};

        dataParams().forEach(function(i){
          if (val.paralink.hasOwnProperty(i.name)) {
            cleanlink[i.name] = val.paralink[i.name];
          }
        });

        val.paralink = cleanlink;
        return val;
      }

      // Копировать содержимое блока
       /** 
       * @fixme Эта функция использует getPaper который мутирует 
       * копируемые объекты, удаляя в них id,
       * это может вызвать неожиданные баги. Необходимо это исправить
      */
      function getPaperForCopy() {
        let value = getPaper(), data = {};

        for (let key in value) {
          data[key] = value[key];
        }

        data.columns = copyObjectData(value.columns);
        data.paralink = {};
        return data;
      }

      // регистрация слушателя событий
      Dispatcher.register(function(action, payload) {
        switch (action) {
          // выбрали таблицу
          case BLOCK_WIZ_SET_TABLE:
            if (payload.blkid != id) break;
            if (val.use_table == payload.value) break;

            val.use_table = payload.value;
            val.use_status = 'active';
            val.columns = [];
            wizColumnAdd(val.use_table, val.columns);
            break;

          // выбрали заголовок
          case BLOCK_WIZ_SET_CAPTION:
            if (payload.blkid == id) val.caption = payload.value;
            break;

          // добавление "Столбца"
          case BLOCK_WIZ_COLUMN_ADD:
            if (payload.blkid == id) wizColumnAdd(val.use_table, val.columns);
            break;

          // удаление "Столбца"
          case BLOCK_WIZ_COLUMN_DELETE:
            if (payload.blkid == id) val.columns = val.columns.filter((i) => i.id != payload.colid);
            break;

          // установить значение "Столбца"
          case BLOCK_WIZ_COLUMN_SET_VALUE:
            if (payload.blkid == id) {
              wizColumnSet(val.use_table, val.columns, payload.colid, payload.name, payload.value);
            }
            break;

          // перемещение столбца по вертикали (dragZone)
          case BLOCK_WIZ_COLUMN_MOVE:
            if (payload.blkid == id) {
              const elem = val.columns.find(function(i) {return i.id == payload.element_id});
              let res = [];

              val.columns.forEach(function(i) {
                if (i.id == payload.element_id) return;
                if (i.id == payload.sibling_id) res.push(elem);
                res.push(i);
              });

              if (payload.sibling_id == '') res.push(elem);
              val.columns = res;
            }
            break;

          // раскрыть/свернуть секцию "Дополнительно"
          case BLOCK_WIZ_SHOW_OPTIONS:
            if (payload.blkid == id) showOptions = payload.show;
            break;

          // изменить фильтр
          case BLOCK_WIZ_SET_FILTER:
            if (payload.blkid == id) {
              val.use_filter = payload.value;
            }
            break;

          // установить параметр
          case BLOCK_WIZ_SET_PARALINK:
            if (payload.blkid != id) break;

            if (payload.value == '') {
              delete val.paralink[payload.param];
            } else {
              val.paralink[payload.param] = payload.value;
            }
            break;

          // изменение "Ширины блока"
          case BLOCK_WIZ_SET_WIDTH:
            if (payload.blkid == id) val.width = payload.value;
            break;

          // изменить "Использовать записи" (status=0)
          case BLOCK_WIZ_SET_STATUS:
            if (payload.blkid == id) val.use_status = payload.value || 'active';
            break;

          // изменить "Выравнивание"
          case BLOCK_WIZ_SET_LINKS:
            if (payload.blkid == id) val.use_links = payload.value;
            break;

          // изменить "Выравнивание"
          case BLOCK_WIZ_ALIGNMENT:
            if (payload.blkid == id) val.alignment = payload.value;
            break;

          case BLOCK_WIZ_SET_LIMIT:
            if (payload.blkid == id) val.limit = payload.value;
            break;

          case BLOCK_WIZ_SET_CUT_TO:
            if (payload.blkid == id) val.cut_to = payload.value;
            break;

          case BLOCK_WIZ_SET_LAST_LINES:
            if (payload.blkid == id) val.last_lines = payload.value;
            break;

          default:
              break;
        }
      });

      return {
        id: function() { return id; },
        copyObject: function() { return PaperBlockWizSearchBlock(getPaperForCopy(), prnt); },
        canBeDeleted: function() { return true; },
        getPaper: function() { return getPaper() },
        getView: function() {
          return m('div.yamlview__block#' + id + '[style=' + blockStyling() + ']', [
            m('div.yamlview__block_inner[style=position:relative]', 'BLOCK_TABLE')
          ]);
        },

        // Отображение в списке блоков (h_id="rb_report_form")
        viewAsListItem: function() {
          return m(listItem, {
            caption: buildItemTitle(lang['Search'], val.caption, MD.getTableName(val.use_table)),
            item_id: id,
            parent_id: supra.id,
            key: id,
          })
        },

        // Верстка развернутого блока настроек
        viewAsDetails: function() {
          var prms = dataParams();

          return m(detailsBlock, {
            title: buildItemTitle(lang['Search'], val.caption, MD.getTableName(val.use_table))
          }, [

            // строка "Таблица"
            m(interfaceRow, { label: lang['Table2'], help: 'rb_Table' }, [
              m(selectee, {
                width: 250,
                onchange: {
                  action: BLOCK_WIZ_SET_TABLE,
                  payload: {blkid: id}
                }
              }, MD.getTableList().map(function(i) { return m('option', {value: i.id, selected: (val.use_table == i.id)}, i.name) })),

              // шестеренка перехода в таблицу
              val.use_table ? m(gear, {href: 'edit_field.php?table='+ MD.ti(val.use_table, 'id'), title: lang['Table_settings']}) : null,
            ]),

            // если выбрали таблицу
            val.use_table ? [

              // Строка "Заголовок"
              m(interfaceRow, {label: lang['Title'], help: 'rb_Table_title'}, [
                m(inputText, {value: val.caption, width: 260, onchange: {action: BLOCK_WIZ_SET_CAPTION, payload: {blkid: id}}}, null),
              ]),

              // "Столбцы"
              m(interfaceRow, {label: lang['Columns'], help: 'rb_Columns'}, [
                m(dragZone, {onmove: {action: BLOCK_WIZ_COLUMN_MOVE, payload: {blkid: id}}}, [
                  val.columns.map(function(i) { return m(columnRowWizTable, {
                    key: i.id,
                    col: i,
                    blkid: id,
                    table: val.use_table,
                    need_more_fields: false,
                    extended_group: false,
                    multiple_choice_disabled: true,
                  })}),
                ]),
                m(aee, {onclick: {action: BLOCK_WIZ_COLUMN_ADD, payload: {blkid: id}}}, lang['add_column']),
              ]),

              // Кнопка "Дополнительно"
              m(interfaceRow, {label: ''}, [
                m(aee, {
                  onclick: {action: BLOCK_WIZ_SHOW_OPTIONS, payload: {blkid: id, show: !showOptions}}
                }, (showOptions ? lang['Hide'] : (lang['Additional'] + '...'))),
              ]),

              showOptions ? [
                // Связать общий параметр
                prms.length > 0 ? m(interfaceRow, {label: lang['Link_shared_param'], help: 'rb_Link_shared_param'}, [
                  prms.map(function(item) {
                    return m(parameterLinkRow, {
                      blkid: id, table: val.use_table, item: item, link: val.paralink[item.name], params_length: prms.length, multiple_choice_disabled: true
                    })
                  })
                ]) : null,

                // Фильтр
                m(interfaceRow, { label: lang['Filter'], help: 'rb_Filter' }, [
                  m(selectee, {
                    width: 250, onchange: { action: BLOCK_WIZ_SET_FILTER, payload: { blkid: id } }
                  }, MD.getFilterList(val.use_table).map(function(i) {
                    return m('option', { value: i.id, selected: (val.use_filter == i.id) }, i.parent + i.name)
                  })),

                  m(gear, {href: 'edit_filter.php?table=' + MD.ti(val.use_table, 'id'), title: lang['Filter_settings']}),
                ]),

                // Ширина блока
                m(interfaceRow, {label: lang['Width_block'], help: 'rb_Table_width', key: (id + 'cap')}, [
                  m(selectee, {
                    width: 250, onchange: {action: BLOCK_WIZ_SET_WIDTH, payload: {blkid: id}}
                  }, KIND_OF_WIDTH.map(function(i) {
                    return m('option', {value: i.value, selected: (val.width == i.value)}, i.label)
                  }))
                ]),

                // использовать статусы
                m(interfaceRow, {label: lang['Use_records'], help: 'rb_Use_records'}, [
                  m(statusCheckSet, {blkid: id, value: val.use_status}),
                ]),

                // Настройка столбцов
                m(interfaceRow, {label: lang['Column_settings'], help: 'rb_Column_settings'}, [
                  val.columns.map(function(i) { return m(columnRowWizTableSettings, {
                    key: i.id,
                    col: i,
                    blkid: id,
                    table: val.use_table,
                    total: false,
                    format: false
                  })}),
                ]),

                // Ссылки
                m(interfaceRow, {label: lang['Links'], help:'rb_Links'}, [
                  m(selectee, {
                    width: 200,
                    onchange: {action: BLOCK_WIZ_SET_LINKS, payload: {blkid: id}}
                  }, LINKS_STATUS.map(function(i) {
                    return m('option', {value: i.value, selected: (val.use_links == i.value)}, i.label)
                  }))
                ]),

                // Выравнивание
                m(interfaceRow,{label: lang['Alignment'], help: 'rb_Alignment'}, [
                  m(selectee, {
                    width: 200, onchange: {action: BLOCK_WIZ_ALIGNMENT, payload: {blkid: id}}
                  }, ALIGNMENT.map(function(i) {
                    return m('option', {value: i.value, selected: (val.alignment==i.value)}, i.label)
                  })),
                ]),

                // Лимит строк
                m(interfaceRow, {label: lang['Line_limit'], help: 'rb_Line_limit'}, [
                  m(inputText, {
                    value: val.limit,
                    width: 35,
                    onchange: {action: BLOCK_WIZ_SET_LIMIT, payload: {blkid: id}},
                  }),
                ]),

                // Обрезать до X символов
                m(interfaceRow, {
                  label: 'Обрезать до',
                  help: 'report-constructor__cut-to'
                }, [
                  m(inputText, {
                    value: val.cut_to,
                    width: 35,
                    onchange: {action: BLOCK_WIZ_SET_CUT_TO, payload: {blkid: id}},
                  }),
                  m('span', {style: {'margin-left': '5px'}}, 'символов')
                ]),

                // Выводить Х последних строк
                m(interfaceRow, {
                  label: 'Выводить',
                  help: 'report-constructor__last-lines'
                }, [
                  m(inputText, {
                    value: val.last_lines,
                    width: 35,
                    onchange: {action: BLOCK_WIZ_SET_LAST_LINES, payload: {blkid: id}},
                  }),
                  m('span', {style: {'margin-left': '5px'}}, 'последних строк')
                ]),
              ] : null
            ] : null,
          ]);
        },
      }
    }

    function PaperTable(yaml,prnt) {
        var supra = prnt, id = genid();
        var initval = yaml || {type:'table',data:'',caption:'',head:[],body:[],foot:[]};
        var data = initval.data || '',
            caption = initval.caption || '',
            head = initval.head || [],
            body = initval.body || [],
            foot = initval.foot || [],
            type = 'table';
        function getPaper() {
            return {
                type: type,
                data: data,
                caption: caption,
                head: head,
                body: body,
                foot: foot,
            }
        }
        var dispatch = function (action,payload) {
            switch (action) {
                default:
                    break;
            }
        }
        Dispatcher.register(dispatch);

        return {
            id: function(){ return id; },
            copyObject: function(){ return PaperTable(getPaper(),prnt); },
            canBeDeleted: function() { return true; },
            getPaper: function() { return getPaper() },
            getView: function() {
                return m('div.yamlview__block#'+id, [
                    m('div.yamlview__block_inner[style=position:relative]',[
                        m(PaperToolbar, { blockid:id, blocktype:'table', tools: [
                            { name:lang['delete'],call:function(){raise(DELETE_LAYOUT_ITEM,{parent_id:supra.id,item_id:id})}},
                        ]}),
                        m('table',
                            caption ? m('caption',caption) : null,
                            m('thead', m('tr', head.map(function(item){return m('th',item)}))),
                            m('tbody', m('tr', body.map(function(item){return m('td',item)}))),
                            m('tfoot', m('tr', foot.map(function(item){return m('td',item)}))),
                        )
                    ])
                ]);
            },
            viewAsListItem: function() {
                return m(listItem,{
                    caption: lang['Table_block'],
                    item_id: id,
                    parent_id: supra.id,
                    key: id,
                })
            },
            viewAsDetails: function() {
                return m(detailsBlock,{title:lang['Table_block']},m(interfaceRow,{label:'YAML'},m('pre',yamlify(getPaper()))))
            },
        }
    }

    function PaperLayoutItem(item,prnt) {
        var self = (prnt instanceof Object) ? prnt : this;
        if (item instanceof Object) {
            switch (item.type) {
                case 'inline': return PaperInline('div',item,self);
                case 'block': return PaperBlock(item,self);
                case 'table': return PaperTable(item,self);
                case 'block_wiz_table': return PaperBlockWizTable(item,self);
                case 'block_wiz_multitable': return PaperBlockWizMultitable(item,self);
                case 'block_wiz_indicator': return PaperBlockWizIndicator(item,self);
                case 'block_wiz_text': return PaperBlockWizText(item,self);
                case 'block_wiz_chart': return PaperBlockWizCharts(item,self);
                case 'block_wiz_progress_bar': return PaperBlockWizProgressBar(item,self);
                case 'block_wiz_kanban': return PaperBlockWizKanban(item,self);
                case 'block_wiz_search': return PaperBlockWizSearchBlock(item, self);
                default: return PaperUnknown(item,self);
            }
        } else {
            return PaperInline('div',item,self);
        }
    }

    function PaperView(yaml) {
      var id = 'yamlview';
      var initval = yaml || {doctype: 'view', version: '0', data: [], layout: []};
      var doctype = initval.doctype || 'view';
      DATA = initval.data || [];
      var layout = (initval.layout instanceof Array) ? initval.layout.map(PaperLayoutItem, {id: id}) : [];
      var details_item;

      var dispatch = function(action, payload) {
        switch (action) {
          // событие добавления блока
          case ADD_LAYOUT_ITEM:
            var new_item = PaperLayoutItem({type: payload.item_type}, {id: id});
            layout.push(new_item);

            switch (payload.item_type) {
              case 'block_wiz_table':
                raise(BLOCK_WIZ_SET_CAPTION, {
                  blkid: new_item.id(), value: lang['New_table'] + ' ' + layout.length
                });
                break;

             case 'block_wiz_multitable':
                raise(BLOCK_WIZ_SET_CAPTION, {
                    blkid: new_item.id(), value: lang['New_multitable'] + ' ' + layout.length
                });
                break;

              case 'block_wiz_indicator':
                raise(BLOCK_WIZ_SET_CAPTION, {
                  blkid: new_item.id(), value: lang['New_indicator'] + ' ' + layout.length
                });
                break;

              case 'block_wiz_text':
                raise(BLOCK_WIZ_SET_CAPTION, {blkid: new_item.id(), value: ''});
                break;

              default:
                break;
            }

            raise(SET_DETAILS_ITEM, {item_id: new_item.id()});
            break;

          // событие удаления блока
          case DELETE_LAYOUT_ITEM:
            if (payload.parent_id == id) {
              layout = layout.filter(function(item) {
                return (item.id() != payload.item_id) || !item.canBeDeleted()
              });
            }
            break;

          // копирование блока
          case COPY_LAYOUT_ITEM:
            if (payload.parent_id == id) {
              for (let key in layout) {
                if (layout[key].id() == payload.item_id) {
                  layout.push(layout[key].copyObject());
                  break;
                }
              }
            }
            break;

          // перемещение блока
          case MOVE_LAYOUT_ITEM:
            if (payload.parent_id == id) {
              var elem = layout.find(function(item) { return item.id() == payload.element_id});
              var res = [];

              layout.forEach(function(item) {
                if (item.id() == payload.element_id) return;
                if (item.id() == payload.sibling_id) res.push(elem);
                res.push(item);
              });

              if (payload.sibling_id == '') res.push(elem);
              layout = res;
            }
            break;

          // добавление параметра
          case DATA_ITEM_APPEND:
            DATA.push(payload.item);
            break;

          // удаление параметра
          case DATA_ITEM_DELETE:
            if (payload.item_name == '/all') {
              for (let data_item of DATA) {
                if (data_item.type == 'parameter') {
                  for (let item of layout) {
                    raise(BLOCK_WIZ_SET_PARALINK, {
                      blkid: item.id(), value: '', param: data_item.name
                    });
                  }
                }
              }
              DATA = [];
            } else {
              DATA = DATA.filter(function(i) { return i.name != payload.item_name; });
            }
            break;

          // перемещение параметра
          case MOVE_PARAMETER_ROW:
            let new_params = [];
            const current_element = DATA.find(function(item) {
              return item.name == payload.element_id;
            });

            DATA.forEach(item => {
              if (item.name == payload.element_id) {
                return;
              } else if (item.name == payload.sibling_id) {
                new_params.push(current_element);
                new_params.push(item);
              } else {
                new_params.push(item);
              }
            });

            if (payload.sibling_id == '') new_params.push(current_element);
            setDataParams(new_params);
            break;

          case DATA_ITEM_SET:
            DATA.forEach(function(item) {
              if (item.name == payload.item_name) item[payload.name] = payload.value;
            });
            break;

          case APPEND_LAYOUT_ITEM:
            if (payload.parent_id == id) {
              layout.push(PaperLayoutItem(payload.item, {id: id}));
            }
            break;

          case SET_DETAILS_ITEM:
            details_item = payload.item_id;
            break;

          default:
            break;
        }
      }
      Dispatcher.register(dispatch);

      return {
        id: function() { return id; },
        copyObject: function() { return PaperView(yaml); },
        canBeDeleted: function() { return false; },
        getYaml: function() { return YAML.dump(paper.getPaper(), 42, 2) },
        getJson: function() { return JSON.stringify(paper.getPaper(), undefined, 2) },

        getPaper: function() {
          return {
            doctype: doctype,
            data:    DATA,
            layout:  layout.map(function(item) { return item.getPaper() }),
          }
        },

        getView: function() {
          return {
            view: function(vnode) {
              return m('div',[
                m('ul.yamltoolbar',[
                  m('li', {onclick: function() { raise(ADD_LAYOUT_ITEM, {parent_id: id, item_type: 'inline'}) }}, lang['add_text']),
                  m('li', {onclick: function() { raise(ADD_LAYOUT_ITEM, {parent_id: id, item_type: 'block'}) }}, lang['add_block']),
                  m('li', {onclick: function() { raise(SHOW_DIALOG, {
                    width:  '900px',
                    height: '500px',
                    title:  lang['Table_creation_wizard'],
                    body:   m((WizardTableCreate()).getView()),
                  })}}, lang['Table_creation_wizard']),
                ]),

                m('div#yamlview', m('div.yamlview__block_layout', layout.map(function(item){return item.getView()}))),

                (
                  DATA.length > 0
                  ? m('div', m('h5',lang['Data_source']), DATA.map(function(item) {
                      var sourceName = '?';
                      if (item.table) sourceName = item.table;
                      else if (item.variable) sourceName = item.variable;
                      else if (item.parameter) sourceName = item.parameter;
                      else ;
                      return m('span[style=border:1px solid gray; padding:8px; margin:8px;]', sourceName);
                    })
                  ) : null
                ),

                dialog ? m(PaperDialog, dialog) : null,
              ]);
            },
          }
        },

        viewAsList: function() {
          return {
            view: function(vnode) {
              var params = dataParams();

              return m.fragment({ key: id }, [
                // Задавать общие параметры
                m(interfaceRow, {label: lang['Set_shared_param'], help: 'Set_shared_param'}, [
                  m(inputRadioLine,{items: [
                    // Нет
                    {value: 'P1', checked: (params.length == 0), label: lang['No'], onchange: {
                      action: DATA_ITEM_DELETE, payload: {item_name: '/all'}}
                    },
                    // Да
                    {value: 'P1', checked: (params.length > 0), label: lang['Yes'], onchange: {
                      action:DATA_ITEM_APPEND, payload: {
                        item: {type: 'parameter', name: 'P1', datatype: 'period', default: 'half_month', datatype_details: ''}
                      }
                    }},
                  ]}),
                ]),

                ( // Общие параметры
                  params.length > 0
                  ? m(interfaceRow, {label: lang['Shared_param'], help: 'Shared_param'}, [
                      m(dragZone, {
                        onmove: {action: MOVE_PARAMETER_ROW, payload: {blkid: id}}
                      }, DATA.map(function(item) {
                        var params = dataParams();
                        return m(parameterDefinitionRow, {item: item, params_length: params.length});
                      })),

                      // добавить параметр
                      m(aee, {onclick: {action: DATA_ITEM_APPEND, payload: {
                        item: {type: 'parameter', name: wizNextName('P', params), datatype: 'period', default: 'half_month', datatype_details: ''}
                      }}}, lang['add_param']),
                    ])
                  : null
                ),

                // Отображение
                m(interfaceRow, {label: lang['report_form'],  help: 'rb_report_form'},
                  m(dragZone, {
                    className: 'report-constructor-blocklist',
                    onmove: {action: MOVE_LAYOUT_ITEM, payload: {parent_id: id}},
                  }, [
                    layout.map(function(item) { return item.viewAsListItem(); })
                  ]),

                  // Выбор блока
                  m('div[style=font-size:108%]', [
                    m('span', lang['Add'] + ':'), // Добавить:
                    // Таблица
                    m(aee, {style: 'margin-left:.5em', onclick: {
                      action: ADD_LAYOUT_ITEM, payload: {parent_id: id, item_type: 'block_wiz_table'}
                    }}, lang['Table2']),

                    // Мультитаблица
                    (view_multitable || 0) != 0 ? m(aee, {style: 'margin-left: 0.5em', onclick: {
                        action: ADD_LAYOUT_ITEM, payload: {parent_id: id, item_type: 'block_wiz_multitable'}
                      }}, lang['Multitable']) : m('a', {
                        style: 'margin-left: 0.5em; color: grey; text-decoration: none; cursor: default',
                        title: 'Данный функционал доступен на тарифной линейке Pro'
                      }, lang['Multitable']),

                    // Показатель
                    m(aee, {style: 'margin-left:.5em', onclick: {
                      action: ADD_LAYOUT_ITEM, payload: {parent_id: id, item_type: 'block_wiz_indicator'}
                    }}, lang['Indicator']),

                    // Текстовый блок
                    m(aee, {style: 'margin-left:.5em', onclick: {
                      action: ADD_LAYOUT_ITEM, payload: {parent_id: id, item_type: 'block_wiz_text'}
                    }}, lang['text-block']),

                    // График
                    m(aee, {style: 'margin-left:.5em', onclick: {
                      action: ADD_LAYOUT_ITEM, payload: {parent_id: id, item_type: 'block_wiz_chart'}
                    }}, lang['Chart']),

                    // Прогресс-бар
                    m(aee, {style: 'margin-left:.5em', onclick: {
                      action: ADD_LAYOUT_ITEM, payload: {parent_id: id, item_type: 'block_wiz_progress_bar'}
                    }}, lang['Progress_bar']),

                    ( // Канбан
                      MD.getShowBlock("ko_kanban")
                      ? m(aee, {style: 'margin-left:.5em', onclick: {
                        action: ADD_LAYOUT_ITEM, payload: {parent_id: id, item_type: 'block_wiz_kanban'}
                      }}, lang['Kanban'])
                      : null
                    ),

                    m(aee, {style: 'margin-left:.5em', onclick: {
                      action: ADD_LAYOUT_ITEM, payload: {parent_id: id, item_type: 'block_wiz_search'}
                    }}, lang['Search']),

                    // Yaml представление (блок скрыт, для того чтобы увидеть надо нажать на блок с зажатой клавишей 'ctrl')
                    m('span.alaction[style=padding-left:.5em;]', {onclick: vnode.attrs.hidden_action}, ' '),
                  ]),
                ),

                ( // надо описать, хз что это
                  details_item
                  ? layout.filter(function(item) {
                    return item.id() == details_item;
                    }).map(function(item) { 
                        return item.viewAsDetails(); 
                    })
                  : null
                ),
              ]);
            }
          }
        },
      }
    }

    var yaml = '';
    try {
      yaml = YAML.parse(yamltext)
    } catch (e) {
      console.log(e.message);
    }

    paper = PaperView(yaml);

    return paper;
}

function clientbaseMetaData(metadataobj, show_block) {
    var metadata = metadataobj;
    var sb = show_block || {};
    // tables
    var tabIds = Object.keys(metadata.tables).reduce(function(total,key){
        total[metadata.tables[key].name] = metadata.tables[key].id;
        total[metadata.tables[key].id] = metadata.tables[key].id;
        return total;
    },{0:'','':''});
    var tabNms = Object.keys(metadata.tables).reduce(function(total,key){
        total[metadata.tables[key].name] = metadata.tables[key].name;
        total[metadata.tables[key].id] = metadata.tables[key].name;
        return total;
    },{'':'',0:''});
    var tablist = Object.keys(metadata.tables).reduce(function(total,key){
        total.push({id:metadata.tables[key].id,name:metadata.tables[key].name});
        return total;
    },[{id:'',name:''}]);
    tablist.sort(function(a,b){return (a.name==b.name)?0:((a.name>b.name)?+1:-1)});

    // fields
    var fldIds = {}, fldNms = {};
    var fieldlist = Object.keys(metadata.fields).reduce(function(total, key) {
        var result = Object.keys(metadata.fields[key]).reduce(function(tot,k){
            var fi = metadata.fields[key][k];
            tot.push({id:fi.db_name_field,name:fi.name,num:fi.num,type:fi.type,options:fi.value, mult_value: fi.mult_value});
            return tot;
        },[]);

        result.sort(function(a,b){return (a.name==b.name)?0:((a.name>b.name)?+1:-1)});

        fldIds[key] = Object.keys(metadata.fields[key]).reduce(function(tot,k){
            tot[metadata.fields[key][k].name] = metadata.fields[key][k].db_name_field;
            tot[metadata.fields[key][k].db_name_field] = metadata.fields[key][k].db_name_field;
            tot[metadata.fields[key][k].id] = metadata.fields[key][k].db_name_field;
            return tot;
        },{});

        fldNms[key] = Object.keys(metadata.fields[key]).reduce(function(tot,k){
            tot[metadata.fields[key][k].name] = metadata.fields[key][k].name;
            tot[metadata.fields[key][k].db_name_field] = metadata.fields[key][k].name;
            tot[metadata.fields[key][k].id] = metadata.fields[key][k].name;
            return tot;
        },{});

        total[key] = result;
        return total;
    },{});

    // filters
    var filterlist = Object.keys(metadata.filters).reduce(function(total,key){
        var result = Object.keys(metadata.filters[key]).reduce(function(tot,k){
            tot.push({id:metadata.filters[key][k].id,name:metadata.filters[key][k].name,pid:metadata.filters[key][k].pid});
            return tot;
        },[{id:'',name:''}]);
        result.sort(function(a,b){return (a.name==b.name)?0:((a.name>b.name)?+1:-1)});
        let filters = [];
        for(let filter of result){
            filters[filter.id] = {
                name: filter.name,
                pid: filter.pid || 0,
            };
        }
        for(let filter of result){
            let parent = '';
            let pid = filter.pid || 0;
            while(pid > 0){
                if (filters[pid] == null) {
                    pid = 0;
                } else {
                    parent = `${filters[pid].name} - ${parent}`;
                    pid = filters[pid].pid;
                }
            }
            filter.parent = parent;
        }
        total[key] = result;
        return total;
    },{});

    function ti(table_id,name) {
        return metadata.tables[tabIds[table_id]][name];
    };
    function fi(table_id,field_id,name) {
        var tabid = tabIds[table_id];
        var fldid = fldIds[tabid][field_id];
        return metadata.fields[tabid][fldid][name];
    };

    function getUpdatedTableList(val, MD) {
        const existingTableIds = tablist.map(t => t.id); // список ID существующих таблиц
        const newTables = val.tables.filter(t => !existingTableIds.includes(t.use_table) && t.use_table !== ''); // новые таблицы
        const updatedTableList = [ ...tablist, ...newTables.map(t => ({ id: t.use_table, name: MD.getTableName(t.use_table) })) ];
        return updatedTableList;
      }

    return {
       getTableInfoSet: function(table_id) {
            var res = metadata.tables[table_id];
            return res || {};
        },
        getFieldInfoSet: function(table_id) {
            var res = metadata.fields[table_id];
            return res || {};
        },
        getTableList: function() {
            return tablist;
        },
        getTableId: function(value) {
            return tabIds[value];
        },
        getTableName: function(value) {
            return tabNms[value];
        },
        getFieldList: function(table_id) {
            return fieldlist[table_id];
        },
        getFieldId: function(table,field) {
            return fldIds[table][field];
        },
        getFieldName: function(table,field) {
            return fldNms[table][field];
        },
        getFilterList: function(table_id) {
            return filterlist[table_id];
        },
        getAA: function(table_id) {
            let aas = [];
            for(let item of metadata.additional_actions){
                if(item.table_id == table_id){
                    aas.push(item);
                }
            }
            return aas;
        },

        getFieldAndLinkList: function(table_id, multiple_choice_disabled) {
          var res = [],
            src = fieldlist[table_id];

          src.forEach(function(item) {
            var field_info = metadata.fields[table_id][item.id];

            switch (parseInt(field_info.type)) {
              case 7:
              case 11:
                var userinfo = [{id:'fio',nm:lang['Fillot']},{id:'e_mail',nm:lang['e_mail']},{id:'phone',nm:lang['Phone']},{id:'login',nm:lang['Login']}];
                userinfo.forEach(function(i) {
                  res.push({id:'user|'+item.id+'|'+i.id,name:item.name+'.'+i.nm})
                });
                break;

              case 5:
                if (multiple_choice_disabled && field_info['mult_value'] == 1) {
                  break;
                }

                var linkspec = field_info.value.split('|');
                var lnk = fieldlist[linkspec[0]] || [];
                lnk.forEach(function(i){
                  res.push({id:'link|'+item.id+'|'+i.id,name:item.name+'.'+i.name});
                });
                break;

              default:
                res.push({id:'field|'+item.id,name:item.name});
                break;
            }
          });

          return res;
        },

        getFieldForKanbanList: function(table_id) {
          var res = [],
            src = fieldlist[table_id];

          src.forEach(function(item) {
            var field_info = metadata.fields[table_id][item.id];

            switch (field_info.type) {
              case 7 || '7':
                var userinfo = [{id:'fio',nm:lang['Fillot']}];
                userinfo.forEach(function(i){
                  res.push({id:'user|'+item.id+'|'+i.id,name:item.name})
                });
                break;

              case 5 || '5':
                if (field_info['mult_value'] == 1) {
                  break;
                }

                var linkspec = field_info.value.split('|');
                var lnk = fieldlist[linkspec[0]];
                lnk?.forEach(function(i){
                  res.push({id:'link|'+item.id+'|'+i.id,name:item.name+'.'+i.name});
                });
                break;

              case 4 || '4':
                res.push({id:'field|'+item.id,name:item.name});
                break;
            }
          });

          return res;
        },

        getLinkedTables: function(table_id) { // TODO
            var res = [], src = fieldlist[table_id];
            src.forEach(function(item){
                var field_info = metadata.fields[table_id][item.id];
                switch (parseInt(field_info.type)) {
                    case 7: case 11:
                        var userinfo = [{id:'fio',nm:lang['Fillot']},{id:'e_mail',nm:lang['e_mail']},{id:'phone',nm:lang['Phone']},{id:'login',nm:lang['Login']}];
                        userinfo.forEach(function(i){
                            res.push({id:'user|'+item.id+'|'+i.id,name:item.name+'.'+i.nm})
                        });
                        break;
                    case 5:
                        var linkspec = field_info.value.split('|');
                        var lnk = fieldlist[linkspec[0]];
                        lnk.forEach(function(i){
                            res.push({id:'link|'+item.id+'|'+i.id,name:item.name+'.'+i.name});
                        });
                        break;
                    default:
                        res.push({id:'field|'+item.id,name:item.name});
                        break;
                }
            });
            return res;
        },
        ti: function(table_id,name) {
            return ti(table_id,name);
        },
        fi: function(table_id,field_id,name) {
            return fi(table_id,field_id,name);
        },
        getFieldInfo: function(table_id,field_id) {
            var tabid = tabIds[table_id];
            var fldid = fldIds[tabid][field_id];
            return metadata.fields[tabid][fldid];
        },
        getGroups: function() {
            return metadata.groups;
        },
        getShowBlock(block_name) {
            return (sb[block_name] || false);
        },
        getUpdatedTableList,
    }
}
