Skip to content
Snippets Groups Projects
Commit 3571d5ec authored by Samuel Mortenson's avatar Samuel Mortenson Committed by Sam Mortenson
Browse files

Issue #3353114 by samuel.mortenson: Copy Single Directory Components and...

Issue #3353114 by samuel.mortenson: Copy Single Directory Components and auto-included co-located CSS/JS files
parent 1b3b95a6
No related branches found
No related tags found
No related merge requests found
Showing
with 167 additions and 12 deletions
......@@ -139,11 +139,22 @@ the providing module's path.
If your component has a library dependency, you can set `$dependencies` to an
array of library names.
If you prefer to have CSS/JS in a separate file, you can set `$library` to an
array that represents a Drupal library. This library will be included
automatically where your template is used, so there's no need to use
`{{ attach_library() }}`. Defining `$library` is useful if you don't like
defining assets inline, which doesn't suit everyone.
If you prefer to have CSS/JS in a separate file, there are two options:
1. Create a `component_id.css` or `component_id.js` file in the same directory
as your `component_id.sfc` file. These will be auto-included in a library
definition and loaded when your component renders.
Some library dependencies will be included based on the contents of your JS
file, for instance if `jQuery` is found, `core/jquery` will be added as a
dependency. Additional dependencies can be set by setting
`$library['dependencies']` in the PHP section of yoru `.sfc` file.
See modules/sfc_example/example_local_assets.sfc/css/js for an example.
2. Set `$library` to an array that represents a Drupal library. This library
will be included automatically where your template is used, so there's no need
to use `{{ attach_library() }}`.
Any and all combinations of defining libraries and CSS/JS should work.
......
.example_local_assets {
color: red;
}
.example_local_assets.clicked {
color: green;
}
/**
* @file
* Contains example JS for the example_local_assets component.
*/
(function ($, Drupal) {
"use strict";
/**
* Changes the color of the example component.
*
* @type {Drupal~behavior}
*/
Drupal.behaviors.sfcExampleLocalAssets = {
attach: function (context, settings) {
$(once('sfc-example-local-assets', '.example_local_assets', context)).each(function () {
$(this).click(function () {
$(this).toggleClass('clicked');
});
});
}
};
}(jQuery, Drupal));
<!--
If a CSS or JS file exists in the same directory as a component with the same
filename, they will automatically be loaded. This allows you to split up
CSS/JS into separate without defining $library.
-->
<template>
<div class="example_local_assets">
Click me to make sure local CSS/JS is still working!
</div>
</template>
......@@ -117,7 +117,11 @@ class SimpleComponentDeriver extends DeriverBase implements ContainerDeriverInte
$match = FALSE;
$should_cache = TRUE;
foreach ($this->container->getServiceIds() as $service_id) {
$service = $this->container->get($service_id);
try {
$service = $this->container->get($service_id);
} catch (\Exception $e) {
continue;
}
if ($service === $type) {
$match = $service_id;
break;
......
......@@ -263,21 +263,81 @@ class SimpleComponent extends ComponentBase {
* {@inheritdoc}
*/
protected function hasLibraryData() {
return (bool) $this->getFileData()['LIBRARY'];
return (bool) $this->getFileData()['LIBRARY'] || !empty($this->getLocalLibraryData());
}
/**
* {@inheritdoc}
*/
protected function getLibraryData() {
$local_library = $this->getLocalLibraryData();
$library = $this->getFileData()['LIBRARY'];
if (isset($library['css'])) {
foreach ($library['css'] as &$files) {
$this->processLibraryFiles($files);
if ($library) {
if (isset($library['css'])) {
foreach ($library['css'] as &$files) {
$this->processLibraryFiles($files);
}
}
if (isset($library['js'])) {
$this->processLibraryFiles($library['js']);
}
}
else {
$library = [];
}
if ($local_library) {
if (!empty($library['dependencies'])) {
unset($local_library['dependencies']);
}
$library = array_merge_recursive($library, $local_library);
}
return $library;
}
/**
* Returns a library definition if <plugin_id>.<css|js> files exist.
*
* @return array
* A library definition.
*/
protected function getLocalLibraryData() {
$parts = pathinfo($this->getComponentFileName());
$prefix = $parts['dirname'] . '/' . $parts['filename'];
$css = $prefix . '.css';
$js = $prefix . '.js';
$library = [];
if (file_exists($css)) {
$relative_css = str_replace($this->appRoot, '', $css);
$library['css'] = [
'base' => [
$relative_css => [],
],
];
}
if (isset($library['js'])) {
$this->processLibraryFiles($library['js']);
if (file_exists($js)) {
$relative_js = str_replace($this->appRoot, '', $js);
$library['js'] = [
$relative_js => [],
];
$contents = file_get_contents($js);
$dependencies = [];
$depmap = [
'once(' => 'core/once',
'jQuery' => 'core/jquery',
'Drupal.ajax' => 'core/drupal.ajax',
'Drupal.Ajax' => 'core/drupal.ajax',
'drupalSettings' => 'core/drupalSettings',
'Drupal.' => 'core/drupal',
];
foreach ($depmap as $search => $dep) {
if (strpos($contents, $search) !== FALSE) {
$dependencies[] = $dep;
}
}
$library['dependencies'] = $dependencies;
}
return $library;
}
......
body {
background: blue;
}
console.log(jQuery);
console.log('Hello world');
<template>
Hello world!
</template>
<?php
$library['dependencies'][] = 'core/sortable';
$library['css']['base']['main.css'] = [];
console.log(jQuery);
console.log(Drupal.ajax);
<template>
Hello world!
</template>
body {
color: blue;
}
......@@ -176,4 +176,20 @@ class SimpleComponentTest extends KernelTestBase {
$this->assertEquals(\Drupal::currentUser()->id(), $result);
}
/**
* Tests that local assets work as expected.
*/
public function testLocalLibrary() {
/** @var \Drupal\Component\Plugin\PluginManagerInterface $manager */
$manager = \Drupal::service('plugin.manager.single_file_component');
$component = $manager->createInstance('simple_local_assets');
$this->stringContains('main.css', array_keys($component->getLibrary()['css']['base'])[0]);
$this->stringContains('simple_local_assets.css', array_keys($component->getLibrary()['css']['base'])[1]);
$this->assertTrue(file_exists($this->root . array_keys($component->getLibrary()['css']['base'])[1]));
$this->assertTrue(file_exists($this->root . array_keys($component->getLibrary()['js'])[0]));
$this->assertEquals(['core/sortable'], $component->getLibrary()['dependencies']);
$component = $manager->createInstance('simple_local_deps');
$this->assertEquals(['core/jquery', 'core/drupal.ajax', 'core/drupal'], $component->getLibrary()['dependencies']);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment