diff --git css/views-admin.css css/views-admin.css
index b0aeb1e..4a94cba 100644
--- css/views-admin.css
+++ css/views-admin.css
@@ -404,6 +404,10 @@ html.js #views-ajax-pad {
padding-left: 30px;
}
+#views-ajax-pad .breadcrumb-custom-settings input {
+ width: 95%;
+}
+
/*
* Add, Rearrange and Configure buttons using sprites
*/
diff --git includes/admin.inc includes/admin.inc
index 850cb35..a3f1887 100644
--- includes/admin.inc
+++ includes/admin.inc
@@ -4087,3 +4087,30 @@ function theme_views_ui_style_plugin_table($form) {
return $output;
}
+/**
+ * Theme the form for the table style plugin
+ */
+function theme_views_ui_breadcrumb_plugin_custom($form) {
+ $output = drupal_render($form['description_markup']);
+
+ $header = array(
+ t('Path'),
+ t('Title'),
+ t('Link Title'),
+ );
+ $rows = array();
+ foreach (element_children($form['items']['path']) as $path_id) {
+ $row = array();
+ $title_id = str_replace('path_', 'title_', $path_id);
+ $link_title_id = str_replace('path_', 'link_title_', $path_id);
+ $row[] = drupal_render($form['items']['path'][$path_id]);
+ $row[] = drupal_render($form['items']['title'][$title_id]);
+ $row[] = drupal_render($form['items']['link_title'][$link_title_id]);
+ $rows[] = $row;
+ }
+
+ $output .= theme('table', $header, $rows, array('class' => 'breadcrumb-custom-settings'));
+ $output .= drupal_render($form);
+ return $output;
+}
+
diff --git includes/plugins.inc includes/plugins.inc
index 4a80885..69f606e 100644
--- includes/plugins.inc
+++ includes/plugins.inc
@@ -274,6 +274,26 @@ function views_views_plugins() {
'help topic' => 'cache-time',
),
),
+ 'breadcrumb' => array(
+ 'parent' => array(
+ 'no ui' => TRUE,
+ 'handler' => 'views_plugin_breadcrumb',
+ 'parent' => '',
+ ),
+ 'default' => array(
+ 'title' => t('Default'),
+ 'help' => t('Default breadcrumb system.'),
+ 'handler' => 'views_plugin_breadcrumb_default',
+ 'help topic' => 'breadcrumb-default',
+ ),
+ 'custom' => array(
+ 'title' => t('Custom'),
+ 'help' => t('Customized breadcrumb system.'),
+ 'handler' => 'views_plugin_breadcrumb_custom',
+ 'uses options' => TRUE,
+ 'help topic' => 'breadcrumb-default',
+ ),
+ ),
'exposed_form' => array(
'parent' => array(
'no ui' => TRUE,
diff --git includes/view.inc includes/view.inc
index 2b38dab..3f551a6 100644
--- includes/view.inc
+++ includes/view.inc
@@ -71,10 +71,7 @@ class view extends views_db_object {
var $style_plugin;
/**
- * The current
-
- /**
- * Constructor
+ * The current constructor
*/
function __construct() {
parent::init();
@@ -1250,30 +1247,13 @@ class view extends views_db_object {
* If true, use drupal_set_breadcrumb() to install the breadcrumb.
*/
function get_breadcrumb($set = FALSE) {
- // Now that we've built the view, extract the breadcrumb.
- $base = TRUE;
- $breadcrumb = array();
+ $breadcrumb_plugin = $this->display_handler->get_plugin('breadcrumb');
- if (!empty($this->build_info['breadcrumb'])) {
- foreach ($this->build_info['breadcrumb'] as $path => $title) {
- // Check to see if the frontpage is in the breadcrumb trail; if it
- // is, we'll remove that from the actual breadcrumb later.
- if ($path == variable_get('site_frontpage', 'node')) {
- $base = FALSE;
- $title = t('Home');
- }
- if ($title) {
- $breadcrumb[] = l($title, $path, array('html' => true));
- }
- }
-
- if ($set) {
- if ($base) {
- $breadcrumb = array_merge(drupal_get_breadcrumb(), $breadcrumb);
- }
- drupal_set_breadcrumb($breadcrumb);
- }
+ $breadcrumb = array();
+ if ($breadcrumb_plugin) {
+ $breadcrumb = $breadcrumb_plugin->get_breadcrumb($set);
}
+
return $breadcrumb;
}
diff --git plugins/views_plugin_breadcrumb.inc plugins/views_plugin_breadcrumb.inc
new file mode 100644
index 0000000..7fcb005
--- /dev/null
+++ plugins/views_plugin_breadcrumb.inc
@@ -0,0 +1,30 @@
+view = &$view;
+ $this->display = &$display;
+
+ $this->unpack_options($this->options, $options);
+ }
+
+ /**
+ * Return a string to display as the clickable title for the
+ * access control.
+ */
+ function summary_title() {
+ return t('Unknown');
+ }
+
+ function get_breadcrumb($set = FALSE) { }
+
+}
diff --git plugins/views_plugin_breadcrumb_custom.inc plugins/views_plugin_breadcrumb_custom.inc
new file mode 100644
index 0000000..81ab5f3
--- /dev/null
+++ plugins/views_plugin_breadcrumb_custom.inc
@@ -0,0 +1,192 @@
+ array(
+ 'title' => array(),
+ 'path' => array(),
+ 'link_title' => array(),
+ ),
+ 'unpack_translatable' => 'unpack_breadcrumbs_translatable',
+ );
+ return $options;
+ }
+
+ function options_form(&$form, &$form_state) {
+ $custom_breadcrumb = $this->options['items'];
+
+ // Provide at least five items to configure the breadcrumb
+ $max_count = max(count(array_filter($custom_breadcrumb['title'])), 3) + 2;
+
+ for ($breadcrumb_item = 0; $breadcrumb_item < $max_count; $breadcrumb_item++) {
+ $form['items']['path']['path_' . $breadcrumb_item] = array(
+ '#type' => 'textfield',
+ '#default_value' => !empty($custom_breadcrumb['path']['path_' . $breadcrumb_item]) ? $custom_breadcrumb['path']['path_' . $breadcrumb_item] : '',
+ '#size' => 40,
+ );
+
+ $form['items']['title']['title_' . $breadcrumb_item] = array(
+ '#type' => 'textfield',
+ '#default_value' => !empty($custom_breadcrumb['title']['title_' . $breadcrumb_item]) ? $custom_breadcrumb['title']['title_' . $breadcrumb_item] : '',
+ );
+
+ $form['items']['link_title']['link_title_' . $breadcrumb_item] = array(
+ '#type' => 'textfield',
+ '#default_value' => !empty($custom_breadcrumb['link_title']['link_title_' . $breadcrumb_item]) ? $custom_breadcrumb['link_title']['link_title_' . $breadcrumb_item] : '',
+ );
+ }
+
+ $count = 0;
+ foreach ($this->view->display_handler->get_handlers('argument') as $arg => $handler) {
+ $options[t('Arguments')]['%' . ++$count] = t('@argument title', array('@argument' => $handler->ui_name()));
+ $options[t('Arguments')]['!' . $count] = t('@argument input', array('@argument' => $handler->ui_name()));
+ }
+
+ // Default text.
+ // We have some options, so make a list.
+ $output = '
' . t('The following tokens are available for this breadcrumb.') . '
';
+ if (!empty($options)) {
+ foreach (array_keys($options) as $type) {
+ if (!empty($options[$type])) {
+ $items = array();
+ foreach ($options[$type] as $key => $value) {
+ $items[] = $key . ' == ' . $value;
+ }
+ $output .= theme('item_list', $items, $type);
+ }
+ }
+ }
+ $global_tokens = array(
+ 'front' => t('You can use <front> in the path section to link the tilte to the front page.'),
+ );
+ $output .= theme('item_list', $global_tokens, t('Global tokens'));
+
+ $form['description_markup'] = array(
+ '#prefix' => '',
+ '#suffix' => '
',
+ '#value' => t('Here you can configure the breadcrumb to display when this view page is rendered. If the path is not defined, "title" will be rendered as normal text without link.') . $output,
+ );
+ $form['#theme'] = 'views_ui_breadcrumb_plugin_custom';
+ }
+
+ function summary_title() {
+ return t('Custom');
+ }
+
+ /**
+ * Get the breadcrumb used for this view.
+ *
+ * @param $set
+ * If true, use drupal_set_breadcrumb() to install the breadcrumb.
+ */
+ function get_breadcrumb($set = FALSE) {
+ // Now that we've built the view, extract the breadcrumb.
+ $breadcrumb = array();
+
+ $custom_breadcrumb = $this->options['items'];
+ $tokens = $this->get_arguments_tokens();
+
+ foreach (array_filter($custom_breadcrumb['title']) as $id => $title) {
+ $path_id = str_replace('title_', 'path_', $id);
+ $link_title_id = str_replace('title_', 'link_title_', $id);
+ $path = $custom_breadcrumb['path'][$path_id];
+ $link_title = $custom_breadcrumb['link_title'][$link_title_id];
+
+ if (!empty($path)) {
+ if (strpos($path, '!') !== FALSE || strpos($path, '%') !== FALSE) {
+ $path = strtr($path, $tokens);
+ }
+ }
+ if (strpos($title, '!') !== FALSE || strpos($title, '%') !== FALSE) {
+ $title = strtr($title, $tokens);
+ }
+ if (strpos($link_title, '!') !== FALSE || strpos($link_title, '%') !== FALSE) {
+ $link_title = strtr($link_title, $tokens);
+ }
+
+ if (!empty($title)) {
+ if (!empty($path)) {
+ if (!empty($link_title)) {
+ $breadcrumb[] = l($title, $path, array('html' => TRUE, 'attributes' => array('title' => check_plain($link_title))));
+ }
+ else {
+ $breadcrumb[] = l($title, $path, array('html' => TRUE));
+ }
+ }
+ else {
+ $breadcrumb[] = check_plain($title);
+ }
+ }
+ }
+
+ if ($set) {
+ drupal_set_breadcrumb($breadcrumb);
+ }
+
+ return $breadcrumb;
+ }
+
+ /**
+ * Returns to tokens for arguments.
+ *
+ * This function is similar to views_handler_field::get_render_tokens()
+ * but without fields tokens.
+ */
+ function get_arguments_tokens() {
+ $tokens = array();
+ if (!empty($this->view->build_info['substitutions'])) {
+ $tokens = $this->view->build_info['substitutions'];
+ }
+ $count = 0;
+ foreach ($this->view->display_handler->get_handlers('argument') as $arg => $handler) {
+ $token = '%' . ++$count;
+ if (!isset($tokens[$token])) {
+ $tokens[$token] = '';
+ }
+
+ // Use strip tags as there should never be HTML in the path.
+ // However, we need to preserve special characters like " that
+ // were removed by check_plain().
+ $tokens['!' . $count] = isset($this->view->args[$count - 1]) ? strip_tags(html_entity_decode($this->view->args[$count - 1])) : '';
+ }
+
+ return $tokens;
+ }
+
+ function unpack_options(&$storage, $options, $definition = NULL, $all = TRUE, $check = TRUE, $localization_keys = array()) {
+ if ($check && !is_array($options)) {
+ return;
+ }
+ // Provide translatables for dynamic items
+ foreach ($options as $key => $value) {
+ if (!empty($value) && (strpos($key, 'title_') !== FALSE)) {
+ $definition[$key]['translatable'] = TRUE;
+ }
+ }
+ // Then continue unpacking as usual
+ parent::unpack_options($storage, $options, $definition, $all, $check, $localization_keys);
+ }
+
+ /**
+ * Custom implementation of unpack_translatable
+ */
+ function unpack_breadcrumbs_translatable(&$translatable, $storage, $option, $definition, $parents, $keys = array()) {
+ $options = $storage['items']['title'];
+ $translation_keys = array_merge($keys, array($key));
+ foreach ($options as $key => $value) {
+ $translatable[] = array(
+ 'value' => $value,
+ 'keys' => $translation_keys,
+ 'format' => NULL,
+ );
+ }
+ return $translatable;
+ }
+
+}
diff --git plugins/views_plugin_breadcrumb_default.inc plugins/views_plugin_breadcrumb_default.inc
new file mode 100644
index 0000000..74978b4
--- /dev/null
+++ plugins/views_plugin_breadcrumb_default.inc
@@ -0,0 +1,45 @@
+view->build_info['breadcrumb'])) {
+ foreach ($this->view->build_info['breadcrumb'] as $path => $title) {
+ // Check to see if the frontpage is in the breadcrumb trail; if it
+ // is, we'll remove that from the actual breadcrumb later.
+ if ($path == variable_get('site_frontpage', 'node')) {
+ $base = FALSE;
+ $title = t('Home');
+ }
+ if ($title) {
+ $breadcrumb[] = l($title, $path, array('html' => true));
+ }
+ }
+
+ if ($set) {
+ if ($base) {
+ $breadcrumb = array_merge(drupal_get_breadcrumb(), $breadcrumb);
+ }
+ drupal_set_breadcrumb($breadcrumb);
+ }
+ }
+ return $breadcrumb;
+ }
+}
diff --git plugins/views_plugin_display_page.inc plugins/views_plugin_display_page.inc
index adac656..e5bf46a 100644
--- plugins/views_plugin_display_page.inc
+++ plugins/views_plugin_display_page.inc
@@ -40,7 +40,12 @@ class views_plugin_display_page extends views_plugin_display {
'name' => array('default' => 'navigation'),
),
);
-
+ $options['breadcrumb'] = array(
+ 'contains' => array(
+ 'type' => array('default' => 'default', 'export' => 'export_plugin', 'unpack_translatable' => 'unpack_plugin'),
+ 'options' => array('default' => array(), 'export' => FALSE),
+ ),
+ );
return $options;
}
@@ -278,6 +283,24 @@ class views_plugin_display_page extends views_plugin_display {
if ($menu['type'] == 'default tab') {
$options['menu']['links']['tab_options'] = t('Change settings for the parent menu');
}
+
+ $breadcrumb_plugin = $this->get_plugin('breadcrumb');
+ if (!$breadcrumb_plugin) {
+ // use default breadcrumb plugin.
+ $breadcrumb_plugin = views_get_plugin('breadcrumb', 'default');
+ }
+
+ $breadcrumb_str = $breadcrumb_plugin->summary_title();
+
+ $options['breadcrumb'] = array(
+ 'category' => 'page',
+ 'title' => t('Breadcrumb'),
+ 'value' => $breadcrumb_str,
+ );
+
+ if (!empty($breadcrumb_plugin->definition['uses options'])) {
+ $options['breadcrumb']['links']['breadcrumb_options'] = t('Change settings for breadcrumb');
+ }
}
/**
@@ -295,9 +318,9 @@ class views_plugin_display_page extends views_plugin_display {
'#type' => 'textfield',
'#description' => t('This view will be displayed by visiting this path on your site. You may use "%" in your URL to represent values that will be used for arguments: For example, "node/%/feed".'),
'#default_value' => $this->get_option('path'),
- '#field_prefix' => '' . url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q='),
- '#field_suffix' => '',
- '#attributes' => array('dir'=>'ltr'),
+ '#field_prefix' => '' . url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q='),
+ '#field_suffix' => '',
+ '#attributes' => array('dir'=>'ltr'),
);
break;
case 'menu':
@@ -458,6 +481,48 @@ class views_plugin_display_page extends views_plugin_display {
'#dependency' => array('radio:tab_options[type]' => array('tab')),
);
break;
+ case 'breadcrumb':
+ $form['#title'] .= t('Breadcrumb');
+ $form['breadcrumb'] = array(
+ '#prefix' => '',
+ '#suffix' => '
',
+ '#tree' => TRUE,
+ );
+
+ $breadcrumb = $this->get_option('breadcrumb');
+ $form['breadcrumb']['type'] = array(
+ '#type' => 'radios',
+ '#options' => views_fetch_plugin_names('breadcrumb'),
+ '#default_value' => $breadcrumb['type'],
+ );
+
+ $breadcrumb_plugin = views_fetch_plugin_data('breadcrumb', $breadcrumb['type']);
+ if (!empty($breadcrumb_plugin['uses options'])) {
+ $form['markup'] = array(
+ '#prefix' => '',
+ '#suffix' => '
',
+ '#value' => t('You may also adjust the !settings for the currently selected breadcrumb mechanism by clicking on the icon.', array('!settings' => $this->option_link(t('settings'), 'breadcrumb_options'))),
+ );
+ }
+ break;
+ case 'breadcrumb_options':
+ $breadcrumb = $this->get_option('breadcrumb');
+ $plugin = $this->get_plugin('breadcrumb');
+ $form['#title'] .= t('Breadcrumb options');
+ if ($plugin) {
+ $form['#help_topic'] = $plugin->definition['help topic'];
+ $form['#help_module'] = $plugin->definition['module'];
+
+ $form['breadcrumb_options'] = array(
+ '#tree' => TRUE,
+ );
+ $form['breadcrumb_options']['type'] = array(
+ '#type' => 'value',
+ '#value' => $breadcrumb['type'],
+ );
+ $plugin->options_form($form['breadcrumb_options'], $form_state);
+ }
+ break;
}
}
@@ -516,6 +581,28 @@ class views_plugin_display_page extends views_plugin_display {
case 'tab_options':
$this->set_option('tab_options', $form_state['values']['tab_options']);
break;
+ case 'breadcrumb':
+ $breadcrumb = $this->get_option('breadcrumb');
+ if ($breadcrumb['type'] != $form_state['values']['breadcrumb']['type']) {
+ $plugin = views_get_plugin('breadcrumb', $form_state['values']['breadcrumb']['type']);
+ if ($plugin) {
+ $breadcrumb = array('type' => $form_state['values']['breadcrumb']['type']);
+ $this->set_option('breadcrumb', $breadcrumb);
+ if (!empty($plugin->definition['uses options'])) {
+ views_ui_add_form_to_stack('display', $this->view, $this->display->id, array('breadcrumb_options'));
+ }
+ }
+ }
+ break;
+ case 'breadcrumb_options':
+ $plugin = $this->get_plugin('breadcrumb');
+ if ($plugin) {
+ $breadcrumb = $this->get_option('breadcrumb');
+ $plugin->options_submit($form['breadcrumb_options'], $form_state);
+ $breadcrumb['options'] = $form_state['values'][$form_state['section']];
+ $this->set_option('breadcrumb', $breadcrumb);
+ }
+ break;
}
}
diff --git views_ui.module views_ui.module
index fbb581c..03c0c79 100644
--- views_ui.module
+++ views_ui.module
@@ -239,6 +239,10 @@ function views_ui_theme() {
'arguments' => array('form' => NULL),
'file' => 'includes/admin.inc',
),
+ 'views_ui_breadcrumb_plugin_custom' => array(
+ 'arguments' => array('form' => NULL),
+ 'file' => 'includes/admin.inc',
+ ),
);
}