? spaces_taxonomy/tests
Index: spaces.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/spaces/spaces.module,v
retrieving revision 1.25.4.33.2.32.2.34
diff -u -p -r1.25.4.33.2.32.2.34 spaces.module
--- spaces.module	25 May 2010 19:04:11 -0000	1.25.4.33.2.32.2.34
+++ spaces.module	1 Jul 2010 00:31:53 -0000
@@ -2,6 +2,21 @@
 // $Id: spaces.module,v 1.25.4.33.2.32.2.34 2010/05/25 19:04:11 yhahn Exp $
 
 /**
+ * When there are multiple potential spaces, select the canonical space.
+ */
+define('SPACES_MULTIPLE_HANDLING_CANONICAL', 1);
+
+/**
+ * When there are multiple potential spaces, randomly select one.
+ */
+define('SPACES_MULTIPLE_HANDLING_RANDOM', 2);
+
+/**
+ * Use an unmodified path as the canonical URL.
+ */
+define('SPACES_CANONICAL_UNMODIFIED', 'unmodified');
+
+/**
  * Core API ===========================================================
  */
 
Index: plugins/space.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/spaces/plugins/Attic/space.inc,v
retrieving revision 1.1.2.1
diff -u -p -r1.1.2.1 space.inc
--- plugins/space.inc	14 Dec 2009 23:19:16 -0000	1.1.2.1
+++ plugins/space.inc	1 Jul 2010 00:31:53 -0000
@@ -15,6 +15,7 @@ class space {
   var $type;
   var $id;
   var $active;
+  var $canonical;
 
   /**
    * Constructor.
Index: spaces_taxonomy/spaces_taxonomy.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/spaces/spaces_taxonomy/Attic/spaces_taxonomy.module,v
retrieving revision 1.1.2.4.2.4.2.3
diff -u -p -r1.1.2.4.2.4.2.3 spaces_taxonomy.module
--- spaces_taxonomy/spaces_taxonomy.module	17 Dec 2009 22:33:05 -0000	1.1.2.4.2.4.2.3
+++ spaces_taxonomy/spaces_taxonomy.module	1 Jul 2010 00:31:53 -0000
@@ -97,17 +97,43 @@ function spaces_taxonomy_menu_alter(&$it
  * Implementation of hook_form_alter().
  */
 function spaces_taxonomy_form_alter(&$form, $form_state, $form_id) {
-  if ($form['#id'] == 'node-form' && (arg(0) .'/'. arg(1) != 'admin/content')) {
+  if ($form['#id'] == 'node-form' && isset($form['taxonomy']) && (arg(0) .'/'. arg(1) != 'admin/content')) {
     $vid = variable_get('spaces_taxonomy_vid', 0);
-    $space = spaces_get_space();
-    if ($vid && !empty($form['taxonomy'][$vid]) && $space->type == 'taxonomy') {
-      $form['taxonomy'][$vid]['#disabled'] = TRUE;
-      $form['taxonomy'][$vid]['#default_value'] = $space->id;
+    if ($vid && !empty($form['taxonomy'][$vid])) {
+      // #input must be TRUE to trigger #process callbacks.
+      $form['taxonomy']['#input'] = TRUE;
+      $form['taxonomy']['#process'][] = '_spaces_taxonomy_form_process';
     }
   }
 }
 
 /**
+ * Forms API process callback for node forms.
+ *
+ * Selectively set the disabled state and default value of the spaces taxonomy term selects.
+ */
+function _spaces_taxonomy_form_process($element) {
+  $keys = array(variable_get('spaces_taxonomy_vid', 0));
+  // For consistency, support a key set by primary_term module.
+  if (isset($element['primaryterm'])) {
+    $keys[] = 'primaryterm';
+  }
+  $space = spaces_get_space();
+  if ($space->type == 'taxonomy') {
+    foreach ($keys as $key) {
+      if ($key != 'primaryterm' && !$element[$key]['#multiple']) {
+        $element[$key]['#disabled'] = TRUE;
+      }
+      $default_value = array_filter($element[$key]['#default_value']);
+      if (empty($default_value)) {
+        $element[$key]['#default_value'] = $space->id;
+      }
+    }
+  }
+  return $element;
+}
+
+/**
  * Implementation of hook_form_alter() for taxonomy_form_term.
  */
 function spaces_taxonomy_form_taxonomy_form_term_alter(&$form, $form_state) {
@@ -170,22 +196,32 @@ function spaces_taxonomy_taxonomy($op, $
  * Spaces Taxonomy settings form.
  */
 function spaces_taxonomy_settings(&$form_state) {
-  $form = array();
   // Collect an array of valid vocab options
-  $vocabs = array(0 => '---');
-  foreach (taxonomy_get_vocabularies() as $vocab) {
-    // Vocab may not be multiple
-    if (!$vocab->multiple && !$vocab->tags) {
-      $vocabs[$vocab->vid] = $vocab->name;
+  $options = array(0 => '---');
+  $vocabs = taxonomy_get_vocabularies();
+  foreach ($vocabs as $vocab) {
+    if (!$vocab->tags) {
+      $options[$vocab->vid] = $vocab->name;
     }
   }
+  $vid = variable_get('spaces_taxonomy_vid', 0);
   $form['spaces_taxonomy_vid'] = array(
     '#type' => 'select',
     '#title' => t('Spaces vocabulary'),
     '#description' => t('Choose one of the following vocabularies to enable for use with Spaces.'),
-    '#options' => $vocabs,
-    '#default_value' => variable_get('spaces_taxonomy_vid', 0),
+    '#options' => $options,
+    '#default_value' => $vid,
   );
+  if ($vid && $vocabs[$vid]->multiple) {
+    $options = array(SPACES_MULTIPLE_HANDLING_CANONICAL => t('primary (canonical)'), SPACES_MULTIPLE_HANDLING_RANDOM => t('random'));
+    $form['spaces_taxonomy_multiple_handling'] = array(
+      '#type' => 'radios',
+      '#title' => t('Method to select between multiple term spaces'),
+      '#description' => t('If multiple terms from the spaces vocabulary are selected for a piece of content and users are coming from outside any of those spaces, which term should be selected? Choose "primary (canonical)" to have users forwarded every time to a particular term\'s space. Chose "random" to have users forwarded to a potentially different term\'s space each time. If you choose "primary (canonical)", a specific primary space can be set for each node using the <a href="http://drupal.org/project/primary_term">Primary term</a> module. To enable this functionality, install Primary term and configure selected node types to use the Spaces vocabulary for primary terms. Otherwise, term weights on the Spaces vocabulary can be used to set priority; lighter terms will take priority as the primary or canonical space.'),
+      '#options' => $options,
+      '#default_value' => variable_get('spaces_taxonomy_multiple_handling', SPACES_MULTIPLE_HANDLING_CANONICAL),
+    );
+  }
   $form = system_settings_form($form);
   return $form;
 }
Index: spaces_taxonomy/plugins/space_taxonomy.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/spaces/spaces_taxonomy/plugins/Attic/space_taxonomy.inc,v
retrieving revision 1.1.2.3
diff -u -p -r1.1.2.3 space_taxonomy.inc
--- spaces_taxonomy/plugins/space_taxonomy.inc	26 Apr 2010 19:33:30 -0000	1.1.2.3
+++ spaces_taxonomy/plugins/space_taxonomy.inc	1 Jul 2010 00:31:53 -0000
@@ -38,9 +38,20 @@ class space_taxonomy extends space_type_
         if (implode('/', array(arg(0), arg(1))) === 'taxonomy/term' && arg(2)) {
           $terms = taxonomy_terms_parse_string(arg(2));
           if (!empty($terms['tids'])) {
-            foreach ($terms['tids'] as $tid) {
-              if ($term = taxonomy_get_term($tid)) {
-                $this->router_term($term);
+            // If we have a current taxonomy space, stay in it if possible.
+            if (!empty($this->id) && in_array($this->id, $terms['tids'])) {
+              $this->router_term(taxonomy_get_term($this->id));
+            }
+            else {
+              if (variable_get('spaces_taxonomy_multiple_handling', SPACES_MULTIPLE_HANDLING_CANONICAL) == SPACES_MULTIPLE_HANDLING_RANDOM) {
+                // Randomize the term selected.
+                shuffle($terms['tids']);
+              }
+              foreach ($terms['tids'] as $tid) {
+                if ($term = taxonomy_get_term($tid)) {
+                  $this->router_term($term);
+                  break;
+                }
               }
             }
           }
@@ -49,9 +60,53 @@ class space_taxonomy extends space_type_
       case 'node':
         $node = $object;
         if (!empty($node->taxonomy)) {
-          foreach ($node->taxonomy as $term) {
-            if ($term->vid == variable_get('spaces_taxonomy_vid', 0)) {
-              $this->router_term($term);
+          $spaces_vid = variable_get('spaces_taxonomy_vid', 0);
+          $terms = $node->taxonomy;
+          foreach ($terms as $tid => $term) {
+            if ($term->vid != $spaces_vid) {
+              unset($terms[$tid]);
+            }
+          }
+          // Multiple handling is needed only if the node has more than one term in
+          // the Spaces vocabulary.
+          if (count($terms) > 1) {
+            $multiple_handling = variable_get('spaces_taxonomy_multiple_handling', SPACES_MULTIPLE_HANDLING_CANONICAL);
+
+            switch ($multiple_handling) {
+              case SPACES_MULTIPLE_HANDLING_CANONICAL:
+                // If there is a primary_term designated, priorize it. If a site has the
+                // primary_term module installed and configured to use the spaces_taxonomy
+                // vocabulary for primary terms for a given content type, node authors
+                // will be able to select per-node canonical spaces.
+                if (isset($node->primary_term) && isset($node->taxonomy[$node->primary_term->tid]) && $node->primary_term->vid == variable_get('spaces_taxonomy_vid', 0)) {
+                  $this->canonical = $node->primary_term->tid;
+                }
+                // Otherwise, take the first term. Doing so allows site admins to set priority based on term
+                // weight.
+                else {
+                  $this->canonical = key($terms);
+                }
+                break;
+              case SPACES_MULTIPLE_HANDLING_RANDOM:
+                $this->canonical = SPACES_CANONICAL_UNMODIFIED;
+                // Randomize the term selected.
+                shuffle($terms);
+                break;
+            }
+          }
+
+          // If we have a current taxonomy space, stay in it if this node has its term.
+          if (!empty($this->id) && isset($terms[$this->id])) {
+            $this->router_term($terms[$this->id]);
+          }
+          else {
+            // If we have a canonical term set, use it.
+            if ($this->canonical && isset($terms[$this->canonical])) {
+              $this->router_term($terms[$this->canonical]);
+            }
+            // Otherwise, take the first term.
+            else {
+              $this->router_term(reset($terms));
             }
           }
         }
@@ -70,6 +125,28 @@ class space_taxonomy extends space_type_
       if ($space && (!$this->active || ($this->id != $space->id))) {
         $space->activate();
       }
+      // If we're already in the active taxonomy space, determine if there is a
+      // canonical space.
+      elseif ($space && $this->id && !empty($this->canonical) && ($this->canonical == SPACES_CANONICAL_UNMODIFIED || $this->canonical != $this->id)) {
+        // Don't bother if PURL is using separate domains or subdomains.
+        $purl_method = variable_get('purl_method_spaces_taxonomy', 0);
+        if (!empty($purl_method) && !in_array($purl_method, array('domain', 'subdomain'))) {
+          // Only act if we are on a node's primary page.
+          if ($node = menu_get_object()) {
+            $options = array('purl' => array());
+            // Set a space option if a space is designated as canonical.
+            if ($this->canonical == SPACES_CANONICAL_UNMODIFIED) {
+              $options['purl']['disabled'] = TRUE;
+            }
+            // Otherwise, the canonical URL is unmodified.
+            else {
+              $options['purl']['id'] = $this->canonical;
+              $options['purl']['provider'] = 'spaces_taxonomy';
+            }
+            purl_canonical(array('path' => 'node/' . $node->nid, 'options' => $options));
+          }
+        }
+      }
     }
   }
 
