Commit d98c3bb1 authored by Quan Nguyen's avatar Quan Nguyen

push custom breadcrumb module

parent 9a0a919c
......@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "75d7d453c2d0621df49776ec65aa1d55",
"content-hash": "ac59bc355f548e3ddc274cea247055d3",
"packages": [
{
"name": "asm89/stack-cors",
......@@ -1226,6 +1226,73 @@
"source": "https://git.drupalcode.org/project/csv_serialization"
}
},
{
"name": "drupal/custom_breadcrumbs",
"version": "1.0.0-alpha1",
"source": {
"type": "git",
"url": "https://git.drupalcode.org/project/custom_breadcrumbs.git",
"reference": "1.0.0-alpha1"
},
"dist": {
"type": "zip",
"url": "https://ftp.drupal.org/files/projects/custom_breadcrumbs-1.0.0-alpha1.zip",
"reference": "1.0.0-alpha1",
"shasum": "1a89f33be922e687662ae47d9a9b7c41e995139f"
},
"require": {
"drupal/core": "^8 || ^9",
"drupal/token": "^1.0"
},
"type": "drupal-module",
"extra": {
"drupal": {
"version": "1.0.0-alpha1",
"datestamp": "1594887609",
"security-coverage": {
"status": "not-covered",
"message": "Project has not opted into security advisory coverage!"
}
}
},
"notification-url": "https://packages.drupal.org/8/downloads",
"license": [
"GPL-2.0+"
],
"authors": [
{
"name": "Szczepan Musial (lamp5)",
"homepage": "https://www.drupal.org/u/lamp5",
"role": "Maintainer"
},
{
"name": "Contributors",
"homepage": "https://www.drupal.org/node/98576/committers",
"role": "Contributors"
},
{
"name": "colan",
"homepage": "https://www.drupal.org/user/58704"
},
{
"name": "lamp5",
"homepage": "https://www.drupal.org/user/2870321"
},
{
"name": "thePanz",
"homepage": "https://www.drupal.org/user/58689"
}
],
"description": "Custom breadcrumbs helps the user to create and manage breadcrumbs menu on all content entity pages and other like views, page manager, controllers.",
"homepage": "https://www.drupal.org/project/custom_breadcrumbs",
"keywords": [
"Drupal"
],
"support": {
"source": "http://cgit.drupalcode.org/custom_breadcrumbs",
"issues": "https://www.drupal.org/project/issues/custom_breadcrumbs"
}
},
{
"name": "drupal/easy_breadcrumb",
"version": "1.13.0",
......@@ -1305,6 +1372,75 @@
"issues": "https://www.drupal.org/project/issues/easy_breadcrumb"
}
},
{
"name": "drupal/token",
"version": "1.7.0",
"source": {
"type": "git",
"url": "https://git.drupalcode.org/project/token.git",
"reference": "8.x-1.7"
},
"dist": {
"type": "zip",
"url": "https://ftp.drupal.org/files/projects/token-8.x-1.7.zip",
"reference": "8.x-1.7",
"shasum": "c7e3a3757282e4c94e3c1fff08d01e22155cb853"
},
"require": {
"drupal/core": "^8.8 || ^9"
},
"type": "drupal-module",
"extra": {
"drupal": {
"version": "8.x-1.7",
"datestamp": "1589314266",
"security-coverage": {
"status": "covered",
"message": "Covered by Drupal's security advisory policy"
}
},
"drush": {
"services": {
"drush.services.yml": "^9 || ^10"
}
}
},
"notification-url": "https://packages.drupal.org/8/downloads",
"license": [
"GPL-2.0+"
],
"authors": [
{
"name": "Berdir",
"homepage": "https://www.drupal.org/user/214652"
},
{
"name": "Dave Reid",
"homepage": "https://www.drupal.org/user/53892"
},
{
"name": "eaton",
"homepage": "https://www.drupal.org/user/16496"
},
{
"name": "fago",
"homepage": "https://www.drupal.org/user/16747"
},
{
"name": "greggles",
"homepage": "https://www.drupal.org/user/36762"
},
{
"name": "mikeryan",
"homepage": "https://www.drupal.org/user/4420"
}
],
"description": "Provides a user interface for the Token API, some missing core tokens.",
"homepage": "https://www.drupal.org/project/token",
"support": {
"source": "https://git.drupalcode.org/project/token"
}
},
{
"name": "drupal/views_data_export",
"version": "1.0.0",
......
This diff is collapsed.
INTRODUCTION
------------
Custom breadcrumbs helps the user to create and manage breadcrumbs menu on all
content entity pages and other like views, page manager, controllers.
REQUIREMENTS
------------
This module requires the following modules:
* Tokens (https://www.drupal.org/project/tokens)
INSTALLATION
------------
* Install as you would normally install a contributed Drupal module. Visit
https://www.drupal.org/node/1897420 for further information.
CONFIGURATION
-------------
* Configure the user permissions in Administration » People » Permissions:
* Customize the basic breadcrumbs settings in Configuration » User interface » Custom breadcrumbs settings
* You can add a new breadcrumbs instances in Structure » Custom breadcrumbs
USAGE
-------------
* go to Structure » Custom breadcrumbs and add a new breadcrumbs instance
* you can create breadcrumbs for your entities like nodes or pages using path
* remember to check "Enabled" status
* setup urls and titles, one per line
* you can use an extra vars like <nolink> or <term_hierarchy:field_name> to attach taxonomy tree to breadcrumbs
* if you want to use query value from token, for example for search results,
you have to define extra cache contexts ```url.query_args:search``` where search is your query key
* On every content type manage display page, you can display breadcrumbs like field,
this solution has been designed for displaying breadcrumbs on node teaser display mode in
search results.
MAINTAINERS
-----------
Current maintainers:
* Szczepan Musial (lamp5) - https://www.drupal.org/u/lamp5
This project has been sponsored by:
* Abventor
A Drupal Development Team Who Deliver.
We create flexible solutions that companies and organizations from around the world use.
{
"name": "drupal/custom_breadcrumbs",
"type": "drupal-module",
"description": "Custom breadcrumbs helps the user to create and manage breadcrumbs menu on all content entity pages and other like views, page manager, controllers.",
"keywords": [
"Drupal"
],
"license": "GPL-2.0+",
"homepage": "https://www.drupal.org/project/custom_breadcrumbs",
"authors": [
{
"name": "Szczepan Musial (lamp5)",
"homepage": "https://www.drupal.org/u/lamp5",
"role": "Maintainer"
},
{
"name": "Contributors",
"homepage": "https://www.drupal.org/node/98576/committers",
"role": "Contributors"
}
],
"support": {
"issues": "https://www.drupal.org/project/issues/custom_breadcrumbs",
"source": "http://cgit.drupalcode.org/custom_breadcrumbs"
},
"require": {
"drupal/token": "^1.0"
}
}
home: TRUE
home_link: "Home"
current_page: TRUE
current_page_link: FALSE
trim_title: 0
custom_breadcrumbs.custom_breadcrumbs.*:
type: config_entity
label: Custom breadcrumbs
mapping:
id:
type: string
label: ID
label:
type: label
label: Label
uuid:
type: string
description:
type: string
entityType:
type: string
entityBundle:
type: string
language:
type: string
breadcrumbPaths:
type: string
breadcrumbTitles:
type: string
type:
type: string
pathPattern:
type: string
custom_breadcrumbs.settings:
type: config_object
label: 'Custom breadcrumbs settings'
mapping:
home:
label: 'Home'
type: boolean
home_link:
label: 'Home link'
type: string
current_page:
label: 'Current page'
type: boolean
current_page_link:
label: 'Current page link'
type: boolean
trim_title:
label: 'Trim title'
type: integer
name: Custom breadcrumbs
type: module
description: 'Provides a custom breadcrumbs configuration entity.'
package: Custom
core: 8.x
core_version_requirement: ^8 || ^9
configure: custom_breadcrumbs.config
dependencies:
- token:token
# Information added by Drupal.org packaging script on 2020-07-16
version: '1.0.0-alpha1'
project: 'custom_breadcrumbs'
datestamp: 1594887610
entity.custom_breadcrumbs.add_form:
route_name: 'entity.custom_breadcrumbs.add_form'
title: 'Add custom breadcrumbs'
appears_on:
- entity.custom_breadcrumbs.collection
entity.custom_breadcrumbs.overview:
title: Custom breadcrumbs
parent: system.admin_structure
description: 'List of custom breadcrumbs to extend site functionality.'
route_name: entity.custom_breadcrumbs.collection
custom_breadcrumbs.settings:
title: Custom breadcrumbs settings
route_name: custom_breadcrumbs.config
parent: system.admin_config_ui
<?php
/**
* @file
* Primary module hooks for Custom breadcrumbs module.
*
* @DCG
* This file is no longer required in Drupal 8.
* @see https://www.drupal.org/node/2217931
*/
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Routing\RouteMatch;
use Drupal\Core\Routing\RouteMatchInterface;
/**
* Implements hook_help().
*/
function custom_breadcrumbs_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.custom_breadcrumbs':
$text = file_get_contents(dirname(__FILE__) . '/README.md');
if (!\Drupal::moduleHandler()->moduleExists('markdown')) {
return '<pre>' . $text . '</pre>';
}
else {
// Use the Markdown filter to render the README.
$filter_manager = \Drupal::service('plugin.manager.filter');
$settings = \Drupal::configFactory()
->get('markdown.settings')
->getRawData();
$config = ['settings' => $settings];
$filter = $filter_manager->createInstance('markdown', $config);
return $filter->process($text, 'en');
}
}
return NULL;
}
/**
* Implements hook_entity_extra_field_info().
*/
function custom_breadcrumbs_entity_extra_field_info() {
$extra = [];
$entity_types = \Drupal::entityTypeManager()->getDefinitions();
$entityBundleInfo = \Drupal::service('entity_type.bundle.info');
foreach ($entity_types as $key => $type) {
foreach ($entityBundleInfo->getBundleInfo($key) as $bundle_key => $bundle_name) {
$extra[$key][$bundle_key]['display']['breadcrumbs'] = [
'label' => t('Breadcrumbs'),
'description' => t('Breadcrumbs'),
'weight' => 100,
'visible' => FALSE,
];
}
}
return $extra;
}
/**
* Implements hook_entity_view().
*/
function custom_breadcrumbs_entity_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
if ($display->getComponent('breadcrumbs')) {
$url = $entity->toUrl();
$router = \Drupal::service('router.no_access_checks');
$result = $router->match($url->toString());
$paramsObj = [];
foreach ($result as $key => $val) {
if (isset($url->getRouteParameters()[$key])) {
$paramsObj[$key] = $val;
}
}
$route_match = new RouteMatch($url->getRouteName(), $result['_route_object'], $paramsObj, $url->getRouteParameters());
$build['breadcrumbs'] = \Drupal::service('breadcrumb')
->build($route_match)
->toRenderable();
}
}
administer custom_breadcrumbs:
title: 'Administer custom breadcrumbs'
entity.custom_breadcrumbs.collection:
path: '/admin/structure/custom-breadcrumbs'
defaults:
_entity_list: 'custom_breadcrumbs'
_title: 'Custom breadcrumbs configuration'
requirements:
_permission: 'administer custom_breadcrumbs'
entity.custom_breadcrumbs.add_form:
path: '/admin/structure/custom_breadcrumbs/add'
defaults:
_entity_form: 'custom_breadcrumbs.add'
_title: 'Add a custom breadcrumb'
requirements:
_permission: 'administer custom_breadcrumbs'
entity.custom_breadcrumbs.edit_form:
path: '/admin/structure/custom-breadcrumbs/{custom_breadcrumbs}'
defaults:
_entity_form: 'custom_breadcrumbs.edit'
_title: 'Edit a custom breadcrumb'
requirements:
_permission: 'administer custom_breadcrumbs'
entity.custom_breadcrumbs.delete_form:
path: '/admin/structure/custom-breadcrumbs/{custom_breadcrumbs}/delete'
defaults:
_entity_form: 'custom_breadcrumbs.delete'
_title: 'Delete a custom breadcrumb'
requirements:
_permission: 'administer custom_breadcrumbs'
custom_breadcrumbs.config:
path: '/admin/config/user-interface/custom-breadcrumbs'
defaults:
_form: '\Drupal\custom_breadcrumbs\Form\CustomBreadcrumbsSettingsForm'
_title: 'Custom breadcrumb settings'
requirements:
_permission: 'administer custom_breadcrumbs'
services:
custom_breadcrumbs.breadcrumb:
class: Drupal\custom_breadcrumbs\BreadcrumbBuilder
arguments: ['@config.factory', '@entity_type.manager', '@language_manager', '@request_stack', '@title_resolver', '@token', '@path_alias.manager', '@path.matcher']
tags:
- { name: breadcrumb_builder, priority: 1003 }
This diff is collapsed.
<?php
namespace Drupal\custom_breadcrumbs;
use Drupal\Core\Config\Entity\ConfigEntityInterface;
/**
* Provides an interface defining a custom breadcrumbs entity type.
*/
interface CustomBreadcrumbsInterface extends ConfigEntityInterface {
}
<?php
namespace Drupal\custom_breadcrumbs;
use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
use Drupal\Core\Entity\EntityInterface;
/**
* Provides a listing of custom breadcrumbs.
*/
class CustomBreadcrumbsListBuilder extends ConfigEntityListBuilder {
/**
* {@inheritdoc}
*/
public function buildHeader() {
$header['label'] = $this->t('Label');
$header['entityType'] = $this->t('Entity type');
$header['entityBundle'] = $this->t('Entity bundle');
$header['language'] = $this->t('Language');
$header['status'] = $this->t('Status');
return $header + parent::buildHeader();
}
/**
* {@inheritdoc}
*/
public function buildRow(EntityInterface $entity) {
/** @var \Drupal\custom_breadcrumbs\CustomBreadcrumbsInterface $entity */
$row['label'] = $entity->label();
$row['entityType'] = $entity->get('entityType');
$row['entityBundlee'] = $entity->get('entityBundle');
$row['language'] = $entity->get('language');
$row['status'] = $entity->status() ? $this->t('Enabled') : $this->t('Disabled');
return $row + parent::buildRow($entity);
}
}
<?php
namespace Drupal\custom_breadcrumbs\Entity;
use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\custom_breadcrumbs\CustomBreadcrumbsInterface;
/**
* Defines the custom breadcrumbs entity type.
*
* @ConfigEntityType(
* id = "custom_breadcrumbs",
* label = @Translation("Custom breadcrumbs"),
* label_collection = @Translation("Custom breadcrumbs"),
* label_singular = @Translation("custom breadcrumb"),
* label_plural = @Translation("custom breadcrumbs"),
* label_count = @PluralTranslation(
* singular = "@count custom breadcrumb",
* plural = "@count custom breadcrumbs",
* ),
* handlers = {
* "list_builder" =
* "Drupal\custom_breadcrumbs\CustomBreadcrumbsListBuilder",
* "form" = {
* "add" = "Drupal\custom_breadcrumbs\Form\CustomBreadcrumbsForm",
* "edit" = "Drupal\custom_breadcrumbs\Form\CustomBreadcrumbsForm",
* "delete" = "Drupal\Core\Entity\EntityDeleteForm"
* }
* },
* config_prefix = "custom_breadcrumbs",
* admin_permission = "administer custom_breadcrumbs",
* links = {
* "collection" = "/admin/structure/custom-breadcrumbs",
* "add-form" = "/admin/structure/custom-breadcrumbs/add",
* "edit-form" =
* "/admin/structure/custom-breadcrumbs/{custom_breadcrumbs}",
* "delete-form" =
* "/admin/structure/custom-breadcrumbs/{custom_breadcrumbs}/delete"
* },
* entity_keys = {
* "id" = "id",
* "label" = "label",
* "uuid" = "uuid"
* },
* config_export = {
* "id",
* "label",
* "status",
* "description",
* "entityType",
* "entityBundle",
* "language",
* "breadcrumbPaths",
* "breadcrumbTitles",
* "type",
* "pathPattern",
* "extraCacheContexts"
* }
* )
*/
class CustomBreadcrumbs extends ConfigEntityBase implements CustomBreadcrumbsInterface {
/**
* The custom breadcrumb ID.
*
* @var string
*/
protected $id;
/**
* The custom breadcrumb label.
*
* @var string
*/
protected $label;
/**
* The custom breadcrumb status.
*
* @var bool
*/
protected $status;
/**
* The custom_breadcrumbs description.
*
* @var string
*/
protected $description;
/**
* The entity type.
*
* @var string
*/
protected $entityType;
/**
* The entity bundle.
*
* @var string
*/
protected $entityBundle;
/**
* Language.
*
* @var string
*/
protected $language;
/**
* Breadcrum paths.
*
* @var string
*/
protected $breadcrumbPaths;
/**
* The breadcrumb titles.
*
* @var string
*/
protected $breadcrumbTitles;
/**
* Type of breadcrumb.
*
* @var string
*/
protected $type;
/**
* Path pattern.
*
* @var string
*/
protected $pathPattern;
/**
* Extra cache contexts.
*
* @var string
*/
protected $extraCacheContexts;
/**
* Helper function to get values and split per one line.
*
* @param string $field
* Field name.
*
* @return array|false|string[]
* Values form field.
*/
public function getMultiValues($field) {
return preg_split('/\r\n|\r|\n/', $this->get($field));
}
}
<?php
namespace Drupal\custom_breadcrumbs\Form;
use Drupal\Core\Entity\ContentEntityType;
use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Custom breadcrumbs form.
*
* @property \Drupal\custom_breadcrumbs\CustomBreadcrumbsInterface $entity
*/
class CustomBreadcrumbsForm extends EntityForm {
/**
* EntityTypeBundleInfo.
*
* @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
*/
protected $entityTypeBundleInfo;
/**
* Language interface.
*
* @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
/**
* CustomBreadcrumbsForm constructor.
*
* @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entityTypeBundleInfo
* EntityTypeBundleInfo service.
* @param \Drupal\Core\Language\LanguageManagerInterface $languageManager
* LanguageManager service.
*/
public function __construct(EntityTypeBundleInfoInterface $entityTypeBundleInfo, LanguageManagerInterface $languageManager) {
$this->entityTypeBundleInfo = $entityTypeBundleInfo;
$this->languageManager = $languageManager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('entity_type.bundle.info'),
$container->get('language_manager')
);
}
/**
* {@inheritdoc}
*/
public function form(array $form, FormStateInterface $form_state) {
$form = parent::form($form, $form_state);
$form['label'] = [
'#type' => 'textfield',
'#title' => $this->t('Label'),
'#maxlength' => 255,
'#default_value' => $this->entity->label(),
'#description' => $this->t('Label for the custom breadcrumb.'),
'#required' => TRUE,
];
$form['id'] = [
'#type' => 'machine_name',
'#default_value' => $this->entity->id(),
'#machine_name' => [
'exists' => '\Drupal\custom_breadcrumbs\Entity\CustomBreadcrumbs::load',
],
'#disabled' => !$this->entity->isNew(),
];
$form['status'] = [
'#type' => 'checkbox',
'#title' => $this->t('Enabled'),
'#default_value' => $this->entity->status(),
];
$form['description'] = [
'#type' => 'textarea',
'#title' => $this->t('Description'),
'#default_value' => $this->entity->get('description'),
'#description' => $this->t('Description of the custom breadcrumb.'),
];
$form['type'] = [
'#type' => 'select',
'#title' => $this->t('Type of breadcrumb'),
'#options' => [
1 => $this->t('Content entity'),
2 => $this->t('Path'),
],
'#requires' => TRUE,
'#default_value' => $this->entity->get('type'),
];
$entity = $this->entity->get('entityType');
$entity = ($form_state->hasValue('entityType')) ? $form_state->getValue('entityType') : $entity;
$form['entityType'] = [
'#type' => 'select',
'#title' => $this->t('Entity type'),
'#default_value' => $entity,
'#description' => $this->t('Select your entity type.'),
'#options' => $this->getEntityTypes(),
'#empty_value' => '_none',
'#ajax' => [
'callback' => [$this, 'ajaxCallback'],
'wrapper' => 'entity_bundle_configuration',
'method' => 'replace',
'effect' => 'fade',
],
'#states' => [
'visible' => [
':input[name="type"]' => ['value' => '1'],
],
],
];
$form['entityBundle'] = [
'#prefix' => '<div id="entity_bundle_configuration">',
'#suffix' => '</div>',
'#type' => 'select',
'#title' => $this->t('Entity bundle'),
'#default_value' => $this->entity->get('entityBundle'),
'#description' => $this->t('Select your entity bundle.'),
'#options' => $this->getEntityBundle($entity),
'#empty_value' => '_none',
'#states' => [
'visible' => [
':input[name="type"]' => ['value' => '1'],
],
],
];
$form['language'] = [
'#type' => 'select',
'#title' => $this->t('Language'),
'#default_value' => $this->entity->get('language'),
'#description' => $this->t('Select language'),
'#options' => $this->getAvailableLanguages(),
];
$form['pathPattern'] = [
'#type' => 'textarea',
'#title' => $this->t('Path pattern'),
'#default_value' => $this->entity->get('pathPattern'),
'#description' => $this->t('A set of patterns separated by a newline.'),
'#states' => [
'visible' => [
':input[name="type"]' => ['value' => '2'],
],
],
];
$form['breadcrumbPaths'] = [
'#type' => 'textarea',
'#title' => $this->t('Breadcrumb paths'),
'#default_value' => $this->entity->get('breadcrumbPaths'),
'#required' => TRUE,
'#description' => $this->t('One url per line, you can use <a href="@token">Token</a> module. Url should start from "/".', ['@token' => 'https://www.drupal.org/project/token']),
];
$form['breadcrumbTitles'] = [
'#type' => 'textarea',
'#title' => $this->t('Breadcrumb titles'),
'#default_value' => $this->entity->get('breadcrumbTitles'),
'#required' => TRUE,
'#description' => $this->t('One title per line, you can use <a href="@token">Token</a> module.', ['@token' => 'https://www.drupal.org/project/token']),
];
$form['extraCacheContexts'] = [
'#type' => 'textarea',
'#title' => $this->t('Extra cache contexts'),
'#default_value' => $this->entity->get('extraCacheContexts'),
'#description' => $this->t('You can define an extra cache contexts for example for curent request query "url.query_args:search".'),
];
$form['token_tree'] = [
'#theme' => 'token_tree_link',
'#token_types' => [self::getTokenEntity($entity)],
'#show_restricted' => TRUE,
'#weight' => 90,
];
$form['token_details'] = [
'#type' => 'details',
'#title' => $this->t('Custom breadcrumbs extra vars'),
'#open' => FALSE,
];
$form['token_details']['vars'] = [
'#theme' => 'item_list',
'#items' => [
$this->t('&ltnolink&gt - adds ability to create crumb without url'),
$this->t('&ltterm_hierarchy:field_name&gt - taxonomy term field with hierarchy'),
],
];
return $form;
}
/**
* Get token type by entity.
*
* @param string $entity_type
* Entity type.
*
* @return string
* Array of token types.
*/
public static function getTokenEntity($entity_type) {
if ($entity_type === 'taxonomy_term') {
return 'term';
}
return $entity_type;
}
/**
* {@inheritdoc}
*/
public function save(array $form, FormStateInterface $form_state) {
$result = parent::save($form, $form_state);
$message_args = ['%label' => $this->entity->label()];
$message = $result == SAVED_NEW
? $this->t('Created new custom breadcrumb %label.', $message_args)
: $this->t('Updated custom breadcrumb %label.', $message_args);
$this->messenger()->addStatus($message);
$form_state->setRedirectUrl($this->entity->toUrl('collection'));
return $result;
}
/**
* Ajax callback for the entity bundle dependent configuration options.
*
* @param array $form
* Form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* Form State.
*
* @return array
* The form element containing the entity bundle options.
*/
public static function ajaxCallback(array &$form, FormStateInterface $form_state) {
return $form['entityBundle'];
}
/**
* Get all available content entity types.
*
* @return array
* Array of entity types.
*/
private function getEntityTypes() {
$options = [];
$options['_none'] = $this->t('Select entity type');
$types = $this->entityTypeManager->getDefinitions();
foreach ($types as $key => $type) {
if ($type instanceof ContentEntityType && $type->getLinkTemplates('canocical')) {
$options[$key] = $type->getLabel();
}
}
return $options;
}
/**
* Get list of entity bundle.
*
* @param string $entity
* Entity type.
*
* @return array
* Array of values.
*/
private function getEntityBundle($entity) {
$options = [];
$options['_none'] = $this->t('Select entity bundle');
foreach ($this->entityTypeBundleInfo->getBundleInfo($entity) as $key => $type) {
$options[$key] = $type['label'];
}
return $options;
}
/**
* Get all available languages.
*
* @return array
* Array of available languages.
*/
private function getAvailableLanguages() {
$options = ['und' => $this->t('Language not specified')];
$langs = $this->languageManager->getLanguages(LanguageInterface::STATE_CONFIGURABLE);
foreach ($langs as $key => $lang) {
$options[$key] = $lang->getName();
}
return $options;
}
}
<?php
namespace Drupal\custom_breadcrumbs\Form;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
/**
* Configure Custom breadcrumb settings for this site.
*/
class CustomBreadcrumbsSettingsForm extends ConfigFormBase {
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'custom_breadcrumbs_settings';
}
/**
* {@inheritdoc}
*/
protected function getEditableConfigNames() {
return ['custom_breadcrumbs.settings'];
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$config = $this->config('custom_breadcrumbs.settings');
$form['home'] = [
'#type' => 'checkbox',
'#title' => $this->t('Prepend default "Home" link'),
'#default_value' => $config->get('home'),
];
$form['home_link'] = [
'#type' => 'textfield',
'#title' => $this->t('"Home" text'),
'#default_value' => $config->get('home_link'),
'#states' => [
'visible' => [
'input[name="home"]' => ['checked' => TRUE],
],
],
];
$form['current_page'] = [
'#type' => 'checkbox',
'#title' => $this->t('Append curent page title like the latest crumb'),
'#default_value' => $config->get('current_page'),
];
$form['current_page_link'] = [
'#type' => 'checkbox',
'#title' => $this->t('Last crumb with link'),
'#default_value' => $config->get('current_page_link'),
'#states' => [
'visible' => [
'input[name="current_page"]' => ['checked' => TRUE],
],
],
];
$form['trim_title'] = [
'#type' => 'number',
'#title' => $this->t('Trim title length'),
'#default_value' => $config->get('trim_title'),
'#min' => 0,
];
return parent::buildForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$this->config('custom_breadcrumbs.settings')
->set('home', $form_state->getValue('home'))
->set('home_link', $form_state->getValue('home_link'))
->set('current_page', $form_state->getValue('current_page'))
->set('current_page_link', $form_state->getValue('current_page_link'))
->set('trim_title', $form_state->getValue('trim_title'))
->save();
parent::submitForm($form, $form_state);
}
}
File mode changed from 100644 to 100755
<?php
namespace Drupal\token;
use Drupal\Core\Field\EntityReferenceFieldItemList;
use Drupal\Core\TypedData\ComputedItemListTrait;
/**
* Defines a menu link list class for storen menu link information.
*
* @see token_entity_base_field_info()
*/
class MenuLinkFieldItemList extends EntityReferenceFieldItemList {
use ComputedItemListTrait;
/**
* {@inheritdoc}
*/
protected function computeValue() {
// This field does not really compute anything, it is used to store
// the referenced menu link.
return NULL;
}
}
<?php
namespace Drupal\token;
use Drupal\Core\Security\TrustedCallbackInterface;
use Drupal\Core\Render\Element;
class TokenFieldRender implements TrustedCallbackInterface {
/**
* {@inheritdoc}
*/
public static function trustedCallbacks() {
return ['preRender'];
}
/**
* Pre-render callback for field output used with tokens.
*/
public static function preRender($elements) {
// Remove the field theme hook, attachments, and JavaScript states.
unset($elements['#theme']);
unset($elements['#states']);
unset($elements['#attached']);
// Prevent multi-value fields from appearing smooshed together by appending
// a join suffix to all but the last value.
$deltas = Element::getVisibleChildren($elements);
$count = count($deltas);
if ($count > 1) {
$join = isset($elements['#token_options']['join']) ? $elements['#token_options']['join'] : ", ";
foreach ($deltas as $index => $delta) {
// Do not add a suffix to the last item.
if ($index < ($count - 1)) {
$elements[$delta] += ['#suffix' => $join];
}
}
}
return $elements;
}
}
......@@ -5,7 +5,7 @@ package: Testing
core_version_requirement: ^8.7.7 || ^9
hidden: TRUE
# Information added by Drupal.org packaging script on 2019-12-30
version: '8.x-1.6'
# Information added by Drupal.org packaging script on 2020-04-26
version: '8.x-1.7'
project: 'token'
datestamp: 1577708590
datestamp: 1587893591
......@@ -7,7 +7,7 @@ hidden: TRUE
dependencies:
- drupal:image
# Information added by Drupal.org packaging script on 2019-12-30
version: '8.x-1.6'
# Information added by Drupal.org packaging script on 2020-04-26
version: '8.x-1.7'
project: 'token'
datestamp: 1577708590
datestamp: 1587893591
......@@ -88,7 +88,7 @@ public function setUp($modules = []) {
'bundle' => 'article',
])->save();
entity_get_form_display('node', 'article', 'default')
\Drupal::service('entity_display.repository')->getFormDisplay('node', 'article', 'default')
->setComponent('field_body', [
'type' => 'text_textarea_with_summary',
'settings' => [
......
......@@ -3,13 +3,12 @@
namespace Drupal\Tests\token\Functional;
use Behat\Mink\Element\NodeElement;
use Drupal\node\Entity\Node;
use Drupal\Core\Url;
use Drupal\node\Entity\NodeType;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\Core\Language\LanguageInterface;
use Drupal\system\Entity\Menu;
use Drupal\menu_link_content\Entity\MenuLinkContent;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
use Drupal\system\Entity\Menu;
/**
* Tests menu tokens.
......@@ -103,7 +102,7 @@ function testMenuTokens() {
//$this->config('menu.entity.node.' . $node->getType())->set('available_menus', ['main-menu'])->save();
// Add a node menu link.
/** @var \Drupal\menu_link_content\Plugin\Menu\MenuLinkContent $node_link */
/** @var \Drupal\menu_link_content\MenuLinkContentInterface $node_link */
$node_link = MenuLinkContent::create([
'link' => ['uri' => 'entity:node/' . $node->id()],
'title' => 'Node link',
......@@ -120,7 +119,7 @@ function testMenuTokens() {
'menu-link:menu' => 'Main menu',
'menu-link:url' => $node->toUrl('canonical', ['absolute' => TRUE])->toString(),
'menu-link:url:path' => '/node/' . $node->id(),
'menu-link:edit-url' => $node_link->url('edit-form', ['absolute' => TRUE]),
'menu-link:edit-url' => $node_link->toUrl('edit-form', ['absolute' => TRUE])->toString(),
'menu-link:parent' => 'Configuration',
'menu-link:parent:id' => $parent_link->getPluginId(),
'menu-link:parents' => 'Administration, Configuration',
......@@ -185,7 +184,7 @@ function testMenuTokens() {
// @see token_node_menu_link_submit()
$selects = $this->cssSelect('select[name="menu[menu_parent]"]');
$select = reset($selects);
$options = $this->getAllOptions($select);
$options = $select->findAll('css', 'option');
// Filter to items with title containing 'Test preview'.
$options = array_filter($options, function (NodeElement $element) {
return strpos($element->getText(), 'Test preview') !== FALSE;
......@@ -217,7 +216,7 @@ function testMenuTokens() {
$this->drupalGet('node/add/page');
$selects = $this->cssSelect('select[name="menu[menu_parent]"]');
$select = reset($selects);
$options = $this->getAllOptions($select);
$options = $select->findAll('css', 'option');
// Filter to items with title containing 'Test preview'.
$options = array_filter($options, function (NodeElement $item) {
return strpos($item->getText(), 'Child link') !== FALSE;
......@@ -251,7 +250,7 @@ function testMenuTokens() {
->sort('id', 'ASC')
->range(0, 1);
$result = $query->execute();
$this->assertTrue($result);
$this->assertNotEmpty($result);
// Create a node with a menu link and create 2 menu links linking to this
// node after. Verify that the menu link provided by the node has priority.
......
......@@ -5,12 +5,15 @@
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Language\Language;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Tests\Traits\Core\PathAliasTestTrait;
/**
* Helper test trait with some added functions for testing.
*/
trait TokenTestTrait {
use PathAliasTestTrait;
function assertToken($type, array $data, $token, $expected, array $options = []) {
return $this->assertTokens($type, $data, [$token => $expected], $options);
}
......@@ -28,7 +31,7 @@ function assertTokens($type, array $data, array $tokens, array $options = []) {
$this->fail(t("Token value for @token was not generated.", ['@type' => $type, '@token' => $token]));
}
elseif (!empty($options['regex'])) {
$this->assertTrue(preg_match('/^' . $expected . '$/', $replacements[$token]), t("Token value for @token was '@actual', matching regular expression pattern '@expected'.", ['@type' => $type, '@token' => $token, '@actual' => $replacements[$token], '@expected' => $expected]));
$this->assertEquals(1, preg_match('/^' . $expected . '$/', $replacements[$token]), t("Token value for @token was '@actual', matching regular expression pattern '@expected'.", ['@type' => $type, '@token' => $token, '@actual' => $replacements[$token], '@expected' => $expected]));
}
else {
$this->assertEquals($expected, $replacements[$token], t("Token value for @token was '@actual', expected value '@expected'.", ['@type' => $type, '@token' => $token, '@actual' => $replacements[$token], '@expected' => $expected]));
......@@ -57,13 +60,7 @@ function assertNoTokens($type, array $data, array $tokens, array $options = [])
}
function saveAlias($source, $alias, $language = Language::LANGCODE_NOT_SPECIFIED) {
$alias = [
'source' => $source,
'alias' => $alias,
'language' => $language,
];
\Drupal::service('path.alias_storage')->save($alias['source'], $alias['alias']);
return $alias;
return $this->createPathAlias($source, $alias, $language);
}
function saveEntityAlias($entity_type, EntityInterface $entity, $alias, $language = Language::LANGCODE_NOT_SPECIFIED) {
......@@ -103,7 +100,7 @@ function assertPageTokens($url, array $tokens, array $data = [], array $options
$this->fail(t('Failed to generate token @token.', ['@token' => $token]));
}
else {
$this->assertIdentical($result['values'][$token], (string) $expected, t("Token value for @token was '@actual', expected value '@expected'.", ['@token' => $token, '@actual' => $result['values'][$token], '@expected' => $expected]));
$this->assertSame($result['values'][$token], (string) $expected, t("Token value for @token was '@actual', expected value '@expected'.", ['@token' => $token, '@actual' => $result['values'][$token], '@expected' => $expected]));
}
}
}
......
......@@ -17,7 +17,7 @@
use Drupal\Component\Utility\Html;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\Tests\taxonomy\Functional\TaxonomyTestTrait;
use Drupal\Tests\taxonomy\Traits\TaxonomyTestTrait;
/**
* Tests field tokens.
......@@ -401,7 +401,7 @@ public function testTokenViewMode() {
'targetEntityType' => 'node',
]);
$view_mode->save();
$entity_display = entity_get_display('node', 'article', 'token');
$entity_display = \Drupal::service('entity_display.repository')->getViewDisplay('node', 'article', 'token');
$entity_display->setComponent('test_field', [
'type' => 'text_trimmed',
'settings' => [
......
......@@ -17,7 +17,7 @@
*
* @var array
*/
public static $modules = ['path', 'token', 'token_module_test', 'system', 'user'];
public static $modules = ['path', 'token', 'token_module_test', 'system', 'user', 'path_alias'];
/**
* {@inheritdoc}
......@@ -25,9 +25,7 @@
protected function setUp() {
parent::setUp();
if (\Drupal::entityTypeManager()->hasDefinition('path_alias')) {
$this->installEntitySchema('path_alias');
}
\Drupal::service('router.builder')->rebuild();
$this->installConfig(['system']);
}
......
......@@ -21,7 +21,7 @@ function testRandomTokens() {
$first_set = $this->assertTokens('random', [], $tokens, ['regex' => TRUE]);
$second_set = $this->assertTokens('random', [], $tokens, ['regex' => TRUE]);
foreach ($first_set as $token => $value) {
$this->assertNotIdentical($first_set[$token], $second_set[$token]);
$this->assertNotSame($first_set[$token], $second_set[$token]);
}
}
......
type: module
name: Token
description: Provides a user interface for the Token API and some missing core tokens.
core_version_requirement: ^8.7.7 || ^9
core_version_requirement: ^8.8 || ^9
# Information added by Drupal.org packaging script on 2019-12-30
version: '8.x-1.6'
# Information added by Drupal.org packaging script on 2020-04-26
version: '8.x-1.7'
project: 'token'
datestamp: 1577708590
datestamp: 1587893591
......@@ -673,6 +673,7 @@ function token_entity_base_field_info(EntityTypeInterface $entity_type) {
->setDescription(t('Computed menu link for the node (only available during node saving).'))
->setRevisionable(TRUE)
->setSetting('target_type', 'menu_link_content')
->setClass('\Drupal\token\MenuLinkFieldItemList')
->setTranslatable(TRUE)
->setInternal(TRUE)
->setDisplayOptions('view', [
......@@ -701,12 +702,6 @@ function token_form_node_form_alter(&$form, FormStateInterface $form_state) {
if (!\Drupal::moduleHandler()->moduleExists('menu_ui')) {
return;
}
/** @var \Drupal\node\NodeForm $form_object */
if (!\Drupal::currentUser()->hasPermission('administer menu')) {
// We're only interested in when the node is unsaved and the editor has
// permission to create new menu links.
return;
}
$form['#entity_builders'][] = 'token_node_menu_link_submit';
}
......
......@@ -791,7 +791,7 @@ function token_tokens($type, array $tokens, array $data = [], array $options = [
if ($arg_tokens = \Drupal::token()->findWithPrefix($tokens, 'arg')) {
$path = ltrim(\Drupal::service('path.current')->getPath(), '/');
// Make sure its a system path.
$path = \Drupal::service('path.alias_manager')->getPathByAlias($path);
$path = \Drupal::service('path_alias.manager')->getPathByAlias($path);
foreach ($arg_tokens as $name => $original) {
$parts = explode('/', $path);
if (is_numeric($name) && isset($parts[$name])) {
......@@ -848,13 +848,13 @@ function token_tokens($type, array $tokens, array $data = [], array $options = [
foreach ($tokens as $name => $original) {
switch ($name) {
case 'path':
$value = !($url->getOption('alias')) ? \Drupal::service('path.alias_manager')->getAliasByPath($path, $langcode) : $path;
$value = !($url->getOption('alias')) ? \Drupal::service('path_alias.manager')->getAliasByPath($path, $langcode) : $path;
$replacements[$original] = $value;
break;
case 'alias':
// @deprecated
$alias = \Drupal::service('path.alias_manager')->getAliasByPath($path, $langcode);
$alias = \Drupal::service('path_alias.manager')->getAliasByPath($path, $langcode);
$replacements[$original] = $alias;
break;
......@@ -876,7 +876,7 @@ function token_tokens($type, array $tokens, array $data = [], array $options = [
break;
case 'args':
$value = !($url->getOption('alias')) ? \Drupal::service('path.alias_manager')->getAliasByPath($path, $langcode) : $path;
$value = !($url->getOption('alias')) ? \Drupal::service('path_alias.manager')->getAliasByPath($path, $langcode) : $path;
$replacements[$original] = token_render_array(explode('/', $value), $options);
break;
}
......@@ -884,7 +884,7 @@ function token_tokens($type, array $tokens, array $data = [], array $options = [
// [url:args:*] chained tokens.
if ($arg_tokens = \Drupal::token()->findWithPrefix($tokens, 'args')) {
$value = !($url->getOption('alias')) ? \Drupal::service('path.alias_manager')->getAliasByPath($path, $langcode) : $path;
$value = !($url->getOption('alias')) ? \Drupal::service('path_alias.manager')->getAliasByPath($path, $langcode) : $path;
$replacements += \Drupal::token()->generate('array', $arg_tokens, ['array' => explode('/', ltrim($value, '/'))], $options, $bubbleable_metadata);
}
......@@ -1024,7 +1024,7 @@ function token_tokens($type, array $tokens, array $data = [], array $options = [
$algos = hash_algos();
foreach ($hash_tokens as $name => $original) {
if (in_array($name, $algos)) {
$replacements[$original] = hash($name, Crypt::randomBytes(55));
$replacements[$original] = hash($name, random_bytes(55));
}
}
}
......@@ -1630,7 +1630,7 @@ function field_tokens($type, $tokens, array $data = [], array $options = [], Bub
$field_output = $entity->$field_name->view($display_options);
// If we are displaying all field items we need this #pre_render
// callback.
$field_output['#pre_render'][] = 'token_pre_render_field_token';
$field_output['#pre_render'][] = '\Drupal\token\TokenFieldRender::preRender';
}
$field_output['#token_options'] = $options;
$replacements[$original] = \Drupal::service('renderer')->renderPlain($field_output);
......@@ -1773,28 +1773,3 @@ function field_tokens($type, $tokens, array $data = [], array $options = [], Bub
}
return $replacements;
}
/**
* Pre-render callback for field output used with tokens.
*/
function token_pre_render_field_token($elements) {
// Remove the field theme hook, attachments, and JavaScript states.
unset($elements['#theme']);
unset($elements['#states']);
unset($elements['#attached']);
// Prevent multi-value fields from appearing smooshed together by appending
// a join suffix to all but the last value.
$deltas = Element::getVisibleChildren($elements);
$count = count($deltas);
if ($count > 1) {
$join = isset($elements['#token_options']['join']) ? $elements['#token_options']['join'] : ", ";
foreach ($deltas as $index => $delta) {
// Do not add a suffix to the last item.
if ($index < ($count - 1)) {
$elements[$delta] += ['#suffix' => $join];
}
}
}
return $elements;
}
......@@ -1252,6 +1252,75 @@
"source": "https://git.drupalcode.org/project/csv_serialization"
}
},
{
"name": "drupal/custom_breadcrumbs",
"version": "1.0.0-alpha1",
"version_normalized": "1.0.0.0-alpha1",
"source": {
"type": "git",
"url": "https://git.drupalcode.org/project/custom_breadcrumbs.git",
"reference": "1.0.0-alpha1"
},
"dist": {
"type": "zip",
"url": "https://ftp.drupal.org/files/projects/custom_breadcrumbs-1.0.0-alpha1.zip",
"reference": "1.0.0-alpha1",
"shasum": "1a89f33be922e687662ae47d9a9b7c41e995139f"
},
"require": {
"drupal/core": "^8 || ^9",
"drupal/token": "^1.0"
},
"type": "drupal-module",
"extra": {
"drupal": {
"version": "1.0.0-alpha1",
"datestamp": "1594887609",
"security-coverage": {
"status": "not-covered",
"message": "Project has not opted into security advisory coverage!"
}
}
},
"installation-source": "dist",
"notification-url": "https://packages.drupal.org/8/downloads",
"license": [
"GPL-2.0+"
],
"authors": [
{
"name": "Szczepan Musial (lamp5)",
"homepage": "https://www.drupal.org/u/lamp5",
"role": "Maintainer"
},
{
"name": "Contributors",
"homepage": "https://www.drupal.org/node/98576/committers",
"role": "Contributors"
},
{
"name": "colan",
"homepage": "https://www.drupal.org/user/58704"
},
{
"name": "lamp5",
"homepage": "https://www.drupal.org/user/2870321"
},
{
"name": "thePanz",
"homepage": "https://www.drupal.org/user/58689"
}
],
"description": "Custom breadcrumbs helps the user to create and manage breadcrumbs menu on all content entity pages and other like views, page manager, controllers.",
"homepage": "https://www.drupal.org/project/custom_breadcrumbs",
"keywords": [
"Drupal"
],
"support": {
"source": "http://cgit.drupalcode.org/custom_breadcrumbs",
"issues": "https://www.drupal.org/project/issues/custom_breadcrumbs"
}
},
{
"name": "drupal/easy_breadcrumb",
"version": "1.13.0",
......@@ -1333,6 +1402,77 @@
"issues": "https://www.drupal.org/project/issues/easy_breadcrumb"
}
},
{
"name": "drupal/token",
"version": "1.7.0",
"version_normalized": "1.7.0.0",
"source": {
"type": "git",
"url": "https://git.drupalcode.org/project/token.git",
"reference": "8.x-1.7"
},
"dist": {
"type": "zip",
"url": "https://ftp.drupal.org/files/projects/token-8.x-1.7.zip",
"reference": "8.x-1.7",
"shasum": "c7e3a3757282e4c94e3c1fff08d01e22155cb853"
},
"require": {
"drupal/core": "^8.8 || ^9"
},
"type": "drupal-module",
"extra": {
"drupal": {
"version": "8.x-1.7",
"datestamp": "1589314266",
"security-coverage": {
"status": "covered",
"message": "Covered by Drupal's security advisory policy"
}
},
"drush": {
"services": {
"drush.services.yml": "^9 || ^10"
}
}
},
"installation-source": "dist",
"notification-url": "https://packages.drupal.org/8/downloads",
"license": [
"GPL-2.0+"
],
"authors": [
{
"name": "Berdir",
"homepage": "https://www.drupal.org/user/214652"
},
{
"name": "Dave Reid",
"homepage": "https://www.drupal.org/user/53892"
},
{
"name": "eaton",
"homepage": "https://www.drupal.org/user/16496"
},
{
"name": "fago",
"homepage": "https://www.drupal.org/user/16747"
},
{
"name": "greggles",
"homepage": "https://www.drupal.org/user/36762"
},
{
"name": "mikeryan",
"homepage": "https://www.drupal.org/user/4420"
}
],
"description": "Provides a user interface for the Token API, some missing core tokens.",
"homepage": "https://www.drupal.org/project/token",
"support": {
"source": "https://git.drupalcode.org/project/token"
}
},
{
"name": "drupal/views_data_export",
"version": "1.0.0",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment