From 7d60336378a5dafbba01563c9686b39f51ed272e Mon Sep 17 00:00:00 2001
From: Jorrit Schippers <jorrit@161217.no-reply.drupal.org>
Date: Mon, 30 Jul 2012 12:40:34 +0200
Subject: [PATCH] Issue #1664502 by Jorrit: Added an alternative widget that
 allows sorting relation instances

---
 css/relation-select.css              |   27 +-
 includes/relation_select.widget2.inc |  477 +++++++++++++++++++++++++++++++
 js/relation-select-table.js          |  190 +++++++++++++
 js/relation-select.js                |    4 +
 relation_select.module               |  518 ++++++++++++++++++++--------------
 theme/theme.inc                      |   82 ++++++
 6 files changed, 1081 insertions(+), 217 deletions(-)
 create mode 100644 includes/relation_select.widget2.inc
 create mode 100644 js/relation-select-table.js

diff --git a/css/relation-select.css b/css/relation-select.css
index c3402d5..b02227b 100644
--- a/css/relation-select.css
+++ b/css/relation-select.css
@@ -154,4 +154,29 @@
 .views-view-relation-select table tbody{
   border-left: 1px solid #ccc;
   border-collapse: separate;
-}
\ No newline at end of file
+}
+
+.relation-select-table tr.field-formatter-settings-changed {
+  background: #FFFFBB;
+}
+.relation-select-table tr.drag {
+  background: #FFEE77;
+}
+.relation-select-table tr.field-formatter-settings-editing {
+  background: #D5E9F2;
+}
+.relation-select-table .form-actions,
+.relation-select-table .form-actions .form-submit {
+  margin-bottom: 0;
+}
+.relation-select-new-button {
+  display: none;
+}
+.relation-select-table-operations {
+  width: 300px;
+}
+.relation-select-table-operations .form-submit {
+  margin-bottom: 0;
+  margin-top: 0;
+  vertical-align: middle;
+}
diff --git a/includes/relation_select.widget2.inc b/includes/relation_select.widget2.inc
new file mode 100644
index 0000000..03f695d
--- /dev/null
+++ b/includes/relation_select.widget2.inc
@@ -0,0 +1,477 @@
+<?php
+/**
+ * Implements hook_field_widget_form().
+ */
+function relation_select_table_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
+  if (!empty($instance['settings']['relation_view'])){
+    list($viewname, $display) = explode(':', $instance['settings']['relation_view']);
+  }
+  else {
+    $viewname = relation_select_get_default_view();
+    $display = 'default';
+  }
+
+  $view = views_get_view($viewname);
+  $view->set_display($display);
+  $relation = relation_type_load($instance['settings']['relation_type']);
+
+  if (empty($instance['settings']['relation_type'])) {
+    // We're in the "Add field" screen, no relation_type is available yet.
+    return array();
+  }
+  if (!$relation) {
+    drupal_set_message(t('Relation type @relation-type-name could not be loaded.', array('@relation-type-name' => $instance['settings']['relation_type'])), 'error');
+    return array();
+  }
+  if ($relation->min_arity != 2 || $relation->max_arity != 2) {
+    drupal_set_message(t('The %widget-name widget only works on relations that have <a href="@edit-url">%min-arity and %max-arity</a> set to 2.', array('%widget-name' => t('Relation select table'), '@edit-url' => url('admin/structure/relation/manage/' . $relation->relation_type), '%min-arity' => t('Minimum Arity'), '%max-arity' => t('Maximum Arity'))), 'error');
+    return array();
+  }
+
+  $element += array(
+    '#type' => 'relation_select_table',
+    '#default_value' => $items,
+    '#relation' => $relation,
+    '#view' => $view,
+    '#cardinality' => $field['cardinality'],
+    '#weightfield' => $instance['widget']['settings']['weightfield'],
+  );
+
+  return $element;
+}
+
+/**
+ * Implements hook_element_process().
+ */
+function relation_select_table_element_process(&$element, &$form_state, $form) {
+  $fields = field_info_instances('relation', $element['#relation']->relation_type);
+  $weightfield = $element['#weightfield'];
+  $hasweight = isset($fields[$weightfield]); // @todo check type
+  unset($fields['endpoints'], $fields[$weightfield]);
+  $hasadditionalfields = !empty($fields);
+  $langcode = $element['#language'];
+  $relation = $element['#relation'];
+  $view = $element['#view'];
+
+  $element['#hasweight'] = $hasweight;
+  $element['#hasadditionalfields'] = $hasadditionalfields;
+  $element['#prefix'] = '<div id="'.$element['#id'].'-wrapper">';
+  $element['#suffix'] = '</div>';
+
+  // Create a container for the temporary settings
+  $field_name = $element['#field_name'];
+  $parents = $element['#field_parents'];
+  $field_state = field_form_get_state($parents, $field_name, $langcode, $form_state);
+
+  if (!isset($field_state['values'])) {
+    $field_state['values'] = drupal_array_get_nested_value($form_state['values'], $element['#parents']);
+    $field_state['current'] = NULL;
+    field_form_set_state($parents, $field_name, $langcode, $form_state, $field_state);
+  }
+
+  // Store the number of non-deleted values
+  $numvalues = 0;
+
+  foreach ($element['#value'] as $delta => $value) {
+    if ($delta === 'add') continue;
+    // This field is deleted when the endpoints are empty
+    if (empty($value['endpoints'])) continue;
+
+    // @todo : load in one go
+    // Find the entity that this relation points to
+    // The 'endpoints' array only contains endpoints that are not the current entity
+    // Only arity = 2 is supported here.
+    $endpoint = current($value['endpoints'][$langcode]);
+    if (empty($endpoint)) {
+      // This should not happen.
+      continue;
+    }
+    $target_entity_type = $endpoint['entity_type'];
+    $target_entity_id = $endpoint['entity_id'];
+    $target_entity = reset(entity_load($endpoint['entity_type'], array($endpoint['entity_id'])));
+    if (empty($target_entity)) {
+      // The target entity seems to be gone.
+      continue;
+    }
+
+    // Base button element for the various relation instance settings actions.
+    $base_button = array(
+      '#submit' => array('relation_select_table_multistep_submit'),
+      '#ajax' => array(
+        'callback' => 'relation_select_table_multistep_js',
+        'wrapper' => $element['#id'] . '-wrapper',
+        'effect' => 'fade',
+      ),
+      // Store the delta information so the exact item can be found in the submit handler
+      '#item_delta' => $delta,
+      '#field_name' => $field_name,
+      '#limit_validation_errors' => array(
+        array_merge($element['#parents']),
+      ),
+      '#name' => implode('-', $element['#parents']) . '-' . $delta,
+    );
+
+    $element[$delta] = array(
+      '#tree' => TRUE,
+      '#parents' => array_merge($element['#parents'], array($delta)),
+      'relation_fields' => array(
+        '#parents' => array_merge($element['#parents'], array($delta, 'relation_fields')),
+      ),
+      '#weight' => $delta,
+    );
+
+    field_attach_form('relation', (object)$value, $element[$delta]['relation_fields'], $form_state);
+    unset($element[$delta]['relation_fields']['endpoints']);
+
+    if ($hasweight) {
+      $element[$delta][$weightfield] = $element[$delta]['relation_fields'][$weightfield];
+      $element[$delta][$weightfield][$langcode][0]['value']['#attributes'] = array('class' => array('field-weight'));
+      $element[$delta][$weightfield]['#parents'] = array_merge($element[$delta]['#parents'], array('relation_fields', $weightfield));
+      unset($element[$delta]['relation_fields'][$weightfield]);
+
+      $element[$delta]['#weight'] = 0;
+      if (isset($value[$weightfield][$langcode][0])) {
+        $element[$delta]['#weight'] = intval($value[$weightfield][$langcode][0]['value']);
+      }
+    }
+    $element[$delta]['title'] = array(
+      '#markup' => check_plain(entity_label($target_entity_type, $target_entity)) . ' (' . check_plain($target_entity_type) . ': ' . $target_entity_id . ')',
+    );
+    if ($hasadditionalfields) {
+      // Check if the current relation is in edit mode
+      if (isset($field_state['current']) && $field_state['current'] === $delta) {
+        foreach (element_children($element[$delta]['relation_fields']) as $subformkey) {
+          $element[$delta][$subformkey] = $element[$delta]['relation_fields'][$subformkey];
+        }
+
+        $element[$delta]['edit'] = array(
+          '#type' => 'container',
+          'actions' => array(
+            '#type' => 'actions',
+            'save_settings' => $base_button + array(
+              '#type' => 'submit',
+              '#value' => t('Update'),
+              '#op' => 'update',
+            ),
+            'cancel_settings' => $base_button + array(
+              '#type' => 'submit',
+              '#value' => t('Cancel'),
+              '#op' => 'cancel',
+            ),
+          ),
+        );
+      }
+      else {
+        // @todo display a summary
+        $element[$delta]['edit'] = array(
+          '#type' => 'image_button',
+          '#src' => 'misc/configure.png',
+          '#attributes' => array('class' => array(), 'alt' => t('Edit')),
+          '#op' => 'edit',
+          '#name' => $base_button['#name'] . '-edit', // This button has no value, so only the name must be unique to identify this button
+        ) + $base_button;
+      }
+    }
+
+    $element[$delta]['delete'] = $base_button + array(
+      '#type' => 'submit',
+      '#value' => t('Delete'),
+      '#op' => 'delete',
+    );
+
+    $numvalues++;
+  }
+
+  // "Add Item" logic
+  $allowsmore = $element['#cardinality'] == FIELD_CARDINALITY_UNLIMITED || $element['#cardinality'] > $numvalues;
+
+  // Add 'add more' button, if not working with a programmed form.
+  if ($allowsmore && empty($form_state['programmed'])) {
+    $element['#target_bundles'] = relation_select_get_target_bundles($relation);
+    $element['add'] = array('#tree' => TRUE, '#weight' => 9999);
+
+    if (count($view->display_handler->get_option('exposed_form'))) {
+      $style = $view->display_handler->get_plugin('style');
+      $element['add']['exposed_filters'] = array(
+        '#type' => 'subform',
+        '#subform_id' => 'relation_select_views_exposed_form',
+        '#subform_arguments' => array(
+          $view,
+          &$element,
+          isset($style->options['lookup_on_change']) ? array_filter($style->options['lookup_on_change']) : array(),
+        ),
+        '#required' => FALSE,
+        '#submit' => array('relation_select_views_exposed_form_submit'),
+        '#limit_validation_errors' => TRUE,
+      );
+
+      // Placeholder for the search view output
+      $element['add']['view_output'] = array(
+        '#prefix' => '<div class="relation-select-views-output" id="' . $element['#id'] . '-ajax-wrapper">',
+        '#markup' => '<div></div>',
+        '#suffix' => '</div>',
+      );
+    }
+    else {
+      drupal_set_message(t('There are no exposed filters for the view being used in the relation select field'), 'error');
+    }
+
+    $element['add']['newitem'] = array(
+      '#type' => 'hidden',
+      '#title' => t('New item'),
+      '#attributes' => array('class' => array('relation-select-new-field')),
+    );
+
+    $element['add']['button'] = array(
+      '#type' => 'submit',
+      '#value' => t('Add item'),
+      '#op' => 'add',
+      '#limit_validation_errors' => array(
+        array_merge($element['#parents'], array('add')),
+      ),
+      '#submit' => array('relation_select_table_multistep_submit'),
+      '#ajax' => array(
+        'callback' => 'relation_select_table_multistep_js',
+        'wrapper' => $element['#id'] . '-wrapper',
+        'effect' => 'fade',
+        'progress' => 'none',
+      ),
+      '#field_name' => $field_name,
+      '#attributes' => array('class' => array('relation-select-new-button')),
+      '#name' => implode('-', $element['#parents']),
+    );
+  }
+
+  $path = drupal_get_path('module', 'relation_select');
+  $element['#attached']['css'][] = drupal_get_path('module', 'field_ui') . '/field_ui.css';
+  $element['#attached']['css'][] = $path . '/css/relation-select.css';
+  $element['#attached']['js'][] = $path . '/js/relation-select-table.js';
+  if ($hasweight) {
+    $element['#attached']['drupal_add_tabledrag'][] = array($element['#id'], 'order', 'sibling', 'field-weight');
+  }
+
+  return $element;
+}
+
+/**
+ * Submit handler for AJAX submits.
+ *
+ * This submit handler must change the $form_state array to control the AJAX 
+ * form.
+ * After this submit handler, relation_select_table_multistep_js() is executed to
+ * create an AJAX response. 
+ */
+function relation_select_table_multistep_submit($form, &$form_state) {
+  $trigger = $form_state['triggering_element'];
+  $field_name = $trigger['#field_name'];
+  $parents = $trigger['#parents'];
+  $langcode = 'und';
+  $delta = 0;
+  for ($k = count($parents) - 1; $k >= 0; $k--) {
+    if ($parents[$k] === $field_name) {
+      if (isset($parents[$k + 2])) {
+        $delta = $parents[$k + 2];
+      }
+      else {
+        $delta = NULL;
+      }
+      $langcode = $parents[$k + 1];
+      $parents = array_slice($parents, 0, $k);
+      break;
+    }
+  }
+  $field_state = field_form_get_state($parents, $field_name, $langcode, $form_state);
+
+  $element = drupal_array_get_nested_value($form, array_merge($parents, array($field_name, $langcode)));
+  $input = drupal_array_get_nested_value($form_state['values'], array_merge($parents, array($field_name, $langcode)));
+
+  switch ($trigger['#op']) {
+    case 'edit':
+      // Store the row whose settings are currently being edited.
+      $field_state['current'] = $delta;
+      break;
+
+    case 'update':
+      // Find the subform and get the values
+      unset($input[$delta]['edit']);
+
+      // Merge the subform values with the main values array
+      $field_state['values'][$delta] = array_merge($field_state['values'][$delta], $input[$delta]['relation_fields']);
+
+      // Set the field back to 'non edit' mode.
+      $field_state['current'] = NULL;
+      break;
+
+    case 'cancel':
+      // Set the field back to 'non edit' mode.
+      $field_state['current'] = NULL;
+      break;
+
+    case 'delete':
+      $field_state['current'] = NULL;
+      $field_state['values'][$delta]['endpoints'] = NULL;
+      break;
+
+    case 'add':
+      $addidentifier = array_merge($element['#parents'], array('add', 'newitem'));
+      $newitem = drupal_array_get_nested_value($form_state['values'], $addidentifier);
+      if ($newitem == '' || strpos($newitem, ':') === FALSE) {
+        form_error($element['add']['newitem'], t('No target entity given'));
+        return;
+      }
+      list($target_entity_type, $target_entity_id) = explode(':', $newitem);
+
+      $entity_info = entity_get_info($target_entity_type);
+      if (empty($entity_info)) {
+        form_error($element['add']['newitem'], t('Target entity type does not exist'));
+        return;
+      }
+      
+      // Check if the entity exists
+      $target_entity = entity_load($target_entity_type, array($target_entity_id));
+      if (count($target_entity) == 0) {
+        form_error($element['add']['newitem'], t('Target entity does not exist'));
+        return;
+      }
+
+      // Our own endpoint is added in relation_select_field_insert() because
+      // for new entities, the id is not yet know.
+      $endpoints = array(
+        array('entity_type' => $target_entity_type, 'entity_id' => intval($target_entity_id)),
+      );
+
+      $relation = relation_create($element['#relation']->relation_type, $endpoints);
+      $field_state['values'][] = (array)$relation;
+      break;
+  }
+
+  // Process the weights - they are saved for every button click
+  $weightfield = $element['#weightfield'];
+  foreach ($input as $delta => $value) {
+    if (isset($value['relation_fields'][$weightfield]) && isset($field_state['values'][$delta])) {
+      $field_state['values'][$delta][$weightfield] = $value['relation_fields'][$weightfield];
+    }
+  }
+
+  // Write the values
+  field_form_set_state($parents, $field_name, $langcode, $form_state, $field_state);
+
+  $form_state['rebuild'] = TRUE;
+}
+
+/**
+ * AJAX response builder
+ *
+ * This function is responsible for creating the AJAX response by only
+ * returning the part of the response that needs to be updated.
+ */
+function relation_select_table_multistep_js($form, &$form_state) {
+  $trigger = $form_state['triggering_element']; // the button
+
+  // Pick the elements that need to receive the ajax-new-content effect.
+  switch ($trigger['#op']) {
+    case 'edit':
+    case 'delete':
+      // Get the table element and delta
+      $tableidentifier = array_slice($trigger['#parents'], 0, -2);
+      $element = drupal_array_get_nested_value($form, $tableidentifier);
+      $delta = array_slice($trigger['#parents'], -2, 1);
+
+      $updated_rows = array($delta);
+      $updated_columns = array('edit');
+      break;
+
+    case 'update':
+    case 'cancel':
+      // Get the table element and delta
+      $tableidentifier = array_slice($trigger['#parents'], 0, -4);
+      $element = drupal_array_get_nested_value($form, $tableidentifier);
+      $delta = array_slice($trigger['#parents'], -2, 1);
+
+      $updated_rows = array($delta);
+      $updated_columns = array('edit');
+      break;
+
+    case 'add':
+      $tableidentifier = array_slice($trigger['#parents'], 0, -2);
+      $element = drupal_array_get_nested_value($form, $tableidentifier);
+      // Clear the value
+      $element['add']['newitem']['#value'] = '';
+      break;
+  }
+
+  // Return the whole table.
+  return $element;
+}
+
+/**
+ * Implements form_type_TYPE_value().
+ */
+function form_type_relation_select_table_value($element, $input = FALSE, $form_state = array()) {
+  // Check if there is anything in the form state
+  $field_name = $element['#field_name'];
+  $parents = $element['#field_parents'];
+  $langcode = $element['#language'];
+  $field_state = field_form_get_state($parents, $field_name, $langcode, $form_state);
+
+  if (array_key_exists('values', $field_state)) {
+    $value = $field_state['values'];
+  }
+  else {
+    // If not, take the default value
+    $value = $element['#default_value'];
+
+    // The current entity must not appear in the list of endpoints, so fetch its information
+    if (isset($element['#entity'])) {
+      list($entity_id, ,) = entity_extract_ids($element['#entity_type'], $element['#entity']);
+    }
+    else {
+      $entity_id = 0;
+    }
+
+    $relationentityids = array();
+    foreach ($value as $delta => $item) {
+      if (isset($item['relation_id'])) {
+        $relationentityids[] = $item['relation_id'];
+      }
+    }
+
+    $relations = !empty($relationentityids) ? entity_load('relation', $relationentityids) : array();
+    foreach ($value as $delta => $item) {
+      if (isset($item['relation_id']) && isset($relations[$item['relation_id']])) {
+        $value[$delta] = (array)$relations[$item['relation_id']];
+
+        // Remove the current entity from the list of endpoints
+        // This mimics the behavior of relation_select_entity_get_relations()
+        if ($entity_id > 0) {
+          foreach ($value[$delta]['endpoints'] as $langcode => $endpoints) {
+            foreach ($endpoints as $epdelta => $endpoint) {
+              if ($endpoint['entity_type'] == $element['#entity_type'] && $endpoint['entity_id'] == $entity_id) {
+                unset($value[$delta]['endpoints'][$langcode][$epdelta]);
+              }
+            }
+          }
+        }
+      }
+      else {
+        unset($value[$delta]);
+      }
+    }
+  }
+
+  // $input can be NULL when there is no "Add" field because the
+  // field cardinality limit has been reached.
+  if ($input !== FALSE && $input !== NULL) {
+    foreach ($input as $delta => $item) {
+      if (!isset($value[$delta])) {
+        continue;
+      }
+      
+      $value[$delta] = array_merge($value[$delta], $item);
+    }
+  }
+
+  return $value;
+}
+
+
diff --git a/js/relation-select-table.js b/js/relation-select-table.js
new file mode 100644
index 0000000..726a757
--- /dev/null
+++ b/js/relation-select-table.js
@@ -0,0 +1,190 @@
+/**
+ * Relation select file
+ */
+(function($){
+  Drupal.behaviors.relationSelect = {
+    attach: function(context){
+      /**
+       * Add event handlers etc.,
+       */
+      function init(){
+        // Close the pop up when document is clicked
+        $(document).click(handleCloseClick);
+        addFilterEventHandlers(context);
+        addCloseEventHandlers(context);
+        addRowEventHandlers(context);
+      }
+
+      // Events
+
+      // Event handler: close button clicked
+      function addCloseEventHandlers(context){
+        $('.relation-select-close:not(.processed)', context)
+            .click(handleCloseClick).addClass('processed');
+
+        $('.view-relation-select-node', context).click(function(e){
+          e.stopPropagation();
+        })
+      }
+
+      function addRowEventHandlers(context){
+        // Check selected & add event handler: row clicked
+        $('.views-view-relation-select tr', context).once(
+          function(){
+            var entitydata = $(this).attr('data-entity');
+            $(this).click(function(){
+              handleRowClick($(this));
+              return false;
+            });
+          }
+        );
+      }
+
+      function addFilterEventHandlers(context){
+        // Add submit on change event handlers
+        $('.rs-on-change').change(submit);
+      }
+
+      function addFilterBundleEventHandlers(context, relationType){
+        if(Drupal.settings.relationSelect[relationType]['targetBundles']) {
+          var $entityTypeSelect = $('select[name$="entity_type]"]', context);
+          var $bundleSelect = $('select[name$="bundle]"]', context);
+
+          if($entityTypeSelect.length && $bundleSelect.length) {
+
+            $entityTypeSelect
+                .change(function(){
+                  filterBundles(
+                      Drupal.settings.relationSelect[relationType]['targetBundles'],
+                      $(this).val(), $bundleSelect);
+                });
+
+            // Filter bundles on load too
+            filterBundles(
+                Drupal.settings.relationSelect[relationType]['targetBundles'],
+                $entityTypeSelect.val(), $bundleSelect);
+          }
+        }
+      }
+
+      // Event Handlers
+      function handleCloseClick(){
+        close();
+      }
+
+      /**
+       * An item has been selected
+       */
+      function handleRowClick($row){
+        var entitydata = $row.attr('data-entity');
+        var ajaxcontainer = $row.parents('.relation-select-views-output').parent();
+        var input = ajaxcontainer.find('.relation-select-new-field');
+        input.val(entitydata);
+        var button = ajaxcontainer.find('.relation-select-new-button');
+        button.mousedown();
+        close();
+      }
+
+      /**
+       * Close the drop down
+       */
+      function close(){
+        $('.relation-select-views-output div').empty();
+      }
+
+      /**
+       * Get input
+       */
+      function getInput(id, entitydata){
+    	  if (!relationSelectItems[id]) {
+    		  return { length : 0 };
+    	  }
+    	  
+        return $('input[value="' + entitydata + '"]',
+            relationSelectItems[id]['element']);
+      }
+
+      function countArity(id){
+        // Count the arity (number of relations)
+        // Always +1 as the edited / new node counts too
+        return $('input', relationSelectItems[id]['element']).length + 1;
+      }
+
+      /**
+       * De-select a row
+       */
+      function deselectItem($input, id, entitydata, $row){
+        // Remove selected class if this is for a row
+        if(typeof $row != 'undefined'){
+          $row.removeClass('selected');
+        }
+        // Destroy the form element
+        $input.parents('.rs-wrapper').remove();
+        relationSelectItems[id]['element'].trigger('deselectItem', [id, entitydata]);
+      }
+
+      function themeValue($row, entitydata){
+
+        var entityType = entitydata.split(':').shift();
+        var bundle = $row.attr('data-bundle');
+
+        // Try a number of javscript template functions
+        // RelationSelect+bundle+Value
+        // RelationSelect+entityType+Value
+        // RelationSelectValue
+        var themeHooksuggestions = ['RelationSelect' + bundle + 'Value',
+            'RelationSelect' + entityType + 'Value', 'RelationSelectValue'];
+        for(i in themeHooksuggestions) {
+          if(typeof Drupal.theme.prototype[themeHooksuggestions[i]] == 'function') {
+            return Drupal.theme(themeHooksuggestions[i], $row, entitydata,
+                entityType, bundle);
+          }
+        }
+      }
+
+      function submit(){
+        $('input[type="submit"]', $(this).parents('div.views-exposed-form'))
+            .mousedown();
+      }
+
+      function filterBundles(bundles, entityType, $bundleSelect){
+
+        $.each($('option', $bundleSelect), function(i, op){
+
+          if($(op).val() == 'All'
+              || bundles[entityType].indexOf($(op).val()) !== -1) {
+            $(op).removeAttr("disabled");
+          } else {
+            $(op).attr("disabled", "disabled");
+          }
+
+        });
+
+        // Set the select to the first enabled value
+        $bundleSelect
+            .val($('option:not(:disabled)', $bundleSelect).eq(0).val());
+
+      }
+
+      init();
+
+    }
+  };
+
+  /**
+   * Provide the HTML to create the selected item Javascript equivalent of
+   * relation_select_value
+   */
+  Drupal.theme.prototype.RelationSelectValue = function($row, entitydata,
+    entityType, bundle){
+    var html = '';
+    if((label = $('td.label', $row)).length) {
+      html += '<span class="title">' + $(label).text() + '</span>';
+      html += ' (' + entitydata + ')';
+    } else {
+      html += entitydata;
+    }
+    return html;
+  }
+
+})(jQuery);
diff --git a/js/relation-select.js b/js/relation-select.js
index 5fab36e..83bc5c8 100644
--- a/js/relation-select.js
+++ b/js/relation-select.js
@@ -189,6 +189,10 @@
        * Get input
        */
       function getInput(id, entitydata){
+    	  if (!relationSelectItems[id]) {
+    		  return { length : 0 };
+    	  }
+    	  
         return $('input[value="' + entitydata + '"]',
             relationSelectItems[id]['element']);
       }
diff --git a/relation_select.module b/relation_select.module
index 0d148bc..ef26eb0 100644
--- a/relation_select.module
+++ b/relation_select.module
@@ -1,4 +1,5 @@
 <?php
+require dirname(__FILE__) . '/includes/relation_select.widget2.inc';
 
 /*********************************************************************************************
  * 
@@ -21,6 +22,7 @@ function relation_select_menu(){
     'title' => 'Views',
     'page callback' => 'relation_select_ajax',
     'delivery callback' => 'ajax_deliver',
+    'theme callback' => 'ajax_base_page_theme',
     'access callback' => TRUE,
     'description' => 'Ajax callback for view loading.',
     'type' => MENU_CALLBACK,
@@ -136,7 +138,12 @@ function relation_select_theme($existing, $type, $theme, $path){
       'template' => 'relation-select-field',
       'file' => 'theme.inc',
       'path' => $path . '/theme'
-    )
+    ),
+    'relation_select_table' => array(
+      'render element' => 'element',
+      'file' => 'theme.inc',
+      'path' => $path . '/theme',
+    ),
   );
 }
 
@@ -159,132 +166,151 @@ function relation_select_modules_enabled($modules){
  *
  * Define a relation select element
  */
-function relation_select_element_info(){
+function relation_select_element_info() {
   $path = drupal_get_path('module', 'relation_select');
+
+  $types = array();
+
   $types['relation_select'] = array(
     '#input' => TRUE,
-    '#process' => array(
-      'relation_select_element_process'
-    ),
-    '#element_validate' => array(
-      'relation_select_element_validate'
-    ),
+    '#process' => array('relation_select_element_process'),
+    '#element_validate' => array('relation_select_element_validate'),
     '#view' => array(
       'name' => relation_select_get_default_view(),
-      'display' => 'default'
+      'display' => 'default',
     ),
     '#extended' => FALSE,
-    '#theme_wrappers' => array(
-      'form_element'
-    ),
+    '#theme_wrappers' => array('form_element'),
     '#attached' => array(
-      'css' => array(
-        $path . '/css/relation-select.css'
-      ),
-      'js' => array(
-        $path . '/js/relation-select.js'
-      ),
+      'css' => array($path . '/css/relation-select.css'),
+      'js' => array($path . '/js/relation-select.js'),
       'library' => array(
-        array(
-          'system',
-          'ui.sortable'
-        )
-      )
-    )
+        array('system', 'ui.sortable'),
+      ),
+    ),
   );
