Exemple #1
0
 /**
  * see html::wysiwyg();
  */
 public static function wysiwyg($options = [])
 {
     // tinymce library
     library::add('tinymce');
     $options['class'] = $options['class'] ?? '';
     $options['class'] .= ' wysiwyg';
     layout::onload("tinymce.init({selector: 'textarea.wysiwyg', height: 500, plugins: ['advlist autolink lists link image charmap print preview hr anchor pagebreak','searchreplace wordcount visualblocks visualchars code fullscreen','insertdatetime media nonbreaking save table contextmenu directionality','emoticons template paste textcolor colorpicker textpattern imagetools'],toolbar1: 'insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image',toolbar2: 'print preview media | forecolor backcolor emoticons'});");
     return html::textarea($options);
 }
Exemple #2
0
 /**
  * see html::calendar()
  */
 public static function calendar($options = [])
 {
     // include js & css files
     if (empty($options['readonly'])) {
         layout::add_js('/numbers/media_submodules/numbers_frontend_components_calendar_numbers_media_js_base.js');
         layout::add_css('/numbers/media_submodules/numbers_frontend_components_calendar_numbers_media_css_base.css');
     }
     // font awesome icons
     library::add('fontawesome');
     // widget parameters
     $type = $options['calendar_type'] ?? $options['type'] ?? 'date';
     $widget_options = ['id' => $options['id'], 'type' => $type, 'format' => $options['calendar_format'] ?? format::get_date_format($type), 'date_week_start_day' => $options['calendar_date_week_start_day'] ?? 1, 'date_disable_week_days' => $options['calendar_date_disable_week_days'] ?? null, 'master_id' => $options['calendar_master_id'] ?? null, 'slave_id' => $options['calendar_slave_id'] ?? null];
     $options['type'] = 'text';
     // determine input size
     $placeholder = format::get_date_placeholder($widget_options['format']);
     $options['size'] = strlen($placeholder);
     // set placeholder
     if (!empty($options['placeholder']) && $options['placeholder'] == 'format::get_date_placeholder') {
         $options['placeholder'] = $placeholder;
         $options['title'] = ($options['title'] ?? '') . ' (' . $placeholder . ')';
     }
     if (isset($options['calendar_icon']) && ($options['calendar_icon'] == 'left' || $options['calendar_icon'] == 'right')) {
         $position = $options['calendar_icon'];
         if (i18n::rtl()) {
             if ($position == 'left') {
                 $position = 'right';
             } else {
                 $position = 'left';
             }
         }
         $icon_type = $type == 'time' ? 'clock-o' : 'calendar';
         unset($options['calendar_icon']);
         if (empty($options['readonly'])) {
             $icon_onclick = 'numbers_calendar_var_' . $options['id'] . '.show();';
         } else {
             $icon_onclick = null;
         }
         $icon_value = html::span(['onclick' => $icon_onclick, 'class' => 'numbers_calendar_icon numbers_prevent_selection', 'value' => html::icon(['type' => $icon_type])]);
         $result = html::input_group(['value' => html::input($options), $position => $icon_value, 'dir' => 'ltr']);
         $div_id = $options['id'] . '_div_holder';
         $result .= html::div(['id' => $div_id, 'class' => 'numbers_calendar_div_holder']);
         $widget_options['holder_div_id'] = $div_id;
     } else {
         $result = html::input($options);
     }
     // we do not render a widget if readonly
     if (empty($options['readonly'])) {
         layout::onload('numbers_calendar(' . json_encode($widget_options) . ');');
     }
     return $result;
 }
    public static function js()
    {
        $js = <<<TTT
\t\t\t/* custom locale methods */
\t\t\tnumbers.format.__custom = {
\t\t\t\tamount: function(amount, options) {
\t\t\t\t\treturn amount.toString().replace(/[0123456789]/g, function(number) { return '٠١٢٣٤٥٦٧٨٩'[parseInt(number)]; });
\t\t\t\t},
\t\t\t\tread_floatval: function(amount, options) {
\t\t\t\t\treturn amount.replace(/[٠١٢٣٤٥٦٧٨٩]/g, function(char) { return char.charCodeAt(0) - 1632; }).replace(/[۰۱۲۳۴۵۶۷۸۹]/g, function(char) { return char.charCodeAt(0) - 1776; });
\t\t\t\t}
\t\t\t};
TTT;
        layout::onload($js);
    }
