Skip to content
This repository has been archived by the owner on Sep 30, 2024. It is now read-only.

Commit

Permalink
Added Tide Site Preview submodule. (#69)
Browse files Browse the repository at this point in the history
* Added Tide Site Preview submodule.

On-behalf-of: @salsadigitalauorg <[email protected]>
  • Loading branch information
sonnykt authored Dec 8, 2020
1 parent 912e59d commit c5360bd
Show file tree
Hide file tree
Showing 11 changed files with 461 additions and 3 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ Tide is a Drupal 8 distribution focused on delivering an API first, headless Dru
[![Pull Requests](https://img.shields.io/github/issues-pr/dpc-sdp/tide_page.svg)](https://github.com/dpc-sdp/tide_site/pulls)

## What is in this package
- Fiedls for `Site` taxonomy vocabulary
- JSONAPI module integration
- Fields for `Site` taxonomy vocabulary
- JSONAPI and Tide API module integration
- Preview Links support (with Tide API)
- Simple Sitemap integration configuration

## Installation
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
langcode: en
status: true
dependencies:
module:
- tide_site_preview
theme:
- seven
id: seven_tide_site_preview_links
theme: seven
region: highlighted
weight: -3
provider: null
plugin: tide_site_preview_links_block
settings:
id: tide_site_preview_links_block
label: 'Click the links below to preview this revision on frontend sites'
provider: tide_site_preview
label_display: visible
open_new_window: 1
visibility: { }
14 changes: 14 additions & 0 deletions modules/tide_site_preview/css/tide_site_preview.preview_links.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* @file
* Theme styles for the tide site preview links.
*/
.block-tide-site-preview-links-block {
border: 1px dashed #bbb;
margin: 2em 0;
background: #fff;
padding-left: 1em;
}

.tide-site-preview-link .site-name::after {
content: ':';
}
326 changes: 326 additions & 0 deletions modules/tide_site_preview/src/Plugin/Block/PreviewLinksBlock.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,326 @@
<?php

namespace Drupal\tide_site_preview\Plugin\Block;

use Drupal\Core\Access\AccessResult;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Drupal\node\NodeInterface;
use Drupal\taxonomy\TermInterface;
use Drupal\tide_site\TideSiteHelper;
use Exception;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
* Class PreviewLinksBlock.
*
* @Block(
* id = "tide_site_preview_links_block",
* admin_label = @Translation("Frontend Preview Links"),
* category = @Translation("Tide Site"),
* )
*
* @package Drupal\tide_site_preview\Plugin\Block
*/
class PreviewLinksBlock extends BlockBase implements ContainerFactoryPluginInterface {

/**
* Tide Site Helper service.
*
* @var \Drupal\tide_site\TideSiteHelper
*/
protected $siteHelper;

/**
* Route Match service.
*
* @var \Drupal\Core\Routing\RouteMatchInterface
*/
protected $routeMatch;

/**
* Entity Type Manage.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;

/**
* The current node.
*
* @var \Drupal\node\NodeInterface
*/
protected $currentNode;

/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, TideSiteHelper $site_helper, RouteMatchInterface $route_match, EntityTypeManagerInterface $entity_type_manager) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->siteHelper = $site_helper;
$this->routeMatch = $route_match;
$this->entityTypeManager = $entity_type_manager;
$this->getCurrentNode();
}

/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('tide_site.helper'),
$container->get('current_route_match'),
$container->get('entity_type.manager')
);
}

/**
* {@inheritdoc}
*/
public function blockForm($form, FormStateInterface $form_state) {
$form = parent::blockForm($form, $form_state);

$config = $this->getConfiguration();
$form['open_new_window'] = [
'#type' => 'checkbox',
'#title' => $this->t('Open preview links in a new window or browser tab'),
'#default_value' => $config['open_new_window'] ?? TRUE,
];

return $form;
}

/**
* {@inheritdoc}
*/
public function blockSubmit($form, FormStateInterface $form_state) {
parent::blockSubmit($form, $form_state);
$values = $form_state->getValues();
$this->configuration['open_new_window'] = $values['open_new_window'];
}

/**
* {@inheritdoc}
*/
public function blockAccess(AccountInterface $account) {
return AccessResult::allowedIf($account->hasPermission('view tide_site preview links'));
}

/**
* {@inheritdoc}
*/
public function build() {
if (!$this->currentNode || !$this->isValidRoute()) {
return [];
}

$preview_urls = [];
// Load all sites of the current node.
$sites = $this->siteHelper->getEntitySites($this->currentNode, TRUE);
if (!empty($sites['ids'])) {
// Generate the preview URLs on all sites.
foreach ($sites['ids'] as $site_id) {
$site = $this->siteHelper->getSiteById($site_id);
if ($site) {
$section = NULL;
if (!empty($sites['sections'][$site_id])) {
$section = $this->siteHelper->getSiteById($sites['sections'][$site_id]);
}
$preview_urls[$site_id] = $this->buildFrontendPreviewLink($this->currentNode, $site, $section);
}
}
}

// Prepend the preview URL of the primary site to the Preview Links.
$primary_site = $this->siteHelper->getEntityPrimarySite($this->currentNode);
if ($primary_site) {
$primary_site_section = NULL;
if (!empty($sites['sections'][$primary_site->id()])) {
$primary_site_section = $this->siteHelper->getSiteById($sites['sections'][$primary_site->id()]);
}
$primary_preview_url = $this->buildFrontendPreviewLink($this->currentNode, $primary_site, $primary_site_section);
unset($preview_urls[$primary_site->id()]);
array_unshift($preview_urls, $primary_preview_url);
}

$config = $this->getConfiguration();
$build = [
'#theme' => 'tide_site_preview_links',
'#node' => $this->currentNode,
'#open_in_new_window' => !(empty($config['open_new_window'])),
'#preview_links' => $preview_urls,
'#attached' => [
'library' => ['tide_site_preview/preview-links'],
],
];

return $build;
}

/**
* {@inheritdoc}
*/
public function getCacheContexts() {
$contexts = parent::getCacheContexts();
if ($this->currentNode) {
$contexts = Cache::mergeTags($contexts, $this->currentNode->getCacheContexts());
}
return Cache::mergeContexts($contexts, [
'url',
'url.query_args',
'user.roles',
]);
}

/**
* {@inheritdoc}
*/
public function getCacheTags() {
$tags = parent::getCacheTags();
if ($this->currentNode) {
$tags = Cache::mergeTags($tags, $this->currentNode->getCacheTags());
}
return $tags;
}

/**
* Check if the current route is valid for this block.
*
* @return bool
* TRUE if the route is Node view or Node revision view.
*/
protected function isValidRoute() : bool {
// Only display on Node view and Node Revision view.
$valid_routes = [
'entity.node.revision',
'entity.node.latest_version',
'entity.node.canonical',
];
$route_name = $this->routeMatch->getRouteName();
return in_array($route_name, $valid_routes);
}

/**
* Get the current node.
*
* @return \Drupal\node\NodeInterface|null
* The node.
*/
protected function getCurrentNode() : ?NodeInterface {
if ($this->currentNode) {
return $this->currentNode;
}

$route_name = $this->routeMatch->getRouteName();
// Load the node from URL.
/** @var \Drupal\node\NodeInterface $node */
$node = $this->routeMatch->getParameter('node');
if ($route_name === 'entity.node.revision') {
try {
$vid = $this->routeMatch->getParameter('node_revision');
$node = $this->entityTypeManager->getStorage('node')
->loadRevision($vid);
}
catch (Exception $exception) {
watchdog_exception('tide_site_preview', $exception);
$node = NULL;
}
}
$this->currentNode = $node;

return $this->currentNode;
}

/**
* Build the frontend preview link array of a node.
*
* @param \Drupal\node\NodeInterface $node
* The node.
* @param \Drupal\taxonomy\TermInterface $site
* The site of the preview link.
* @param \Drupal\taxonomy\TermInterface|null $section
* The section of the preview link.
*
* @return array
* The preview link array with following keys:
* * #site: The site object.
* * #section: The section object.
* * name: The site/section name.
* * url: The absolute URL of the preview link.
*/
protected function buildFrontendPreviewLink(NodeInterface $node, TermInterface $site, TermInterface $section = NULL) : array {
$config = $this->getConfiguration();
$url_options = [
'attributes' => !(empty($config['open_new_window'])) ? ['target' => '_blank'] : [],
];
if ($section) {
$url_options['query']['section'] = $section->id();
}

$preview_link = [
'#site' => $site,
'#section' => $section,
'name' => $site->getName(),
];
if ($section && $section->id() !== $site->id()) {
$preview_link['name'] = $site->getName() . ' - ' . $section->getName();
}
$site_base_url = $this->siteHelper->getSiteBaseUrl($site);
if ($node->isPublished() && $node->isDefaultRevision()) {
unset($url_options['query']['section']);
$preview_link['url'] = $this->getNodeFrontendUrl($node, $site_base_url, $url_options);
}
else {
$revision_id = $node->getLoadedRevisionId();
$is_latest_revision = $node->isLatestRevision();
$content_type = $node->bundle();
$url = !empty($site_base_url) ? ($site_base_url . '/preview/' . $content_type . '/' . $node->uuid() . '/' . ($is_latest_revision ? 'latest' : $revision_id)) : '';
$preview_link['url'] = (!empty($url) && !empty($url_options)) ? Url::fromUri($url, $url_options) : '';
}

return $preview_link;
}

/**
* Get the frontend URL of a node.
*
* @param \Drupal\node\NodeInterface $node
* The node.
* @param string $site_base_url
* The base URL of the frontend.
* @param array $url_options
* The extra options.
*
* @return \Drupal\Core\Url|string
* The Url.
*/
protected function getNodeFrontendUrl(NodeInterface $node, $site_base_url = '', array $url_options = []) {
try {
$url = $node->toUrl('canonical', [
'absolute' => TRUE,
'base_url' => $site_base_url,
] + $url_options);

$pattern = '/^\/site\-(\d+)\//';
if ($site_base_url) {
$pattern = '/' . preg_quote($site_base_url, '/') . '\/site\-(\d+)\//';
}
$clean_url = preg_replace($pattern, $site_base_url . '/', $url->toString());
return $clean_url ? Url::fromUri($clean_url, $url_options) : $url;
}
catch (Exception $exception) {
watchdog_exception('tide_site_preview', $exception);
}
return '';
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{#
/**
* @file
* Default theme implementation for the preview links.
*
* Available variables:
* - node: The node of the preview links.
* - open_in_new_window: whether to open all links in a new window.
* - preview_links: The preview links array, each item has:
* - name: The site/section name of the link.
* - url: The absolute URL of the preview link.
* - link: The pregenerated anchor link.
*
* @ingroup themeable
*/
#}
<ul class="tide-site-preview-links">
{% for link in preview_links %}
<li class="tide-site-preview-link">
<span class="site-name">{{ link.name }}</span> <span class="preview-link">{{ link.link }}</span>
</li>
{% endfor %}
</ul>
Loading

0 comments on commit c5360bd

Please sign in to comment.