Loading edge.module +154 −3 Original line number Diff line number Diff line Loading @@ -12,8 +12,20 @@ function edge_element_info() { $types['table'] = array( '#header' => array(), '#rows' => array(), '#empty' => '', '#pre_render' => array('edge_pre_render_table'), '#theme' => 'table', // Properties for tableselect support. '#tableselect' => FALSE, '#input' => TRUE, '#value_callback' => 'edge_type_table_value', '#tree' => TRUE, // Note that MODULE_process_THEME() clashes with global theme system process // callbacks. '#process' => array('edge_element_process_table'), '#element_validate' => array('edge_element_validate_table'), '#multiple' => TRUE, '#js_select' => TRUE, ); return $types; } Loading Loading @@ -83,6 +95,145 @@ function edge_css_alter(&$css) { } } /** * Helper function to determine the value of a table form element. * * @param $element * The form element whose value is being populated. * @param $input * The incoming input to populate the form element. If this is FALSE, * the element's default value should be returned. * * @return * The data that will appear in the $form_state['values'] collection * for this element. Return nothing to use the default. */ function edge_type_table_value($element, $input = FALSE) { // If #multiple is FALSE, the regular default value of radio buttons is used. if (!empty($element['#multiple'])) { // Contrary to #type 'checkboxes', the default value of checkboxes in a // table is built from the array keys (instead of array values) of the // #default_value property. // @todo D8: Remove this weirdness. if ($input === FALSE) { $element += array('#default_value' => array()); return drupal_map_assoc(array_keys(array_filter($element['#default_value']))); } else { return is_array($input) ? drupal_map_assoc($input) : array(); } } } /** * #process callback for #type 'table' to add tableselect support. * * @see form_process_tableselect() * @see theme_tableselect() */ function edge_element_process_table($element, &$form_state) { if ($element['#tableselect']) { if ($element['#multiple']) { $value = is_array($element['#value']) ? $element['#value'] : array(); } // Advanced selection behaviour makes no sense for radios. else { $element['#js_select'] = FALSE; } // Add a "Select all" checkbox column to the header. // @todo D8: Rename into #select_all? if ($element['#js_select']) { $element['#attached']['js'][] = 'misc/tableselect.js'; array_unshift($element['#header'], array('class' => array('select-all'))); } // Add an empty header column for radio buttons or when a "Select all" // checkbox is not desired. else { array_unshift($element['#header'], ''); } // @todo FIXME if (!isset($element['#default_value']) || $element['#default_value'] === 0) { $element['#default_value'] = array(); } // Create a checkbox or radio for each row in a way that the value of the // tableselect element behaves as if it had been of #type checkboxes or // radios. foreach (element_children($element) as $key) { // Do not overwrite manually created children. if (!isset($element[$key]['select'])) { // Determine option label; either an assumed 'title' column, or the // first available column containing a #title or #markup. // @todo Consider to add an optional $element[$key]['#title_key'] // defaulting to 'title'? $title = ''; if (!empty($element[$key]['title']['#title'])) { $title = $element[$key]['title']['#title']; } else { // @todo Performance-optimization. foreach (element_children($element[$key]) as $column) { if (isset($element[$key][$column]['#title'])) { $title = $element[$key][$column]['#title']; break; } if (isset($element[$key][$column]['#markup'])) { $title = $element[$key][$column]['#markup']; break; } } } if ($title !== '') { $title = t('Update !title', array('!title' => $title)); } // Prepend the select column to existing columns. $element[$key] = array('select' => array()) + $element[$key]; $element[$key]['select'] += array( '#type' => $element['#multiple'] ? 'checkbox' : 'radio', '#title' => $title, '#title_display' => 'invisible', // @todo If rows happen to use numeric indexes instead of string keys, // this results in a first row with $key === 0, which is always FALSE. '#return_value' => $key, '#attributes' => $element['#attributes'], ); $element_parents = array_merge($element['#parents'], array($key)); if ($element['#multiple']) { $element[$key]['select']['#default_value'] = isset($value[$key]) ? $key : NULL; $element[$key]['select']['#parents'] = $element_parents; } else { $element[$key]['select']['#default_value'] = ($element['#default_value'] == $key ? $key : NULL); $element[$key]['select']['#parents'] = $element['#parents']; $element[$key]['select']['#id'] = drupal_html_id('edit-' . implode('-', $element_parents)); } } } } return $element; } /** * #element_validate callback for #type 'table'. */ function edge_element_validate_table($element, &$form_state) { $error = FALSE; if ($element['#multiple']) { if (!is_array($element['#value']) || !count(array_filter($element['#value']))) { $error = TRUE; } } elseif (!isset($element['#value']) || $element['#value'] === '') { $error = TRUE; } // @todo Add dependency on #required? if ($error) { form_error($element, t('No items selected.')); } } /** * #pre_render callback to transform children of an element into #rows suitable for theme_table(). * Loading Loading @@ -148,6 +299,8 @@ function edge_pre_render_table($element) { $row += $element[$first]['#attributes']; } // Turn second-level elements into table row columns. // @todo Do not render a cell for children of #type 'value'. // @see http://drupal.org/node/1248940 foreach (element_children($element[$first]) as $second) { // Assign the element by reference, so any potential changes to the // original element are taken over. Loading @@ -157,9 +310,7 @@ function edge_pre_render_table($element) { } // Take over $element['#id'] as HTML ID attribute, if not already set. if (!isset($element['#attributes']['id']) && !empty($element['#id'])) { $element['#attributes']['id'] = $element['#id']; } element_set_attributes($element, array('id')); // If the custom #attached][tabledrag] is set and there is a HTML ID, convert // it into #attached][drupal_add_tabledrag] and inject the HTML ID as first Loading Loading
edge.module +154 −3 Original line number Diff line number Diff line Loading @@ -12,8 +12,20 @@ function edge_element_info() { $types['table'] = array( '#header' => array(), '#rows' => array(), '#empty' => '', '#pre_render' => array('edge_pre_render_table'), '#theme' => 'table', // Properties for tableselect support. '#tableselect' => FALSE, '#input' => TRUE, '#value_callback' => 'edge_type_table_value', '#tree' => TRUE, // Note that MODULE_process_THEME() clashes with global theme system process // callbacks. '#process' => array('edge_element_process_table'), '#element_validate' => array('edge_element_validate_table'), '#multiple' => TRUE, '#js_select' => TRUE, ); return $types; } Loading Loading @@ -83,6 +95,145 @@ function edge_css_alter(&$css) { } } /** * Helper function to determine the value of a table form element. * * @param $element * The form element whose value is being populated. * @param $input * The incoming input to populate the form element. If this is FALSE, * the element's default value should be returned. * * @return * The data that will appear in the $form_state['values'] collection * for this element. Return nothing to use the default. */ function edge_type_table_value($element, $input = FALSE) { // If #multiple is FALSE, the regular default value of radio buttons is used. if (!empty($element['#multiple'])) { // Contrary to #type 'checkboxes', the default value of checkboxes in a // table is built from the array keys (instead of array values) of the // #default_value property. // @todo D8: Remove this weirdness. if ($input === FALSE) { $element += array('#default_value' => array()); return drupal_map_assoc(array_keys(array_filter($element['#default_value']))); } else { return is_array($input) ? drupal_map_assoc($input) : array(); } } } /** * #process callback for #type 'table' to add tableselect support. * * @see form_process_tableselect() * @see theme_tableselect() */ function edge_element_process_table($element, &$form_state) { if ($element['#tableselect']) { if ($element['#multiple']) { $value = is_array($element['#value']) ? $element['#value'] : array(); } // Advanced selection behaviour makes no sense for radios. else { $element['#js_select'] = FALSE; } // Add a "Select all" checkbox column to the header. // @todo D8: Rename into #select_all? if ($element['#js_select']) { $element['#attached']['js'][] = 'misc/tableselect.js'; array_unshift($element['#header'], array('class' => array('select-all'))); } // Add an empty header column for radio buttons or when a "Select all" // checkbox is not desired. else { array_unshift($element['#header'], ''); } // @todo FIXME if (!isset($element['#default_value']) || $element['#default_value'] === 0) { $element['#default_value'] = array(); } // Create a checkbox or radio for each row in a way that the value of the // tableselect element behaves as if it had been of #type checkboxes or // radios. foreach (element_children($element) as $key) { // Do not overwrite manually created children. if (!isset($element[$key]['select'])) { // Determine option label; either an assumed 'title' column, or the // first available column containing a #title or #markup. // @todo Consider to add an optional $element[$key]['#title_key'] // defaulting to 'title'? $title = ''; if (!empty($element[$key]['title']['#title'])) { $title = $element[$key]['title']['#title']; } else { // @todo Performance-optimization. foreach (element_children($element[$key]) as $column) { if (isset($element[$key][$column]['#title'])) { $title = $element[$key][$column]['#title']; break; } if (isset($element[$key][$column]['#markup'])) { $title = $element[$key][$column]['#markup']; break; } } } if ($title !== '') { $title = t('Update !title', array('!title' => $title)); } // Prepend the select column to existing columns. $element[$key] = array('select' => array()) + $element[$key]; $element[$key]['select'] += array( '#type' => $element['#multiple'] ? 'checkbox' : 'radio', '#title' => $title, '#title_display' => 'invisible', // @todo If rows happen to use numeric indexes instead of string keys, // this results in a first row with $key === 0, which is always FALSE. '#return_value' => $key, '#attributes' => $element['#attributes'], ); $element_parents = array_merge($element['#parents'], array($key)); if ($element['#multiple']) { $element[$key]['select']['#default_value'] = isset($value[$key]) ? $key : NULL; $element[$key]['select']['#parents'] = $element_parents; } else { $element[$key]['select']['#default_value'] = ($element['#default_value'] == $key ? $key : NULL); $element[$key]['select']['#parents'] = $element['#parents']; $element[$key]['select']['#id'] = drupal_html_id('edit-' . implode('-', $element_parents)); } } } } return $element; } /** * #element_validate callback for #type 'table'. */ function edge_element_validate_table($element, &$form_state) { $error = FALSE; if ($element['#multiple']) { if (!is_array($element['#value']) || !count(array_filter($element['#value']))) { $error = TRUE; } } elseif (!isset($element['#value']) || $element['#value'] === '') { $error = TRUE; } // @todo Add dependency on #required? if ($error) { form_error($element, t('No items selected.')); } } /** * #pre_render callback to transform children of an element into #rows suitable for theme_table(). * Loading Loading @@ -148,6 +299,8 @@ function edge_pre_render_table($element) { $row += $element[$first]['#attributes']; } // Turn second-level elements into table row columns. // @todo Do not render a cell for children of #type 'value'. // @see http://drupal.org/node/1248940 foreach (element_children($element[$first]) as $second) { // Assign the element by reference, so any potential changes to the // original element are taken over. Loading @@ -157,9 +310,7 @@ function edge_pre_render_table($element) { } // Take over $element['#id'] as HTML ID attribute, if not already set. if (!isset($element['#attributes']['id']) && !empty($element['#id'])) { $element['#attributes']['id'] = $element['#id']; } element_set_attributes($element, array('id')); // If the custom #attached][tabledrag] is set and there is a HTML ID, convert // it into #attached][drupal_add_tabledrag] and inject the HTML ID as first Loading