Exemple #4
0
 /**
  * see html::select();
  */
 public static function select($options = [])
 {
     // we do not process readonly selects
     if (empty($options['readonly'])) {
         // include js & css files
         layout::add_js('/numbers/media_submodules/numbers_frontend_components_select_numbers_media_js_base.js', 10000);
         layout::add_css('/numbers/media_submodules/numbers_frontend_components_select_numbers_media_css_base.css', 10000);
         // font awesome icons
         library::add('fontawesome');
         // id with name
         if (empty($options['id']) && !empty($options['name'])) {
             $options['id'] = $options['name'];
         }
         layout::onload('numbers_select(' . json_encode(['id' => $options['id']]) . ');');
     }
     // must gain proper class from previous submodule
     $options['flag_call_previous_parent'] = true;
     return html::select($options);
 }
Exemple #5
0
    /**
     * @see html::tabs();
     */
    public static function tabs($options = [])
    {
        $header = $options['header'] ?? [];
        $values = $options['options'] ?? [];
        $id = $options['id'] ?? 'tabs_default';
        // determine active tab
        $active_id = $id . '_active_hidden';
        $active_tab = $options['active_tab'] ?? request::input($active_id);
        if (empty($active_tab)) {
            $active_tab = key($header);
        }
        $result = '';
        $result .= '<div id="' . $id . '" class="' . ($options['class'] ?? '') . '">';
        $result .= html::hidden(['name' => $active_id, 'id' => $active_id, 'value' => $active_tab]);
        $tabs = [];
        $panels = [];
        $class = $li_class = $id . '_tab_li';
        foreach ($header as $k => $v) {
            $li_id = $id . '_tab_li_' . $k;
            $content_id = $id . '_tab_content_' . $k;
            $class2 = $class;
            if ($k == $active_tab) {
                $class2 .= ' active';
            }
            if (!empty($options['tab_options'][$k]['hidden'])) {
                $class2 .= ' hidden';
            }
            $tabindex = '';
            if (!empty($options['tab_options'][$k]['tabindex'])) {
                $tabindex = ' tabindex="' . $options['tab_options'][$k]['tabindex'] . '" ';
            }
            $tabs[$k] = '<li id="' . $li_id . '" class="' . $class2 . '"' . $tabindex . ' role="presentation"><a href="#' . $content_id . '" tab-data-id="' . $k . '" aria-controls="' . $content_id . '" role="tab" data-toggle="tab">' . $v . '</a></li>';
            $panels[$k] = '<div role="tabpanel" class="tab-pane ' . ($k == $active_tab ? 'active' : '') . ' ' . $k . '" id="' . $content_id . '">' . $values[$k] . '</div>';
        }
        $result .= '<ul class="nav nav-tabs" role="tablist" id="' . $id . '_links' . '">';
        $result .= implode('', $tabs);
        $result .= '</ul>';
        $result .= '<div class="tab-content">';
        $result .= implode('', $panels);
        $result .= '</div>';
        $result .= '</div>';
        $js = <<<TTT
\t\t\t\$('#{$id}_links a').click(function(e) {
\t\t\t\te.preventDefault();
\t\t\t\t\$(this).tab('show');
\t\t\t\t\$('#{$active_id}').val(\$(this).attr('tab-data-id'));
\t\t\t});
\t\t\t\$('.{$li_class}').mousedown(function(e) {
\t\t\t\tvar that = \$(this);
\t\t\t\tif (!that.is(':focus')) {
\t\t\t\t\tthat.data('mousedown', true);
\t\t\t\t}
\t\t\t});
\t\t\t\$('.{$li_class}').focus(function(e) {
\t\t\t\te.preventDefault();
\t\t\t\tvar mousedown = \$(this).data('mousedown'), tabindex = parseInt(\$(this).attr('tabindex'));
\t\t\t\t\$(this).removeData('mousedown');
\t\t\t\t\$(this).find('a:first').click();
\t\t\t\tif (!mousedown && tabindex > 0) {
\t\t\t\t\t\$("[tabindex='" + (tabindex + 1) + "']").focus();
\t\t\t\t} else if (mousedown) {
\t\t\t\t\t\$(this).blur();
\t\t\t\t}
\t\t\t\te.preventDefault();
\t\t\t});
TTT;
        layout::onload($js);
        return $result;
    }
