Index: modules/field/modules/options/options.module =================================================================== RCS file: /cvs/drupal/drupal/modules/field/modules/options/options.module,v retrieving revision 1.3 diff -u -p -r1.3 options.module --- modules/field/modules/options/options.module 10 Feb 2009 03:16:15 -0000 1.3 +++ modules/field/modules/options/options.module 24 Mar 2009 18:34:30 -0000 @@ -44,7 +44,7 @@ function options_field_widget_info() { return array( 'options_select' => array( 'label' => t('Select list'), - 'field types' => array('list', 'list_boolean', 'list_text', 'list_number'), + 'field types' => array('list', 'list_boolean', 'list_text', 'list_number', 'term'), 'behaviors' => array( 'multiple values' => FIELD_BEHAVIOR_CUSTOM, 'default value' => FIELD_BEHAVIOR_DEFAULT, @@ -52,7 +52,7 @@ function options_field_widget_info() { ), 'options_buttons' => array( 'label' => t('Check boxes/radio buttons'), - 'field types' => array('list', 'list_boolean', 'list_text', 'list_number'), + 'field types' => array('list', 'list_boolean', 'list_text', 'list_number', 'term'), 'behaviors' => array( 'multiple values' => FIELD_BEHAVIOR_CUSTOM, 'default value' => FIELD_BEHAVIOR_DEFAULT, Index: modules/taxonomy/taxonomy.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.admin.inc,v retrieving revision 1.47 diff -u -p -r1.47 taxonomy.admin.inc --- modules/taxonomy/taxonomy.admin.inc 14 Mar 2009 20:13:27 -0000 1.47 +++ modules/taxonomy/taxonomy.admin.inc 24 Mar 2009 18:34:31 -0000 @@ -25,7 +25,6 @@ function taxonomy_overview_vocabularies( $form[$vocabulary->vid]['#vocabulary'] = $vocabulary; $form[$vocabulary->vid]['name'] = array('#markup' => check_plain($vocabulary->name)); $form[$vocabulary->vid]['types'] = array('#markup' => implode(', ', $types)); - $form[$vocabulary->vid]['weight'] = array('#type' => 'weight', '#delta' => 10, '#default_value' => $vocabulary->weight); $form[$vocabulary->vid]['edit'] = array('#markup' => l(t('edit vocabulary'), "admin/content/taxonomy/$vocabulary->vid")); $form[$vocabulary->vid]['list'] = array('#markup' => l(t('list terms'), "admin/content/taxonomy/$vocabulary->vid/list")); $form[$vocabulary->vid]['add'] = array('#markup' => l(t('add terms'), "admin/content/taxonomy/$vocabulary->vid/add")); @@ -36,9 +35,6 @@ function taxonomy_overview_vocabularies( if (count($vocabularies) > 1) { $form['submit'] = array('#type' => 'submit', '#value' => t('Save')); } - elseif (isset($vocabulary)) { - unset($form[$vocabulary->vid]['weight']); - } return $form; } @@ -49,8 +45,7 @@ function taxonomy_overview_vocabularies( */ function taxonomy_overview_vocabularies_submit($form, &$form_state) { foreach ($form_state['values'] as $vid => $vocabulary) { - if (is_numeric($vid) && $form[$vid]['#vocabulary']->weight != $form_state['values'][$vid]['weight']) { - $form[$vid]['#vocabulary']->weight = $form_state['values'][$vid]['weight']; + if (is_numeric($vid)) { taxonomy_vocabulary_save($form[$vid]['#vocabulary']); } } @@ -71,10 +66,6 @@ function theme_taxonomy_overview_vocabul $row = array(); $row[] = drupal_render($vocabulary['name']); $row[] = drupal_render($vocabulary['types']); - if (isset($vocabulary['weight'])) { - $vocabulary['weight']['#attributes']['class'] = 'vocabulary-weight'; - $row[] = drupal_render($vocabulary['weight']); - } $row[] = drupal_render($vocabulary['edit']); $row[] = drupal_render($vocabulary['list']); $row[] = drupal_render($vocabulary['add']); @@ -87,13 +78,24 @@ function theme_taxonomy_overview_vocabul $header = array(t('Vocabulary name'), t('Content types')); if (isset($form['submit'])) { - $header[] = t('Weight'); - drupal_add_tabledrag('taxonomy', 'order', 'sibling', 'vocabulary-weight'); + drupal_add_tabledrag('taxonomy', 'order', 'sibling'); } $header[] = array('data' => t('Operations'), 'colspan' => '3'); return theme('table', $header, $rows, array('id' => 'taxonomy')) . drupal_render_children($form); } + +/** + * Take a user-entered name and make it machine-safe. + * + * Replace spaces and all unknown characters with underscores and lowercase. + * + * @TODO get this into common.inc + */ +function drupal_system_string($string, $replacement = '_') { + return preg_replace('/[^a-z0-9]+/', $replacement, strtolower($string)); +} + /** * Display form for adding and editing vocabularies. * @@ -103,18 +105,16 @@ function theme_taxonomy_overview_vocabul function taxonomy_form_vocabulary(&$form_state, $edit = array()) { if (!is_array($edit)) { $edit = (array)$edit; - } + } $edit += array( 'name' => '', 'description' => '', 'help' => '', - 'nodes' => array(), 'hierarchy' => 0, 'relations' => 0, 'tags' => 0, 'multiple' => 0, 'required' => 0, - 'weight' => 0, ); // Check whether we need a deletion confirmation form. if (isset($form_state['confirm_delete']) && isset($form_state['values']['vid'])) { @@ -127,6 +127,7 @@ function taxonomy_form_vocabulary(&$form '#maxlength' => 255, '#description' => t('The name for this vocabulary, e.g., "Tags".'), '#required' => TRUE, + '#field_suffix' => '  ', ); $form['help'] = array( '#type' => 'textfield', @@ -141,13 +142,37 @@ function taxonomy_form_vocabulary(&$form '#default_value' => $edit['description'], '#description' => t('Description of the vocabulary; can be used by modules.'), ); - $form['nodes'] = array( - '#type' => 'checkboxes', - '#title' => t('Content types'), - '#default_value' => $edit['nodes'], - '#options' => array_map('check_plain', node_get_types('names')), - '#description' => t('Select content types to categorize using this vocabulary.'), - ); + if (module_exists('term')) { + $edit['field_name'] = ''; + $edit['nodes'] = array(); + if (array_key_exists('vid', $edit)) { + $instances = array(); + foreach (field_read_fields(array('module' => 'term')) as $field) { + if ($field['settings']['vid'] == $edit['vid']) { + $edit['field_name'] = $field['field_name']; + $fields[] = $field['field_name']; + $instances = array_merge(field_read_instances(array('field_name' => $fields)), $instances); + } + } + foreach ($instances as $instance) { + $edit['nodes'][] = $instance['bundle']; + } + } + $form['field_name'] = array( + '#type' => 'textfield', + '#title' => t('Field name'), + '#default_value' => $edit['field_name'], + '#maxlength' => 32, + '#description' => t('The machine-readable name for this vocabulary\'s field. This name must contain only lowercase letters, numbers, and underscores. This name must be unique.'), + ); + $form['nodes'] = array( + '#type' => 'checkboxes', + '#title' => t('Content types'), + '#default_value' => $edit['nodes'], + '#options' => array_map('check_plain', node_get_types('names')), + '#description' => t('Select content types to categorize using this vocabulary.'), + ); + } $form['settings'] = array( '#type' => 'fieldset', '#title' => t('Settings'), @@ -158,7 +183,7 @@ function taxonomy_form_vocabulary(&$form '#title' => t('Tags'), '#default_value' => $edit['tags'], '#description' => t('Terms are created by users when submitting posts by typing a comma separated list.'), - ); + ); $form['settings']['multiple'] = array( '#type' => 'checkbox', '#title' => t('Multiple select'), @@ -171,6 +196,8 @@ function taxonomy_form_vocabulary(&$form '#default_value' => $edit['required'], '#description' => t('At least one term in this vocabulary must be selected when submitting a post.'), ); + + // @TODO - what? this *disables* multiple parents, and there's no UI way to turn it on!?! // Set the hierarchy to "multiple parents" by default. This simplifies the // vocabulary form and standardizes the term form. $form['hierarchy'] = array( @@ -215,6 +242,36 @@ function taxonomy_form_vocabulary_submit watchdog('taxonomy', 'Updated vocabulary %name.', array('%name' => $vocabulary->name), WATCHDOG_NOTICE, l(t('edit'), 'admin/content/taxonomy/' . $vocabulary->vid)); break; } + if (module_exists('term')) { + if (!field_read_field($vocabulary->field_name)) { + $field = array( + 'field_name' => $vocabulary->field_name, + 'module' => 'term', + 'type' => 'term', + 'cardinality' => ($vocabulary->multiple ? FIELD_CARDINALITY_UNLIMITED : 1), + 'settings' => array( + 'vid' => $vocabulary->vid, + ), + ); + field_create_field($field); + } + $instance = array( + 'field_name' => $vocabulary->field_name, + 'bundle' => '', + 'label' => $vocabulary->name, + 'description' => $vocabulary->description, + 'required' => $vocabulary->required, + 'widget' => array( + 'type' => 'options_select', + ), + ); + foreach ($vocabulary->nodes as $node_type) { + $instance['bundle'] = $node_type; + if (!field_read_instance($vocabulary->field_name, $node_type)) { + field_create_instance($instance); + } + } + } $form_state['vid'] = $vocabulary->vid; $form_state['redirect'] = 'admin/content/taxonomy'; @@ -265,7 +322,7 @@ function taxonomy_overview_terms(&$form_ if ($vocabulary->tags) { // We are not calling taxonomy_get_tree because that might fail with a big // number of tags in the freetagging vocabulary. - $results = pager_query(db_rewrite_sql('SELECT t.*, h.parent FROM {taxonomy_term_data} t INNER JOIN {taxonomy_term_hierarchy} h ON t.tid = h.tid WHERE t.vid = %d ORDER BY weight, name', 't', 'tid'), $page_increment, 0, NULL, $vocabulary->vid); + $results = pager_query(db_rewrite_sql('SELECT t.*, h.parent FROM {taxonomy_term_data} t INNER JOIN {taxonomy_term_hierarchy} h ON t.tid = h.tid WHERE t.vid = %d ORDER BY name', 't', 'tid'), $page_increment, 0, NULL, $vocabulary->vid); $total_entries = db_query(db_rewrite_sql('SELECT COUNT(*) FROM {taxonomy_term_data} t INNER JOIN {taxonomy_term_hierarchy} h ON t.tid = h.tid WHERE t.vid = :vid'), array(':vid' => $vocabulary->vid)); while ($term = db_fetch_object($results)) { $key = 'tid:' . $term->tid . ':0'; Index: modules/taxonomy/taxonomy.module =================================================================== RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.module,v retrieving revision 1.463 diff -u -p -r1.463 taxonomy.module --- modules/taxonomy/taxonomy.module 21 Mar 2009 00:59:02 -0000 1.463 +++ modules/taxonomy/taxonomy.module 24 Mar 2009 18:34:32 -0000 @@ -212,17 +212,10 @@ function taxonomy_vocabulary_save($vocab if (!empty($vocabulary->vid) && !empty($vocabulary->name)) { $status = drupal_write_record('taxonomy_vocabulary', $vocabulary, 'vid'); - db_query("DELETE FROM {taxonomy_vocabulary_node_type} WHERE vid = %d", $vocabulary->vid); - foreach ($vocabulary->nodes as $type => $selected) { - db_query("INSERT INTO {taxonomy_vocabulary_node_type} (vid, type) VALUES (%d, '%s')", $vocabulary->vid, $type); - } module_invoke_all('taxonomy_vocabulary_update', $vocabulary); } elseif (empty($vocabulary->vid)) { $status = drupal_write_record('taxonomy_vocabulary', $vocabulary); - foreach ($vocabulary->nodes as $type => $selected) { - db_query("INSERT INTO {taxonomy_vocabulary_node_type} (vid, type) VALUES (%d, '%s')", $vocabulary->vid, $type); - } module_invoke_all('taxonomy_vocabulary_insert', $vocabulary); } Index: modules/taxonomy/term.info =================================================================== RCS file: modules/taxonomy/term.info diff -N modules/taxonomy/term.info --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/taxonomy/term.info 24 Mar 2009 18:34:32 -0000 @@ -0,0 +1,6 @@ +; $Id$ +name = Term +description = Defines taxonomy term field types. Use with Options to create selection lists. +package = Core - fields +core = 7.x +files[]=term.module Index: modules/taxonomy/term.module =================================================================== RCS file: modules/taxonomy/term.module diff -N modules/taxonomy/term.module --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/taxonomy/term.module 24 Mar 2009 18:34:32 -0000 @@ -0,0 +1,154 @@ + array( + 'arguments' => array('element' => NULL), + ), + 'field_formatter_term_key' => array( + 'arguments' => array('element' => NULL), + ), + ); +} + +/** + * Implementation of hook_field_info(). + */ +function term_field_info() { + return array( + 'term' => array( + 'label' => t('Term'), + 'description' => t('This field stores keys from key/value terms of allowed numbers where the stored numeric key has significance and must be preserved, i.e. \'Lifetime in days\': 1|1 day, 7|1 week, 31|1 month.'), + 'settings' => array('allowed_values_function' => ''), + 'default_widget' => 'options_select', + 'default_formatter' => 'term_default', + 'settings' => array('vid' => 0), + ), + ); +} + +/** + * Implementation of hook_field_columns(). + * + * @TODO text.module calls this an implementation of hook_field_schema(), + * any deep meaning in that or just correct it in text.module? + */ +function term_field_columns($field) { + $columns = array( + 'value' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => FALSE, + ), + ); + return $columns; +} + +/** + * Implementation of hook_field_validate(). + */ +function term_field_validate($obj_type, $object, $field, $instance, $items, $form) { + $allowed_values = term_allowed_values($field); + if (is_array($items)) { + foreach ($items as $delta => $item) { + $error_element = isset($item['_error_element']) ? $item['_error_element'] : ''; + if (is_array($item) && isset($item['_error_element'])) unset($item['_error_element']); + if (!empty($item['value'])) { + if (count($allowed_values) && !array_key_exists($item['value'], $allowed_values)) { + form_set_error($error_element, t('%name: illegal value.', array('%name' => t($instance['label'])))); + } + } + } + } +} + +/** + * Implementation of hook_field_is_empty(). + */ +function term_field_is_empty($item, $field) { + if (empty($item['value']) && (string)$item['value'] !== '0') { + return TRUE; + } + return FALSE; +} + +/** + * Implementation of hook_field_formatter_info(). + */ +function term_field_formatter_info() { + return array( + 'term_default' => array( + 'label' => t('Default'), + 'field types' => array('term'), + 'behaviors' => array( + 'multiple values' => FIELD_BEHAVIOR_DEFAULT, + ), + ), + 'term_id' => array( // why this second one..? + 'label' => t('Id'), + 'field types' => array('term'), + 'behaviors' => array( + 'multiple values' => FIELD_BEHAVIOR_DEFAULT, + ), + ), + ); +} + +/** + * Theme function for 'default' term field formatter. + */ +function theme_field_formatter_term_default($element) { + $field = field_info_field($element['#field_name']); + if (($allowed_values = term_allowed_values($field)) && isset($allowed_values[$element['#item']['value']])) { + return $allowed_values[$element['#item']['value']]; + } + // If no match was found in allowed values, fall back to the key. + return $element['#item']['safe']; +} + +/** + * Theme function for 'key' term field formatter. + */ +function theme_field_formatter_term_key($element) { + return $element['#item']['safe']; +} + +/** + * Create an array of the allowed values for this field. + * + * Call the allowed_values_function to retrieve the allowed + * values array. + * + * This function should imitate the features of _taxonomy_term_select + * + * TODO Rework this to create a method of selecting plugable allowed values terms + * TODO deal with excluded tids + * + */ +function term_allowed_values($field) { + $tree = taxonomy_get_tree($field['settings']['vid']); + $options = array(); + +// if ($blank) { +// $options[0] = $blank; +// } + if ($tree) { + foreach ($tree as $term) { +// if (!in_array($term->tid, $exclude)) { + $choice = new stdClass(); + $choice->option = array($term->tid => str_repeat('-', $term->depth) . $term->name); + $options[] = $choice; +// } + } + } + return $options; +}