? 0-field-tokens-D7.patch
? 0-temp.patch
? 0-token-array-tokens-D7.patch
? 0-token-get-info-type-D7.patch
? 0-token-hidden-D7.patch
? 0-token-lightestterm-D7.patch
? 0-token-upgrade-info-D7.patch
? 0-user-text-field-tokens.txt
? 125640-token-profile-D7.patch
? 273893-token-current-page-arg-tokens-D7.patch
? 333590-token-menu-link-loading-D7.patch
? 550164-token-current-page-query-tokens-D7.patch
? 776952-token-blocks-D7.patch
? 821008-token-devel-D7.patch
? 829744-token-entity-path-D7.patch
? 844912-token-search-tokens-D7.patch
? 845146-token-presort-tokens-D7.patch
? 845148-token-user-email-tree-D7.patch
? 967136-token-content-type-tokens-D7.patch
? jquery-ui-tree
? jstree
? menu.tokens.inc
? patches
? temp-D7.patch
? temp-token-entity-id-D7.patch
? tests
? token.inc
? treeTable
Index: token.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/token/token.module,v
retrieving revision 1.47
diff -u -p -r1.47 token.module
--- token.module	13 Nov 2010 19:12:44 -0000	1.47
+++ token.module	14 Nov 2010 17:31:33 -0000
@@ -711,3 +711,131 @@ function token_find_duplicate_tokens() {
 
   return $all_tokens;
 }
