/** * Render * * @param object $object * @return string */ public static function render($object) { $input = $object->options['input']; if (empty($input['sort'])) { $i = 0; foreach ($object->orderby as $k => $v) { $input['sort'][$i]['column'] = $k; $input['sort'][$i]['order'] = $v; $i++; } } // generating form $table = ['header' => ['row_number' => ' ', 'column' => i18n(null, 'Column'), 'order' => i18n(null, 'Order')], 'options' => []]; $order_model = new object_data_model_order(); $columns = []; // we need to skip certain columns foreach ($object->columns as $k => $v) { if (!in_array($k, ['row_number', 'offset_number', 'action'])) { $v['name'] = i18n(null, $v['name']); $columns[$k] = $v; } } // full text search goes last if (!empty($object->filter['full_text_search'])) { $columns['full_text_search'] = ['name' => i18n(null, 'Text Search')]; } // render 5 rows for ($i = 0; $i < 5; $i++) { if (empty($input['sort'][$i]['column'])) { $input['sort'][$i]['order'] = SORT_ASC; } $column = html::select(['id' => 'sort_' . $i . '_column', 'name' => 'sort[' . $i . '][column]', 'options' => $columns, 'value' => $input['sort'][$i]['column'] ?? null]); $order = html::select(['id' => 'sort_' . $i . '_order', 'name' => 'sort[' . $i . '][order]', 'no_choose' => true, 'options' => $order_model->options(['i18n' => true]), 'value' => $input['sort'][$i]['order'] ?? null]); $table['options'][$i] = ['row_number' => ['value' => format::id($i + 1) . '.', 'width' => '1%', 'align' => 'right'], 'column' => ['value' => $column, 'width' => '25%', 'class' => 'list_sort_name'], 'order' => ['value' => $order, 'width' => '30%']]; } $body = html::table($table); $footer = html::button2(['name' => 'submit_sort', 'value' => i18n(null, 'Submit'), 'type' => 'primary', 'onclick' => "numbers.modal.hide('list_{$object->list_link}_sort'); \$('#list_{$object->list_link}_form').attr('target', '_self'); \$('#list_{$object->list_link}_form').attr('no_ajax', ''); return true;"]); return html::modal(['id' => "list_{$object->list_link}_sort", 'class' => 'large', 'title' => i18n(null, 'Sort'), 'body' => $body, 'footer' => $footer]); }
function id() { global $tree; if (is_array($tree->tree)) { reset($tree->tree); while (list($key, $item) = each($tree->tree)) { if ($item['navigation'] && ($tree->hasOverlap($this->id, $item['id']) || $item['id'] == $this->id)) { return htmlspecialchars(format::id($item['slug']), ENT_QUOTES); } } } }
/** * Get translation * * @param string $i18n * @param string $text * @param array $options * @return string */ public static function get($i18n, $text, $options = []) { // try to ge it by i18n $i18n = abs(intval($i18n)); $translated = false; if (empty($i18n)) { // some texts we skip if (in_array($text . '', [' ', ' ', '-', '', ' '])) { $result = $text; $skip_translation_symbol = true; goto finish; } // integers and floats if (is_numeric($text)) { $result = format::id($text); $skip_translation_symbol = true; goto finish; } } // if we have i18n if (!empty($i18n) && isset(self::$data['ids'][$i18n])) { $result = self::$data['hashes'][self::$data['ids'][$i18n]]; goto finish; } // we translate if language is not system if (self::$language_code != 'sys') { // continue logic $hash = $text; if (strlen($hash) > 40) { $hash = sha1($hash); } if (array_key_exists($hash, self::$data['hashes'])) { $result = self::$data['hashes'][$hash]; $translated = true; } else { $result = $text; // put data into missing if (self::$language_code != 'eng') { if (!isset(self::$missing[$result])) { self::$missing[$result] = 1; } else { self::$missing[$result] += 1; } } } } else { $result = $text; } finish: // append translation symbol for system language if (debug::$debug && application::get('flag.global.__content_type') == 'text/html' && empty($skip_translation_symbol) && empty($options['skip_translation_symbol']) && self::$language_code == 'sys') { $color = $translated ? 'blue' : 'red'; $result .= '<span style="color: ' . $color . '; font-weight: bold:"><span style="display:none"> (</span>i<span style="display:none">)</span></span>'; } return $result; }
/** * Details - render table * * @param array $rows * @param array $values * @param array $options */ public function render_container_type_details_rows($rows, $values, $options = []) { $result = ''; // empty_warning_message if (empty($options['details_new_rows']) && empty($values) && isset($options['details_empty_warning_message'])) { if (empty($options['details_empty_warning_message'])) { return html::message(['type' => 'warning', 'options' => [object_content_messages::no_rows_found]]); } else { return html::message(['type' => 'warning', 'options' => [$options['details_empty_warning_message']]]); } } // building table $table = ['header' => ['row_number' => '', 'row_data' => '', 'row_delete' => ''], 'options' => [], 'skip_header' => true]; if (!empty($options['details_11'])) { $table['class'] = 'table grid_table_details_11'; $table['header'] = ['row_data' => '']; } // header rows for table if ($options['details_rendering_type'] == 'table') { foreach ($rows as $k => $v) { array_key_sort($v['elements'], ['order' => SORT_ASC]); // group by $groupped = []; foreach ($v['elements'] as $k2 => $v2) { $groupped[$v2['options']['label_name'] ?? ''][$k2] = $v2; } foreach ($groupped as $k2 => $v2) { $first = current($v2); $first_key = key($v2); foreach ($v2 as $k3 => $v3) { // hidden row if ($k === $this::hidden && !application::get('flag.numbers.frontend.html.form.show_field_settings')) { $v3['options']['row_class'] = ($v3['options']['row_class'] ?? '') . ' grid_row_hidden'; } $data['options'][$k][$k2][$k3] = ['label' => $this->render_element_name($first), 'options' => $v3['options'], 'row_class' => $v3['options']['row_class'] ?? null]; } } } // add a row to a table $table['options']['__header'] = ['row_number' => ['value' => ' ', 'width' => '1%'], 'row_data' => ['value' => html::grid($data), 'width' => !empty($options['details_11']) ? '100%' : '98%'], 'row_delete' => ['value' => ' ', 'width' => '1%']]; } // we must sort array_key_sort($rows, ['order' => SORT_ASC]); // generating rows $row_number = 1; // 1 to 1 if (!empty($options['details_11'])) { $max_rows = 1; $processing_values = 1; } else { $max_rows = count($values) + ($options['details_new_rows'] ?? 0); $processing_values = !empty($values); } do { // we exit if there's no rows and if we have no values if ($row_number > $max_rows) { break; } // render $data = ['options' => []]; // grab next element from an array if ($processing_values) { if (!empty($options['details_11'])) { $k0 = null; $v0 = $values; } else { $k0 = key($values); $v0 = current($values); } } else { $k0 = $row_number; $v0 = []; } $i0 = $row_number; // we need to preset default values if (!empty($options['details_parent_key'])) { $fields = $this->sort_fields_for_processing($this->detail_fields[$options['details_parent_key']]['subdetails'][$options['details_key']]['elements'], $this->detail_fields[$options['details_parent_key']]['subdetails'][$options['details_key']]['options']); } else { $fields = $this->sort_fields_for_processing($this->detail_fields[$options['details_key']]['elements'], $this->detail_fields[$options['details_key']]['options']); } // todo: handle changed field foreach ($fields as $k19 => $v19) { if (array_key_exists('default', $v19['options']) && !isset($v0[$k19])) { $temp = $this->process_default_value($k19, $v19['options']['default'], $v0[$k19] ?? null, $v0, true); } } // looping though rows foreach ($rows as $k => $v) { // row_id if (empty($options['details_parent_key'])) { $row_id = "form_{$this->form_link}_details_{$options['details_key']}_{$row_number}_row"; } else { $row_id = "form_{$this->form_link}_subdetails_{$options['details_parent_key']}_{$options['__parent_row_number']}_{$options['details_key']}_{$row_number}_row"; } array_key_sort($v['elements'], ['order' => SORT_ASC]); // group by $groupped = []; foreach ($v['elements'] as $k2 => $v2) { $groupped[$v2['options']['label_name'] ?? ''][$k2] = $v2; } foreach ($groupped as $k2 => $v2) { $first = current($v2); $first_key = key($v2); if ($first_key == self::separator_horisontal) { $data['options'][$row_number . '_' . $k][$k2][0] = ['value' => html::separator(['value' => $first['options']['label_name'], 'icon' => $first['options']['icon'] ?? null]), 'separator' => true]; } else { $first['prepend_to_field'] = ':'; foreach ($v2 as $k3 => $v3) { // generate id, name and error name if (empty($options['details_parent_key'])) { // 1 to 1 if (!empty($options['details_11'])) { $name = "{$options['details_key']}[{$k3}]"; $id = "form_{$this->form_link}_details_{$options['details_key']}_{$k3}"; $error_name = "{$options['details_key']}[{$k3}]"; $values_key = [$options['details_key'], $k3]; $field_values_key = [$options['details_key'], $k3]; } else { // 1 to M $name = "{$options['details_key']}[{$i0}][{$k3}]"; $id = "form_{$this->form_link}_details_{$options['details_key']}_{$row_number}_{$k3}"; $error_name = "{$options['details_key']}[{$k0}][{$k3}]"; $values_key = [$options['details_key'], $k0, $k3]; $field_values_key = [$options['details_key'], $i0, $k3]; } } else { $name = "{$options['details_parent_key']}[{$options['__parent_row_number']}][{$options['details_key']}][{$k0}][{$k3}]"; $id = "form_{$this->form_link}_subdetails_{$options['details_parent_key']}_{$options['__parent_row_number']}_{$options['details_key']}_{$row_number}_{$k3}"; $error_name = "{$options['details_parent_key']}[{$options['__parent_key']}][{$options['details_key']}][{$k0}][{$k3}]"; $values_key = [$options['details_parent_key'], $options['__parent_key'], $options['details_key'], $k0, $k3]; $field_values_key = [$options['details_parent_key'], $options['__parent_row_number'], $options['details_key'], $k0, $k3]; } // error $error = $this->get_field_errors(['options' => ['name' => $error_name]]); // counter for 1 to M only if (!empty($error['counters'])) { $this->error_in_tabs($error['counters']); } // hidden row $hidden = false; if ($k === $this::hidden && !application::get('flag.numbers.frontend.html.form.show_field_settings')) { $v3['options']['row_class'] = ($v3['options']['row_class'] ?? '') . ' grid_row_hidden'; $hidden = true; } // generate proper element $value_options = $v3; $value_options['options']['id'] = $id; $value_options['options']['name'] = $name; $value_options['options']['error_name'] = $error_name; $value_options['options']['details_parent_key'] = $options['details_parent_key'] ?? null; $value_options['options']['__parent_row_number'] = $options['__parent_row_number'] ?? null; $value_options['options']['__row_number'] = $row_number; $value_options['options']['__new_row'] = !$processing_values; // need to set values_key $value_options['options']['values_key'] = $values_key; $value_options['options']['field_values_key'] = $field_values_key; // tabindex but not for subdetails if (!$hidden && empty($options['__parent_row_number'])) { $value_options['options']['tabindex'] = $this->tabindex; $this->tabindex++; } // label $label = null; if ($options['details_rendering_type'] == 'grid_with_label') { $label = $this->render_element_name($first); } // add element to grid $data['options'][$row_number . '_' . $k][$k2][$k3] = ['error' => $error, 'label' => $label, 'value' => $this->render_element_value($value_options, $v0[$k3] ?? null, $v0), 'description' => $v3['options']['description'] ?? null, 'options' => $v3['options'], 'row_class' => ($value_options['options']['row_class'] ?? '') . (!($row_number % 2) ? ' grid_row_even' : ' grid_row_odd')]; } } } } // increase counter if ($processing_values && empty($options['details_11'])) { $this->error_in_tabs(['records' => 1]); } // subdetails if (!empty($this->detail_fields[$options['details_key']]['subdetails'])) { $tab_id = "form_tabs_{$this->form_link}_subdetails_{$options['details_key']}_{$row_number}"; $tab_header = ['tabs_subdetails_none' => html::icon(['type' => 'toggle-on'])]; $tab_values = ['tabs_subdetails_none' => '']; $tab_options = ['tabs_subdetails_none' => []]; // sort subdetail tabs $tab_sorted = []; foreach ($this->detail_fields[$options['details_key']]['subdetails'] as $k10 => $v10) { $tab_sorted[$k10] = ['order' => $v10['options']['order'] ?? 0]; } array_key_sort($tab_sorted, ['order' => SORT_ASC]); // render tabs $have_tabs = false; foreach ($tab_sorted as $k10 => $v10) { $v10 = $this->detail_fields[$options['details_key']]['subdetails'][$k10]; $this->current_tab[] = "{$tab_id}_{$k10}"; $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[$k10] = i18n(null, $v10['options']['label_name']) . $labels; $tab_values[$k10] = ''; // handling override_tabs method if (!empty($this->wrapper_methods['override_tabs']['main'])) { $tab_options[$k10] = call_user_func_array($this->wrapper_methods['override_tabs']['main'], [&$this, &$v10, &$k10, &$v0]); if (empty($tab_options[$k10]['hidden'])) { $have_tabs = true; } } else { $have_tabs = true; } $v10['__values'] = $v0[$v10['options']['details_key']] ?? []; $v10['__parent_row_number'] = $row_number; $v10['__parent_key'] = $k0; $temp = $this->render_container_type_subdetails($v10['options']['container_link'], $v10); if ($temp['success']) { $tab_values[$k10] .= $temp['data']['html']; } // we must unset it array_pop($this->current_tab); } // if we do not have tabs if (!$have_tabs) { $tab_options['tabs_subdetails_none']['hidden'] = true; } $subdetails = html::tabs(['id' => $tab_id, 'header' => $tab_header, 'options' => $tab_values, 'class' => 'tabs_subdetails', 'tab_options' => $tab_options]); // add row to the end $data['options'][$row_number . '_subdetails']['subdetails']['subdetails'] = ['error' => null, 'label' => null, 'value' => $subdetails, 'description' => null, 'options' => ['percent' => 100], 'row_class' => !($row_number % 2) ? 'grid_row_even' : 'grid_row_odd']; } // delete link if (empty($options['details_cannot_delete'])) { $link = html::a(['href' => 'javascript:void(0);', 'value' => '<i class="fa fa-trash-o"></i>', 'onclick' => "if (confirm('" . strip_tags(i18n(null, object_content_messages::confirm_delete)) . "')) { numbers.form.details_delete_row('form_{$this->form_link}_form', '{$row_id}'); } return false;"]); } else { $link = ''; unset($table['header']['row_delete']); } // add a row to a table $table['options'][$row_number] = ['row_number' => ['value' => format::id($row_number) . '.', 'width' => '1%', 'row_id' => $row_id], 'row_data' => ['value' => html::grid($data), 'width' => !empty($options['details_11']) ? '100%' : '98%'], 'row_delete' => ['value' => $link, 'width' => '1%']]; $row_number++; // we need to determine if we have values if (next($values) === false) { $processing_values = false; } } while (1); return html::table($table); }
/** * Data default renderer * * @return string */ private final function render_data_default() { $result = ''; // if we have no rows we display a messsage if ($this->num_rows == 0) { return html::message(['type' => 'warning', 'options' => [i18n(null, object_content_messages::no_rows_found)]]); } $counter = 1; $table = ['header' => [], 'options' => []]; // action flags $actions = []; if (object_controller::can('record_view')) { $actions['view'] = true; } // generate columns foreach ($this->columns as $k => $v) { // if we can not view we skip action column if (empty($actions) && $k == 'action') { continue; } $table['header'][$k] = ['value' => i18n(null, $v['name']), 'nowrap' => true, 'width' => $v['width'] ?? null]; } // generate rows foreach ($this->rows as $k => $v) { // process all columns first $row = []; foreach ($this->columns as $k2 => $v2) { // if we can not view we skip action column if (empty($actions) && $k2 == 'action') { continue; } $value = []; // create cell properties foreach (['width', 'align'] as $v3) { if (isset($v2[$v3])) { $value[$v3] = $v2[$v3]; } } // process rows if ($k2 == 'action') { $value['value'] = []; if (!empty($actions['view'])) { $mvc = application::get('mvc'); $pk = extract_keys($this->model_object->pk, $v); $url = $mvc['controller'] . '/_edit?' . http_build_query2($pk); $value['value'][] = html::a(['value' => i18n(null, 'View'), 'href' => $url]); } $value['value'] = implode(' ', $value['value']); } else { if ($k2 == 'row_number') { $value['value'] = format::id($counter) . '.'; } else { if ($k2 == 'offset_number') { $value['value'] = format::id($this->offset + $counter) . '.'; } else { if (!empty($v2['options_model'])) { if (strpos($v2['options_model'], '::') === false) { $v2['options_model'] .= '::options'; } $params = $v2['options_params'] ?? []; if (!empty($v2['options_depends'])) { foreach ($v2['options_depends'] as $k0 => $v0) { $params[$k0] = $v[$v0]; } } $crypt_object = new crypt(); $hash = $crypt_object->hash($v2['options_model'] . serialize($params)); if (!isset($this->cached_options[$hash])) { $method = factory::method($v2['options_model'], null, true); $this->cached_options[$hash] = call_user_func_array($method, [['where' => $params]]); } if (isset($this->cached_options[$hash][$v[$k2]])) { $value['value'] = $this->cached_options[$hash][$v[$k2]]['name']; } else { $value['value'] = null; } } else { if (!empty($v2['options']) && !is_array($v[$k2])) { if (isset($v2['options'][$v[$k2]])) { $value['value'] = $v2['options'][$v[$k2]]['name']; } else { $value['value'] = null; } } else { if (isset($v[$k2])) { $value['value'] = $v[$k2]; } else { $value['value'] = null; } } } } } } // put value into row if (!empty($v2['format'])) { $format_options = $v2['format_options'] ?? []; if (!empty($v2['format_depends'])) { $format_depends = $v2['format_depends']; $this->process_params_and_depends($format_depends, $v); $format_options = array_merge_hard($format_options, $format_depends); } $method = factory::method($v2['format'], 'format'); $value['value'] = call_user_func_array([$method[0], $method[1]], [$value['value'], $format_options]); } $row[$k2] = $value; } // put processed columns though user defined function if (method_exists($this, 'render_data_rows')) { $table['options'][$counter] = $this->render_data_rows($row, $v); } else { $table['options'][$counter] = $row; } $counter++; } return html::table($table); }