public static function ChartDataCollectorTable::processDataCollectorTable in Charts 5.0.x
Same name and namespace in other branches
- 8.4 src/Element/ChartDataCollectorTable.php \Drupal\charts\Element\ChartDataCollectorTable::processDataCollectorTable()
Processes the element to render a table to collect a data for the chart.
Parameters
array $element: The element.
\Drupal\Core\Form\FormStateInterface $form_state: The form state.
array $complete_form: The complete form.
Return value
array The processed element.
File
- src/
Element/ ChartDataCollectorTable.php, line 66
Class
- ChartDataCollectorTable
- Provides a chart data collector table form element.
Namespace
Drupal\charts\ElementCode
public static function processDataCollectorTable(array &$element, FormStateInterface $form_state, array &$complete_form) {
$parents = $element['#parents'];
$id_prefix = implode('-', $parents);
$wrapper_id = Html::getUniqueId($id_prefix . '-ajax-wrapper');
$value = $element['#value'];
$required = !empty($element['#required']);
$user_input = $form_state
->getUserInput();
$element_state = self::getElementState($parents, $form_state);
// Getting columns and rows count.
if (empty($element_state['data_collector_table']) || empty($element_state['table_categories_identifier'])) {
$identifier_value = $value['table_categories_identifier'] ?? self::FIRST_COLUMN;
$element_state['table_categories_identifier'] = $identifier_value;
$element_state['data_collector_table'] = $value['data_collector_table'] ?? [];
$element_state['data_collector_table'] = $element_state['data_collector_table'] ?: self::initializeEmptyTable($element, $identifier_value);
self::setElementState($parents, $form_state, $element_state);
}
else {
// This is hack to make ajax call retun the proper identifier.
$element_state['table_categories_identifier'] = $value['table_categories_identifier'];
}
// Enforce tree.
$element = [
'#tree' => TRUE,
'#prefix' => '<div id="' . $wrapper_id . '">',
'#suffix' => '</div>',
// Pass the id along to other methods.
'#wrapper_id' => $wrapper_id,
] + $element;
$element['table_categories_identifier'] = [
'#type' => 'radios',
'#title' => t('Categories are identified by'),
'#options' => [
self::FIRST_COLUMN => t('First column'),
self::FIRST_ROW => t('First row'),
],
'#description' => t('Select whether the first row or column hold the categories data'),
'#required' => $required,
'#default_value' => $element_state['table_categories_identifier'],
'#ajax' => [
'callback' => [
get_called_class(),
'ajaxRefresh',
],
'progress' => [
'type' => 'throbber',
],
'wrapper' => $wrapper_id,
'effect' => 'fade',
],
];
$table = [
'#type' => 'table',
'#tree' => TRUE,
'#header' => [],
'#responsive' => FALSE,
'#attributes' => [
'class' => 'data-collector-table',
],
];
$table_drag = $element['#table_drag'];
$table_drag_group = Html::cleanCssIdentifier($id_prefix . '-order-weight');
if ($table_drag) {
$table['#tabledrag'] = [
[
'action' => 'order',
'relationship' => 'sibling',
'group' => $table_drag_group,
],
];
}
if ($element['#table_wrapper'] && $element['#table_wrapper'] === 'container') {
$element['table_wrapper'] = [
'#type' => 'container',
'#attributes' => $element['#table_wrapper_attributes'],
'#tree' => FALSE,
];
$element['table_wrapper']['data_collector_table'] =& $table;
}
else {
$element['data_collector_table'] =& $table;
}
$rows = count($element_state['data_collector_table']);
// Make the weight list always reflect the current number of values.
$max_weight = count($element_state['data_collector_table']);
$max_row = max(array_keys($element_state['data_collector_table']));
// The first column need to be for colors.
$is_first_column = $element_state['table_categories_identifier'] === self::FIRST_COLUMN;
$first_row_key = NULL;
foreach ($element_state['data_collector_table'] as $i => $row) {
$first_row_key = $first_row_key === NULL ? $i : $first_row_key;
$table_first_row = $i === $first_row_key;
$add_color_first_row = $is_first_column && $table_first_row;
$first_col_key = NULL;
$row_form =& $table[$i];
$row_form['#attributes']['class'][] = 'data-collector-table--row';
// Adding the row textfield cells.
foreach ($row as $j => $column) {
if ($j === 'weight') {
continue;
}
$first_col_key = $first_col_key === NULL ? $j : $first_col_key;
$table_first_col = $j === $first_col_key;
// To be used to skip color input on cell[0][0].
$is_category_cell = $table_first_col && $table_first_row;
$row_form[$j]['data'] = [
'#type' => 'textfield',
'#title' => t('Data for column @col - Row @row', [
'@row' => $i,
'@col' => $j,
]),
'#title_display' => 'invisible',
'#size' => 10,
'#default_value' => is_array($column) ? $column['data'] : $column,
'#wrapper_attributes' => [
'class' => [
'data-collector-table--row--cell',
],
],
];
if (!$is_category_cell && ($add_color_first_row || !$is_first_column && $j === $first_col_key)) {
$row_form[$j]['#wrapper_attributes'] = [
'class' => [
'container-inline',
],
];
$row_form[$j]['color'] = [
'#type' => 'textfield',
'#title' => t('Color'),
'#title_display' => 'invisible',
'#attributes' => [
'TYPE' => 'color',
],
'#size' => 10,
'#maxlength' => 7,
'#default_value' => $column['color'] ?? ChartsDefaultColors::randomColor(),
];
}
}
// Adding weight if table drag enabled.
if ($table_drag) {
$row_form['#attributes']['class'][] = 'draggable';
if ($i + 1 === $rows) {
$default_weight = $max_weight;
}
else {
$default_weight = $max_row + 1;
}
$row_form['weight'] = [
'#type' => 'weight',
'#title' => t('Weight'),
'#title_display' => 'invisible',
'#delta' => $max_weight,
'#default_value' => $element_state['data_collector_table'][$i]['weight'] ?? $default_weight,
'#attributes' => [
'class' => [
$table_drag_group,
],
],
];
// Used by SortArray::sortByWeightProperty to sort the rows.
if (isset($user_input['data_collector_table'][$i])) {
$input_weight = $user_input['data_collector_table'][$i]['weight'];
// Make sure the weight is not out of bounds due to removals.
if ($user_input['data_collector_table'][$i]['weight'] > $max_weight) {
$input_weight = $max_weight;
}
// Reflect the updated user input on the element.
$row_form['weight']['#value'] = $input_weight;
$row_form['#weight'] = $input_weight;
}
else {
$row_form['#weight'] = $default_weight;
}
}
// Row delete button.
$row_form['delete'] = self::buildOperationButton('delete', 'row', $id_prefix, $wrapper_id, $i, [], [
'class' => [
'data-collector-table--row--delete',
],
]);
}
$colspan = 1;
if ($table_drag) {
// Sort the values by weight. Ensures weight is preserved on ajax refresh.
uasort($table, [
'\\Drupal\\Component\\Utility\\SortArray',
'sortByWeightProperty',
]);
// Increasing colspan when weight column is added.
$colspan = 2;
}
// Building the column delete button.
$table['_delete_column_buttons'] = [
'#attributes' => [
'class' => [
'data-collector-table--column-deletes-row',
],
],
];
// Using first row to get the count of columns.
$first_row = current($element_state['data_collector_table']);
// Using array filter to exclude weight key when grabbing the row columns.
$columns = self::excludeWeightColumnFromRow($first_row);
$max_column = max(array_keys($first_row));
foreach ($columns as $column) {
$table['_delete_column_buttons'][$column] = self::buildOperationButton('delete', 'column', $id_prefix, $wrapper_id, $column, [], [
'class' => [
'data-collector-table--column--delete',
],
]);
if ($column === $max_column) {
$table['_delete_column_buttons'][$column]['#wrapper_attributes']['colspan'] = $colspan;
}
}
// Empty Column under delete operation placeholder.
$table['_delete_column_buttons'][$max_column + 1] = [
'#markup' => '',
];
// Footer operations.
$table['_operations'] = [
'#attributes' => [
'class' => [
'data-collector-table--oprations-row',
],
],
];
$table['_operations']['wrapper'] = [
'#type' => 'container',
'#wrapper_attributes' => [
'colspan' => count($columns) + $colspan,
],
];
$table['_operations']['wrapper']['add_column'] = self::buildOperationButton('add', 'column', $id_prefix, $wrapper_id, NULL);
$table['_operations']['wrapper']['add_row'] = self::buildOperationButton('add', 'row', $id_prefix, $wrapper_id, NULL);
if ($element['#import_csv']) {
$element['import'] = [
'#type' => 'details',
'#title' => t('Import Data from CSV'),
'#description' => t('Note importing data from CSV will overwrite all the current data entry in the table.'),
'#open' => FALSE,
];
$element['import']['csv'] = [
'#name' => 'files[' . $id_prefix . ']',
'#title' => t('File upload'),
'#title_display' => 'invisible',
'#type' => 'file',
'#upload_validators' => [
'file_validate_extensions' => [
'csv',
],
'file_validate_size' => [
Environment::getUploadMaxSize(),
],
],
];
$element['import']['upload'] = [
'#type' => 'submit',
'#value' => t('Upload CSV'),
'#name' => $id_prefix . '-import-csv',
'#attributes' => [
'class' => [
Html::cleanCssIdentifier($id_prefix . '--import-csv'),
],
],
'#submit' => [
[
get_called_class(),
'importCsvToTableSubmit',
],
],
'#limit_validation_errors' => [
array_merge($parents, [
'import',
'csv',
]),
array_merge($parents, [
'import',
'upload',
]),
],
'#ajax' => [
'callback' => [
get_called_class(),
'ajaxRefresh',
],
'progress' => [
'type' => 'throbber',
],
'wrapper' => $wrapper_id,
'effect' => 'fade',
],
'#operation' => 'csv',
'#csv_separator' => $element['#import_csv_separator'] ?? ',',
];
}
return $element;
}