diff --git a/cck_select_other.js b/cck_select_other.js index c5d6617..bd95a33 100644 --- a/cck_select_other.js +++ b/cck_select_other.js @@ -26,7 +26,11 @@ // We need to go up further up the element chain to work around 'add another item' $('select#edit-' + select_id).bind(ActionBind,function() { // Add parent() to hide input wrapper - $('input#edit-' + text_id).parent().css('display', ($(this).val() == "other") ? 'block' : 'none'); + var selected_other = 'none'; + $(this).children(':selected').each(function() { + selected_other = ($(this).val() == 'other') ? 'block' : 'none'; + }); + $('input#edit-' + text_id).parent().css('display', selected_other); }).trigger(ActionBind); }); }); diff --git a/cck_select_other.module b/cck_select_other.module index ac8404b..b9d1c93 100644 --- a/cck_select_other.module +++ b/cck_select_other.module @@ -153,7 +153,7 @@ function cck_select_other_field_widget_form(&$form, &$form_state, $field, $insta '#prefix' => '
', '#suffix' => '
', '#field_name' => $field['field_name'], // Required fields for field_conditional_state. - '#field_parents' => $form['#parents'], + '#field_parents' => isset($form['#parents']) ? $form['#parents'] : array(), '#bundle' => $instance['bundle'], ); @@ -218,7 +218,7 @@ function cck_select_other_widget_validate($element, &$form_state) { // Empty other field. if ($field[$langcode]['instance']['required'] && $form_state['values'][$field_name][$langcode][$delta]['select_other_list'] == 'other' && empty($form_state['values'][$field_name][$langcode][$delta]['select_other_text_input'])) { - form_set_error($field_name . '[' . $langcode . '][' . $delta . '][select_other_text_input]', t('A non-empty value is required for this option.')); + form_set_error($element['#name'], t('A non-empty value is required for this option.')); } // Non-required field value. @@ -361,6 +361,15 @@ function cck_select_other_process($element, &$form_state) { function cck_select_other_pre_render($element, $form_state = NULL) { static $js; + $errors = form_get_errors(); + if (!empty($errors)) { + // Validation errors for the text input box get lost so need to be injected. + $text_element = $element['#name'] . '[select_other_text_input]'; + if (in_array($text_element, array_keys($errors))) { + $element['select_other_text_input']['#attributes']['class'][] = 'error'; + } + } + if (!isset($form_state)) { return $element; } diff --git a/views/cck_select_other.views.inc b/views/cck_select_other.views.inc index 6543e80..3be4467 100644 --- a/views/cck_select_other.views.inc +++ b/views/cck_select_other.views.inc @@ -15,6 +15,8 @@ function cck_select_other_views_data_alter(&$data) { $field = $instance['field_name'] . '_value'; $data[$table]['entity_id']['field']['handler'] = 'cck_select_other_handler_field'; $data[$table][$field]['filter']['handler'] = 'cck_select_other_handler_filter'; + $data[$table][$field]['filter']['entity_type'] = $instance['entity_type']; + $data[$table][$field]['filter']['bundle'] = $instance['bundle']; } } } diff --git a/views/cck_select_other_handler_filter.inc b/views/cck_select_other_handler_filter.inc index 2ab2019..e889077 100644 --- a/views/cck_select_other_handler_filter.inc +++ b/views/cck_select_other_handler_filter.inc @@ -5,25 +5,185 @@ /** - * Extends Content Handler Filter Many To One for CCK Select Other + * Extends Views in operator filter. */ -class cck_select_other_handler_filter extends views_handler_filter_field_list { +class cck_select_other_handler_filter extends views_handler_filter_in_operator { + + /** + * Init + */ + function init(&$view, &$options) { + parent::init($view, $options); + + $this->instance = field_info_instance($this->definition['entity_type'], $this->definition['field_name'], $this->definition['bundle']); + } + + /** + * Exposed form + */ + function exposed_form(&$form, &$form_state) { + parent::exposed_form($form, $form_state); + + $identifier = $this->options['expose']['identifier']; + + // Populate other default value if any. + $otherdef = ''; + $other_values = array_diff($this->value, $this->value_options); + $otherdef = empty($other_values) ? '' : array_pop($other_values); + + $form[$identifier]['select_other_text_input'] = array( + '#type' => 'textfield', + '#title' => t('Other'), + '#title_display' => 'invisible', + '#attributes' => array( + 'class' => array('form-text select_other_text_input'), + ), + '#default_value' => $otherdef, + '#parents' => array('options', 'value', 'select_other_text_input'), + '#size' => 10, + ); + + $form[$identifier]['#parents'] = array('options', $identifier); + $form[$identifier]['select_other_list']['#type'] = 'select'; + $form[$identifier]['select_other_list']['#multiple'] = $this->options['expose']['multiple']; + $form[$identifier]['select_other_list']['#parents'] = array('options', $identifier, 'select_other_list'); + $form[$identifier]['select_other_text_input']['#parents'] = array('options', $identifier, 'select_other_text_input'); + + $field_id = str_replace('_', '-', 'options-' . $identifier); + drupal_add_js(array('CCKSelectOther' => array(array('field_id' => $field_id))), array('type' => 'setting')); + } + + function exposed_submit($form, &$form_state) { + $identifier = $this->options['expose']['identifier']; + $values = $form_state['values']['options'][$identifier]; + $form_state['values'][$identifier] = array(); + + foreach ($values['select_other_list'] as $key => $value) { + if ($value && $key == $value) { + if ($value <> 'other') { + $form_state['values'][$identifier][] = $value; + } + else { + // Set the other value instead of 'other' + $form_state['values'][$identifier][] = $values['select_other_text_input']; + } + } + } + + } + + /** + * Value form + */ + function value_form(&$form, &$form_state) { + static $js; + + parent::value_form($form, $form_state); + + $default = array(); + foreach ($this->value as $key => $value) { + // Populate default values. + if (in_array($value, $this->value_options)) { + $default[] = $value; + } + else { + $default[] = 'other'; + } + } + + $options = $form['value']['#options']; + $form['value'] = array( + '#type' => 'container', + '#tree' => TRUE, + '#parents' => array('options', 'value'), + 'select_other_list' => array( + // @note I am using checkboxes instead of select in the filter. + '#type' => 'checkboxes', + '#options' => $options, + '#default_value' => $default, + '#parents' => array('options', 'value', 'select_other_list'), + ), + ); + + if (!$js) { + drupal_add_js(drupal_get_path('module', 'cck_select_other') . '/cck_select_other.js'); + $js = TRUE; + } + drupal_add_js(array('CCKSelectOther' => array(array('field_id' => 'options-value'))), array('type' => 'setting')); + } + + function value_submit($form, &$form_state) { + // Capture the values into a separate array and reset the value array. + $values = $form_state['values']['options']['value']; + $form_state['values']['options']['value'] = array(); + + foreach ($values['select_other_list'] as $key => $value) { + if ($value && $key == $value) { + $form_state['values']['options']['value'][] = $value; + } + } + } function get_value_options() { - // This is a gigantic hack because views and views documentation suck. - $n = preg_match_all("/(\S+):(\S+)/", $this->definition['help'], $matches); - $entity_type = isset($matches[1]) ? $matches[1] : ''; - $bundle = isset($matches[2]) ? $matches[2] : ''; + $this->value_options = cck_select_other_options($this->instance); - $instance = field_read_instance($entity_type, $this->definition['field_name'], $bundle); - $this->value_options = cck_select_other_options($instance); + // Get rid of none options. + unset($this->value_options['']); + unset($this->value_options['_none']); + } + + function accept_exposed_input($input) { + $ret = parent::accept_exposed_input($input); + return $ret; } function query() { - if (isset($this->value[0]) && $this->value[0] == 'other') { + if (!empty($this->value)) { + // Only query if we have a value. + + if (in_array('other', $this->value)) { + // Remove other from values and add condition for any value not in values. + $this->value = array_diff($this->value, array('other')); + } + else { + // Query as normal. + parent::query(); + } + } - else { - parent::query(); + } + + function admin_summary() { + if (!empty($this->options['exposed'])) { + return t('exposed'); + } + + $info = $this->operators(); + + $this->get_value_options(); + + if (!is_array($this->value)) { + return; } + + $operator = check_plain($info[$this->operator]['short']); + $values = ''; + + $count = count($this->value); + $i = 1; + foreach ($this->value as $value) { + if (isset($this->value_options[$value])) { + $values .= check_plain($this->value_options[$value]); + } + else { + $values .= t('%value', array('%value' => $value)); + } + if ($i < $count) { + $values .= ', '; + } + $i++; + } + + return $operator . (($values !== '') ? ' (' . $values . ')' : ''); } }