Esempio n. 1
0
 /**
  * @see html::table()
  */
 public static function table($options = [])
 {
     $rows = isset($options['options']) ? $options['options'] : [];
     if (!empty($options['header']) && is_array($options['header'])) {
         $header = $options['header'];
     } else {
         // we need to grab header from first row
         $header = current($rows);
         $options['skip_header'] = true;
     }
     $result = [];
     $first_column = null;
     // header first
     if (!empty($header) && empty($options['skip_header'])) {
         $temp2 = '<thead>';
         $temp2 .= '<tr>';
         foreach ($header as $k => $v) {
             // determine first column
             if ($first_column === null) {
                 $first_column = $k;
             }
             if (is_array($v)) {
                 $tag = !empty($v['header_use_td_tag']) ? 'td' : 'th';
                 $temp_value = isset($v['value']) ? $v['value'] : '';
                 unset($v['value']);
                 $temp2 .= '<' . $tag . ' ' . self::generate_attributes($v, $tag) . '>' . $temp_value . '</' . $tag . '>';
             } else {
                 $temp2 .= '<th nowrap>' . $v . '</th>';
             }
         }
         $temp2 .= '</tr>';
         $temp2 .= '</thead>';
         $result[] = $temp2;
     }
     // unsetting some values
     unset($options['options'], $options['header'], $options['skip_header']);
     // rows second
     foreach ($rows as $k => $v) {
         // we need to extract row attributes from first column
         $row_options = [];
         foreach ($header as $k2 => $v2) {
             if (isset($v[$k2]) && is_array($v[$k2])) {
                 $row_options = array_merge_hard($row_options, array_key_extract_by_prefix($v[$k2], 'row_'));
             }
         }
         $temp2 = '<tr ' . self::generate_attributes($row_options, 'tr') . '>';
         // important we render based on header array and not on what is in rows
         $flag_colspan = 0;
         foreach ($header as $k2 => $v2) {
             if ($flag_colspan > 0) {
                 $flag_colspan--;
                 continue;
             }
             if (!isset($v[$k2])) {
                 $v[$k2] = null;
             }
             if (is_array($v[$k2])) {
                 $temp3 = isset($v[$k2]['value']) ? $v[$k2]['value'] : '';
                 unset($v[$k2]['value']);
                 if (!empty($v[$k2]['nowrap'])) {
                     $v[$k2]['nowrap'] = 'nowrap';
                 }
                 if (!empty($v[$k2]['colspan'])) {
                     $flag_colspan = $v[$k2]['colspan'];
                     $flag_colspan--;
                 }
                 $temp2 .= '<td ' . self::generate_attributes($v[$k2], 'td') . '>' . $temp3 . '</td>';
             } else {
                 $temp2 .= '<td nowrap>' . $v[$k2] . '</td>';
             }
         }
         // reset colspan
         $flag_colspan = 0;
         $temp2 .= '</tr>';
         $result[] = $temp2;
     }
     // todo: add footer
     // todo: maybe use <thead>, <tfoot>, and a <tbody> tags
     return '<table ' . self::generate_attributes($options, 'table') . '>' . implode('', $result) . '</table>';
 }
Esempio n. 2
0
 /**
  * Render elements value
  *
  * @param array $options
  * @param mixed $value
  * @param array $neighbouring_values
  * @return string
  * @throws Exception
  */
 public function render_element_value(&$options, $value = null, &$neighbouring_values = [])
 {
     // field name and values_key
     $options['options']['field_name'] = $options['options']['details_field_name'] ?? $options['options']['name'];
     $options['options']['field_values_key'] = implode('[::]', $options['options']['field_values_key'] ?? [$options['options']['field_name']]);
     // custom renderer
     if (!empty($options['options']['custom_renderer'])) {
         $method = factory::method($options['options']['custom_renderer'], null, true);
         $options_custom_renderer = $options;
         call_user_func_array($method, [&$this, &$options, &$value, &$neighbouring_values]);
     }
     // handling override_field_value method
     if (!empty($this->wrapper_methods['override_field_value']['main'])) {
         call_user_func_array($this->wrapper_methods['override_field_value']['main'], [&$this, &$options, &$value, &$neighbouring_values]);
     }
     $result_options = $options['options'];
     $options['options']['value'] = $value;
     array_key_extract_by_prefix($result_options, 'label_');
     $element_expand = !empty($result_options['expand']);
     $html_suffix = $result_options['html_suffix'] ?? '';
     // unset certain keys
     unset($result_options['order'], $result_options['required'], $result_options['html_suffix']);
     // processing options
     $flag_select_or_autocomplete = !empty($result_options['options_model']) || !empty($result_options['options']);
     if (!empty($result_options['options_model'])) {
         if (empty($result_options['options_params'])) {
             $result_options['options_params'] = [];
         }
         if (empty($result_options['options_options'])) {
             $result_options['options_options'] = [];
         }
         $result_options['options_options']['i18n'] = $result_options['options_options']['i18n'] ?? true;
         $result_options['options_options']['acl'] = $result_options['options_options']['acl'] ?? $this->acl;
         if (empty($result_options['options_depends'])) {
             $result_options['options_depends'] = [];
         }
         // options depends & params
         $this->process_params_and_depends($result_options['options_depends'], $neighbouring_values, $options, true);
         $this->process_params_and_depends($result_options['options_params'], $neighbouring_values, $options, false);
         $result_options['options_params'] = array_merge_hard($result_options['options_params'], $result_options['options_depends']);
         // we do not need options for autocomplete
         if (strpos($result_options['method'], 'autocomplete') === false) {
             $skip_values = [];
             if (!empty($options['options']['details_key'])) {
                 if (!empty($options['options']['details_parent_key'])) {
                     $temp_key = $options['options']['details_parent_key'] . '::' . $options['options']['details_key'];
                     if (!empty($this->misc_settings['details_unique_select'][$temp_key][$options['options']['details_field_name']][$options['options']['__parent_row_number']])) {
                         $skip_values = array_keys($this->misc_settings['details_unique_select'][$temp_key][$options['options']['details_field_name']][$options['options']['__parent_row_number']]);
                     }
                 } else {
                     if (!empty($this->misc_settings['details_unique_select'][$options['options']['details_key']][$options['options']['details_field_name']])) {
                         $skip_values = array_keys($this->misc_settings['details_unique_select'][$options['options']['details_key']][$options['options']['details_field_name']]);
                     }
                 }
             }
             $result_options['options'] = object_data_common::process_options($result_options['options_model'], $this, $result_options['options_params'], $value, $skip_values, $result_options['options_options']);
         } else {
             // we need to inject form id into autocomplete
             $result_options['form_id'] = "form_{$this->form_link}_form";
         }
     }
     // by default all selects are searchable if not specified otherwise
     if ($flag_select_or_autocomplete) {
         $result_options['searchable'] = $result_options['searchable'] ?? false;
     }
     // different handling for different type
     switch ($options['type']) {
         case 'container':
             $options_container = $options;
             //$options_container['previous_data'] = $v;
             // todo: pass $form_data_key from parent
             $options_container['previous_key'] = $options['previous_key'];
             // render container
             $temp_container_value = $this->render_container($data['fm_part_child_container_name'], $parents, $options_container);
             if (!empty($html_expand)) {
                 // get part id
                 $temp_id = $this->id('part_details', ['part_name' => $data['fm_part_name'], 'part_id' => $options_container['previous_id']]);
                 $temp_id_div_inner = $temp_id . '_html_expand_div_inner';
                 $temp_expand_div_inner = ['id' => $temp_id_div_inner, 'style' => 'display: none;', 'value' => $temp_container_value];
                 $temp_expand_div_a = ['href' => 'javascript:void(0);', 'onclick' => "numbers.element.toggle('{$temp_id_div_inner}');", 'value' => '+ / -'];
                 $temp_expand_div_outer = ['align' => 'left', 'value' => html::a($temp_expand_div_a) . '<br />' . html::div($temp_expand_div_inner)];
                 $value = html::div($temp_expand_div_outer);
             } else {
                 $value = $temp_container_value;
             }
             $result_options['value'] = $value;
             break;
         case 'field':
             $element_method = $result_options['method'] ?? 'html::input';
             if (strpos($element_method, '::') === false) {
                 $element_method = 'html::' . $element_method;
             }
             // value in special order
             $flag_translated = false;
             if (in_array($element_method, ['html::a', 'html::submit', 'html::button', 'html::button2'])) {
                 // translate value
                 $result_options['value'] = i18n($result_options['i18n'] ?? null, $result_options['value'] ?? null);
                 // process confirm_message
                 $result_options['onclick'] = $result_options['onclick'] ?? '';
                 if (!empty($result_options['confirm_message'])) {
                     $result_options['onclick'] .= 'return confirm(\'' . strip_tags(i18n(null, $result_options['confirm_message'])) . '\');';
                 }
                 // processing onclick for buttons
                 if (in_array($element_method, ['html::submit', 'html::button', 'html::button2'])) {
                     if (!empty($result_options['onclick']) && strpos($result_options['onclick'], 'this.form.submit();') !== false) {
                         $result_options['onclick'] = str_replace('this.form.submit();', "numbers.form.trigger_submit(this.form);", $result_options['onclick']) . ' return true;';
                     } else {
                         if (empty($result_options['onclick'])) {
                             $result_options['onclick'] .= 'numbers.form.trigger_submit_on_button(this); return true;';
                         } else {
                             $result_options['onclick'] = 'numbers.form.trigger_submit_on_button(this); ' . $result_options['onclick'];
                         }
                     }
                 }
                 $flag_translated = true;
                 // icon
                 if (!empty($result_options['icon'])) {
                     $result_options['value'] = html::icon(['type' => $result_options['icon']]) . ' ' . $result_options['value'];
                 }
                 // accesskey
                 if (isset($result_options['accesskey'])) {
                     $accesskey = explode('::', i18n(null, 'accesskey::' . $result_options['name'] . '::' . $result_options['accesskey'], ['skip_translation_symbol' => true]));
                     $result_options['accesskey'] = $accesskey[2];
                     $result_options['title'] = ($result_options['title'] ?? '') . ' ' . i18n(null, 'Shortcut Key: ') . $accesskey[2];
                 }
             } else {
                 if (in_array($element_method, ['html::div', 'html::span'])) {
                     if (!empty($result_options['i18n'])) {
                         $result_options['value'] = i18n($result_options['i18n'] ?? null, $result_options['value'] ?? null);
                         $flag_translated = true;
                     }
                 } else {
                     // editable fields
                     $result_options['value'] = $value;
                     // if we need to empty value, mostly for password fields
                     if (!empty($result_options['empty_value'])) {
                         $result_options['value'] = '';
                     }
                     // we need to empty zero integers and sequences, before format
                     if (($result_options['php_type'] ?? '') == 'integer' && ($result_options['type'] ?? '') != 'boolean' && ($result_options['domain'] ?? '') != 'counter' && 'counter' && empty($result_options['value'])) {
                         $result_options['value'] = '';
                     }
                     // format, not for selects/autocompletes/presets
                     if (!$flag_select_or_autocomplete) {
                         if (!empty($result_options['format'])) {
                             if (!empty($this->errors['fields'][$result_options['error_name']]) && empty($this->errors['formats'][$result_options['error_name']])) {
                                 // nothing
                             } else {
                                 $result_options['format_options'] = $result_options['format_options'] ?? [];
                                 if (!empty($result_options['format_depends'])) {
                                     $this->process_params_and_depends($result_options['format_depends'], $neighbouring_values, $options, true);
                                     $result_options['format_options'] = array_merge_hard($result_options['format_options'], $result_options['format_depends']);
                                 }
                                 $method = factory::method($result_options['format'], 'format');
                                 $result_options['value'] = call_user_func_array([$method[0], $method[1]], [$result_options['value'], $result_options['format_options']]);
                             }
                         }
                     }
                     // align
                     if (!empty($result_options['align'])) {
                         $result_options['style'] = ($result_options['style'] ?? '') . 'text-align:' . $result_options['align'] . ';';
                     }
                     // processing persistent
                     if (!empty($result_options['persistent']) && $this->values_loaded) {
                         if ($result_options['persistent'] === 'if_set') {
                             $original_value = $detail = array_key_get($this->original_values, $result_options['values_key']);
                             if (!empty($original_value)) {
                                 $result_options['readonly'] = true;
                             }
                         } else {
                             if (count($result_options['values_key']) == 1) {
                                 // parent record
                                 $result_options['readonly'] = true;
                             } else {
                                 if (empty($result_options['__new_row'])) {
                                     // details
                                     $temp = $result_options['values_key'];
                                     array_pop($temp);
                                     $detail = array_key_get($this->original_values, $temp);
                                     if (!empty($detail)) {
                                         $result_options['readonly'] = true;
                                     }
                                 }
                             }
                         }
                     }
                     // maxlength
                     if (in_array($result_options['type'] ?? '', ['char', 'varchar']) && !empty($result_options['length'])) {
                         $result_options['maxlength'] = $result_options['length'];
                     }
                     // global readonly
                     if (!empty($this->misc_settings['global']['readonly']) && empty($result_options['navigation'])) {
                         $result_options['readonly'] = true;
                     }
                     // title
                     if (isset($options['options']['label_name'])) {
                         $result_options['title'] = ($result_options['title'] ?? '') . ' ' . strip_tags(i18n(null, $options['options']['label_name']));
                     }
                 }
             }
             // translate place holder
             if (array_key_exists('placeholder', $result_options)) {
                 if (!empty($result_options['placeholder'])) {
                     $result_options['placeholder'] = strip_tags(i18n(null, $result_options['placeholder']));
                 }
             } else {
                 if (!empty($result_options['validator_method']) && empty($result_options['value'])) {
                     $temp = object_validator_base::method($result_options['validator_method'], $result_options['value'], $result_options['validator_params'] ?? [], $options['options'], $neighbouring_values);
                     if ($flag_select_or_autocomplete) {
                         $placeholder = $temp['placeholder_select'];
                     } else {
                         $placeholder = $temp['placeholder'];
                     }
                     if (!empty($placeholder)) {
                         $result_options['placeholder'] = strip_tags(i18n(null, $placeholder));
                     }
                 }
             }
             // events
             foreach (numbers_frontend_html_class_html5::$events as $e) {
                 if (!empty($result_options['readonly'])) {
                     // important - readonly emenets cannot have events
                     unset($result_options[$e]);
                 } else {
                     if (!empty($result_options[$e])) {
                         $result_options[$e] = str_replace('this.form.submit();', 'numbers.form.trigger_submit(this);', $result_options[$e]);
                         $result_options[$e] = str_replace('this.form.extended.', $this->misc_settings['extended_js_class'] . '.', $result_options[$e]);
                     }
                 }
             }
             break;
         case 'html':
             $element_method = null;
             break;
         default:
             throw new Exception('Render detail type: ' . $data['fm_part_type']);
     }
     // handling html_method
     if (isset($element_method)) {
         $method = factory::method($element_method, 'html');
         $field_method_object = factory::model($method[0], true);
         // todo: unset non html attributes
         $value = $field_method_object->{$method[1]}($result_options);
         // building navigation
         if (!empty($result_options['navigation'])) {
             $name = 'navigation[' . $result_options['name'] . ']';
             $temp = '<table width="100%" dir="ltr">';
             // always left to right
             $temp .= '<tr>';
             $temp .= '<td width="1%">' . html::button2(['name' => $name . '[first]', 'value' => html::icon(['type' => 'step-backward']), 'onclick' => 'numbers.form.trigger_submit_on_button(this);', 'title' => i18n(null, 'First')]) . '</td>';
             $temp .= '<td width="1%">&nbsp;</td>';
             $temp .= '<td width="1%">' . html::button2(['name' => $name . '[previous]', 'value' => html::icon(['type' => 'caret-left']), 'onclick' => 'numbers.form.trigger_submit_on_button(this);', 'title' => i18n(null, 'Previous')]) . '</td>';
             $temp .= '<td width="1%">&nbsp;</td>';
             $temp .= '<td width="90%">' . $value . '</td>';
             $temp .= '<td width="1%">&nbsp;</td>';
             $temp .= '<td width="1%">' . html::button2(['name' => $name . '[refresh]', 'value' => html::icon(['type' => 'refresh']), 'onclick' => 'numbers.form.trigger_submit_on_button(this);', 'title' => i18n(null, 'Refresh')]) . '</td>';
             $temp .= '<td width="1%">&nbsp;</td>';
             $temp .= '<td width="1%">' . html::button2(['name' => $name . '[next]', 'value' => html::icon(['type' => 'caret-right']), 'onclick' => 'numbers.form.trigger_submit_on_button(this);', 'title' => i18n(null, 'Next')]) . '</td>';
             $temp .= '<td width="1%">&nbsp;</td>';
             $temp .= '<td width="1%">' . html::button2(['name' => $name . '[last]', 'value' => html::icon(['type' => 'step-forward']), 'onclick' => 'numbers.form.trigger_submit_on_button(this);', 'title' => i18n(null, 'Last')]) . '</td>';
             $temp .= '</tr>';
             $temp .= '</table>';
             $value = $temp;
         }
     }
     // html suffix and prefix
     if (!empty($html_suffix)) {
         $value .= $html_suffix;
     }
     // if we need to display settings
     if (application::get('flag.numbers.frontend.html.form.show_field_settings')) {
         $id_original = $result_options['id'] . '__settings_original';
         $id_modified = $result_options['id'] . '__settings_modified';
         $value .= html::a(['href' => 'javascript:void(0);', 'onclick' => "\$('#{$id_original}').toggle();", 'value' => html::label2(['type' => 'primary', 'value' => count($options['options'])])]);
         $value .= html::a(['href' => 'javascript:void(0);', 'onclick' => "\$('#{$id_modified}').toggle();", 'value' => html::label2(['type' => 'warning', 'value' => count($result_options)])]);
         $value .= '<div id="' . $id_original . '" style="display:none; position: absolute; text-align: left; width: 500px; z-index: 32000;">' . print_r2($options['options'], true) . '</div>';
         $value .= '<div id="' . $id_modified . '" style="display:none; position: absolute; text-align: left; width: 500px; z-index: 32000;">' . print_r2($result_options, true) . '</div>';
     }
     // we need to put original options back
     if (!empty($options['options']['custom_renderer'])) {
         $options = $options_custom_renderer;
     }
     return $value;
 }