Exemple #6
0
 /**
  * @see html::select()
  */
 public static function select($options = [])
 {
     $multiselect = null;
     if (isset($options['multiselect'])) {
         $multiselect = $options['multiselect'];
         $multiselect['flag_present'] = true;
     }
     unset($options['multiselect']);
     $no_choose = false;
     if (!empty($options['multiple']) || !empty($multiselect)) {
         $options['name'] = !empty($options['name']) ? $options['name'] . '[]' : '';
         $options['multiple'] = 'multiple';
         $no_choose = true;
     }
     if (!empty($options['no_choose'])) {
         $no_choose = true;
     }
     // disabled
     if (!empty($options['disabled'])) {
         $options['disabled'] = 'disabled';
     } else {
         unset($options['disabled']);
     }
     // readonly
     if (!empty($options['readonly'])) {
         layout::onload("\$('#{$options['id']} option:not(:selected)').prop('disabled', true);");
     }
     // options & optgroups
     $optgroups_array = !empty($options['optgroups']) ? $options['optgroups'] : [];
     $options_array = !empty($options['options']) ? $options['options'] : [];
     $value = isset($options['value']) ? $options['value'] : null;
     unset($options['options'], $options['optgroups'], $options['value'], $options['no_choose']);
     // assembling
     $result = '';
     if (!$no_choose) {
         $result .= '<option value=""></option>';
     }
     // options first
     if (!empty($options_array)) {
         $result .= self::generate_select_options($options_array, $value);
     }
     // optgroups second
     if (!empty($optgroups_array)) {
         $options['optgroups'] = 'optgroups';
         foreach ($optgroups_array as $k2 => $v2) {
             $result .= '<optgroup label="' . $v2['name'] . '" id="' . $k2 . '">';
             $result .= self::generate_select_options($v2['options'], $value);
             $result .= '</optgroup>';
         }
     }
     return '<select ' . self::generate_attributes($options, 'select') . '>' . $result . '</select>';
 }
Exemple #7
0
 /**
  * Render form
  *
  * @return mixed
  */
 public function render()
 {
     // ajax requests from another form
     if ($this->flag_another_ajax_call) {
         return null;
     }
     $this->tabindex = 1;
     // css & js
     numbers_frontend_media_libraries_jssha_base::add();
     layout::add_js('/numbers/media_submodules/numbers_frontend_html_form_media_js_base.js', -10000);
     // include master js
     if (!empty($this->master_object) && method_exists($this->master_object, 'add_js')) {
         $this->master_object->add_js();
     }
     // include js
     $filename = str_replace('_model_', '_media_js_', $this->form_class) . '.js';
     if (file_exists('./../libraries/vendor/' . str_replace('_', '/', $filename))) {
         layout::add_js('/numbers/media_submodules/' . $filename);
     }
     $this->misc_settings['extended_js_class'] = 'numbers.' . $this->form_class;
     // include css
     $filename = str_replace('_model_', '_media_css_', $this->form_class) . '.css';
     if (file_exists('./../libraries/vendor/' . str_replace('_', '/', $filename))) {
         layout::add_css('/numbers/media_submodules/' . $filename);
     }
     // load mask
     numbers_frontend_media_libraries_loadmask_base::add();
     // new record action
     $mvc = application::get('mvc');
     if (object_controller::can('record_new')) {
         $onclick = 'return confirm(\'' . strip_tags(i18n(null, object_content_messages::confirm_blank)) . '\');';
         $this->actions['form_new'] = ['value' => 'New', 'sort' => -31000, 'icon' => 'file-o', 'href' => $mvc['full'] . '?' . $this::button_submit_blank . '=1', 'onclick' => $onclick, 'internal_action' => true];
     }
     // back to list
     if (object_controller::can('list_view')) {
         $this->actions['form_back'] = ['value' => 'Back', 'sort' => -32000, 'icon' => 'arrow-left', 'href' => $mvc['controller'] . '/_index', 'internal_action' => true];
     }
     // reload button
     if ($this->values_loaded) {
         $url = $mvc['full'] . '?' . http_build_query2($this->pk);
         $this->actions['form_refresh'] = ['value' => 'Refresh', 'sort' => 32000, 'icon' => 'refresh', 'href' => $url, 'internal_action' => true];
     }
     // handling override_field_value method
     if (!empty($this->wrapper_methods['pre_render']['main'])) {
         call_user_func_array($this->wrapper_methods['pre_render']['main'], [&$this]);
     }
     // assembling everything into result variable
     $result = [];
     // order containers based on order column
     array_key_sort($this->data, ['order' => SORT_ASC]);
     foreach ($this->data as $k => $v) {
         if (!$v['flag_child']) {
             if ($v['type'] == 'fields' || $v['type'] == 'details') {
                 // reset tabs
                 $this->current_tab = [];
                 $temp = $this->render_container($k);
                 if ($temp['success']) {
                     $result[$k] = $temp['data'];
                 }
             } else {
                 if ($v['type'] == 'tabs') {
                     // tabs
                     $tab_id = "form_tabs_{$this->form_link}_{$k}";
                     $tab_header = [];
                     $tab_values = [];
                     $tab_options = [];
                     $have_tabs = false;
                     // sort rows
                     array_key_sort($v['rows'], ['order' => SORT_ASC]);
                     foreach ($v['rows'] as $k2 => $v2) {
                         $this->current_tab[] = "{$tab_id}_{$k2}";
                         $labels = '';
                         foreach (['records', 'danger', 'warning', 'success', 'info'] as $v78) {
                             $labels .= html::label2(['type' => $v78 == 'records' ? 'primary' : $v78, 'style' => 'display: none;', 'value' => 0, 'id' => implode('__', $this->current_tab) . '__' . $v78]);
                         }
                         $tab_header[$k2] = i18n(null, $v2['options']['label_name']) . $labels;
                         $tab_values[$k2] = '';
                         // handling override_tabs method
                         if (!empty($this->wrapper_methods['override_tabs']['main'])) {
                             $tab_options[$k2] = call_user_func_array($this->wrapper_methods['override_tabs']['main'], [&$this, &$v2, &$k2, &$this->values]);
                             if (empty($tab_options[$k2]['hidden'])) {
                                 $have_tabs = true;
                             }
                         } else {
                             $have_tabs = true;
                         }
                         // tab index for not hidden tabs
                         if (empty($tab_options[$k2]['hidden'])) {
                             $tab_options[$k2]['tabindex'] = $this->tabindex;
                             $this->tabindex++;
                         }
                         // render containers
                         array_key_sort($v2['elements'], ['order' => SORT_ASC]);
                         foreach ($v2['elements'] as $k3 => $v3) {
                             $temp = $this->render_container($v3['options']['container']);
                             if ($temp['success']) {
                                 $tab_values[$k2] .= $temp['data']['html'];
                             }
                         }
                         // remove last element from an array
                         array_pop($this->current_tab);
                     }
                     // if we do not have tabs
                     if ($have_tabs) {
                         $result[$k]['html'] = html::tabs(['id' => $tab_id, 'class' => 'form-tabs', 'header' => $tab_header, 'options' => $tab_values, 'tab_options' => $tab_options]);
                     }
                 }
             }
         }
     }
     // formatting data
     $temp = [];
     foreach ($result as $k => $v) {
         $temp[] = $v['html'];
     }
     $result = implode('', $temp);
     // we need to skip internal actions
     if (!empty($this->options['no_actions'])) {
         foreach ($this->actions as $k0 => $v0) {
             if (!empty($v0['internal_action'])) {
                 unset($this->actions[$k0]);
             }
         }
     }
     // rendering actions
     if (!empty($this->actions)) {
         $value = '<div style="text-align: right;">' . $this->render_actions() . '</div>';
         $value .= '<hr class="simple" />';
         $result = $value . $result;
     }
     // messages
     if (!empty($this->errors['general'])) {
         $messages = '';
         foreach ($this->errors['general'] as $k => $v) {
             $messages .= html::message(['options' => $v, 'type' => $k]);
         }
         $result = '<div class="form_message_container">' . $messages . '</div>' . $result;
     }
     // couple hidden fields
     $result .= html::hidden(['name' => '__form_link', 'value' => $this->form_link]);
     $result .= html::hidden(['name' => '__form_values_loaded', 'value' => $this->values_loaded]);
     $result .= html::hidden(['name' => '__form_onchange_field_values_key', 'value' => '']);
     if (!empty($this->options['bypass_hidden_values'])) {
         foreach ($this->options['bypass_hidden_values'] as $k => $v) {
             $result .= html::hidden(['name' => $k, 'value' => $v]);
         }
     }
     // js to update counters in tabs
     if (!empty($this->errors['tabs'])) {
         foreach ($this->errors['tabs'] as $k => $v) {
             layout::onload("\$('#{$k}').html({$v}); \$('#{$k}').show();");
         }
     }
     // if we have form
     if (empty($this->options['skip_form'])) {
         $mvc = application::get('mvc');
         $result = html::form(['action' => $mvc['full'], 'name' => "form_{$this->form_link}_form", 'id' => "form_{$this->form_link}_form", 'value' => $result, 'onsubmit' => empty($this->options['no_ajax_form_reload']) ? 'return numbers.form.on_form_submit(this);' : null]);
     }
     // if we came from ajax we return as json object
     if (!empty($this->options['input']['__ajax'])) {
         $result = ['success' => true, 'error' => [], 'html' => $result, 'js' => layout::$onload];
         layout::render_as($result, 'application/json');
     }
     $result = "<div id=\"form_{$this->form_link}_form_mask\"><div id=\"form_{$this->form_link}_form_wrapper\">" . $result . '</div></div>';
     // if we have segment
     if (isset($this->options['segment'])) {
         $temp = is_array($this->options['segment']) ? $this->options['segment'] : [];
         $temp['value'] = $result;
         $result = html::segment($temp);
     }
     return $result;
 }
