欢迎各位兄弟 发布技术文章
这里的技术是共享的
我们先来分析一个问题,区块上面的上下文链接,怎么生成的。我们来看一下左边导航区块;
然后使用Firefox打开,使用firebug查看一下,上下文链接的源代码。
在区块的标题和正文之间,插入了一个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';
}
}
而且,我们看到区块最外面的div的class里面的'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_links是Drupal里面的一个元素,类似于表单元素一样,当呈现这个元素的时候,就会加载对应的JS、CSS文件,分别为contextual.js,contextual.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的内部。这个时候,面包屑右边的上下文链接显示出来了。
只不过显示的是别处的上下文链接。不过我们已经向前前进了一大步。接着可以尝试使用使用:'breadcrumb2' => array('breadcrumb', array('1')),来构建上下文链接,这次也出来了,只不过这些链接,是bid为1的上下文链接。
可能有读者会问,我怎么知道的,这样构建上下文链接,这个我是参考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