addfolder

This commit is contained in:
2018-04-23 21:14:46 +02:00
parent cec9a0314b
commit a7cb972085
192 changed files with 16037 additions and 24 deletions
@@ -0,0 +1,116 @@
<?php
namespace Drupal\ng_lightbox\Form;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\ng_lightbox\NgLightbox;
use Symfony\Component\DependencyInjection\ContainerInterface;
class NgLightboxSettingsForm extends ConfigFormBase {
/**
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $config;
/**
* An array of Lightbox renderers.
*
* @var array
*/
protected $renderers = [];
/**
* Constructs a \Drupal\system\ConfigFormBase object.
*
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The factory for configuration objects.
*/
public function __construct(ConfigFactoryInterface $config_factory, array $lightbox_renderers) {
parent::__construct($config_factory);
$this->renderers = $lightbox_renderers;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('config.factory'),
$container->getParameter('ng_lightbox_renderers')
);
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$this->config = $this->configFactory()->getEditable('ng_lightbox.settings');
$form['container']['patterns'] = array(
'#type' => 'textarea',
'#title' => $this->t('Paths'),
'#default_value' => $this->config->get('patterns'),
'#description' => $this->t('New line separated paths that must start with a leading slash. Wildcard character is *. E.g. /comment/*/reply.'),
);
$form['container']['default_width'] = array(
'#type' => 'textfield',
'#title' => $this->t('Default Width'),
'#default_value' => $this->config->get('default_width'),
'#description' => $this->t('The default width for modals opened with NG Lightbox.'),
);
$form['container']['lightbox_class'] = array(
'#type' => 'textfield',
'#title' => $this->t('Lightbox Class'),
'#default_value' => $this->config->get('lightbox_class'),
'#description' => $this->t('The css custom class for modals opened with NG Lightbox.'),
);
$form['container']['skip_admin_paths'] = array(
'#title' => $this->t('Skip all admin paths'),
'#type' => 'checkbox',
'#default_value' => $this->config->get('skip_admin_paths'),
'#description' => $this->t('This will exclude all admin paths from the lightbox. If you want some paths, see hook_ng_lightbox_ajax_path_alter().'),
);
$form['container']['renderer'] = array(
'#title' => $this->t('Renderer'),
'#type' => 'select',
'#default_value' => $this->config->get('renderer') ?: NgLightbox::DEFAULT_MODAL,
'#description' => $this->t('Select which renderer should be used for the lightbox.'),
'#options' => $this->renderers,
);
return parent::buildForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$values = $form_state->getValues();
$this->config
->set('patterns', $values['patterns'])
->set('default_width', $values['default_width'])
->set('lightbox_class', $values['lightbox_class'])
->set('skip_admin_paths', $values['skip_admin_paths'])
->set('renderer', $values['renderer'])
->save();
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'ng_lightbox_settings';
}
/**
* {@inheritdoc}
*/
protected function getEditableConfigNames() {
return [];
}
}
+152
View File
@@ -0,0 +1,152 @@
<?php
namespace Drupal\ng_lightbox;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Path\AliasManagerInterface;
use Drupal\Core\Path\PathMatcherInterface;
use Drupal\Core\Routing\AdminContext;
use Drupal\Core\Routing\RouteMatch;
use Drupal\Core\Url;
use Symfony\Component\HttpFoundation\Request;
class NgLightbox {
/**
* The default modal when none is selected.
*/
const DEFAULT_MODAL = 'drupal_modal';
/**
* @var \Drupal\Core\Path\PathMatcherInterface
*/
protected $pathMatcher;
/**
* @var \Drupal\Core\Path\AliasManagerInterface
*/
protected $aliasManager;
/**
* @var \Drupal\Core\Config\ImmutableConfig
*/
protected $config;
/**
* @var \Drupal\Core\Routing\AdminContext
*/
protected $adminContext;
/**
* An array of paths that were already checked and their match status.
*
* @var array
*/
protected $matches = [];
/**
* Constructs a new NgLightbox service.
*
* @param \Drupal\Core\Path\PathMatcherInterface $path_matcher
* Patch matcher services for comparing the lightbox patterns.
* @param \Drupal\Core\Path\AliasManagerInterface $alias_manager
* Alias manager so we can also test path aliases.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory so we can get the lightbox settings.
*/
public function __construct(PathMatcherInterface $path_matcher, AliasManagerInterface $alias_manager, ConfigFactoryInterface $config_factory, AdminContext $admin_context) {
$this->pathMatcher = $path_matcher;
$this->aliasManager = $alias_manager;
$this->config = $config_factory->get('ng_lightbox.settings');
$this->adminContext = $admin_context;
}
/**
* Checks whether a give path matches the ng-lightbox path rules.
* This function checks both internal paths and aliased paths.
*
* @param \Drupal\Core\Url $url
* The Url object.
*
* @return bool
* TRUE if it matches the given rules.
*/
public function isNgLightboxEnabledPath(Url $url) {
// No lightbox on external Urls.
if ($url->isExternal()) {
return FALSE;
}
// If we don't want to enable the Lightbox on admin pages.
if ($this->config->get('skip_admin_paths') && $this->adminContext->isAdminRoute()) {
return FALSE;
}
// @TODO, decide whether we want to try and support paths or to adopt routes
// like core is trying to force us into.
$path = strtolower($url->toString());
// We filter out empty paths because some modules (such as Media) use
// theme_link() to generate links with empty paths and we filter out paths
// that do not start with a /, such as #hash-only URLs.
if (empty($path) || $path[0] !== '/') {
return FALSE;
}
// Remove the base path.
if ($base_path = \Drupal::request()->getBasePath()) {
$path = substr($path, strlen($base_path));
}
// Check the cache, see if we've handled this before.
if (isset($this->matches[$path])) {
return $this->matches[$path];
}
// Normalise the patterns as well so they match the normalised paths.
$patterns = strtolower($this->config->get('patterns'));
// Check for internal paths first which is much quicker than the alias lookup.
if ($this->pathMatcher->matchPath($path, $patterns)) {
$this->matches[$path] = TRUE;
}
else {
// Now check for aliases paths.
$aliased_path = strtolower($this->aliasManager->getAliasByPath($path));
if ($path != $aliased_path && $this->pathMatcher->matchPath($aliased_path, $patterns)) {
$this->matches[$path] = TRUE;
}
else {
// No match.
$this->matches[$path] = FALSE;
}
}
return $this->matches[$path];
}
/**
* Adds a lightbox to a link.
*
* @param array $link
* The link we want to add the lightbox to.
*/
public function addLightbox(array &$link) {
// Safety check if class isn't an array.
if (!isset($link['options']['attributes']['class'])) {
$link['options']['attributes']['class'] = array();
}
// Add our lightbox class.
$link['options']['attributes']['class'][] = 'use-ajax';
$link['options']['attributes']['data-dialog-type'] = str_replace('drupal_', '', $this->config->get('renderer') ?: static::DEFAULT_MODAL);
$data = [
'width' => $this->config->get('default_width'),
'dialogClass' => $this->config->get('lightbox_class'),
];
$link['options']['attributes']['data-dialog-options'] = json_encode($data);
}
}
@@ -0,0 +1,34 @@
<?php
/**
* @file
* Contains \Drupal\ng_lightbox\NgLightboxPass
*/
namespace Drupal\ng_lightbox;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* The NgLightboxPass class.
*/
class NgLightboxPass implements CompilerPassInterface {
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container) {
$lightbox_renderers = [];
foreach ($container->findTaggedServiceIds('render.main_content_renderer') as $id => $attributes_list) {
foreach ($attributes_list as $attributes) {
if (!empty($attributes['ng_lightbox'])) {
$format = $attributes['format'];
$lightbox_renderers[$format] = $attributes['ng_lightbox'];
}
}
}
$container->setParameter('ng_lightbox_renderers', $lightbox_renderers);
}
}
@@ -0,0 +1,53 @@
<?php
/**
* @file
* Contains \Drupal\ng_lightbox\NgLightboxServiceProvider
*/
namespace Drupal\ng_lightbox;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceProviderBase;
/**
* The NgLightboxServiceProvider class.
*/
class NgLightboxServiceProvider extends ServiceProviderBase {
/**
* {@inheritdoc}
*/
public function register(ContainerBuilder $container) {
$container->addCompilerPass(new NgLightboxPass());
}
/**
* {@inheritdoc}
*/
public function alter(ContainerBuilder $container) {
$this->addLightbox($container, 'main_content_renderer.dialog', 'Core Dialog');
$this->addLightbox($container, 'main_content_renderer.modal', 'Core Modal');
}
/**
* @param \Drupal\Core\DependencyInjection\ContainerBuilder $container
* @param $id
* @param $title
*/
protected function addLightbox(ContainerBuilder $container, $id, $title) {
$definition = $container->getDefinition($id);
$tags = $definition->getTags();
foreach ($tags as $delta => &$tag) {
if ($delta === 'render.main_content_renderer') {
foreach ($tag as &$attribute) {
$attribute['ng_lightbox'] = $title;
}
}
}
$definition->setTags($tags);
}
}
@@ -0,0 +1,131 @@
<?php
/**
* @file
* NG Lightbox tests.
*/
namespace Drupal\ng_lightbox\Tests;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
use Drupal\simpletest\KernelTestBase;
/**
* Test basic functionality of the lightbox.
*
* @group ng_lightbox
*/
class NgLightboxTest extends KernelTestBase {
/**
* @var array
*/
public static $modules = ['system', 'node', 'user', 'ng_lightbox'];
/**
* {@inheritdoc}
*/
public function setUp() {
parent::setUp();
$this->installSchema('system', ['router', 'url_alias']);
\Drupal::service('router.builder')->rebuild();
$this->installEntitySchema('node');
$this->installEntitySchema('user');
$this->installSchema('node', ['node_access']);
$this->installConfig(['ng_lightbox']);
// Create the node type.
NodeType::create(['type' => 'page'])->save();
}
/**
* Test the pattern matching for link paths.
*/
public function testPatternMatching() {
// Test the patterns are enabled on links as expected.
$node = Node::create(['type' => 'page', 'title' => $this->randomString()]);
$node->save();
$config = \Drupal::configFactory()->getEditable('ng_lightbox.settings');
$config->set('patterns', $node->url())->save();
$this->assertLightboxEnabled(\Drupal::l('Normal Path', $node->urlInfo()));
// Create a second node and make sure it doesn't get lightboxed.
$node = Node::create(['type' => 'page', 'title' => $this->randomString()]);
$node->save();
$this->assertLightboxNotEnabled(\Drupal::l('Normal Path', $node->urlInfo()));
// @TODO, these were in D7 but in D8, I can't see how you can even generate
// a link with such a format so maybe it isn't needed at all?
// The uppercase path should still be matched for a lightbox.
// $this->assertLightboxNotEnabled(\Drupal::l('Uppercase Path', 'NODE/1'));
// $this->assertLightboxNotEnabled(\Drupal::l('Alaised Path', $alias));
// $this->assertLightboxNotEnabled(\Drupal::l('Empty Path', ''));
}
/**
* Asserts the lightbox was enabled for the generated link.
*
* @param string $link
* The rendered link.
*/
protected function assertLightboxEnabled($link) {
$this->assertContains('use-ajax', $link);
$this->assertContains('data-dialog-type', $link);
}
/**
* Asserts the lightbox was not enabled for the generated link.
*
* @param string $link
* The rendered link.
*/
protected function assertLightboxNotEnabled($link) {
$this->assertNotContains('use-ajax', $link);
$this->assertNotContains('data-dialog-type', $link);
}
/**
* Asserts a string does exist in the haystack.
*
* @param string $needle
* The string to search for.
* @param string $haystack
* The string to search within.
* @param string $message
* The message to log.
*
* @return bool
* TRUE if it was found otherwise FALSE.
*/
protected function assertContains($needle, $haystack, $message = '') {
if (empty($message)) {
$message = t('%needle was found within %haystack', array('%needle' => $needle, '%haystack' => $haystack));
}
return $this->assertTrue(stripos($haystack, $needle) !== FALSE, $message);
}
/**
* Asserts a string does not exist in the haystack.
*
* @param string $needle
* The string to search for.
* @param string $haystack
* The string to search within.
* @param string $message
* The message to log.
*
* @return bool
* TRUE if it was not found otherwise FALSE.
*/
protected function assertNotContains($needle, $haystack, $message = '') {
if (empty($message)) {
$message = t('%needle was not found within %haystack', array('%needle' => $needle, '%haystack' => $haystack));
}
return $this->assertTrue(stripos($haystack, $needle) === FALSE, $message);
}
}
@@ -0,0 +1,48 @@
<?php
/**
* @file
* Contains \Drupal\ng_lightbox\Tests\NgLightboxWebTest
*/
namespace Drupal\ng_lightbox\Tests;
use Drupal\simpletest\WebTestBase;
/**
* A web test for NG Lightbox.
*
* @group ng_lightbox
*/
class NgLightboxWebTest extends WebTestBase {
protected $profile = 'minimal';
/**
* Default modules to enable.
*
* @var array
*/
public static $modules = ['ng_lightbox', 'views', 'node', 'filter'];
/**
* {@inheritdoc}
*/
public function setUp() {
parent::setUp();
$config = \Drupal::configFactory()->getEditable('ng_lightbox.settings');
$this->createContentType(['type' => 'page']);
$node = $this->drupalCreateNode();
$config->set('patterns', '/node/' . $node->id());
$config->save();
}
/**
* Test that we can render a modal even before selecting one from the admin.
*/
public function testDefaultModal() {
$this->drupalGet('/node');
$this->assertRaw('data-dialog-type="modal"');
}
}