+
+/**
+ * Get a menu link by its mlid, access checked and link translated for rendering.
+ *
+ * This function is a copy of menu_link_load() but with its own cache and a
+ * simpler query to load the link.
+ *
+ * @param $mlid
+ *   The mlid of the menu item.
+ *
+ * @return
+ *   A menu link translated for rendering.
+ *
+ * @see menu_link_load()
+ * @see _token_menu_link_translate()
+ */
+function token_menu_link_load($mlid) {
+  $cache = &drupal_static(__FUNCTION__);
+
+  if (!is_numeric($mlid)) {
+    return FALSE;
+  }
+
+  if (!isset($cache[$mlid])) {
+    $item = db_query("SELECT * FROM {menu_links} ml LEFT JOIN {menu_router} m ON m.path = ml.router_path WHERE ml.mlid = :mlid", array(':mlid' => $mlid))->fetchAssoc();
+    if (!empty($item)) {
+      _token_menu_link_translate($item);
+    }
+    $cache[$mlid] = $item;
+  }
+
+  return $cache[$mlid];
+}
+
+function token_book_link_load($mlid) {
+  $cache = &drupal_static(__FUNCTION__);
+
+  if (!is_numeric($mlid)) {
+    return FALSE;
+  }
+
+  if (!isset($cache[$mlid])) {
+    $item = db_query("SELECT * FROM {menu_links} ml INNER JOIN {book} b ON b.mlid = ml.mlid LEFT JOIN {menu_router} m ON m.path = ml.router_path WHERE ml.mlid = :mlid", array(':mlid' => $mlid))->fetchAssoc();
+    if (!empty($item)) {
+      _token_menu_link_translate($item);
+    }
+    $cache[$mlid] = $item;
+  }
+
+  return $cache[$mlid];
+}
+
+function _token_menu_link_translate(&$item, $translate = FALSE) {
+  if (!is_array($item['options'])) {
+    $item['options'] = unserialize($item['options']);
+  }
+  if ($item['external']) {
+    $item['access'] = 1;
+    $map = array();
+    $item['href'] = $item['link_path'];
+    $item['title'] = $item['link_title'];
+    $item['localized_options'] = $item['options'];
+  }
+  else {
+    // Complete the path of the menu link with elements from the current path,
+    // if it contains dynamic placeholders (%).
+    $map = explode('/', $item['link_path']);
+    if (strpos($item['link_path'], '%') !== FALSE) {
+      // Invoke registered to_arg callbacks.
+      if (!empty($item['to_arg_functions'])) {
+        _menu_link_map_translate($map, $item['to_arg_functions']);
+      }
+      // Or try to derive the path argument map from the current router item,
+      // if this $item's path is within the router item's path. This means
+      // that if we are on the current path 'foo/%/bar/%/baz', then
+      // menu_get_item() will have translated the menu router item for the
+      // current path, and we can take over the argument map for a link like
+      // 'foo/%/bar'. This inheritance is only valid for breadcrumb links.
+      // @see _menu_tree_check_access()
+      // @see menu_get_active_breadcrumb()
+      elseif ($translate && ($current_router_item = menu_get_item())) {
+        // If $translate is TRUE, then this link is in the active trail.
+        // Only translate paths within the current path.
+        if (strpos($current_router_item['path'], $item['link_path']) === 0) {
+          $count = count($map);
+          $map = array_slice($current_router_item['original_map'], 0, $count);
+          $item['original_map'] = $map;
+          if (isset($current_router_item['map'])) {
+            $item['map'] = array_slice($current_router_item['map'], 0, $count);
+          }
+          // Reset access to check it (for the first time).
+          //unset($item['access']);
+        }
+      }
+    }
+    $item['href'] = implode('/', $map);
+
+    // Skip links containing untranslated arguments.
+    if (strpos($item['href'], '%') !== FALSE) {
+      $item['access'] = FALSE;
+      return FALSE;
+    }
+
+    $item['access'] = TRUE;
+    //// menu_tree_check_access() may set this ahead of time for links to nodes.
+    //if (!isset($item['access'])) {
+    //  if (!empty($item['load_functions']) && !_menu_load_objects($item, $map)) {
+    //    // An error occurred loading an object.
+    //    $item['access'] = FALSE;
+    //    return FALSE;
+    //  }
+    //  _menu_check_access($item, $map);
+    //}
+    // For performance, don't localize a link the user can't access.
+    //if ($item['access']) {
+      _menu_item_localize($item, $map, TRUE);
+    //}
+  }
+
+  // Allow other customizations - e.g. adding a page-specific query string to the
+  // options array. For performance reasons we only invoke this hook if the link
+  // has the 'alter' flag set in the options array.
+  if (!empty($item['options']['alter'])) {
+    drupal_alter('translated_menu_link', $item, $map);
+  }
+
+  return $map;
+}
Index: token.test
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/token/token.test,v
retrieving revision 1.21
diff -u -p -r1.21 token.test
--- token.test	13 Nov 2010 21:50:03 -0000	1.21
+++ token.test	14 Nov 2010 17:31:33 -0000
@@ -169,17 +169,49 @@ class TokenMenuTestCase extends TokenTes
   }
 
   function testMenuTokens() {
+    // Add a root link.
     $root_link = array(
-      'link_path' => '<front>',
-      'link_title' => 'Front link',
+      'link_path' => 'root',
+      'link_title' => 'Root link',
       'menu_name' => 'main-menu',
     );
     menu_link_save($root_link);
 
+    // Add another link with the root link as the parent
+    $parent_link = array(
+      'link_path' => 'root/parent',
+      'link_title' => 'Parent link',
+      'menu_name' => 'main-menu',
+      'plid' => $root_link['mlid'],
+    );
+    menu_link_save($parent_link);
+
+    // Test menu link tokens.
+    $tokens = array(
+      'mlid' => $parent_link['mlid'],
+      'title' => 'Parent link',
+      'menu' => 'Main menu',
+      'menu:name' => 'Main menu',
+      'menu:machine-name' => 'main-menu',
+      'menu:description' => 'The <em>Main</em> menu is used on many sites to show the major sections of the site, often in a top navigation bar.',
+      'path' => 'root/parent',
+      'url' => url('root/parent', array('absolute' => TRUE)),
+      'parent' => 'Root link',
+      'parent:mlid' => $root_link['mlid'],
+      'parent:menu' => 'Main menu',
+      'parent:parent' => NULL,
+      'root' => 'Root link',
+      'root:mlid' => $root_link['mlid'],
+      'root:parent' => NULL,
+      'root:root' => NULL,
+    );
+    $this->assertTokens('menu-link', $parent_link, $tokens);
+
+    // Add a node menu link
     $node_link = array(
       'enabled' => TRUE,
       'link_title' => 'Node link',
-      'plid' => $root_link['mlid'],
+      'plid' => $parent_link['mlid'],
       'customized' => 0,
       'description' => '',
     );
@@ -190,30 +222,17 @@ class TokenMenuTestCase extends TokenTes
       'menu-link' => 'Node link',
       'menu-link:mlid' => $node->menu['mlid'],
       'menu-link:title' => 'Node link',
-      'menu-link:menu' => 'main-menu',
-      'menu-link:menu-name' => 'Main menu',
+      'menu-link:menu' => 'Main menu',
       'menu-link:path' => 'node/' . $node->nid,
       'menu-link:url' => url('node/' . $node->nid, array('absolute' => TRUE)),
-      'menu-link:parent' => 'Front link',
+      'menu-link:parent' => 'Parent link',
       'menu-link:parent:mlid' => $node->menu['plid'],
-      'menu-link:parent:mlid' => $root_link['mlid'],
+      'menu-link:parent:mlid' => $parent_link['mlid'],
+      'menu-link:root' => 'Root link',
+      'menu-link:root:mlid' => $root_link['mlid'],
     );
     $this->assertTokens('node', $node, $tokens);
   }
-
-  function testMenuItemAccess() {
-    variable_set('menu_options_page', array('main-menu', 'management'));
-    // Fetch the mlid of the administer
-    $admin_mlid = db_query("SELECT mlid FROM {menu_links} WHERE menu_name = 'management' AND link_path = 'admin'")->fetchField();
-    $node_link = array(
-      'enabled' => TRUE,
-      'link_title' => 'Admin node link',
-      'plid' => $admin_mlid,
-      'customized' => 0,
-      'description' => '',
-    );
-    $node = $this->drupalCreateNode(array('menu' => $node_link));
-  }
 }
 
 class TokenTaxonomyTestCase extends TokenTestHelper {
Index: token.tokens.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/token/token.tokens.inc,v
retrieving revision 1.28
diff -u -p -r1.28 token.tokens.inc
--- token.tokens.inc	13 Nov 2010 21:50:03 -0000	1.28
+++ token.tokens.inc	14 Nov 2010 17:31:33 -0000
@@ -67,7 +67,7 @@ function token_token_info() {
 
   // Content type tokens.
   $info['types']['content-type'] = array(
-    'name' => t('Content type'),
+    'name' => t('Content types'),
     'description' => t('Tokens related to content types.'),
     'needs-data' => 'content-type',
   );
@@ -137,14 +137,6 @@ function token_token_info() {
     'name' => t('Title'),
     'description' => t('The title of the menu link.'),
   );
-  $info['tokens']['menu-link']['menu'] = array(
-    'name' => t('Menu'),
-    'description' => t("The machine name of the link's menu."),
-  );
-  $info['tokens']['menu-link']['menu-name'] = array(
-    'name' => t('Menu name'),
-    'description' => t("The human-readable name of the link's menu."),
-  );
   $info['tokens']['menu-link']['path'] = array(
     'name' => t('Path'),
     'description' => t('The URL alias of the menu link.'),
@@ -253,6 +245,7 @@ function token_tokens($type, $tokens, ar
           $replacements[$original] = $sanitize ? check_plain($node_type->name) : $node_type->name;
           break;
         case 'machine-name':
+          // This is a machine name so does not ever need to be sanitized.
           $replacements[$original] = $node_type->type;
           break;
         case 'description':
@@ -289,8 +282,7 @@ function token_tokens($type, $tokens, ar
     foreach ($tokens as $name => $original) {
       switch ($name) {
         case 'machine-name':
-          // Vocabulary machine names cannot have XSS-capable characters so
-          // there is no need to escape it.
+          // This is a machine name so does not ever need to be sanitized.
           $replacements[$original] = $vocabulary->machine_name;
           break;
         case 'edit-url':
@@ -317,6 +309,11 @@ function token_tokens($type, $tokens, ar
   if ($type == 'menu-link' && !empty($data['menu-link'])) {
     $link = (array) $data['menu-link'];
 
+    if (!isset($link['title'])) {
+      // Re-load the link if it was not loaded via token_menu_link_load().
+      $link = token_menu_link_load($link['mlid']);
+    }
+
     foreach ($tokens as $name => $original) {
       switch ($name) {
         case 'mlid':
@@ -325,16 +322,6 @@ function token_tokens($type, $tokens, ar
         case 'title':
           $replacements[$original] = $sanitize ? check_plain($link['title']) : $link['title'];
           break;
-        case 'menu':
-          // This is a machine name so does not ever need to be sanitized.
-          $replacements[$original] = $link['menu_name'];
-          break;
-        case 'menu-name':
-          $menus = menu_get_menus();
-          if (isset($menus[$link['menu_name']])) {
-            $replacements[$original] = $sanitize ? check_plain($menus[$link['menu_name']]) : $menus[$link['menu_name']];
-          }
-          break;
         case 'path':
           $alias = drupal_get_path_alias($link['href'], $language_code);
           $replacements[$original] = $sanitize ? check_plain($alias) : $alias;
@@ -343,12 +330,12 @@ function token_tokens($type, $tokens, ar
           $replacements[$original] = url($link['href'], $url_options);
           break;
         case 'parent':
-          if (!empty($link['plid']) && $parent = menu_link_load($link['plid'])) {
+          if (!empty($link['plid']) && $parent = token_menu_link_load($link['plid'])) {
             $replacements[$original] = $sanitize ? check_plain($parent['title']) : $parent['title'];
           }
           break;
         case 'root';
-          if (!empty($link['p1']) && $root = menu_link_load($link['p1'])) {
+          if (!empty($link['p1']) && $link['p1'] != $link['mlid'] && $root = token_menu_link_load($link['p1'])) {
             $replacements[$original] = $sanitize ? check_plain($root['title']) : $root['title'];
           }
           break;
@@ -356,11 +343,11 @@ function token_tokens($type, $tokens, ar
     }
 
     // Chained token relationships.
-    if (!empty($link['plid']) && ($source_tokens = token_find_with_prefix($tokens, 'parent')) && $parent = menu_link_load($link['plid'])) {
+    if (!empty($link['plid']) && ($source_tokens = token_find_with_prefix($tokens, 'parent')) && $parent = token_menu_link_load($link['plid'])) {
       $replacements += token_generate('menu-link', $source_tokens, array('menu-link' => $parent), $options);
     }
-    if (!empty($link['p1']) && ($root_tokens = token_find_with_prefix($tokens, 'root')) && $root = menu_link_load($link['p1'])) {
-      $replacements += token_generate('menu-link', $source_tokens, array('menu-link' => $root), $options);
+    if (!empty($link['p1']) && $link['p1'] != $link['mlid'] && ($root_tokens = token_find_with_prefix($tokens, 'root')) && $root = token_menu_link_load($link['p1'])) {
+      $replacements += token_generate('menu-link', $root_tokens, array('menu-link' => $root), $options);
     }
   }
 
@@ -451,11 +438,7 @@ function book_tokens($type, $tokens, arr
     $node = $data['node'];
 
     if (!empty($node->book['mlid'])) {
-      $link = $node->book;
-      if (!isset($link['title'])) {
-        // Links may be impartially loaded, so ensure we have a full link.
-        $link = book_link_load($link['mlid']);
-      }
+      $link = token_book_link_load($node->book['mlid']);
 
       foreach ($tokens as $name => $original) {
         switch ($name) {
@@ -479,11 +462,36 @@ function book_tokens($type, $tokens, arr
  * Implements hook_token_info() on behalf of menu.module.
  */
 function menu_token_info() {
+  // Menu tokens.
+  $info['types']['menu'] = array(
+    'name' => t('Menus'),
+    'description' => t('Tokens related to menus.'),
+    'needs-data' => 'menu',
+  );
+  $info['tokens']['menu']['name'] = array(
+    'name' => t('Name'),
+    'description' => t("The name of the menu."),
+  );
+  $info['tokens']['menu']['machine-name'] = array(
+    'name' => t('Machine-readable name'),
+    'description' => t("The unique machine-readable name of the menu."),
+  );
+  $info['tokens']['menu']['description'] = array(
+    'name' => t('Description'),
+    'description' => t('The optional description of the menu.'),
+  );
+
+  $info['tokens']['menu-link']['menu'] = array(
+    'name' => t('Menu'),
+    'description' => t('The menu of the menu link.'),
+    'type' => 'menu',
+  );
   $info['tokens']['node']['menu-link'] = array(
     'name' => t('Menu link'),
     'description' => t("The menu link for this node."),
     'type' => 'menu-link',
   );
+
   return $info;
 }
 
@@ -504,11 +512,7 @@ function menu_tokens($type, $tokens, arr
     }
 
     if (!empty($node->menu['mlid'])) {
-      $link = $node->menu;
-      if (!isset($link['title'])) {
-        // Links may be impartially loaded, so ensure we have a full link.
-        $link = menu_link_load($node->menu['mlid']);
-      }
+      $link = token_menu_link_load($node->menu['mlid']);
 
       foreach ($tokens as $name => $original) {
         switch ($name) {
@@ -525,6 +529,47 @@ function menu_tokens($type, $tokens, arr
     }
   }
 
+  // Menu link tokens.
+  if ($type == 'menu-link' && !empty($data['menu-link'])) {
+    $link = (array) $data['menu-link'];
+
+    foreach ($tokens as $name => $original) {
+      switch ($name) {
+        case 'menu':
+          if ($menu = menu_load($link['menu_name'])) {
+            $replacements[$original] = $sanitize ? check_plain($menu['title']) : $menu['title'];
+          }
+          break;
+      }
+    }
+
+    // Chained token relationships.
+    if (($menu_tokens = token_find_with_prefix($tokens, 'menu')) && $menu = menu_load($link['menu_name'])) {
+      $replacements += token_generate('menu', $menu_tokens, array('menu' => $menu), $options);
+    }
+  }
+
+  // Menu tokens.
+  if ($type == 'menu' && !empty($data['menu'])) {
+    $menu = (array) $data['menu'];
+
+    foreach ($tokens as $name => $original) {
+      switch ($name) {
+        case 'name':
+          $replacements[$original] = $sanitize ? check_plain($menu['title']) : $menu['title'];
+          break;
+        case 'machine-name':
+          // This is a machine name so does not ever need to be sanitized.
+          $replacements[$original] = $menu['menu_name'];
+          break;
+        case 'description':
+          $replacements[$original] = $sanitize ? filter_xss($menu['description']) : $menu['description'];
+          break;
+        // @todo case 'menu-link-count':
+      }
+    }
+  }
+
   return $replacements;
 }
 
