欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

2 添加上下文链接

作者:老葛,北京亚艾元软件有限责任公司,http://www.yaiyuan.com

我们先来分析一个问题,区块上面的上下文链接,怎么生成的。我们来看一下左边导航区块; 

图片1.png 

然后使用Firefox打开,使用firebug查看一下,上下文链接的源代码。

图片2.png

 

     在区块的标题和正文之间,插入了一个div

<div class="contextual-links-wrapper contextual-links-processed">

里面包含的就是我么看到的上下文链接。打开区块模块里面的block.tpl.php文件,我们发现标题和正文之间,使用的是这行代码:

<?php print render($title_suffix); ?>

我们把这行注释掉,上下文链接就没有了。我们在api.drupal.org上查找template_preprocess_block,这是区块的预处理函数,里面没有$title_suffix的相关定义。我们直接打开contextual.module文件,这个模块非常小,建议阅读一遍。在这里面,我们找到了contextual_preprocess,在这个预处理函数中,有$title_suffix的对应代码:

function contextual_preprocess(&$variables, $hook) {

  // Nothing to do here if the user is not permitted to access contextual links.

  if (!user_access('access contextual links')) {

    return;

  }

 

  $hooks = theme_get_registry(FALSE);

 

  // Determine the primary theme function argument.

  if (!empty($hooks[$hook]['variables'])) {

    $keys = array_keys($hooks[$hook]['variables']);

    $key = $keys[0];

  }

  elseif (!empty($hooks[$hook]['render element'])) {

    $key = $hooks[$hook]['render element'];

  }

  if (!empty($key) && isset($variables[$key])) {

    $element = $variables[$key];

  }

 

  if (isset($element) && is_array($element) && !empty($element['#contextual_links'])) {

    // Initialize the template variable as a renderable array.

    $variables['title_suffix']['contextual_links'] = array(

      '#type' => 'contextual_links',

      '#contextual_links' => $element['#contextual_links'],

      '#element' => $element,

    );

    // Mark this element as potentially having contextual links attached to it.

    $variables['classes_array'][] = 'contextual-links-region';

  }

}

而且,我们看到区块最外面的divclass里面的'contextual-links-region',就是这里设置的。此外,我们在这个模块里面,还会看到:

/**

 * Implements hook_library().

 */

function contextual_library() {

  $path = drupal_get_path('module', 'contextual');

  $libraries['contextual-links'] = array(

    'title' => 'Contextual links',

    'website' => 'http://drupal.org/node/473268',

    'version' => '1.0',

    'js' => array(

      $path . '/contextual.js' => array(),

    ),

    'css' => array(

      $path . '/contextual.css' => array(),

    ),

  );

  return $libraries;

}

 

/**

 * Implements hook_element_info().

 */

function contextual_element_info() {

  $types['contextual_links'] = array(

    '#pre_render' => array('contextual_pre_render_links'),

    '#theme' => 'links__contextual',

    '#links' => array(),

    '#prefix' => '<div class="contextual-links-wrapper">',

    '#suffix' => '</div>',

    '#attributes' => array(

      'class' => array('contextual-links'),

    ),

    '#attached' => array(

      'library' => array(

        array('contextual', 'contextual-links'),

      ),

    ),

  );

  return $types;

}

我们看到contextual_linksDrupal里面的一个元素,类似于表单元素一样,当呈现这个元素的时候,就会加载对应的JSCSS文件,分别为contextual.jscontextual.css。对应的代码为:

    '#attached' => array(

      'library' => array(

        array('contextual', 'contextual-links'),

      ),

    ),

 

由于我们熟悉表单元素,所以只要我们构建出来contextual_links元素的数组,就能将它呈现出来。这样我当时就决定,不通过title_suffix输出上下文链接了,直接通过输出contextual_links元素的形式,来实现我们的目标。我们直接在breadcrumb.tpl.php里面输入以下代码:

<?php 

   $contextual_links   =    array('#contextual_links' => array(

      //'breadcrumb2' => array('breadcrumb', array('1')),

        //'breadcrumb2' => array('breadcrumb', array('add')),

'menu' => array('admin/structure/menu/manage', array('navigation')),

      )); 

   $contextual_link = array(

      '#type' => 'contextual_links',

      '#contextual_links' => $contextual_links['#contextual_links'],

  '#element' => $contextual_links,

    );

  print drupal_render($contextual_link); 

 ?>

我们这里首先构建了$contextual_links,接着设置了一个类型为上下文链接的元素$contextual_link,最后使用drupal_render将它呈现了出来。这个时候,我们通过Firebug,其实就可以看到我们的输出了,但是显示不出来。我阅读了一下contextual.js的源代码,从中发现了原因:

(function ($) {

 

Drupal.contextualLinks = Drupal.contextualLinks || {};

 

/**

 * Attaches outline behavior for regions associated with contextual links.

 */

Drupal.behaviors.contextualLinks = {

  attach: function (context) {

    $('div.contextual-links-wrapper', context).once('contextual-links', function () {

      var $wrapper = $(this);

      var $region = $wrapper.closest('.contextual-links-region');

      var $links = $wrapper.find('ul.contextual-links');

      var $trigger = $('<a class="contextual-links-trigger" href="#" />').text(Drupal.t('Configure')).click(

        function () {

          $links.stop(true, true).slideToggle(100);

          $wrapper.toggleClass('contextual-links-active');

          return false;

        }

      );

      // Attach hover behavior to trigger and ul.contextual-links.

      $trigger.add($links).hover(

        function () { $region.addClass('contextual-links-region-active'); },

        function () { $region.removeClass('contextual-links-region-active'); }

      );

      // Hide the contextual links when user clicks a link or rolls out of the .contextual-links-region.

      $region.bind('mouseleave click', Drupal.contextualLinks.mouseleave);

      // Prepend the trigger.

      $wrapper.prepend($trigger);

    });

  }

};

 

/**

 * Disables outline for the region contextual links are associated with.

 */

Drupal.contextualLinks.mouseleave = function () {

  $(this)

    .find('.contextual-links-active').removeClass('contextual-links-active')

    .find('ul.contextual-links').hide();

};

 

})(jQuery);

我们看到,外面的'contextual-links-region',是需要的,我们没有加上这个class。我们将:

<div class="breadcrumb-wrapper">

修改为:

<div class="breadcrumb-wrapper contextual-links-region">

并将print drupal_render($contextual_link); 放到这个div的内部。这个时候,面包屑右边的上下文链接显示出来了。

图片3.png 

只不过显示的是别处的上下文链接。不过我们已经向前前进了一大步。接着可以尝试使用使用:'breadcrumb2' => array('breadcrumb', array('1')),来构建上下文链接,这次也出来了,只不过这些链接,是bid1的上下文链接。

可能有读者会问,我怎么知道的,这样构建上下文链接,这个我是参考block.module里面的代码:

$build[$key]['#contextual_links']['block'] = array('admin/structure/block/manage', array($block->module, $block->delta));

以及menu.module里面的代码:

$data['content']['#contextual_links']['menu'] = array('admin/structure/menu/manage', array($delta));

我们通过前台知道,就这两个模块有上下文链接。走到这里的时候,需要弄明白这个数组里面的两个参数的含义。这个时候,我还是阅读的源代码:

function contextual_pre_render_links($element) {

  // Retrieve contextual menu links.

  $items = array();

  foreach ($element['#contextual_links'] as $module => $args) {

    $items += menu_contextual_links($module, $args[0], $args[1]);

  }

 

  // Transform contextual links into parameters suitable for theme_link().

  $links = array();

  foreach ($items as $class => $item) {

    $class = drupal_html_class($class);

    $links[$class] = array(

      'title' => $item['title'],

      'href' => $item['href'],

    );

    // @todo theme_links() should *really* use the same parameters as l().

    $item['localized_options'] += array('query' => array());

    $item['localized_options']['query'] += drupal_get_destination();

    $links[$class] += $item['localized_options'];

  }

  $element['#links'] = $links;

 

  // Allow modules to alter the renderable contextual links element.

  drupal_alter('contextual_links_view', $element, $items);

 

  // If there are no links, tell drupal_render() to abort rendering.

  if (empty($element['#links'])) {

    $element['#printed'] = TRUE;

  }

 

  return $element;

}

通过上面的代码,我们可以看到,上下文链接,是通过函数menu_contextual_links生成的,通过查看这个函数的API文档,我们可以弄明白传递给它的三个参数的含义。也就对应于我们代码里面的:

      //'breadcrumb2' => array('breadcrumb', array('1')),

       //'breadcrumb2' => array('breadcrumb', array('add')),

  'menu' => array('admin/structure/menu/manage', array('navigation')),

然后,通过阅读contextual_pre_render_links,我还弄明白了一个问题,那就是上下文链接,本质上还是链接。这不是废话么。理解到这一点,是一个进步,当我们的面包屑对象不存在时,是无法构建出来上下文链接的。中间的这段代码:

'breadcrumb2' => array('breadcrumb', array('add')),

是不工作的。我们理解了,它本质上是一组链接,最后还是通过$element['#links']输出的,所以我们在构建不出来上下文链接的时候,可以直接构建出来链接,放进来。而这里面,还提供了hook_contextual_links_view_alter,通过实现这个钩子,就能够达到添加链接的目的了。

来自 
http://www.thinkindrupal.com/node/5802

普通分类: