contrib modules updates

This commit is contained in:
2019-02-27 10:39:59 +01:00
parent 04a4b8895d
commit e3cf889820
579 changed files with 18343 additions and 4076 deletions
@@ -23,8 +23,9 @@ of additional files. You can check the current status of installation at
/admin/reports/status or read below for further details on how to install
each player.
To install all external audio player libraries at once, you can run the drush
command drush audiofield-download
To install all external audio player libraries at once, you can run the Drush
command drush audiofield-download (Drush 8) or drush audiofield:download (Drush
9).
Audio.js Audio Player
Audio.js requires installation of the audio.js library located at
@@ -32,7 +33,8 @@ Audio.js Audio Player
subfolder titled "audiojs" should be placed in /libraries/audiojs such that
the file audio.min.js is found at /libraries/audiojs/.
Install through drush using command drush audiofield-download audiojs.
Install through drush using command drush audiofield-download audiojs
(Drush 8) or drush audiofield:download audiojs (Drush 9).
Audio.js does not offer any theme options, but can be fully styled by custom
CSS.
@@ -43,7 +45,8 @@ jPlayer Audio Player
in /libraries/jplayer. It should be installed such that the file
jquery.jplayer.min.js can be found at /libraries/jplayer/dist/jplayer/.
Install through drush using command drush audiofield-download jplayer.
Install through drush using command drush audiofield-download jplayer
(Drush 8) or drush audiofield:download jplayer (Drush 9).
jPlayer comes bundled with multiple skins by default. You can install
additional skins by placing them in /libraries/jplayer/dist/skin/ and
@@ -60,7 +63,8 @@ MediaElement Audio Player
in /libraries/mediaelement such that the file mediaelement-and-player.min.js
is found at /libraries/mediaelement/build/.
Install through drush using command drush audiofield-download mediaelement.
Install through drush using command drush audiofield-download mediaelement
(Drush 8) or drush audiofield:download mediaelement (Drush 9).
Projekktor Audio Player
Projekktor requires installation of the Projekktor library located at
@@ -73,7 +77,8 @@ Projekktor Audio Player
projekktor-1.3.09.min.js at /libraries/projekktor/. This file will not exist
unless the distribution has been properly compiled.
Install through drush using command drush audiofield-download projekktor.
Install through drush using command drush audiofield-download projekktor
(Drush 8) or drush audiofield:download projekktor (Drush 9).
SoundManager Audio Player
WordPress Audio Player requires installation of the SoundManager library
@@ -82,7 +87,8 @@ SoundManager Audio Player
that the file soundmanager2-nodebug-jsmin.js can be found at
/libraries/soundmanager/script/.
Install through drush using command drush audiofield-download soundmanager.
Install through drush using command drush audiofield-download soundmanager
(Drush 8) or drush audiofield:download soundmanager (Drush 9).
SoundManager is a highly configurable library. However, handling and allowing
for all of the possible configurations and implementations of SoundManager is
@@ -101,7 +107,8 @@ Wavesurfer Audio Player
but there are small feature differences between the two to be aware of. The
drush command will install the latest version.
Install through drush using command drush audiofield-download wavesurfer.
Install through drush using command drush audiofield-download waveplayer
(Drush 8) or drush audiofield:download waveplayer (Drush 9).
WordPress Audio Player
WordPress Audio Player requires installation of the Standalone version of
@@ -109,7 +116,8 @@ WordPress Audio Player
These files should be downloaded and placed in /libraries/wordpress-audio such
that the file audio-player.js can be found at /libraries/wordpress-audio.
Install through drush using command drush audiofield-download wordpress.
Install through drush using command drush audiofield-download wordpress
(Drush 8) or drush audiofield:download wordpress (Drush 9).
WordPress Audio Player only supports a single skin, but does support a
single audio player for multiple files. However, the multi-file version of
@@ -5,8 +5,8 @@ type: module
package: Field types
# core: '8.x'
# Information added by Drupal.org packaging script on 2017-12-27
version: '8.x-1.6'
# Information added by Drupal.org packaging script on 2018-11-26
version: '8.x-1.8'
core: '8.x'
project: 'audiofield'
datestamp: 1514414887
datestamp: 1543249984
@@ -1,18 +1,25 @@
{
"name": "drupal/audiofield",
"description": "AudioField Module",
"type": "drupal-module",
"license": "GPL-2.0+",
"homepage": "https://www.drupal.org/project/audiofield",
"minimum-stability": "dev",
"authors": [
{
"name": "Daniel Moberly",
"homepage": "https://www.drupal.org/u/danielmoberly",
"role": "Maintainer"
"name": "drupal/audiofield",
"description": "AudioField Module",
"type": "drupal-module",
"license": "GPL-2.0+",
"homepage": "https://www.drupal.org/project/audiofield",
"minimum-stability": "dev",
"authors": [
{
"name": "Daniel Moberly",
"homepage": "https://www.drupal.org/u/danielmoberly",
"role": "Maintainer"
}
],
"support": {
"issues": "https://www.drupal.org/project/issues/audiofield"
},
"extra": {
"drush": {
"services": {
"drush.services.yml": "^9"
}
}
}
],
"support": {
"issues": "https://www.drupal.org/project/issues/audiofield"
}
}
@@ -0,0 +1,7 @@
services:
audiofield.commands:
class: \Drupal\audiofield\Commands\AudiofieldCommands
arguments:
- '@plugin.manager.audiofield'
tags:
- { name: drush.command }
@@ -127,7 +127,7 @@
},
swfPath: '/libraries/jplayer/dist/jplayer',
wmode: 'window',
preload: settings.lazyload,
preload: file.lazyload,
keyEnabled: true,
supplied: file.filetype,
},
@@ -90,7 +90,7 @@
swfPath: '/libraries/jplayer/dist/jplayer',
wmode: 'window',
keyEnabled: true,
preload: settings.lazyload,
preload: file.lazyload,
supplied: file.filetype
});
});
@@ -23,6 +23,18 @@
// Create waveform.
const wavesurfer = WaveSurfer.create({
container: `#${$(wavecontainer).attr('id')} .waveform`,
audioRate: settings.audioRate,
autoCenter: settings.autoCenter,
barGap: settings.barGap,
barHeight: settings.barHeight,
barWidth: settings.barWidth,
cursorColor: settings.cursorColor,
cursorWidth: settings.cursorWidth,
forceDecode: settings.forceDecode,
normalize: settings.normalize,
progressColor: settings.progressColor,
responsive: settings.responsive,
waveColor: settings.waveColor,
});
// Load the file.
@@ -32,12 +44,12 @@
wavesurfer.setVolume(settings.volume);
// Handle play/pause.
$(wavecontainer).find('.player-button.playpause').on('click', () => {
$(wavecontainer).find('.player-button.playpause').on('click', (event) => {
Drupal.AudiofieldWavesurfer.PlayPause(wavecontainer, wavesurfer);
});
// Handle volume change.
$(wavecontainer).find('.volume').on('change', () => {
$(wavecontainer).find('.volume').on('change', (event) => {
wavesurfer.setVolume(($(event.currentTarget).val() / 10));
});
@@ -61,6 +73,18 @@
// Create waveform.
const wavesurfer = WaveSurfer.create({
container: `#${$(wavecontainer).attr('id')} .waveform`,
audioRate: settings.audioRate,
autoCenter: settings.autoCenter,
barGap: settings.barGap,
barHeight: settings.barHeight,
barWidth: settings.barWidth,
cursorColor: settings.cursorColor,
cursorWidth: settings.cursorWidth,
forceDecode: settings.forceDecode,
normalize: settings.normalize,
progressColor: settings.progressColor,
responsive: settings.responsive,
waveColor: settings.waveColor,
});
// Set the default volume.
@@ -77,28 +101,33 @@
wavesurfer.load(first.attr('data-src'));
// Handle play/pause.
$(wavecontainer).find('.player-button.playpause').on('click', () => {
$(wavecontainer).find('.player-button.playpause').on('click', (event) => {
Drupal.AudiofieldWavesurfer.PlayPause(wavecontainer, wavesurfer);
});
// Handle next/previous.
$(wavecontainer).find('.player-button.next').on('click', () => {
$(wavecontainer).find('.player-button.next').on('click', (event) => {
Drupal.AudiofieldWavesurfer.Next(wavecontainer, wavesurfer);
});
$(wavecontainer).find('.player-button.previous').on('click', () => {
$(wavecontainer).find('.player-button.previous').on('click', (event) => {
Drupal.AudiofieldWavesurfer.Previous(wavecontainer, wavesurfer);
});
// Handle clicking track.
$(wavecontainer).find('.playlist .track').on('click', () => {
// Load the track.
Drupal.AudiofieldWavesurfer.Load(wavecontainer, wavesurfer, $(event.currentTarget));
// Play the track.
Drupal.AudiofieldWavesurfer.PlayPause(wavecontainer, wavesurfer);
$(wavecontainer).find('.playlist .track').on('click', (event) => {
// Check if the track is already playing.
if ($(this).hasClass('playing')) {
// Play/pause the track if it is already loaded.
Drupal.AudiofieldWavesurfer.PlayPause(wavecontainer, wavesurfer);
}
else {
// Load the track.
Drupal.AudiofieldWavesurfer.Load(wavecontainer, wavesurfer, $(event.currentTarget));
}
});
// Handle volume change.
$(wavecontainer).find('.volume').on('change', () => {
$(wavecontainer).find('.volume').on('change', (event) => {
wavesurfer.setVolume(($(event.currentTarget).val() / 10));
});
@@ -108,7 +137,7 @@
}
// Handle track finishing.
wavesurfer.on('finish', () => {
wavesurfer.on('finish', (event) => {
Drupal.AudiofieldWavesurfer.Next(wavecontainer, wavesurfer);
});
});
@@ -147,13 +176,13 @@
*/
Drupal.AudiofieldWavesurfer.Load = (wavecontainer, wavesurfer, track) => {
// Load the track.
wavesurfer.on('ready', () => {
wavesurfer.play();
wavesurfer.load(track.attr('data-src'));
wavesurfer.on('ready', (event) => {
$(wavecontainer).removeClass('playing');
$(wavecontainer).addClass('playing');
$(wavecontainer).find('.player-button.playpause').html('Pause');
wavesurfer.play();
});
wavesurfer.load(track.attr('data-src'));
// Remove playing from all other tracks.
$(wavecontainer).find('.track').removeClass('playing');
// Set the class on this track.
@@ -13,18 +13,30 @@
Drupal.AudiofieldWavesurfer.generate = function (context, file, settings) {
$.each($(context).find('#' + file.id).once('generate-waveform'), function (index, wavecontainer) {
var wavesurfer = WaveSurfer.create({
container: '#' + $(wavecontainer).attr('id') + ' .waveform'
container: '#' + $(wavecontainer).attr('id') + ' .waveform',
audioRate: settings.audioRate,
autoCenter: settings.autoCenter,
barGap: settings.barGap,
barHeight: settings.barHeight,
barWidth: settings.barWidth,
cursorColor: settings.cursorColor,
cursorWidth: settings.cursorWidth,
forceDecode: settings.forceDecode,
normalize: settings.normalize,
progressColor: settings.progressColor,
responsive: settings.responsive,
waveColor: settings.waveColor
});
wavesurfer.load(file.path);
wavesurfer.setVolume(settings.volume);
$(wavecontainer).find('.player-button.playpause').on('click', function () {
$(wavecontainer).find('.player-button.playpause').on('click', function (event) {
Drupal.AudiofieldWavesurfer.PlayPause(wavecontainer, wavesurfer);
});
$(wavecontainer).find('.volume').on('change', function () {
$(wavecontainer).find('.volume').on('change', function (event) {
wavesurfer.setVolume($(event.currentTarget).val() / 10);
});
@@ -37,7 +49,19 @@
Drupal.AudiofieldWavesurfer.generatePlaylist = function (context, settings) {
$.each($(context).find('#wavesurfer_playlist').once('generate-waveform'), function (index, wavecontainer) {
var wavesurfer = WaveSurfer.create({
container: '#' + $(wavecontainer).attr('id') + ' .waveform'
container: '#' + $(wavecontainer).attr('id') + ' .waveform',
audioRate: settings.audioRate,
autoCenter: settings.autoCenter,
barGap: settings.barGap,
barHeight: settings.barHeight,
barWidth: settings.barWidth,
cursorColor: settings.cursorColor,
cursorWidth: settings.cursorWidth,
forceDecode: settings.forceDecode,
normalize: settings.normalize,
progressColor: settings.progressColor,
responsive: settings.responsive,
waveColor: settings.waveColor
});
wavesurfer.setVolume(settings.volume);
@@ -51,24 +75,27 @@
wavesurfer.load(first.attr('data-src'));
$(wavecontainer).find('.player-button.playpause').on('click', function () {
$(wavecontainer).find('.player-button.playpause').on('click', function (event) {
Drupal.AudiofieldWavesurfer.PlayPause(wavecontainer, wavesurfer);
});
$(wavecontainer).find('.player-button.next').on('click', function () {
$(wavecontainer).find('.player-button.next').on('click', function (event) {
Drupal.AudiofieldWavesurfer.Next(wavecontainer, wavesurfer);
});
$(wavecontainer).find('.player-button.previous').on('click', function () {
$(wavecontainer).find('.player-button.previous').on('click', function (event) {
Drupal.AudiofieldWavesurfer.Previous(wavecontainer, wavesurfer);
});
$(wavecontainer).find('.playlist .track').on('click', function () {
Drupal.AudiofieldWavesurfer.Load(wavecontainer, wavesurfer, $(event.currentTarget));
Drupal.AudiofieldWavesurfer.PlayPause(wavecontainer, wavesurfer);
$(wavecontainer).find('.playlist .track').on('click', function (event) {
if ($(this).hasClass('playing')) {
Drupal.AudiofieldWavesurfer.PlayPause(wavecontainer, wavesurfer);
}
else {
Drupal.AudiofieldWavesurfer.Load(wavecontainer, wavesurfer, $(event.currentTarget));
}
});
$(wavecontainer).find('.volume').on('change', function () {
$(wavecontainer).find('.volume').on('change', function (event) {
wavesurfer.setVolume($(event.currentTarget).val() / 10);
});
@@ -76,7 +103,7 @@
wavesurfer.on('ready', wavesurfer.play.bind(wavesurfer));
}
wavesurfer.on('finish', function () {
wavesurfer.on('finish', function (event) {
Drupal.AudiofieldWavesurfer.Next(wavecontainer, wavesurfer);
});
});
@@ -95,13 +122,13 @@
};
Drupal.AudiofieldWavesurfer.Load = function (wavecontainer, wavesurfer, track) {
wavesurfer.on('ready', function () {
wavesurfer.play();
wavesurfer.load(track.attr('data-src'));
wavesurfer.on('ready', function (event) {
$(wavecontainer).removeClass('playing');
$(wavecontainer).addClass('playing');
$(wavecontainer).find('.player-button.playpause').html('Pause');
wavesurfer.play();
});
wavesurfer.load(track.attr('data-src'));
$(wavecontainer).find('.track').removeClass('playing');
@@ -9,11 +9,62 @@ use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Component\Utility\Random;
use Drupal\Component\Plugin\PluginBase;
use Drupal\Core\Asset\LibraryDiscovery;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Messenger\Messenger;
use Drupal\Core\Logger\LoggerChannelFactoryInterface ;
/**
* Base class for audiofield plugins. Includes global functions.
*/
abstract class AudioFieldPluginBase extends PluginBase {
abstract class AudioFieldPluginBase extends PluginBase implements ContainerFactoryPluginInterface {
/**
* Library discovery service.
*
* @var Drupal\Core\Asset\LibraryDiscovery
*/
protected $libraryDiscovery;
/**
* Messenger service.
*
* @var Drupal\Core\Messenger\Messenger
*/
protected $messenger;
/**
* Messenger service.
*
* @var Drupal\Core\Logger\LoggerChannelFactoryInterface
*/
protected $loggerFactory;
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, LibraryDiscovery $library_discovery, Messenger $messenger, LoggerChannelFactoryInterface $logger_factory) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->libraryDiscovery = $library_discovery;
$this->messenger = $messenger;
$this->loggerFactory = $logger_factory;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('library.discovery'),
$container->get('messenger'),
$container->get('logger.factory')
);
}
/**
* Renders the player.
@@ -68,7 +119,7 @@ abstract class AudioFieldPluginBase extends PluginBase {
*/
public function getPluginLibrary() {
// Get the main library for this plugin.
return \Drupal::service('library.discovery')->getLibraryByName('audiofield', 'audiofield.' . $this->getPluginLibraryName());
return $this->libraryDiscovery->getLibraryByName('audiofield', 'audiofield.' . $this->getPluginLibraryName());
}
/**
@@ -170,8 +221,8 @@ abstract class AudioFieldPluginBase extends PluginBase {
'%command' => 'drush audiofield-update',
'@status_report' => Link::createFromRoute('status report', 'system.status')->toString(),
];
\Drupal::logger('audiofield')->warning('Warning: @plugin library is out of date. You should upgrade from version @version to version @newversion. You can manually download the required version here: @download-link or you can install automatically by running the command %command. See the @status_report for more information', $message_data);
drupal_set_message(t('Warning: @plugin library is out of date. You should upgrade from version @version to version @newversion. You can manually download the required version here: @download-link or you can install automatically by running the command %command. See the @status_report for more information', $message_data), 'warning');
$this->loggerFactory->get('audiofield')->warning('Warning: @plugin library is out of date. You should upgrade from version @version to version @newversion. You can manually download the required version here: @download-link or you can install automatically by running the command %command. See the @status_report for more information', $message_data);
$this->messenger->addWarning(t('Warning: @plugin library is out of date. You should upgrade from version @version to version @newversion. You can manually download the required version here: @download-link or you can install automatically by running the command %command. See the @status_report for more information', $message_data));
}
return FALSE;
}
@@ -186,8 +237,8 @@ abstract class AudioFieldPluginBase extends PluginBase {
'@library_name' => $this->getPluginLibraryName(),
'@status_report' => Link::createFromRoute('status report', 'system.status')->toString(),
];
\Drupal::logger('audiofield')->error('Error: @library_name library is not currently installed! See the @status_report for more information.', $message_data);
drupal_set_message(t('Error: @library_name library is not currently installed! See the @status_report for more information.', $message_data), 'error');
$this->loggerFactory->get('audiofield')->error('Error: @library_name library is not currently installed! See the @status_report for more information.', $message_data);
$this->messenger->addWarning(t('Error: @library_name library is not currently installed! See the @status_report for more information.', $message_data));
}
/**
@@ -208,8 +259,8 @@ abstract class AudioFieldPluginBase extends PluginBase {
'@player' => $this->getPluginLibraryName(),
'%extensions' => implode(', ', $this->pluginDefinition["fileTypes"]),
];
\Drupal::logger('audiofield')->error('Error playing file %filename: currently selected audio player only supports the following extensions: %extensions', $message_data);
drupal_set_message(t('Error playing file %filename: currently selected audio player only supports the following extensions: %extensions', $message_data), 'error');
$this->loggerFactory->get('audiofield')->error('Error playing file %filename: currently selected audio player only supports the following extensions: %extensions', $message_data);
$this->messenger->addWarning(t('Error playing file %filename: currently selected audio player only supports the following extensions: %extensions', $message_data));
return FALSE;
}
return TRUE;
@@ -232,8 +283,8 @@ abstract class AudioFieldPluginBase extends PluginBase {
$message_data = [
'%link' => $link->toString(),
];
\Drupal::logger('audiofield')->error('Error playing file: invalid link: %link', $message_data);
drupal_set_message(t('Error playing file: invalid link: %link', $message_data), 'error');
$this->loggerFactory->get('audiofield')->error('Error playing file: invalid link: %link', $message_data);
$this->messenger->addWarning(t('Error playing file: invalid link: %link', $message_data));
return FALSE;
}
return TRUE;
@@ -366,20 +417,19 @@ abstract class AudioFieldPluginBase extends PluginBase {
* The source URL of an entity.
*/
private function getAudioSource($item) {
$source_url = '';
if ($this->getClassType($item) == 'FileItem') {
// Load the associated file.
$file = $this->loadFileFromItem($item);
// Get the file URL.
$source_url = Url::fromUri(file_create_url($file->getFileUri()));
return Url::fromUri(file_create_url($file->getFileUri()));
}
// Handle Link entity.
elseif ($this->getClassType($item) == 'LinkItem') {
// Get the file URL.
$source_url = $item->getUrl();
return $item->getUrl();
}
return $source_url;
return '';
}
/**
@@ -392,7 +442,6 @@ abstract class AudioFieldPluginBase extends PluginBase {
* The description of an entity.
*/
private function getAudioDescription($item) {
$entity_description = '';
if ($this->getClassType($item) == 'FileItem') {
// Get the file description - use the filename if it doesn't exist.
$entity_description = $item->get('description')->getString();
@@ -400,19 +449,20 @@ abstract class AudioFieldPluginBase extends PluginBase {
// Load the associated file.
$file = $this->loadFileFromItem($item);
$entity_description = $file->getFilename();
return $file->getFilename();
}
return $entity_description;
}
// Handle Link entity.
elseif ($this->getClassType($item) == 'LinkItem') {
// Get the file description - use the filename if it doesn't exist.
$entity_description = $item->get('title')->getString();
if (empty($entity_description)) {
$entity_description = $item->getUrl()->toString();
return $item->getUrl()->toString();
}
return $entity_description;
}
return $entity_description;
return '';
}
/**
@@ -476,51 +526,29 @@ abstract class AudioFieldPluginBase extends PluginBase {
* A render array containing download links.
*/
public function createDownloadList($items, array $settings) {
$download_links = [];
// Check if download links are turned on.
if ($settings['download_link']) {
// Loop over each item.
foreach ($items as $item) {
// Get the source URL for this item.
$source_url = $this->getAudioSource($item);
// Get the entity description for this item.
$entity_description = $this->getAudioDescription($item);
// Add the link.
$download_links[] = [
'#markup' => Link::fromTextAndUrl($entity_description, $source_url)->toString(),
'#wrapper_attributes' => [
'class' => [
'audiofield-download-link',
],
],
];
}
// Check if download links are turned on and there are items.
if (!$settings['download_link'] || count($items) == 0) {
return [];
}
// Render links if we have them.
$download_render_array = [];
if (count($download_links) > 0) {
$download_render_array = [
'#theme' => 'item_list',
'#list_type' => 'ul',
'#title' => t('Download files:'),
'#wrapper_attributes' => [
'class' => [
'audiofield-downloads',
],
],
'#attributes' => [],
'#empty' => '',
'#items' => $download_links,
$links = [];
// Loop over each item.
foreach ($items as $item) {
// Get the source URL for this item.
$source_url = $this->getAudioSource($item);
// Get the entity description for this item.
$entity_description = $this->getAudioDescription($item);
// Add the link.
$links[] = [
'link' => Link::fromTextAndUrl($entity_description, $source_url)->toString(),
];
}
return [
'#theme' => 'audiofield_download_links',
'#links' => $download_render_array,
'#links' => $links,
];
}
@@ -0,0 +1,268 @@
<?php
namespace Drupal\audiofield\Commands;
use Drush\Commands\DrushCommands;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Finder\Finder;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use Drupal\audiofield\AudioFieldPlayerManager;
/**
* A Drush commandfile for Audiofield module.
*/
class AudiofieldCommands extends DrushCommands {
/**
* Library discovery service.
*
* @var Drupal\audiofield\AudioFieldPlayerManager
*/
protected $playerManager;
/**
* {@inheritdoc}
*/
public function __construct(AudioFieldPlayerManager $player_manager) {
$this->playerManager = $player_manager;
}
/**
* Downloads the suggested Audiofield libraries from their remote repos.
*
* @param string $installLibrary
* The name of the library. If omitted, all libraries will be installed.
* @param bool $print_messages
* Flag indicating if messages should be displayed.
*
* @command audiofield:download
* @aliases audiofield-download
*/
public function download($installLibrary = '', $print_messages = TRUE) {
// Declare filesystem container.
$fs = new Filesystem();
// Get a list of the audiofield plugins.
$pluginList = $this->playerManager->getDefinitions();
// If there is an argument, check to make sure its valid.
if (!empty($installLibrary)) {
if (!isset($pluginList[$installLibrary . '_audio_player'])) {
$this->logger()->error(dt('Error: @library is not a valid Audiofield library.', [
'@library' => $installLibrary,
], 'error'));
return;
}
// If the argument is valid, we only want to install that plugin.
$pluginList = [$installLibrary . '_audio_player' => $pluginList[$installLibrary . '_audio_player']];
}
// Loop over each plugin and make sure it's library is installed.
foreach ($pluginList as $pluginName => $plugin) {
// Create an instance of this plugin.
$pluginInstance = $this->playerManager->createInstance($pluginName);
// Only check install if there is a library for the plugin.
if (!$pluginInstance->getPluginLibrary()) {
continue;
}
// Skip if the plugin is installed.
if ($pluginInstance->checkInstalled()) {
if ($print_messages) {
$this->logger()->notice(dt('Audiofield library for @library is already installed at @location', [
'@library' => $pluginInstance->getPluginTitle(),
'@location' => $pluginInstance->getPluginLibraryPath(),
], 'success'));
}
continue;
}
// Get the library install path.
$path = DRUPAL_ROOT . $pluginInstance->getPluginLibraryPath();
// Create the install directory if it does not exist.
if (!is_dir($path)) {
$fs->mkdir($path);
}
// Download the file.
$client = new Client();
$destination = tempnam(sys_get_temp_dir(), 'file.') . "tar.gz";
try {
$client->get($pluginInstance->getPluginRemoteSource(), ['save_to' => $destination]);
}
catch (RequestException $e) {
// Remove the directory.
$fs->remove($path);
$this->logger()->error(dt('Error: unable to download @library. @exception', [
'@library' => $pluginInstance->getPluginTitle(),
'@exception' => $e->getMessage(),
], 'error'));
continue;
}
$fs->rename($destination, $path . '/audiofield-dl.zip');
if (!file_exists($path . '/audiofield-dl.zip')) {
// Remove the directory where we tried to install.
$fs->remove($path);
if ($print_messages) {
$this->logger()->error(dt('Error: unable to download Audiofield library @library', [
'@library' => $pluginInstance->getPluginTitle(),
], 'error'));
continue;
}
}
// Unzip the file.
$zip = new \ZipArchive();
$res = $zip->open($path . '/audiofield-dl.zip');
if ($res === TRUE) {
$zip->extractTo($path);
$zip->close();
}
else {
// Remove the directory.
$fs->remove($path);
$this->logger()->error(dt('Error: unable to unzip @library.', [
'@library' => $pluginInstance->getPluginTitle(),
], 'error'));
continue;
}
// Remove the downloaded zip file.
$fs->remove($path . '/audiofield-dl.zip');
// If the library still is not installed, we need to move files.
if (!$pluginInstance->checkInstalled()) {
// Find all folders in this directory and move their
// subdirectories up to the parent directory.
$directories = Finder::create()
->directories()
->depth('< 1')
->in($path)
->ignoreDotFiles(TRUE)
->ignoreVCS(TRUE);
foreach ($directories as $dirName) {
$fs->mirror($dirName, $path, NULL, ['override' => TRUE]);
$fs->remove($dirName);
}
// Projekktor source files need to be installed.
if ($pluginInstance->getPluginId() == 'projekktor_audio_player') {
drush_op('chdir', '..');
drush_op('chdir', $path);
drush_shell_exec('npm install');
drush_shell_exec('grunt --force');
}
}
if ($pluginInstance->checkInstalled()) {
if ($print_messages) {
$this->logger()->notice(dt('Audiofield library for @library has been successfully installed at @location', [
'@library' => $pluginInstance->getPluginTitle(),
'@location' => $pluginInstance->getPluginLibraryPath(),
], 'success'));
}
}
else {
// Remove the directory where we tried to install.
$fs->remove($path);
if ($print_messages) {
$this->logger()->error(dt('Error: unable to install Audiofield library @library', [
'@library' => $pluginInstance->getPluginTitle(),
], 'error'));
}
}
}
}
/**
* Updates Audiofield libraries from their remote repos if out of date.
*
* @param string $updateLibrary
* The name of the library. If omitted, all libraries will be updated.
* @param bool $print_messages
* Flag indicating if messages should be displayed.
*
* @command audiofield:update
* @aliases audiofield-update
*/
public function update($updateLibrary = '', $print_messages = TRUE) {
// Declare filesystem container.
$fs = new Filesystem();
// Get a list of the audiofield plugins.
$pluginList = $this->playerManager->getDefinitions();
// If there is an argument, check to make sure its valid.
if (!empty($updateLibrary)) {
if (!isset($pluginList[$updateLibrary . '_audio_player'])) {
$this->logger()->error(dt('Error: @library is not a valid Audiofield library.', [
'@library' => $updateLibrary,
], 'error'));
return;
}
// If the argument is valid, we only want to install that plugin.
$pluginList = [$updateLibrary . '_audio_player' => $pluginList[$updateLibrary . '_audio_player']];
}
// Loop over each plugin and make sure it's library is installed.
foreach ($pluginList as $pluginName => $plugin) {
// Create an instance of this plugin.
$pluginInstance = $this->playerManager->createInstance($pluginName);
// Only check install if there is a library for the plugin.
if (!$pluginInstance->getPluginLibrary()) {
continue;
}
// Get the library install path.
$path = DRUPAL_ROOT . $pluginInstance->getPluginLibraryPath();
// If the library isn't installed at all we just run the install.
if (!$pluginInstance->checkInstalled(FALSE)) {
$this->download($pluginInstance->getPluginLibraryName());
continue;
}
// Don't updating the library if its up to date.
if ($pluginInstance->checkVersion(FALSE)) {
$this->logger()->notice(dt('Audiofield library for @library is already up to date', [
'@library' => $pluginInstance->getPluginTitle(),
], 'success'));
continue;
}
// Move the current installation to the temp directory.
$fs->rename($path, file_directory_temp() . '/temp_audiofield', TRUE);
// If the directory failed to move, just delete it.
if (is_dir($path)) {
$fs->remove($path);
}
// Run the install command now to get the latest version.
$this->download($updateLibrary, FALSE);
// Check if library has been properly installed.
if ($pluginInstance->checkInstalled()) {
// Remove the temporary directory.
$fs->remove(file_directory_temp() . '/temp_audiofield');
$this->logger()->notice(dt('Audiofield library for @library has been successfully updated at @location', [
'@library' => $pluginInstance->getPluginTitle(),
'@location' => $pluginInstance->getPluginLibraryPath(),
], 'success'));
}
else {
// Remove the directory where we tried to install.
$fs->remove($path);
$this->logger()->error(dt('Error: unable to update Audiofield library @library', [
'@library' => $pluginInstance->getPluginTitle(),
], 'error'));
// Restore the original install since we failed to update.
$fs->rename(file_directory_temp() . '/temp_audiofield', $path, TRUE);
}
}
}
}
@@ -45,6 +45,18 @@ class WavesurferAudioPlayer extends AudioFieldPluginBase {
'volume' => ($settings['audio_player_initial_volume'] / 10),
'playertype' => ($settings['audio_player_wavesurfer_combine_files'] ? 'playlist' : 'default'),
'files' => [],
'audioRate' => $settings['audio_player_wavesurfer_audiorate'],
'autoCenter' => $settings['audio_player_wavesurfer_autocenter'],
'barGap' => $settings['audio_player_wavesurfer_bargap'],
'barHeight' => $settings['audio_player_wavesurfer_barheight'],
'barWidth' => $settings['audio_player_wavesurfer_barwidth'],
'cursorColor' => $settings['audio_player_wavesurfer_cursorcolor'],
'cursorWidth' => $settings['audio_player_wavesurfer_cursorwidth'],
'forceDecode' => $settings['audio_player_wavesurfer_forcedecode'],
'normalize' => $settings['audio_player_wavesurfer_normalize'],
'progressColor' => $settings['audio_player_wavesurfer_progresscolor'],
'responsive' => $settings['audio_player_wavesurfer_responsive'],
'waveColor' => $settings['audio_player_wavesurfer_wavecolor'],
'autoplay' => $settings['audio_player_autoplay'],
];
@@ -138,6 +138,140 @@ class AudioFieldFieldFormatter extends FormatterBase implements ContainerFactory
],
],
];
// Settings for WaveSurfer.
$elements['audio_player_wavesurfer_audiorate'] = [
'#type' => 'number',
'#title' => $this->t('Audio Rate'),
'#description' => $this->t("Speed at which to play audio. Lower number is slower."),
'#default_value' => $this->getSetting('audio_player_wavesurfer_audiorate'),
'#states' => [
'visible' => [
[':input[name="fields[' . $fieldname . '][settings_edit_form][settings][audio_player]"]' => ['value' => 'wavesurfer_audio_player']],
],
],
];
$elements['audio_player_wavesurfer_autocenter'] = [
'#type' => 'checkbox',
'#title' => $this->t('Auto Center'),
'#description' => $this->t("If a scrollbar is present, center the waveform around the progress."),
'#default_value' => $this->getSetting('audio_player_wavesurfer_autocenter'),
'#states' => [
'visible' => [
[':input[name="fields[' . $fieldname . '][settings_edit_form][settings][audio_player]"]' => ['value' => 'wavesurfer_audio_player']],
],
],
];
$elements['audio_player_wavesurfer_bargap'] = [
'#type' => 'number',
'#title' => $this->t('Bar Gap'),
'#description' => $this->t("The optional spacing between bars of the wave."),
'#default_value' => $this->getSetting('audio_player_wavesurfer_bargap'),
'#states' => [
'visible' => [
[':input[name="fields[' . $fieldname . '][settings_edit_form][settings][audio_player]"]' => ['value' => 'wavesurfer_audio_player']],
],
],
];
$elements['audio_player_wavesurfer_barheight'] = [
'#type' => 'number',
'#title' => $this->t('Bar Height'),
'#description' => $this->t("Height of the waveform bars. Higher number than 1 will increase the waveform bar heights."),
'#default_value' => $this->getSetting('audio_player_wavesurfer_barheight'),
'#states' => [
'visible' => [
[':input[name="fields[' . $fieldname . '][settings_edit_form][settings][audio_player]"]' => ['value' => 'wavesurfer_audio_player']],
],
],
];
$elements['audio_player_wavesurfer_barwidth'] = [
'#type' => 'number',
'#title' => $this->t('Bar Width'),
'#description' => $this->t("If specified, the waveform will be drawn like this: ▁ ▂ ▇ ▃ ▅ ▂"),
'#default_value' => $this->getSetting('audio_player_wavesurfer_barwidth'),
'#states' => [
'visible' => [
[':input[name="fields[' . $fieldname . '][settings_edit_form][settings][audio_player]"]' => ['value' => 'wavesurfer_audio_player']],
],
],
];
$elements['audio_player_wavesurfer_cursorcolor'] = [
'#type' => 'color',
'#title' => $this->t('Cursor Color'),
'#description' => $this->t("The fill color of the cursor indicating the playhead position."),
'#default_value' => $this->getSetting('audio_player_wavesurfer_cursorcolor'),
'#states' => [
'visible' => [
[':input[name="fields[' . $fieldname . '][settings_edit_form][settings][audio_player]"]' => ['value' => 'wavesurfer_audio_player']],
],
],
];
$elements['audio_player_wavesurfer_cursorwidth'] = [
'#type' => 'number',
'#title' => $this->t('Cursor Width'),
'#description' => $this->t("Width of the cursor indicating the playhead position. Measured in pixels."),
'#default_value' => $this->getSetting('audio_player_wavesurfer_cursorwidth'),
'#states' => [
'visible' => [
[':input[name="fields[' . $fieldname . '][settings_edit_form][settings][audio_player]"]' => ['value' => 'wavesurfer_audio_player']],
],
],
];
$elements['audio_player_wavesurfer_forcedecode'] = [
'#type' => 'checkbox',
'#title' => $this->t('Force Decode'),
'#description' => $this->t("Force decoding of audio using web audio when zooming to get a more detailed waveform."),
'#default_value' => $this->getSetting('audio_player_wavesurfer_forcedecode'),
'#states' => [
'visible' => [
[':input[name="fields[' . $fieldname . '][settings_edit_form][settings][audio_player]"]' => ['value' => 'wavesurfer_audio_player']],
],
],
];
$elements['audio_player_wavesurfer_normalize'] = [
'#type' => 'checkbox',
'#title' => $this->t('Normalize'),
'#description' => $this->t("If checked, normalize by the maximum peak instead of 1.0."),
'#default_value' => $this->getSetting('audio_player_wavesurfer_normalize'),
'#states' => [
'visible' => [
[':input[name="fields[' . $fieldname . '][settings_edit_form][settings][audio_player]"]' => ['value' => 'wavesurfer_audio_player']],
],
],
];
$elements['audio_player_wavesurfer_progresscolor'] = [
'#type' => 'color',
'#title' => $this->t('Progress Color'),
'#description' => $this->t("The fill color of the part of the waveform behind the cursor."),
'#default_value' => $this->getSetting('audio_player_wavesurfer_progresscolor'),
'#states' => [
'visible' => [
[':input[name="fields[' . $fieldname . '][settings_edit_form][settings][audio_player]"]' => ['value' => 'wavesurfer_audio_player']],
],
],
];
$elements['audio_player_wavesurfer_responsive'] = [
'#type' => 'checkbox',
'#title' => $this->t('Responsive'),
'#description' => $this->t("If checked, resize the waveform, when the window is resized. This is debounced with a 100ms timeout by default."),
'#default_value' => $this->getSetting('audio_player_wavesurfer_responsive'),
'#states' => [
'visible' => [
[':input[name="fields[' . $fieldname . '][settings_edit_form][settings][audio_player]"]' => ['value' => 'wavesurfer_audio_player']],
],
],
];
$elements['audio_player_wavesurfer_wavecolor'] = [
'#type' => 'color',
'#title' => $this->t('Wave Color'),
'#description' => $this->t("The fill color of the waveform after the cursor."),
'#default_value' => $this->getSetting('audio_player_wavesurfer_wavecolor'),
'#states' => [
'visible' => [
[':input[name="fields[' . $fieldname . '][settings_edit_form][settings][audio_player]"]' => ['value' => 'wavesurfer_audio_player']],
],
],
];
// Settings for WordPress.
// Only show when WordPress is the selected audio player.
$elements['audio_player_wordpress_combine_files'] = [
@@ -291,6 +425,42 @@ class AudioFieldFieldFormatter extends FormatterBase implements ContainerFactory
$summary[] = $this->t('Combine files into single player? <strong>@combine</strong>', [
'@combine' => ($settings['audio_player_wavesurfer_combine_files'] ? 'Yes' : 'No'),
]);
$summary[] = $this->t('Audio Rate: <strong>@value</strong>', [
'@value' => $settings['audio_player_wavesurfer_audiorate'],
]);
$summary[] = $this->t('Auto Center? <strong>@value</strong>', [
'@value' => ($settings['audio_player_wavesurfer_autocenter'] ? 'Yes' : 'No'),
]);
$summary[] = $this->t('Bar Gap: <strong>@value</strong>', [
'@value' => $settings['audio_player_wavesurfer_bargap'],
]);
$summary[] = $this->t('Bar Height: <strong>@value</strong>', [
'@value' => $settings['audio_player_wavesurfer_barheight'],
]);
$summary[] = $this->t('Bar Width: <strong>@value</strong>', [
'@value' => $settings['audio_player_wavesurfer_barwidth'],
]);
$summary[] = $this->t('Cursor Color: <span style="border:1px solid black;height:10px;width:10px;display:inline-block;background:@value;"></span>', [
'@value' => $settings['audio_player_wavesurfer_cursorcolor'],
]);
$summary[] = $this->t('Cursor Width: <strong>@value</strong>', [
'@value' => $settings['audio_player_wavesurfer_cursorwidth'],
]);
$summary[] = $this->t('Force Decode? <strong>@value</strong>', [
'@value' => ($settings['audio_player_wavesurfer_forcedecode'] ? 'Yes' : 'No'),
]);
$summary[] = $this->t('Normalize? <strong>@value</strong>', [
'@value' => ($settings['audio_player_wavesurfer_normalize'] ? 'Yes' : 'No'),
]);
$summary[] = $this->t('Progress Color: <span style="border:1px solid black;height:10px;width:10px;display:inline-block;background:@value;"></span>', [
'@value' => $settings['audio_player_wavesurfer_progresscolor'],
]);
$summary[] = $this->t('Responsive? <strong>@value</strong>', [
'@value' => ($settings['audio_player_wavesurfer_responsive'] ? 'Yes' : 'No'),
]);
$summary[] = $this->t('Wave Color: <span style="border:1px solid black;height:10px;width:10px;display:inline-block;background:@value;"></span>', [
'@value' => $settings['audio_player_wavesurfer_wavecolor'],
]);
}
// If this is wordpress, add those settings.
elseif ($settings['audio_player'] == 'wordpress_audio_player') {
@@ -384,6 +554,18 @@ class AudioFieldFieldFormatter extends FormatterBase implements ContainerFactory
'audio_player' => 'default_mp3_player',
'audio_player_jplayer_theme' => 'none',
'audio_player_wavesurfer_combine_files' => FALSE,
'audio_player_wavesurfer_audiorate' => 1,
'audio_player_wavesurfer_autocenter' => TRUE,
'audio_player_wavesurfer_bargap' => 0,
'audio_player_wavesurfer_barheight' => 1,
'audio_player_wavesurfer_barwidth' => NULL,
'audio_player_wavesurfer_cursorcolor' => '#333',
'audio_player_wavesurfer_cursorwidth' => 1,
'audio_player_wavesurfer_forcedecode' => FALSE,
'audio_player_wavesurfer_normalize' => FALSE,
'audio_player_wavesurfer_progresscolor' => '#555',
'audio_player_wavesurfer_responsive' => FALSE,
'audio_player_wavesurfer_wavecolor' => '#999',
'audio_player_wordpress_combine_files' => FALSE,
'audio_player_wordpress_animation' => TRUE,
'audio_player_soundmanager_theme' => 'default',
@@ -4,10 +4,16 @@
* Default theme implementation for AudioField audioplayer download links.
*
* Available variables:
* - links: theme_item_list render array containing the download links for
* an audiofield entity.
* - links: downloa
*
* @ingroup themeable
*/
#}
{{ links }}
<table class="audiofield-downloads">
<caption>{{ 'Download files:'|trans }}</caption>
{% for file in links %}
<tr>
<td class="audiofield-download-link">{{ file.link }}</td>
</tr>
{% endfor %}
</table>
@@ -16,24 +16,26 @@
{% if settings.audio_player_jplayer_theme == 'audiofield.jplayer.theme_jplayer_circle' %}
{% for file in files %}
<div id="jquery_jplayer_{{ file.id }}" class="cp-jplayer"></div>
<div class="cp-circle-frame">
<div id="cp_container_{{ file.id }}" class="cp-container">
<div class="cp-buffer-holder">
<div class="cp-buffer-1"></div>
<div class="cp-buffer-2"></div>
<div class="audiofield-player">
<div id="jquery_jplayer_{{ file.id }}" class="cp-jplayer"></div>
<div class="cp-circle-frame">
<div id="cp_container_{{ file.id }}" class="cp-container">
<div class="cp-buffer-holder">
<div class="cp-buffer-1"></div>
<div class="cp-buffer-2"></div>
</div>
<div class="cp-progress-holder">
<div class="cp-progress-1"></div>
<div class="cp-progress-2"></div>
</div>
<div class="cp-circle-control"></div>
<ul class="cp-controls">
<li><a class="cp-play" tabindex="1">play</a></li>
<li><a class="cp-pause" style="display:none;" tabindex="1">pause</a></li>
</ul>
</div>
<div class="cp-progress-holder">
<div class="cp-progress-1"></div>
<div class="cp-progress-2"></div>
</div>
<div class="cp-circle-control"></div>
<ul class="cp-controls">
<li><a class="cp-play" tabindex="1">play</a></li>
<li><a class="cp-pause" style="display:none;" tabindex="1">pause</a></li>
</ul>
<label for="cp_container_{{ file.id }}">{{ file.description }}</label>
</div>
<label for="cp_container_{{ file.id }}">{{ file.description }}</label>
</div>
{% endfor %}
{% endif %}
@@ -14,24 +14,26 @@
#}
<div class="audiofield">
{% for file in files %}
<div id="jquery_jplayer_{{ file.id }}" class="cp-jplayer"></div>
<div class="cp-circle-frame">
<div id="cp_container_{{ file.id }}" class="cp-container">
<div class="cp-buffer-holder">
<div class="cp-buffer-1"></div>
<div class="cp-buffer-2"></div>
<div class="audiofield-player">
<div id="jquery_jplayer_{{ file.id }}" class="cp-jplayer"></div>
<div class="cp-circle-frame">
<div id="cp_container_{{ file.id }}" class="cp-container">
<div class="cp-buffer-holder">
<div class="cp-buffer-1"></div>
<div class="cp-buffer-2"></div>
</div>
<div class="cp-progress-holder">
<div class="cp-progress-1"></div>
<div class="cp-progress-2"></div>
</div>
<div class="cp-circle-control"></div>
<ul class="cp-controls">
<li><a class="cp-play" tabindex="1">play</a></li>
<li><a class="cp-pause" style="display:none;" tabindex="1">pause</a></li>
</ul>
</div>
<div class="cp-progress-holder">
<div class="cp-progress-1"></div>
<div class="cp-progress-2"></div>
</div>
<div class="cp-circle-control"></div>
<ul class="cp-controls">
<li><a class="cp-play" tabindex="1">play</a></li>
<li><a class="cp-pause" style="display:none;" tabindex="1">pause</a></li>
</ul>
<label for="cp_container_{{ file.id }}">{{ file.description }}</label>
</div>
<label for="cp_container_{{ file.id }}">{{ file.description }}</label>
</div>
{% endfor %}
</div>
@@ -14,12 +14,14 @@
#}
<div class="audiofield">
{% for file in files %}
<div class="mediaelementaudio_frame">
<audio id="mediaelement_player_{{ file.id }}" preload="{% if settings.audio_player_lazyload == 1 %}none{% else %}auto{% endif %}" {% if settings.audio_player_autoplay == 1 %} autoplay="autoplay" {% endif %} controls>
<source src="{{ file.url }}">
Your browser does not support the audio element.
</audio>
<div class="audiofield-player">
<div class="mediaelementaudio_frame">
<audio id="mediaelement_player_{{ file.id }}" preload="{% if settings.audio_player_lazyload == 1 %}none{% else %}auto{% endif %}" {% if settings.audio_player_autoplay == 1 %} autoplay="autoplay" {% endif %} controls>
<source src="{{ file.url }}">
Your browser does not support the audio element.
</audio>
</div>
<label for="mediaelement_player_{{ file.id }}">{{ file.description }}</label>
</div>
<label for="mediaelement_player_{{ file.id }}">{{ file.description }}</label>
{% endfor %}
</div>
@@ -14,10 +14,12 @@
#}
<div class="audiofield">
{% for file in files %}
<audio id="{{ file.id }}" preload="{% if settings.audio_player_lazyload == 1 %}none{% else %}auto{% endif %}" class="audiofield-{{ plugin_id }} {{ plugin_id }}" controls>
<source src="{{ file.url }}" type="audio/mpeg">
Your browser does not support the audio element.
</audio>
<label>{{ file.description }}</label>
<div class="audiofield-player">
<audio id="{{ file.id }}" preload="{% if settings.audio_player_lazyload == 1 %}none{% else %}auto{% endif %}" class="audiofield-{{ plugin_id }} {{ plugin_id }}" controls>
<source src="{{ file.url }}" type="audio/mpeg">
Your browser does not support the audio element.
</audio>
<label>{{ file.description }}</label>
</div>
{% endfor %}
</div>
@@ -19,7 +19,7 @@
<div class="sm2-inline-gradient"></div>
<div class="sm2-inline-element sm2-button-element">
<div class="sm2-button-bd">
<a href="#play" class="sm2-inline-button play-pause">Play / pause</a>
<a href="#play" class="sm2-inline-button sm2-icon-play-pause">Play / pause</a>
</div>
</div>
<div class="sm2-inline-element sm2-inline-status">
@@ -47,7 +47,7 @@
</div>
<div class="sm2-inline-element sm2-button-element sm2-menu">
<div class="sm2-button-bd">
<a href="#menu" class="sm2-inline-button menu">menu</a>
<a href="#menu" class="sm2-inline-button sm2-icon-menu">menu</a>
</div>
</div>
</div>
@@ -14,10 +14,12 @@
#}
<div class="audiofield">
{% for file in files %}
<audio preload="{% if settings.audio_player_lazyload == 1 %}none{% else %}auto{% endif %}" controls {% if settings.audio_player_autoplay == 1 %} autoplay {% endif %} {% if settings.download_button != 1 %} controlsList="nodownload" {% endif %}>
<source src="{{ file.url }}" type="audio/mpeg">
Your browser does not support the audio element.
</audio>
<label>{{ file.description }}</label>
<div class="audiofield-player">
<audio preload="{% if settings.audio_player_lazyload == 1 %}none{% else %}auto{% endif %}" controls {% if settings.audio_player_autoplay == 1 %} autoplay {% endif %} {% if settings.download_button != 1 %} controlsList="nodownload" {% endif %}>
<source src="{{ file.url }}" type="audio/mpeg">
Your browser does not support the audio element.
</audio>
<label>{{ file.description }}</label>
</div>
{% endfor %}
</div>
@@ -45,6 +45,8 @@ linkit.matcher.entity:
type: boolean
substitution_type:
type: string
limit:
type: integer
linkit.matcher.entity:*:
type: linkit.matcher.entity
@@ -7,8 +7,8 @@ configure: entity.linkit_profile.collection
test_dependencies:
- imce
# Information added by Drupal.org packaging script on 2018-03-08
version: '8.x-5.0-beta7'
# Information added by Drupal.org packaging script on 2018-12-28
version: '8.x-5.0-beta8'
core: '8.x'
project: 'linkit'
datestamp: 1520552594
datestamp: 1545966788
@@ -28,8 +28,6 @@ class Matcher extends Plugin {
/**
* The human-readable name of the matcher.
*
* The string should be wrapped in a @Translation().
*
* @var \Drupal\Core\Annotation\Translation
*/
public $label;
@@ -2,7 +2,6 @@
namespace Drupal\linkit\Controller;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\linkit\SuggestionManager;
@@ -77,7 +76,7 @@ class AutocompleteController implements ContainerInjectionInterface {
$this->linkitProfile = $this->linkitProfileStorage->load($linkit_profile_id);
$string = $request->query->get('q');
$suggestionCollection = $this->suggestionManager->getSuggestions($this->linkitProfile, Unicode::strtolower($string));
$suggestionCollection = $this->suggestionManager->getSuggestions($this->linkitProfile, mb_strtolower($string));
/*
* If there are no suggestions from the matcher plugins, we have to add a
@@ -26,6 +26,7 @@ class Linkit extends FormElement {
'#process' => [
[$class, 'processLinkitAutocomplete'],
[$class, 'processGroup'],
[$class, 'processAjaxForm'],
],
'#pre_render' => [
[$class, 'preRenderLinkitElement'],
@@ -120,7 +120,7 @@ class AddForm extends FormBase {
]);
}
else {
drupal_set_message($this->t('Added %label matcher.', ['%label' => $plugin->getLabel()]));
$this->messenger()->addMessage($this->t('Added %label matcher.', ['%label' => $plugin->getLabel()]));
$form_state->setRedirect('linkit.matchers', [
'linkit_profile' => $this->linkitProfile->id(),
@@ -70,7 +70,7 @@ class DeleteForm extends ConfirmFormBase {
public function submitForm(array &$form, FormStateInterface $form_state) {
$this->linkitProfile->removeMatcher($this->linkitMatcher);
drupal_set_message($this->t('The matcher %label has been deleted.', ['%label' => $this->linkitMatcher->getLabel()]));
$this->messenger()->addMessage($this->t('The matcher %label has been deleted.', ['%label' => $this->linkitMatcher->getLabel()]));
$this->logger('linkit')->notice('The matcher %label has been deleted in the @profile profile.', [
'%label' => $this->linkitMatcher->getLabel(),
'@profile' => $this->linkitProfile->label(),
@@ -74,7 +74,7 @@ class EditForm extends FormBase {
$this->linkitMatcher->submitConfigurationForm($form, $plugin_data);
$this->linkitProfile->save();
drupal_set_message($this->t('Saved %label configuration.', ['%label' => $this->linkitMatcher->getLabel()]));
$this->messenger()->addMessage($this->t('Saved %label configuration.', ['%label' => $this->linkitMatcher->getLabel()]));
$this->logger('linkit')->notice('The matcher %label has been updated in the @profile profile.', [
'%label' => $this->linkitMatcher->getLabel(),
'@profile' => $this->linkitProfile->label(),
@@ -7,7 +7,7 @@ use Drupal\Core\Form\FormStateInterface;
/**
* Controller for profile addition forms.
*
* @see \Drupal\linkit\Profile\FormBase
* @see \Drupal\linkit\Form\Profile\FormBase
*/
class AddForm extends FormBase {
@@ -7,7 +7,7 @@ use Drupal\Core\Form\FormStateInterface;
/**
* Provides an edit form for profile.
*
* @see \Drupal\linkit\Profile\FormBase
* @see \Drupal\linkit\Form\Profile\FormBase
*/
class EditForm extends FormBase {
@@ -67,7 +67,7 @@ abstract class FormBase extends EntityForm {
$edit_link = $this->entity->toLink($this->t('Edit'), 'edit-form')->toString();
switch ($status) {
case SAVED_NEW:
drupal_set_message($this->t('Created new profile %label.', ['%label' => $linkit_profile->label()]));
$this->messenger()->addMessage($this->t('Created new profile %label.', ['%label' => $linkit_profile->label()]));
$this->logger('linkit')->notice('Created new profile %label.', ['%label' => $linkit_profile->label(), 'link' => $edit_link]);
$form_state->setRedirect('linkit.matchers', [
'linkit_profile' => $linkit_profile->id(),
@@ -75,7 +75,7 @@ abstract class FormBase extends EntityForm {
break;
case SAVED_UPDATED:
drupal_set_message($this->t('Updated profile %label.', ['%label' => $linkit_profile->label()]));
$this->messenger()->addMessage($this->t('Updated profile %label.', ['%label' => $linkit_profile->label()]));
$this->logger('linkit')->notice('Updated profile %label.', ['%label' => $linkit_profile->label(), 'link' => $edit_link]);
$form_state->setRedirectUrl($linkit_profile->toUrl('edit-form'));
break;
@@ -36,6 +36,11 @@ class EntityMatcher extends ConfigurableMatcherBase {
use MatcherTokensTrait;
/**
* The default limit for matches.
*/
const DEFAULT_LIMIT = 100;
/**
* The database connection.
*
@@ -161,6 +166,12 @@ class EntityMatcher extends ConfigurableMatcherBase {
$summery[] = $this->t('Group by bundle: @bundle_grouping', [
'@bundle_grouping' => $this->configuration['group_by_bundle'] ? $this->t('Yes') : $this->t('No'),
]);
if (!empty($this->configuration['limit'])) {
$summery[] = $this->t('Limit: @limit', [
'@limit' => $this->configuration['limit'],
]);
}
}
return $summery;
@@ -175,6 +186,7 @@ class EntityMatcher extends ConfigurableMatcherBase {
'bundles' => [],
'group_by_bundle' => FALSE,
'substitution_type' => SubstitutionManagerInterface::DEFAULT_SUBSTITUTION,
'limit' => static::DEFAULT_LIMIT,
] + parent::defaultConfiguration();
}
@@ -257,6 +269,25 @@ class EntityMatcher extends ConfigurableMatcherBase {
'#description' => $this->t('Configure how the selected entity should be transformed into a URL for insertion.'),
];
$form['limit'] = [
'#type' => 'details',
'#title' => $this->t('Limit'),
'#open' => TRUE,
];
$form['limit']['limit'] = [
'#type' => 'select',
'#options' => [
0 => $this->t('Unlimited'),
20 => 20,
50 => 50,
100 => 100,
200 => 200,
],
'#title' => $this->t('Limit search results'),
'#description' => $this->t('Limit the amount of results displayed when searching.'),
'#default_value' => $this->configuration['limit'],
];
return $form;
}
@@ -274,6 +305,7 @@ class EntityMatcher extends ConfigurableMatcherBase {
$this->configuration['bundles'] = $form_state->getValue('bundles');
$this->configuration['group_by_bundle'] = $form_state->getValue('group_by_bundle');
$this->configuration['substitution_type'] = $form_state->getValue('substitution_type');
$this->configuration['limit'] = $form_state->getValue('limit');
}
/**
@@ -353,6 +385,9 @@ class EntityMatcher extends ConfigurableMatcherBase {
$query->condition($bundle_key, $this->configuration['bundles'], 'IN');
}
if ($this->configuration['limit']) {
$query->range(0, $this->configuration['limit']);
}
$this->addQueryTags($query);
return $query;
@@ -190,22 +190,30 @@ class FileMatcher extends EntityMatcher {
/** @var \Drupal\file\FileInterface $entity */
$file = $entity->getFileUri();
/** @var \Drupal\Core\Image\ImageInterface $image */
$image = \Drupal::service('image.factory')->get($file);
if ($image->isValid()) {
if ($this->configuration['images']['show_dimensions']) {
$description_array[] = $image->getWidth() . 'x' . $image->getHeight() . 'px';
}
if ($this->configuration['images']['show_dimensions'] || $this->configuration['images']['show_thumbnail']) {
$image_factory = \Drupal::service('image.factory');
$supported_extensions = $image_factory->getSupportedExtensions();
if ($this->configuration['images']['show_thumbnail'] && $this->moduleHandler->moduleExists('image')) {
$image_element = [
'#weight' => -10,
'#theme' => 'image_style',
'#style_name' => $this->configuration['images']['thumbnail_image_style'],
'#uri' => $entity->getFileUri(),
];
// Check if the file extension is supported by the image toolkit.
if (empty(file_validate_extensions($entity, implode(' ', $supported_extensions)))) {
/** @var \Drupal\Core\Image\ImageInterface $image */
$image = $image_factory->get($file);
if ($image->isValid()) {
if ($this->configuration['images']['show_dimensions']) {
$description_array[] = $image->getWidth() . 'x' . $image->getHeight() . 'px';
}
$description_array[] = (string) \Drupal::service('renderer')->render($image_element);
if ($this->configuration['images']['show_thumbnail'] && $this->moduleHandler->moduleExists('image')) {
$image_element = [
'#weight' => -10,
'#theme' => 'image_style',
'#style_name' => $this->configuration['images']['thumbnail_image_style'],
'#uri' => $entity->getFileUri(),
];
$description_array[] = (string) \Drupal::service('renderer')->render($image_element);
}
}
}
}
@@ -3,6 +3,7 @@
namespace Drupal\linkit\Plugin\Linkit\Matcher;
use Drupal\Core\Form\FormStateInterface;
use Drupal\node\NodeInterface;
/**
* Provides specific linkit matchers for the node entity type.
@@ -84,9 +85,27 @@ class NodeMatcher extends EntityMatcher {
protected function buildEntityQuery($search_string) {
$query = parent::buildEntityQuery($search_string);
$no_access = !$this->currentUser->hasPermission('bypass node access') && !count($this->moduleHandler->getImplementations('node_grants'));
if ($this->configuration['include_unpublished'] !== TRUE || $no_access) {
$query->condition('status', NODE_PUBLISHED);
if ($this->configuration['include_unpublished'] == FALSE) {
$query->condition('status', NodeInterface::PUBLISHED);
}
elseif (count($this->moduleHandler->getImplementations('node_grants')) === 0) {
if (($this->currentUser->hasPermission('bypass node access') || $this->currentUser->hasPermission('view any unpublished content'))) {
// User can see all content, no check necessary.
}
elseif ($this->currentUser->hasPermission('view own unpublished content')) {
// Users with "view own unpublished content" can see only their own.
if ($this->configuration['include_unpublished'] == TRUE) {
$or_condition = $query
->orConditionGroup()
->condition('status', NodeInterface::PUBLISHED)
->condition('uid', $this->currentUser->id());
$query->condition($or_condition);
}
}
}
else {
// All other users should only get published results.
$query->condition('status', NodeInterface::PUBLISHED);
}
return $query;
@@ -5,7 +5,6 @@ namespace Drupal\linkit\Plugin\Linkit\Substitution;
use Drupal\Component\Plugin\PluginBase;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\GeneratedUrl;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\linkit\SubstitutionInterface;
@@ -21,30 +20,6 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
*/
class Media extends PluginBase implements SubstitutionInterface, ContainerFactoryPluginInterface {
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManager
*/
protected $entityTypeManager;
/**
* Constructs a Media object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Entity\EntityTypeManager $entity_type_manager
* The entity type manager.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManager $entity_type_manager) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->entityTypeManager = $entity_type_manager;
}
/**
* {@inheritdoc}
*/
@@ -2,7 +2,6 @@
namespace Drupal\linkit\Tests;
use Drupal\Component\Utility\Unicode;
use Drupal\linkit\Entity\Profile;
/**
@@ -29,7 +28,7 @@ trait ProfileCreationTrait {
protected function createProfile(array $settings = []) {
// Populate defaults array.
$settings += [
'id' => Unicode::strtolower($this->randomMachineName()),
'id' => mb_strtolower($this->randomMachineName()),
'label' => $this->randomMachineName(),
];
@@ -9,8 +9,8 @@ dependencies:
- drupal:field
- drupal:text
# Information added by Drupal.org packaging script on 2018-03-08
version: '8.x-5.0-beta7'
# Information added by Drupal.org packaging script on 2018-12-28
version: '8.x-5.0-beta8'
core: '8.x'
project: 'linkit'
datestamp: 1520552594
datestamp: 1545966788
@@ -2,7 +2,6 @@
namespace Drupal\Tests\linkit\Functional;
use Drupal\Component\Utility\Unicode;
use Drupal\linkit\Tests\ProfileCreationTrait;
/**
@@ -62,8 +61,8 @@ class ProfileAdminTest extends LinkitBrowserTestBase {
// Create a profile.
$edit = [];
$edit['label'] = Unicode::strtolower($this->randomMachineName());
$edit['id'] = Unicode::strtolower($this->randomMachineName());
$edit['label'] = mb_strtolower($this->randomMachineName());
$edit['id'] = mb_strtolower($this->randomMachineName());
$edit['description'] = $this->randomMachineName(16);
$this->submitForm($edit, t('Save and manage matchers'));
@@ -5,7 +5,6 @@ namespace Drupal\Tests\linkit\Kernel;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Component\Serialization\Json;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\Unicode;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\entity_test\Entity\EntityTestMul;
use Drupal\language\Entity\ConfigurableLanguage;
@@ -153,6 +152,29 @@ class LinkitAutocompleteTest extends LinkitKernelTestBase {
$this->assertEmpty(count($data), 'Autocomplete did not return any suggestions.');
}
/**
* Tests autocompletion with results limit.
*/
public function testAutocompletionWithLimit() {
/** @var \Drupal\linkit\MatcherInterface $plugin */
$plugin = $this->matcherManager->createInstance('entity:entity_test');
$configuration = $plugin->getConfiguration();
$configuration['settings']['limit'] = 2;
$this->linkitProfile->addMatcher($configuration);
$this->linkitProfile->save();
$entity_1 = EntityTest::create(['name' => 'foo 1']);
$entity_1->save();
$entity_2 = EntityTest::create(['name' => 'foo 2']);
$entity_2->save();
$entity_3 = EntityTest::create(['name' => 'foo 3']);
$entity_3->save();
$data = $this->getAutocompleteResult('foo');
$this->assertTrue(count($data) == 2, 'Autocomplete returned the expected amount of suggestions.');
}
/**
* Tests autocompletion with translated entities.
*/
@@ -221,7 +243,7 @@ class LinkitAutocompleteTest extends LinkitKernelTestBase {
protected function createProfile(array $settings = []) {
// Populate defaults array.
$settings += [
'id' => Unicode::strtolower($this->randomMachineName()),
'id' => mb_strtolower($this->randomMachineName()),
'label' => $this->randomMachineName(),
];
@@ -51,7 +51,7 @@ abstract class LinkitKernelTestBase extends KernelTestBase {
if ($permissions) {
// Create a new role and apply permissions to it.
$role = Role::create([
'id' => strtolower($this->randomMachineName(8)),
'id' => mb_strtolower($this->randomMachineName(8)),
'label' => $this->randomMachineName(8),
]);
$role->save();
@@ -18,7 +18,7 @@ class NodeMatcherTest extends LinkitKernelTestBase {
*
* @var array
*/
public static $modules = ['field', 'node'];
public static $modules = ['field', 'node', 'content_moderation', 'workflows'];
/**
* The matcher manager.
@@ -34,6 +34,7 @@ class NodeMatcherTest extends LinkitKernelTestBase {
parent::setUp();
$this->installEntitySchema('node');
$this->installSchema('node', ['node_access']);
$this->installConfig(['field', 'node']);
$this->manager = $this->container->get('plugin.manager.linkit.matcher');
@@ -74,7 +75,7 @@ class NodeMatcherTest extends LinkitKernelTestBase {
]);
$node->save();
// Unpublished node.
// Unpublished nodes.
$node = Node::create([
'title' => 'Lorem unpublishd',
'type' => $type1->id(),
@@ -82,6 +83,13 @@ class NodeMatcherTest extends LinkitKernelTestBase {
]);
$node->save();
$node = Node::create([
'title' => 'Lorem unpublishd 2',
'type' => $type2->id(),
'status' => FALSE,
]);
$node->save();
// Set the current user to someone that is not the node owner.
\Drupal::currentUser()->setAccount($this->createUser([], ['access content']));
}
@@ -133,7 +141,22 @@ class NodeMatcherTest extends LinkitKernelTestBase {
// Test with permissions to see unpublished nodes.
$suggestions = $plugin->execute('Lorem');
$this->assertEquals(5, count($suggestions->getSuggestions()), 'Correct number of suggestions');
// Test with permissions to see own unpublished nodes.
\Drupal::currentUser()->setAccount($this->createUser([], ['access content', 'view own unpublished content']));
$nodes = $this->container->get('entity_type.manager')->getStorage('node')->loadByProperties(['title' => 'Lorem unpublishd']);
$node4 = reset($nodes);
/** @var \Drupal\node\NodeInterface $node4 */
$node4->setOwnerId(\Drupal::currentUser()->id());
$node4->save();
$suggestions = $plugin->execute('Lorem');
$this->assertEquals(4, count($suggestions->getSuggestions()), 'Correct number of suggestions');
// Test with permissions to see any unpublished nodes.
\Drupal::currentUser()->setAccount($this->createUser([], ['access content', 'view any unpublished content']));
$suggestions = $plugin->execute('Lorem');
$this->assertEquals(5, count($suggestions->getSuggestions()), 'Correct number of suggestions');
}
/**
@@ -2,7 +2,6 @@
namespace Drupal\Tests\linkit\Kernel\Matchers;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Language\LanguageInterface;
use Drupal\taxonomy\VocabularyInterface;
use Drupal\Tests\linkit\Kernel\LinkitKernelTestBase;
@@ -118,7 +117,7 @@ class TermMatcherTest extends LinkitKernelTestBase {
$vocabulary = $vocabularyStorage->create([
'name' => $name,
'description' => $name,
'vid' => Unicode::strtolower($name),
'vid' => mb_strtolower($name),
'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
]);
$vocabulary->save();