Exemple #8
0
    /**
     * Expiry dialog
     *
     * @return string
     */
    public function expiry_dialog()
    {
        $body = i18n(null, 'Your session is about to expire, would you like to renew your session?');
        $body .= '<br/><br/>';
        $body .= i18n(null, 'This dialog would close in [seconds] seconds.', ['replace' => ['[seconds]' => '<span id="modal_session_expiry_seconds">60</span>']]);
        $buttons = '';
        $buttons .= html::button2(['id' => 'modal_session_expiry_renew_button', 'type' => 'primary', 'value' => i18n(null, 'Renew'), 'onclick' => 'modal_session_expiry_renew_session();']) . ' ';
        $url = application::get('flag.global.authorization.logout.controller');
        $buttons .= html::button2(['id' => 'modal_session_expiry_close_button', 'type' => 'danger', 'value' => i18n(null, 'Close'), 'onclick' => "window.location.href = '{$url}'"]);
        $options = ['id' => 'modal_session_expiry', 'title' => i18n(null, 'Session'), 'body' => $body, 'footer' => $buttons, 'no_header_close' => true, 'close_by_click_disabled' => true];
        $js = <<<TTT
\t\t\t// Session handling logic
\t\t\tvar flag_modal_session_expiry_waiting = false;
\t\t\tvar modal_session_expiry_waiting_interval;
\t\t\tvar modal_session_expiry_counter_interval, modal_session_expiry_counter_value;
\t\t\tfunction modal_session_expiry_init() {
\t\t\t\tmodal_session_expiry_counter_value = 60;
\t\t\t\t\$('#modal_session_expiry_seconds').html(modal_session_expiry_counter_value);
\t\t\t\tmodal_session_expiry_waiting_interval = setInterval(function(){ modal_session_expiry_check(); }, 2 * 60 * 1000);
\t\t\t}
\t\t\tfunction modal_session_expiry_check() {
\t\t\t\tif (flag_modal_session_expiry_waiting) {
\t\t\t\t\treturn;
\t\t\t\t}
\t\t\t\t// we make a call to the server to see session status
\t\t\t\tvar request = \$.ajax({
\t\t\t\t\turl: '/numbers/backend/session/db/controller/check/_index',
\t\t\t\t\tmethod: "POST",
\t\t\t\t\tdata: {
\t\t\t\t\t\ttoken: numbers.token,
\t\t\t\t\t\t__skip_session: true
\t\t\t\t\t},
\t\t\t\t\tdataType: "json"
\t\t\t\t});
\t\t\t\trequest.done(function(data) {
\t\t\t\t\tvar flag_expired = false;
\t\t\t\t\tif (data.success) {
\t\t\t\t\t\t// if not logged in we redirect
\t\t\t\t\t\tif (!data.loggedin || data.expired) {
\t\t\t\t\t\t\tflag_expired = true;
\t\t\t\t\t\t}
\t\t\t\t\t\t// we check if session expires in 5 minutes, if yes we show dialog
\t\t\t\t\t\tif (data.expires_in <= 300) {
\t\t\t\t\t\t\tnumbers.modal.show('modal_session_expiry');
\t\t\t\t\t\t\tflag_modal_session_expiry_waiting = true;
\t\t\t\t\t\t\tmodal_session_expiry_counter_interval = setInterval(function(){
\t\t\t\t\t\t\t\tmodal_session_expiry_counter_value--;
\t\t\t\t\t\t\t\t\$('#modal_session_expiry_seconds').html(modal_session_expiry_counter_value);
\t\t\t\t\t\t\t\tif (modal_session_expiry_counter_value == 0) {
\t\t\t\t\t\t\t\t\twindow.location.href = '{$url}';
\t\t\t\t\t\t\t\t}
\t\t\t\t\t\t\t}, 1000);
\t\t\t\t
\t\t\t\t\t\t}
\t\t\t\t\t} else {
\t\t\t\t\t\tflag_expired = true;
\t\t\t\t\t}
\t\t\t\t\t// if expired we redirect to logout
\t\t\t\t\tif (flag_expired) {
\t\t\t\t\t\twindow.location.href = '{$url}';
\t\t\t\t\t}
\t\t\t\t});
\t\t\t\trequest.fail(function(jqXHR, textStatus) {
\t\t\t\t\twindow.location.href = '{$url}';
\t\t\t\t});
\t\t\t}
\t\t\twindow.modal_session_expiry_renew_session = function() {
\t\t\t\tnumbers.modal.hide('modal_session_expiry');
\t\t\t\tclearInterval(modal_session_expiry_waiting_interval);
\t\t\t\tclearInterval(modal_session_expiry_counter_interval);
\t\t\t\t// we make a call to the server to renew session
\t\t\t\tvar request = \$.ajax({
\t\t\t\t\turl: '/numbers/backend/session/db/controller/check/_renew',
\t\t\t\t\tmethod: "POST",
\t\t\t\t\tdata: {
\t\t\t\t\t\ttoken: numbers.token
\t\t\t\t\t},
\t\t\t\t\tdataType: "json"
\t\t\t\t});
\t\t\t\trequest.done(function(data) {
\t\t\t\t\tif (data.success) {
\t\t\t\t\t\tflag_modal_session_expiry_waiting = false;
\t\t\t\t\t\tmodal_session_expiry_init();
\t\t\t\t\t} else {
\t\t\t\t\t\twindow.location.href = '{$url}';
\t\t\t\t\t}
\t\t\t\t});
\t\t\t\trequest.fail(function(jqXHR, textStatus) {
\t\t\t\t\twindow.location.href = '{$url}';
\t\t\t\t});
\t\t\t}
\t\t\t// initialize the engine
\t\t\tmodal_session_expiry_init();
TTT;
        layout::onload($js);
        return html::modal($options);
    }
 /**
  * Render
  *
  * @param object $form
  */
 public function render_upload_container(&$form)
 {
     $result = ['success' => false, 'error' => [], 'data' => ['html' => '', 'js' => '', 'css' => '']];
     // values
     $input = $form->options['input'] ?? [];
     $catalogs_model = new numbers_backend_documents_basic_model_catalogs();
     $catalogs_options = $catalogs_model->options();
     $catalogs = $catalogs_model->get();
     // we would assemble everyting into $data variable
     $data = ['options' => []];
     // up to 3 uploads at a time
     for ($row_number = 1; $row_number <= 3; $row_number++) {
         $name = 'upload[' . $row_number . ']';
         $row_class = $row_number % 2 ? 'grid_row_even' : 'grid_row_odd';
         $current_catalog = [];
         if (!empty($input['upload'][$row_number]['catalog_code']) && !empty($catalogs[$input['upload'][$row_number]['catalog_code']])) {
             $current_catalog = $catalogs[$input['upload'][$row_number]['catalog_code']];
         }
         // first line
         $data['options'][$row_number]['row_number']['row_number'] = ['label' => '&nbsp;', 'value' => $row_number . '.', 'options' => ['percent' => 1], 'class' => 'grid_counter_row', 'row_class' => $row_class];
         $data['options'][$row_number]['catalog_code']['catalog_code'] = ['label' => html::label(['value' => i18n(null, 'Catalog') . ':', 'class' => 'control-label']), 'value' => $form->render_element_value(['type' => 'field', 'options' => ['id' => 'catalog_code_' . $row_number, 'name' => $name . '[catalog_code]', 'method' => 'html::select', 'options' => $catalogs_options, 'onchange' => 'this.form.submit();']], $input['upload'][$row_number]['catalog_code'] ?? null), 'options' => ['percent' => 25]];
         $data['options'][$row_number]['file']['file'] = ['label' => html::label(['value' => i18n(null, 'Upload') . ':', 'class' => 'control-label']), 'value' => html::file(['class' => 'file_upload_file', 'skip_form_control' => true, 'multiple' => !empty($current_catalog['dc_catalog_multiple'])]), 'options' => ['percent' => 25]];
         $data['options'][$row_number]['files']['files'] = ['label' => html::label(['value' => i18n(null, 'File(s)') . ':', 'class' => 'control-label']), 'value' => '<div>123</div>', 'options' => []];
         // 2nd row if not multiple
         if (!empty($current_catalog) && empty($current_catalog['dc_catalog_multiple'])) {
             $temp_name = i18n(null, 'ID');
             if ($current_catalog['dc_catalog_id_required']) {
                 $temp_name = html::mandatory(['type' => 'mandatory', 'value' => $temp_name]);
             }
             $temp_name .= ':';
             $data['options'][$row_number . '_2nd']['row_number']['row_number'] = ['label' => '&nbsp;', 'value' => '&nbsp;', 'options' => ['percent' => 1], 'class' => 'grid_counter_row', 'row_class' => $row_class];
             $data['options'][$row_number . '_2nd']['id_required']['id_required'] = ['label' => html::label(['value' => $temp_name, 'class' => 'control-label']), 'error' => $form->get_field_errors(['options' => ['name' => $name . '[id_required]']]), 'value' => $form->render_element_value(['type' => 'field', 'options' => ['id' => 'id_required_' . $row_number, 'name' => $name . '[id_required]', 'method' => 'html::input']], $input['upload'][$row_number]['id_required'] ?? null), 'options' => ['percent' => 25], 'row_class' => $row_class];
             $temp_name = i18n(null, 'Date');
             if ($current_catalog['dc_catalog_date_required']) {
                 $temp_name = html::mandatory(['type' => 'mandatory', 'value' => $temp_name]);
             }
             $temp_name .= ':';
             $data['options'][$row_number . '_2nd']['date_required']['date_required'] = ['label' => html::label(['value' => $temp_name, 'class' => 'control-label']), 'error' => $form->get_field_errors(['options' => ['name' => $name . '[date_required]']]), 'value' => $form->render_element_value(['type' => 'field', 'options' => ['id' => 'date_required_' . $row_number, 'name' => $name . '[date_required]', 'method' => 'html::calendar', 'calendar_icon' => 'right']], $input['upload'][$row_number]['date_required'] ?? null), 'options' => ['percent' => 25], 'row_class' => $row_class];
             $temp_name = i18n(null, 'Comment');
             if ($current_catalog['dc_catalog_comment_required']) {
                 $temp_name = html::mandatory(['type' => 'mandatory', 'value' => $temp_name]);
             }
             $temp_name .= ':';
             $data['options'][$row_number . '_2nd']['comment_required']['comment_required'] = ['label' => html::label(['value' => $temp_name, 'class' => 'control-label']), 'error' => $form->get_field_errors(['options' => ['name' => $name . '[comment_required]']]), 'value' => $form->render_element_value(['type' => 'field', 'options' => ['id' => 'comment_required_' . $row_number, 'name' => $name . '[comment_required]', 'method' => 'html::textarea', 'rows' => 3]], $input['upload'][$row_number]['comment_required'] ?? null), 'options' => ['percent' => 50], 'row_class' => $row_class];
         }
     }
     // add js file and initialize uploads
     layout::add_js('/numbers/media_submodules/numbers_backend_documents_basic_base.js');
     layout::onload('numbers.backend_documents.init();');
     $result['data']['html'] = html::grid($data);
     $result['success'] = true;
     return $result;
 }