diff --git a/flag.info b/flag.info index 426fc47..4d665cc 100644 --- a/flag.info +++ b/flag.info @@ -27,4 +27,5 @@ files[] = includes/views/flag_handler_filter_flagged.inc files[] = includes/views/flag_handler_sort_flagged.inc files[] = includes/views/flag_handler_relationships.inc files[] = includes/views/flag_plugin_argument_validate_flaggability.inc +files[] = includes/views/flag_handler_field_entity_ops.inc files[] = tests/flag.test diff --git a/includes/views/flag.views.inc b/includes/views/flag.views.inc index 076878c..7e5df81 100644 --- a/includes/views/flag.views.inc +++ b/includes/views/flag.views.inc @@ -243,6 +243,17 @@ function flag_views_data_alter(&$data) { 'relationship field' => $info['join field'], ), ); + + // Flag links based on the generic 'views_entity_' . $entity_type tables + // that can be used by any query backend. + $data['views_entity_' . $flag_type]['flag_ops_entity'] = array( + 'title' => t('Flag link for entities'), + 'help' => t('Display flag/unflag link.'), + 'field' => array( + 'handler' => 'flag_handler_field_entity_ops', + 'flag type' => $flag_type, + ), + ); } } diff --git a/includes/views/flag_handler_field_entity_ops.inc b/includes/views/flag_handler_field_entity_ops.inc new file mode 100644 index 0000000..255c448 --- /dev/null +++ b/includes/views/flag_handler_field_entity_ops.inc @@ -0,0 +1,123 @@ +options['flag']); + } + + function option_definition() { + $options = parent::option_definition(); + $options['link_type'] = array('default' => ''); + $options['flag'] = array('default' => NULL); + return $options; + } + + function options_form(&$form, &$form_state) { + parent::options_form($form, $form_state); + + $form['link_type'] = array( + '#type' => 'radios', + '#title' => t('Link type'), + '#options' => array('' => t('Use flag link settings')) + _flag_link_type_options(), + '#default_value' => $this->options['link_type'], + ); + + //@todo: same code in flag_handler_relationship_content + $form['flag'] = flag_views_flag_config_form('radios', $content_type, $this->options['flag']); + if (!$form['flag']['#options']) { + $form = array( + 'error' => array( + '#markup' => '

' . t('No %type flags exist. You must first create a %type flag before being able to use this field.', array('%type' => $content_type, '@create-url' => url(FLAG_ADMIN_PATH))) . '

', + ), + ); + $form_state['no flags exist'] = TRUE; + } + } + +/** + * @todo: same code in flag_handler_relationship->validate() + * + * Make sure the flag exists. + * + * When importing views, or when deleting flags, inconsistent views may + * result. This validator is called by Views before saving or previewing a + * view. + */ + function validate() { + $errors = array(); + $tokens = array( + '@field-name' => $this->definition['title'], + '@flag-name' => $this->options['flag'], + ); + if (!$this->options['flag']) { + $errors[] = t('You must pick a flag to use for the field "@field-name".', $tokens); + } + elseif (!flag_get_flag($this->options['flag'])) { + $errors[] = t('This view is looking for a flag by the name "@flag-name", but there is no such flag. Perhaps it was deleted. Please update the field "@field-name" in this view to use an existing flag.', $tokens); + } + return $errors; + } + + /** + * Find out if the flag applies to each item seen on the page. It's done in a + * separate step so that we can use the access_multiple hook for all results + * at once. + */ + function pre_render(&$values) { + parent::pre_render($values); + if (!($flag = $this->get_flag())) { + // Error message is printed in render(). + return; + } + if (empty($this->entities)) { + // Empty result set. + return; + } + foreach ($this->entities as $entity) { + $id = $flag->get_entity_id($entity); + $is_flagged = $flag->is_flagged($id); + $ids[$id] = $is_flagged ? 'unflag' : 'flag'; + } + $this->ids = $ids; + $this->flag_applies = $ids ? $flag->access_multiple($ids) : array(); + } + + /** + * Render the flag link for a specific entity. + */ + function render($values) { + if (!($flag = $this->get_flag())) { + // get_flag() itself will print a more detailed message. + return t('Missing flag'); + } + $entity = $this->get_value($values); + $id = $flag->get_entity_id($entity); + + if (empty($this->flag_applies[$id])) { + // Flag does not apply to this content. + return; + } + + if (!empty($this->options['link_type'])) { + $flag->link_type = $this->options['link_type']; + } + + $flag_value = $this->ids[$id]; + return $flag->theme($flag_value, $id); + } +}