/** * Render preset url * * @param object $form * @return array */ public function render_preset_url(&$form) { $result = ['success' => true, 'error' => [], 'data' => ['html' => '', 'js' => '', 'css' => '']]; $params = ['lc_translation_language_code' => $form->values['lc_missing_language_code'], 'lc_translation_text_sys' => $form->values['lc_missing_text_sys']]; $result['data']['html'] = html::a(['href' => '/numbers/backend/i18n/basic/controller/translations/_edit?' . http_build_query2($params), 'value' => 'Translate']) . '<br/><br/>'; return $result; }
/** * Generate url * * @param array $options * controller - array or string controller parts * action - string action * id - mixed id * virtual - boolean flag * tinyurl - whether to generate tinuurl * full - boolean flag * get_params - array of GET parameters * @return string */ public static function get($options = []) { // we need to fix controller, action and id $controller = $options['controller'] ?? ''; if (is_array($controller)) { $controller = implode('/', $controller); } $controller = rtrim($controller, '/'); $action = $options['action'] ?? null; $id = $options['id'] ?? null; // processing virtual if (!empty($options['virtual'])) { $virtual_object = new object_virtual_controllers(); $virtual_data = $virtual_object->get(); foreach ($virtual_data as $k => $v) { if ($v['no_virtual_controller_path'] == $controller) { $controller = '/__' . $v['no_virtual_controller_code']; break; } } } // assembling $result = ''; $host = ''; if (!empty($options['full'])) { $host = rtrim(request::host(), '/'); } $result .= $host; $result .= $controller; if (!empty($id) && empty($action)) { $action = 'index'; } if (!empty($action)) { $result .= '/_' . $action; } if (!empty($id)) { $result .= '/' . $id; } // if we have GET parameters if (!empty($options['get_params'])) { $result .= '?' . http_build_query2($options['get_params']); } // if we need to generate tinyurl if (!empty($options['tinyurl'])) { $tinyurl_result = url_tinyurl::set($result); if ($tinyurl_result['success']) { $result = $host . '/__tinyurl/_i/' . $tinyurl_result['data']['hash']; } } return $result; }
function widget_button($icon, $query, $label, $tooltip, $link_suffix = NULL, $flags = 0) { $p = ''; // detect if button is active/selected $t = array(array(), array()); $a = parse_url($query); if (isset($a['query'])) { parse_str($a['query'], $t[0]); } else { if (isset($a['path'])) { parse_str($a['path'], $t[0]); } } parse_str($_SERVER['QUERY_STRING'], $t[1]); // DEBUG // echo '<pre><tt>'; // print_r ($t); // $a = array_keys ($t[0]); $selected = 1; // black-out link // check query // if (isset ($t[0][0])) if (count(array_diff($t[0], $t[1])) > 0) { $selected = 0; } // check domain if ($selected == 1) { if (!isset($t[0][0])) { $t = parse_url($query); // echo $t['host'].', '.$_SERVER['HTTP_HOST'].'<br>'; if (isset($t['host'])) { if ($t['host'] != '') { if (strcasecmp($t['host'], $_SERVER['HTTP_HOST'])) { $selected = 0; } } } } } $p .= '<a'; if ($selected) { $p .= ' class="tv2_selected" style="color:#000;"'; } else { $p .= ' class="tooltip"'; } // if (!strncasecmp ($query, 'http://', 7)) if (strstr($query, '://') || !strncasecmp($query, 'mailto:', 7)) { $p .= ' href="' . $query . '"'; } else { if ($link_suffix) { $t = array(); parse_str($query, $t[0]); parse_str($link_suffix, $t[1]); $a = array_merge($t[1], $t[0]); $query = http_build_query2($a, false); } $p .= ' href="?' . $query . '"'; } $p .= '' . ' alt="' . $label . '"'; if ($tooltip) { if (trim($tooltip) != '') { $p .= '' . ' onmouseover="tv2_tt_show(\'' . str_replace('\'', '\\\'', $tooltip) . '\');"' . ' onmouseout="tv2_tt_hide();"'; } } // if (!$icon) // $p .= ''; $p .= '>'; $s = ''; if ($icon) { $s .= '<img src="' . $icon . '" border="0" alt=""'; // if ($flags & WIDGET_BUTTON_CLIP) // $s .= ' style="width:20%;clip:rect(10px 150px 150px 70px);position:absolute;"'; // if ($flags & WIDGET_BUTTON_SMALL) // $s .= ' height="16"'; $s .= '' . ' onerror="this.parentNode.removeChild(this);"' . '>'; } // if ($icon && $label) // $p .= ' '; // if ($flags & WIDGET_BUTTON_STATIC) // return ($icon ? $s : ''); $p .= $s; if (!($flags & WIDGET_BUTTON_ONLY)) { // if ($selected) // $p .= '<span class="tv2_selected">'; $p .= '' . $label; // if ($selected) // $p .= '</span>'; } // if ($tooltip) // if (trim ($tooltip) != '') // $p .= '<span>'.$tooltip.'</span>'; // if ($selected) // $p .= '</span>'; // else $p .= '</a>'; return $p; }
function misc_getlink($args = array(), $use_existing_arguments = false) { return '?' . http_build_query2($args, $use_existing_arguments); }
/** * 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; }
/** * Render widget * * @return mixed */ public function render() { $result = ''; // action bar $result .= '<div style="text-align: right;">'; $result .= html::a(array('value' => html::icon(['type' => 'comment']) . ' ' . i18n(null, 'New'), 'href' => 'javascript:void(0);', 'onclick' => "numbers.frontend_form.trigger_submit('#form_numbers_frontend_html_widgets_comments_model_form_comment_form', false, true); numbers.modal.show('widgets_comments_{$this->widget_link}_comment');")); $result .= '</div>'; $result .= '<hr class="simple" />'; // form $pk = http_build_query2($this->options['pk']); $js = <<<TTT \t\t\tvar mask_id = 'widgets_comments_{$this->widget_link}_mask'; \t\t\t\$.ajax({ \t\t\t\turl: numbers.controller_full, \t\t\t\tmethod: 'post', \t\t\t\tdata: '__ajax=1&__ajax_form_id=widgets_comments_{$this->widget_link}_list&{$pk}', \t\t\t\tdataType: 'json', \t\t\t\tsuccess: function (data) { \t\t\t\t\tif (data.success) { \t\t\t\t\t\t\$('#widgets_comments_{$this->widget_link}_wrapper').html(data.html); \t\t\t\t\t\teval(data.js); \t\t\t\t\t\t// remove mask after 100 miliseconds to let js to take affect \t\t\t\t\t\tsetTimeout(function() { \t\t\t\t\t\t\t\$('#' + mask_id).unmask(); \t\t\t\t\t\t\t// we need to trigger resize to redraw a screen \t\t\t\t\t\t\t\$(window).trigger('resize'); \t\t\t\t\t\t}, 100); \t\t\t\t\t} \t\t\t\t} \t\t\t}); TTT; $form = new numbers_frontend_html_widgets_comments_model_form_comment(['input' => $this->options['input'], 'no_actions' => true, 'bypass_hidden_values' => $this->options['pk'], 'other' => ['model' => $this->options['model'], 'pk' => $this->options['pk'], 'map' => $this->options['map']], 'on_success_js' => "numbers.modal.hide('widgets_comments_{$this->widget_link}_comment');" . $js]); $body = $form->render(); $footer = html::button2(['name' => 'submit_comment', 'value' => i18n(null, 'Submit'), 'type' => 'primary', 'onclick' => "numbers.frontend_form.trigger_submit('#form_numbers_frontend_html_widgets_comments_model_form_comment_form', true); return false;"]); $result .= html::modal(['id' => "widgets_comments_{$this->widget_link}_comment", 'class' => 'large', 'title' => i18n(null, 'Add Comment'), 'body' => $body, 'footer' => $footer]); // list of comments in descending order $where = []; foreach ($this->options['map'] as $k => $v) { $where[$v] = $this->options['pk'][$k]; } $datasource = new numbers_frontend_html_widgets_comments_model_datasource_comments(); $data = $datasource->get(['model' => $this->options['model'], 'where' => $where]); if (!empty($data)) { $table = ['header' => ['id' => ['value' => '#', 'width' => '1%'], 'inserted' => ['value' => i18n(null, 'Date & Time'), 'width' => '1%', 'nowrap' => true], 'important' => ['value' => i18n(null, 'Important'), 'width' => '1%'], 'em_entity_name' => ['value' => i18n(null, 'Entity'), 'width' => '10%'], 'comment_value' => i18n(null, 'Comment')], 'options' => []]; $row_number = 1; foreach ($data as $k => $v) { // we need to hide old comments $row_style = ''; if ($row_number > 10) { $row_style = 'display: none;'; } $table['options'][$v['id']] = ['id' => ['value' => $row_number . '.', 'row_style' => $row_style, 'row_class' => "widgets_comments_{$this->widget_link}_list_hiden " . ($v['important'] ? 'success' : null)], 'inserted' => format::datetime($v['inserted']), 'important' => ['value' => $v['important'] ? i18n(null, 'Yes') : ''], 'em_entity_name' => ['value' => $v['em_entity_name'], 'width' => '10%', 'nowrap' => true], 'comment_value' => nl2br($v['comment_value'])]; $row_number++; } $result_list = html::table($table); // link to show all rows $total_comments = count($data); if ($total_comments > 10) { $result_list .= '<div style="text-align: right;">' . html::a(['href' => 'javascript:void(0);', 'value' => i18n(null, '[count] comment(s) are hidden. Show all comments.', ['replace' => ['[count]' => $total_comments - 10]]), 'onclick' => "\$('.widgets_comments_{$this->widget_link}_list_hiden').show(); \$(this).hide();"]) . '</div>'; } } else { $result_list = html::message(['type' => 'warning', 'options' => [i18n(null, object_content_messages::no_rows_found)]]); } // if we are making an ajax call if (!empty($this->options['input']['__ajax']) && ($this->options['input']['__ajax_form_id'] ?? '') == "widgets_comments_{$this->widget_link}_list") { layout::render_as(['success' => true, 'error' => [], 'html' => $result_list, 'js' => ''], 'application/json'); } // load mask numbers_frontend_media_libraries_loadmask_base::add(); // put list into result $result .= "<div id=\"widgets_comments_{$this->widget_link}_mask\"><div id=\"widgets_comments_{$this->widget_link}_wrapper\">" . $result_list . '</div></div>'; // wrap everything into segment if (isset($this->options['segment'])) { $temp = is_array($this->options['segment']) ? $this->options['segment'] : []; $temp['value'] = $result; $result = html::segment($temp); } // anchor $result = html::a(['name' => "widgets_comments_{$this->widget_link}_anchor"]) . $result; return $result; }
public function process($data, $options = []) { $temp = []; // we need to precess items that are controller and suboptions at the same time $subgroups = []; foreach ($data as $k => $v) { // determine acl if (!empty($v['sm_menuitm_acl_controller_id']) && !helper_acl::can_see_this_controller($v['sm_menuitm_acl_controller_id'], $v['sm_menuitm_acl_action_id'])) { unset($data[$k]); continue; } // go though each group for ($i = 1; $i <= 4; $i++) { if (!empty($v["g{$i}_code"])) { $subgroups[$v["g{$i}_code"]] = true; } } } $subgroup_items = []; foreach ($data as $k => $v) { if (isset($subgroups[$v['sm_menuitm_code']])) { $subgroup_items[$v['sm_menuitm_code']] = $v; unset($data[$k]); } } // loop though data foreach ($data as $k => $v) { // loop though groups and add them to menu $key = []; for ($i = 1; $i <= 4; $i++) { if (!empty($v['g' . $i . '_code'])) { $key[] = $v['g' . $i . '_code']; // we need to set all groups $temp2 = array_key_get($temp, $key); if (is_null($temp2)) { // if we have a controller that acts as submenu if (!empty($subgroup_items[$v['g' . $i . '_code']])) { $v9 = $subgroup_items[$v['g' . $i . '_code']]; array_key_set($temp, $key, ['code' => $v9['sm_menuitm_code'], 'name' => $v9['sm_menuitm_name'], 'name_extension' => null, 'icon' => $v9['sm_menuitm_icon'], 'url' => $v9['sm_menuitm_url'], 'order' => $v9['sm_menuitm_order'], 'options' => []]); } else { // if we do not have url we assume visitor wants to see extended menu if (empty($v['g' . $i . '_url'])) { $params = []; for ($j = 1; $j <= $i; $j++) { $params['group' . $j . '_code'] = $v['g' . $j . '_code']; } $v['g' . $i . '_url'] = '/numbers/backend/system/menu/controller/menu?' . http_build_query2($params); } array_key_set($temp, $key, ['code' => $v['g' . $i . '_code'], 'name' => $v['g' . $i . '_name'], 'icon' => $v['g' . $i . '_icon'], 'order' => $v['g' . $i . '_order'], 'url' => $v['g' . $i . '_url'], 'options' => []]); } } $key[] = 'options'; } } // some replaces $name_extension = null; if ($v['sm_menuitm_code'] == 'entites.authorization.__entity_name') { $name_extension = '<b>' . session::get(['numbers', 'entity', 'em_entity_name']) . '</b>'; } // finally we need to add menu item to the array $key[] = $v['sm_menuitm_code']; array_key_set($temp, $key, ['code' => $v['sm_menuitm_code'], 'name' => $v['sm_menuitm_name'], 'name_extension' => $name_extension, 'icon' => $v['sm_menuitm_icon'], 'url' => $v['sm_menuitm_url'], 'order' => $v['sm_menuitm_order'], 'options' => []]); // options generator if (!empty($v['sm_menuitm_options_generator'])) { $temp3 = explode('::', $v['sm_menuitm_options_generator']); $temp_data = factory::model($temp3[0])->{$temp3[1]}(); $temp_key = $key; $temp_key[] = 'options'; foreach ($temp_data as $k2 => $v2) { $temp_key2 = $temp_key; $temp_key2[] = $k2; array_key_set($temp, $temp_key2, $v2); } } } // sorting foreach ($temp as $k => $v) { if (!empty($v['options'])) { foreach ($v['options'] as $k2 => $v2) { if (!empty($v2['options'])) { foreach ($v2['options'] as $k3 => $v3) { if (!empty($v3['options'])) { foreach ($v3['options'] as $k4 => $v4) { if (!empty($v4['options'])) { array_key_sort($temp[$k]['options'][$k2]['options'][$k3]['options'][$k4]['options'], ['order' => SORT_ASC], ['order' => SORT_NUMERIC]); } } array_key_sort($temp[$k]['options'][$k2]['options'][$k3]['options'], ['order' => SORT_ASC], ['order' => SORT_NUMERIC]); } } array_key_sort($temp[$k]['options'][$k2]['options'], ['order' => SORT_ASC], ['order' => SORT_NUMERIC]); } } array_key_sort($temp[$k]['options'], ['order' => SORT_ASC], ['order' => SORT_NUMERIC]); } } // sort root array_key_sort($temp, ['order' => SORT_ASC], ['order' => SORT_NUMERIC]); return $temp; }
/** * 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); }