+
+  $types['relation_select_table'] = array(
+    '#input' => TRUE,
+    '#process' => array('relation_select_table_element_process'),
+    '#view' => NULL, // The object
+    '#relation' => NULL, // The object
+    '#language' => LANGUAGE_NONE, // Language code
+    '#cardinality' => 1,
+    '#extended' => FALSE,
+    '#attached' => array(),
+    '#theme' => 'relation_select_table',
+  );
+
   return $types;
 }
 
-function relation_select_element_process(&$element, &$form_state, $form){
-  $field_name = (isset($element['#field_name']) ? $element['#field_name'] : $element['#name']);
-  $delta = (isset($element['#delta']) ? $element['#delta'] : 0);
+function relation_select_element_process(&$element, &$form_state, $form) {
+  $field_name = isset($element['#field_name']) ? $element['#field_name'] : $element['#name'];
+  $delta = isset($element['#delta']) ? $element['#delta'] : 0;
   $element['#tree'] = true;
-  if($view = views_get_view($element['#view']['name'])){
-    // If there's exposed view filters, embed the form as a subform 
-    $view->set_display((isset($element['#view']['display']) ? $element['#view']['display'] : 'default'));
-    $style = $view->display_handler->get_plugin('style');
-    if($relation_type = relation_type_load($element['#relation_type'])){
-      $element['#target_bundles'] = relation_select_get_target_bundles($relation_type);
-      if(count($view->display_handler->get_option('exposed_form'))){
-        $element['exposed_filters'] = array(
-          '#type' => 'subform',
-          '#subform_id' => 'relation_select_views_exposed_form',
-          '#subform_arguments' => array(
-            $view,
-            &$element,
-            (isset($style->options['lookup_on_change']) ? array_filter($style->options['lookup_on_change']) : array())
-          ),
-          '#required' => false,
-          '#submit' => array(
-            'relation_select_views_exposed_form_submit'
-          ),
-          '#limit_validation_errors' => TRUE
-        );
-      }else{
-        drupal_set_message(t('There are no exposed filters for the view being used in the relation select field'), 'error');
-      }
-      // Don't add settings if this is a rebuild (form add more is happening)    
-      if(!@in_array('field_add_more_submit', $form_state['submit_handlers'])){
-        $element['#attached']['js'][] = array(
-          'data' => array(
-            'relationSelect' => array(
-              $relation_type->relation_type => array(
-                'targetBundles' => $element['#target_bundles'],
-                'maxArity' => $relation_type->max_arity
-              )
-            )
-          ),
-          'type' => 'setting'
+  $view = views_get_view($element['#view']['name']);
+
+  if (!$view) {
+    drupal_set_message(t('View @view-name could not be loaded.', array('@view-name' => $element['#view']['name'])), 'error');
+    return $element;
+  }
+
+  $relation_type = relation_type_load($element['#relation_type']);
+  if (!$relation_type) {
+    drupal_set_message(t('Relation type @relation-type-name could not be loaded.', array('@relation-type-name' => $element['#relation_type'])), 'error');
+    return $element;
+  }
+
+  // If there's exposed view filters, embed the form as a subform 
+  $view->set_display((isset($element['#view']['display']) ? $element['#view']['display'] : 'default'));
+  $style = $view->display_handler->get_plugin('style');
+
+  // Subform to search for new items
+  $element['#target_bundles'] = relation_select_get_target_bundles($relation_type);
+  if (count($view->display_handler->get_option('exposed_form'))) {
+    $element['exposed_filters'] = array(
+      '#type' => 'subform',
+      '#subform_id' => 'relation_select_views_exposed_form',
+      '#subform_arguments' => array(
+        $view,
+        &$element,
+        (isset($style->options['lookup_on_change']) ? array_filter($style->options['lookup_on_change']) : array())
+      ),
+      '#required' => false,
+      '#submit' => array(
+        'relation_select_views_exposed_form_submit'
+      ),
+      '#limit_validation_errors' => TRUE
+    );
+  }
+  else {
+    drupal_set_message(t('There are no exposed filters for the view being used in the relation select field'), 'error');
+  }
+
+  // Don't add settings if this is a rebuild (form add more is happening)    
+  if (empty($form_state['submit_handlers']) || !in_array('field_add_more_submit', $form_state['submit_handlers'])){
+    $element['#attached']['js'][] = array(
+      'data' => array(
+        'relationSelect' => array(
+          $relation_type->relation_type => array(
+            'targetBundles' => $element['#target_bundles'],
+            'maxArity' => $relation_type->max_arity,
+          )
+        )
+      ),
+      'type' => 'setting',
+    );
+  }
+
+  // Placeholder for the search view output
+  $element['view_output'] = array(
+    '#prefix' => '<div class="relation-select-views-output" id="' . $element['#id'] . '-ajax-wrapper">',
+    '#markup' => '<div></div>',
+    '#suffix' => '</div>'
+  );
+
+  // Add the actual selected items to the form
+  $element['endpoints'] = array(
+    '#type' => 'container',
+    '#attributes' => array(
+      'class' => array(
+        'relation-select-entities',
+        ($relation_type->max_arity > 2 ? 'sortable' : '')
+      ),
+      'data-field-name' => array(
+        $element['#name'] . '[endpoints]'
+      ),
+      'data-relation-type' => array(
+        $relation_type->relation_type
+      ),
+      'data-relation-arity' => array(
+        $relation_type->max_arity
+      )
+    ),
+    '#weight' => 10
+  );
+
+  if(is_array($element['#value'])){
+    if(isset($element['#value']['endpoints'])){
+      foreach($element['#value']['endpoints'] as $value){
+        $element['endpoints'][] = array(
+          '#type' => 'hidden',
+          '#value' => $value,
+          '#theme_wrappers' => array(
+            'relation_select_item_wrapper'
+          )
         );
       }
-      $element['view_output'] = array(
-        '#prefix' => '<div class="relation-select-views-output" id="' . $element['#id'] . '-ajax-wrapper">',
-        '#markup' => '<div></div>',
-        '#suffix' => '</div>'
-      );
-      // Add the actual selected items to the form
-      $element['endpoints'] = array(
-        '#type' => 'container',
-        '#attributes' => array(
-          'class' => array(
-            'relation-select-entities',
-            ($relation_type->max_arity > 2 ? 'sortable' : '')
-          ),
-          'data-field-name' => array(
-            $element['#name'] . '[endpoints]'
-          ),
-          'data-relation-type' => array(
-            $relation_type->relation_type
-          ),
-          'data-relation-arity' => array(
-            $relation_type->max_arity
-          )
-        ),
-        '#weight' => 10
+    }
+    if(isset($element['#value']['relation_id'])){
+      $element['relation_id'] = array(
+        '#type' => 'hidden',
+        '#value' => $element['#value']['relation_id']
       );
-      if(is_array($element['#value'])){
-        if(isset($element['#value']['endpoints'])){
-          foreach($element['#value']['endpoints'] as $value){
-            $element['endpoints'][] = array(
-              '#type' => 'hidden',
-              '#value' => $value,
-              '#theme_wrappers' => array(
-                'relation_select_item_wrapper'
-              )
-            );
-          }
-        }
-        if(isset($element['#value']['relation_id'])){
-          $element['relation_id'] = array(
-            '#type' => 'hidden',
-            '#value' => $element['#value']['relation_id']
-          );
-        }
-      }
     }
-  }else{
-    drupal_set_message(t('View could not be loaded.'), 'error');
   }
+
   return $element;
 }
 
@@ -401,7 +427,7 @@ function relation_select_field_info_alter(&$info){
 /**
  * Implements hook_field_widget_info().
  */
-function relation_select_field_widget_info(){
+function relation_select_field_widget_info() {
   return array(
     'relation_select' => array(
       'label' => t('Relation select'),
@@ -410,9 +436,18 @@ function relation_select_field_widget_info(){
       ),
       'behaviors' => array(
         'multiple values' => FIELD_BEHAVIOR_CUSTOM,
-        'default value' => FIELD_BEHAVIOR_DEFAULT
+        'default value' => FIELD_BEHAVIOR_DEFAULT,
       )
-    )
+    ),
+    'relation_select_table' => array(
+      'label' => t('Relation select table'),
+      'field types' => array('relation'),
+      'behaviors' => array(
+        'multiple values' => FIELD_BEHAVIOR_CUSTOM,
+        'default value' => FIELD_BEHAVIOR_DEFAULT,
+      ),
+      'settings' => array('weightfield' => NULL),
+    ),
   );
 }
 
@@ -492,18 +527,27 @@ function relation_select_field_prepare_view($entity_type, $entities, &$field, &$
  * Define the actual field input element
  */
 function relation_select_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element){
-  if(isset($instance['settings']['relation_view'])){
+  if ($instance['widget']['type'] == 'relation_select_table') {
+    module_load_include('inc', 'relation_select', 'includes/relation_select.widget2');
+    return relation_select_table_field_widget_form($form, $form_state, $field, $instance, $langcode, $items, $delta, $element);
+  }
+
+  if (isset($instance['settings']['relation_view'])){
     list($view, $display) = explode(':', $instance['settings']['relation_view']);
-  }else{
+  }
+  else {
     $view = relation_select_get_default_view();
     $display = 'default';
   }
+
   $field_elements = array();
-  if($field['cardinality'] == 1){
+  if ($field['cardinality'] == 1) {
     $field_elements[$delta] = _relation_select_field_widget_form($form, $form_state, $field, $instance, $langcode, $items, $delta, $element, $view, $display);
-  }else{
+  }
+  else {
     $field_elements = relation_select_field_widget_multiple_form($form, $form_state, $field, $instance, $langcode, $items, $delta, $element, $view, $display);
   }
+
   return $field_elements;
 }
 
@@ -546,16 +590,6 @@ function _relation_select_field_widget_form(&$form, &$form_state, $field, $insta
 
 /**
  * Special handling to create form elements for multiple values.
- * @param array $form
- * @param array $form_state
- * @param array $field
- * @param array $instance
- * @param array $langcode
- * @param array $items
- * @param array $delta
- * @param array $element
- * @param array $view
- * @param array $display
  */
 function relation_select_field_widget_multiple_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element, $view, $display){
   $title = check_plain($instance['label']);
@@ -572,10 +606,8 @@ function relation_select_field_widget_multiple_form(&$form, &$form_state, $field
       break;
   }
   $description = field_filter_xss($instance['description']);
-  $id_prefix = implode('-', array_merge($parents, array(
-    $field_name
-  )));
-  $wrapper_id = drupal_html_id($id_prefix . '-add-more-wrapper');
+  $id_prefix = implode('-', array_merge($parents, array($field_name)));
+
   $field_elements = array();
   for($delta = 0; $delta < $max; $delta++){
     $multiple = $field['cardinality'] > 1 || $field['cardinality'] == FIELD_CARDINALITY_UNLIMITED;
@@ -596,46 +628,46 @@ function relation_select_field_widget_multiple_form(&$form, &$form_state, $field
     _relation_select_field_widget_form($form, $form_state, $field, $instance, $langcode, $items, $delta, $element, $view, $display);
     $field_elements[$delta] = $element;
   }
-  if($field_elements){
-    $field_elements += array(
-      '#field_name' => $field['field_name'],
-      '#cardinality' => $field['cardinality'],
-      '#title' => $title,
-      '#required' => $instance['required'],
-      '#description' => $description,
-      '#prefix' => '<div id="' . $wrapper_id . '">',
-      '#suffix' => '</div>',
-      '#max_delta' => $max
+
+  if (empty($field_elements)) {
+    return $field_elements;
+  }
+
+  $wrapper_id = drupal_html_id($id_prefix . '-add-more-wrapper');
+
+  $field_elements += array(
+    '#field_name' => $field['field_name'],
+    '#cardinality' => $field['cardinality'],
+    '#title' => $title,
+    '#required' => $instance['required'],
+    '#description' => $description,
+    '#prefix' => '<div id="' . $wrapper_id . '">',
+    '#suffix' => '</div>',
+    '#max_delta' => $max,
+  );
+
+  // Add 'add more' button, if not working with a programmed form.
+  if ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED && empty($form_state['programmed'])) {
+    $field_elements['add_more'] = array(
+      '#type' => 'submit',
+      '#name' => strtr($id_prefix, '-', '_') . '_add_more',
+      '#value' => t('Add another item'),
+      '#attributes' => array(
+        'class' => array('field-add-more-submit'),
+      ),
+      '#limit_validation_errors' => array(
+        array_merge($parents, array($field_name, $langcode)),
+      ),
+      '#submit' => array('field_add_more_submit'),
+      '#ajax' => array(
+        'callback' => 'field_add_more_js',
+        'wrapper' => $wrapper_id,
+        'effect' => 'fade'
+      ),
+      '#weight' => $max + 1
     );
-    // Add 'add more' button, if not working with a programmed form.
-    if($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED && empty($form_state['programmed'])){
-      $field_elements['add_more'] = array(
-        '#type' => 'submit',
-        '#name' => strtr($id_prefix, '-', '_') . '_add_more',
-        '#value' => t('Add another item'),
-        '#attributes' => array(
-          'class' => array(
-            'field-add-more-submit'
-          )
-        ),
-        '#limit_validation_errors' => array(
-          array_merge($parents, array(
-            $field_name,
-            $langcode
-          ))
-        ),
-        '#submit' => array(
-          'field_add_more_submit'
-        ),
-        '#ajax' => array(
-          'callback' => 'field_add_more_js',
-          'wrapper' => $wrapper_id,
-          'effect' => 'fade'
-        ),
-        '#weight' => $max + 1
-      );
-    }
   }
+
   return $field_elements;
 }
 
@@ -649,8 +681,8 @@ function relation_select_field_widget_error($element, $error, $form, &$form_stat
 /**
  * Implements hook_field_is_empty().
  */
-function relation_select_field_is_empty($items, $field){
-  return count($items) == 0;
+function relation_select_field_is_empty($item, $field){
+  return empty($item['endpoints']);
 }
 
 /**
@@ -665,51 +697,70 @@ function relation_select_field_update($entity_type, $entity, $field, $instance,
  * Implements hook_field_insert().
  */
 function relation_select_field_insert($entity_type, $entity, $field, $instance, $langcode, &$items){
-  // If the widget type is relation select, save the content
-  if($instance['widget']['type'] == 'relation_select'){
-    $relation_type = relation_type_load($instance['settings']['relation_type']);
-    list($entity_id) = entity_extract_ids($entity_type, $entity);
-    // Delete exisiting relations of this type
-    $relations = relation_select_entity_get_relations($entity_type, $entity_id, $relation_type->relation_type);
-    $rids = array();
-    foreach($relations as $relation){
-      $rids[] = $relation['relation_id'];
-    }
-    $relation_entities = relation_load_multiple($rids);
-    foreach($items as $delta => $item){
-      if(isset($item['endpoints']) && count($item['endpoints'])){
-        $entity_keys = relation_select_build_entity_keys($entity_type, $entity_id, $item['endpoints']);
-        // If there's a VID we're are editing an existing relation 
-        if(isset($item['relation_id'])){
-          $relation = $relation_entities[$item['relation_id']];
-          $relation->endpoints[LANGUAGE_NONE] = $entity_keys;
-        }
-        else {
-          $relation = relation_create($relation_type->relation_type, $entity_keys);
-        }
-        // Add relation fields
-        $relation_instances = field_info_instances('relation', $relation->relation_type);
-        if (isset($item['relation_fields'])) {
-          foreach ($item['relation_fields'] as $relation_field_name => $relation_field) {
-            if (isset($relation_instances[$relation_field_name])) {
-              $langcode = array_shift(array_keys($relation_field));
-              $relation_field_items = array_shift($relation_field);
-              $relation_field = field_info_field($relation_field_name);
-
-              field_default_submit('relation', $relation, $relation_field, $relation_instances[$relation_field_name], $langcode, $relation_field_items, $item, $form_state);
-              $relation->{$relation_field_name}[$langcode] = $relation_field_items;
-            }
-            else {
-              $relation->{$relation_field_name} = $relation_field;
-            }
+  $relation_type = relation_type_load($instance['settings']['relation_type']);
+  list($entity_id) = entity_extract_ids($entity_type, $entity);
+  // Delete exisiting relations of this type
+  $relations = relation_select_entity_get_relations($entity_type, $entity_id, $relation_type->relation_type);
+  $rids = array();
+  foreach($relations as $relation){
+    $rids[] = $relation['relation_id'];
+  }
+  $relation_entities = relation_load_multiple($rids);
+
+  foreach($items as $delta => $item) {
+    if (!empty($item['endpoints'])) {
+      $entity_keys = $item['endpoints'];
+      if(isset($entity_keys[$langcode])) {
+        $entity_keys = $entity_keys[$langcode];
+      }
+      $entity_keys = relation_select_build_entity_keys($entity_type, $entity_id, $entity_keys);
+
+      // If there's a VID we're are editing an existing relation
+      if(isset($item['rid'])) {
+        $relation = $relation_entities[$item['rid']];
+        unset($relation_entities[$item['rid']]);
+        $relation->endpoints[$langcode] = $entity_keys;
+      } 
+      elseif(isset($item['relation_id'])) {
+        $relation = $relation_entities[$item['relation_id']];
+        unset($relation_entities[$item['relation_id']]);
+        $relation->endpoints[$langcode] = $entity_keys;
+      }
+      else {
+        $relation = relation_create($relation_type->relation_type, $entity_keys);
+      }
+
+      // Add relation fields
+      $relation_instances = field_info_instances('relation', $relation->relation_type);
+      if (isset($item['relation_fields'])) {
+        foreach ($item['relation_fields'] as $relation_field_name => $relation_field) {
+          if (isset($relation_instances[$relation_field_name])) {
+            $langcode = array_shift(array_keys($relation_field));
+            $relation_field_items = array_shift($relation_field);
+            $relation_field = field_info_field($relation_field_name);
+  
+            field_default_submit('relation', $relation, $relation_field, $relation_instances[$relation_field_name], $langcode, $relation_field_items, $item, $form_state);
+            $relation->{$relation_field_name}[$langcode] = $relation_field_items;
+          }
+          else {
+            $relation->{$relation_field_name} = $relation_field;
           }
         }
-        relation_save($relation);
-      }elseif(isset($item['relation_id'])){ // If there's no endpoints & a VID, delete the relation
-        relation_delete($item['relation_id']);
       }
+      relation_save($relation);
+    }
+    elseif(isset($item['relation_id'])) { // If there's no endpoints & a VID, delete the relation
+      relation_delete($item['relation_id']);
+    }
+    elseif(isset($item['rid'])) { // If there's no endpoints & a VID, delete the relation
+      relation_delete($item['rid']);
     }
   }
+
+  // Anything left in $relation_entities must be deleted
+  foreach (array_keys($relation_entities) as $relation_id) {
+    relation_delete($relation_id);
+  }
 }
 
 /**
@@ -760,15 +811,23 @@ function relation_select_build_entity_keys($entity_type, $entity_id, $endpoints)
     array(
       'entity_type' => $entity_type,
       'entity_id' => $entity_id,
-      'r_index' => 0
+      'r_index' => 0,
     )
   );
-  foreach($endpoints as $i => $value){
-    list($relation_entity_type, $relation_entity_id) = explode(':', $value);
+
+  foreach ($endpoints as $i => $value) {
+    if (is_string($value)) {
+      list($relation_entity_type, $relation_entity_id) = explode(':', $value);
+    }
+    else {
+      $relation_entity_type  = $value['entity_type'];
+      $relation_entity_id  = $value['entity_id'];
+    }
+
     $entity_keys[] = array(
       'entity_type' => $relation_entity_type,
       'entity_id' => $relation_entity_id,
-      'r_index' => $i + 1
+      'r_index' => $i + 1,
     );
   }
   return $entity_keys;
@@ -868,15 +927,15 @@ function relation_select_ajax(){
   $ajax_page_state = $_POST['ajax_page_state'];
   $commands = array();
   $views_ajax_commands = views_ajax();
-  foreach($views_ajax_commands['#commands'] as $command){
+  foreach ($views_ajax_commands['#commands'] as $command) {
     // Change the command selector
     $command['selector'] = '#' . $element_id . '-ajax-wrapper div:eq(0)';
     $commands[] = $command;
   }
   // Re-define ajax_post_state before rendering to allow css/js files used by the view to be added
   $_POST['ajax_page_state'] = $ajax_page_state;
-  print ajax_render($commands);
-  exit();
+
+  return array('#type' => 'ajax', '#commands' => $commands);
 }
 
 /**
@@ -1124,4 +1183,31 @@ function relation_select_field_cache_clear($entity){
   }
 }
 
+/**
+ * Implements hook_field_widget_settings_form().
+ */
+function relation_select_field_widget_settings_form($field, $instance) {
+  $form = array();
+  if ($instance['widget']['type'] == 'relation_select_table') {
+    $relationfields = field_info_instances('relation', $instance['settings']['relation_type']);
+
+    $fieldnames = array();
+    foreach ($relationfields as $relationfield) {
+      $module = $relationfield['widget']['module'];
+      $widget = $relationfield['widget']['type'];
+      if ($widget == 'number' && $module == 'number') {
+        $fieldnames[$relationfield['field_name']] = $relationfield['label'];
+      }
+    }
 
+    $form['weightfield'] = array(
+      '#type' => 'select',
+      '#title' => t('Weight field'),
+      '#description' => t('Select an integer field that will be used as a weight field. Selecting a weight field enables the draggable interface.'),
+      '#default_value' => $instance['widget']['settings']['weightfield'],
+      '#options' => $fieldnames,
+      '#empty_value' => '',
+    );
+  }
+  return $form;
+}
diff --git a/theme/theme.inc b/theme/theme.inc
index efc7b10..1453f8e 100644
--- a/theme/theme.inc
+++ b/theme/theme.inc
@@ -121,3 +121,85 @@ function theme_relation_select_attachment_before($variables){
     )
   ));
 }
+
+function theme_relation_select_table($variables) {
+  $element = $variables['element'];
+  $hasweight = $element['#hasweight'];
+  $hasadditionalfields = $element['#hasadditionalfields'];
+  $weightfield = $element['#weightfield'];
+
+  $itemkeys = element_children($element);
+  foreach ($itemkeys as $itemkey) {
+    if (!is_int($itemkey)) {
+      continue;
+    }
+
+    $item = $element[$itemkey];
+    $row = array(
+      'class' => array('draggable', 'tabledrag-leaf'),
+      'data' => array(),
+    );
+    $row['data']['title'] = drupal_render($item['title']);
+    $row['data']['edit'] = '';
+
+    if ($hasweight) {
+      $row['data'][$weightfield] = array(
+        'data' => drupal_render($item[$weightfield]),
+      );
+    }
+    $row['data']['operations'] = array(
+      'data' => drupal_render($item['delete']),
+      'class' => 'relation-select-table-operations',
+    );
+    if ($hasadditionalfields) {
+      // Additional styles for opened row
+      if (isset($item['edit']['actions'])) {
+        $row['data']['edit'] = drupal_render($item['relation_fields']) . drupal_render($item['edit']);
+        $row['class'][] = 'field-formatter-settings-editing';
+      }
+      else {
+        $row['data']['operations']['data'] = drupal_render($item['edit']) . $row['data']['operations']['data'];
+      }
+    }
+
+    $rows[$itemkey] = $row;
+  }
+
+  $output = '';
+
+  if (!empty($rows)) {
+    $header = array(
+      array('data' => t('Title'), 'colspan' => 2),
+    );
+    if ($hasweight) {
+      $header[] = array('data' => t('Weight'));
+    }
+    $header[] = array('data' => t('Operations'));
+    $output = theme('table', array(
+      'attributes' => array(
+        'id' => $element['#id'],
+        'class' => array('relation-select-table'),
+      ),
+      'header' => $header,
+      'rows' => $rows,
+    ));
+  }
+
+  if (isset($element['add'])) {
+    $output .= drupal_render($element['add']);
+  }
+
+  $fieldset = array(
+    '#type' => 'fieldset',
+    '#title' => $element['#title'],
+    '#description' => $element['#description'],
+    '#value' => $output,
+  );
+
+  // Mimic the behavior of required fields
+  if ($element['#required']) {
+    $fieldset['#title'] .= ' ' . theme('form_required_marker', array('element' => $element));
+  }
+
+  return drupal_render($fieldset);
+}
-- 
1.7.9.5

