Create a long text formatter to display a asciinema player.
Asciinema is a tool for recording a terminal.
It's easy to use and let's you share the recording on the site.
Implementation
Generate a module with drush gen module.
Theme
In asciinema_player.module, set up a theme hook.
/**
* Implements hook_theme().
*/
function asciinema_player_theme($existing, $type, $theme, $path) {
return [
'asciinema_player' => [
'render element' => 'player'
]
];
}Preprocess
Attach the asciinema_player/init library, and pass the base64 encoded string to drupalSettings.asciinema_player.src.
/**
* Implements hook_preprocess_HOOK().
*/
function asciinema_player_preprocess_asciinema_player(&$variables) {
$variables['player']['#attached']['library'][] = 'asciinema_player/init';
$variables['player']['#attached']['drupalSettings']['asciinema_player']['src'] = $variables['player']['#src'];
}Field Formatter
Generate a field formatter using drush gen plugin:field:formatter.
Edit the AsciinemaPlayerFormatter class.
<?php
declare(strict_types=1);
namespace Drupal\asciinema_player\Plugin\Field\FieldFormatter;
use Drupal\Core\Field\Attribute\FieldFormatter;
use Drupal\Core\Field\FormatterBase;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
/**
* Plugin implementation of the 'basic_string' formatter.
*/
#[FieldFormatter(
id: 'asciinema_player',
label: new TranslatableMarkup('Asciinema Player'),
field_types: [
'string_long',
],
)]
class AsciinemaPlayerFormatter extends FormatterBase {
/**
* {@inheritdoc}
*/
public function viewElements(FieldItemListInterface $items, $langcode) {
$elements = [];
foreach ($items as $delta => $item) {
$elements[$delta] = [
'#theme' => 'asciinema_player',
'#src' => base64_encode($item->value),
];
}
return $elements;
}
}Libraries
Download the .css and .min.js files from the latest Asciinema Player release to asciinema_player/libraries.
https://github.com/asciinema/asciinema-player/releases
Create asciinema_player.libraries.yml.
lib:
css:
component:
libraries/asciinema-player.css: {}
js:
libraries/asciinema-player.min.js: {}
init:
js:
libraries/asciinema_player.js: {}
dependencies:
- asciinema_player/lib
- core/oncelib is the minified player js, and init is this module's script to launch the player.
Create libraries/asciinema_player.js.
((drupalSettings, once, AsciinemaPlayer) => {
Drupal.behaviors.asciinemaPlayer = {
attach(context) {
const players = once('asciinema-player', '.asciinema-player', context);
players.forEach(player => {
AsciinemaPlayer.create('data:text/plain;base64,' + drupalSettings.asciinema_player.src, player, {
idleTimeLimit: 2
});
})
console.log(document.querySelector('.asciinema-player'))
}
}
})(drupalSettings, once, AsciinemaPlayer)See: https://docs.asciinema.org/manual/player/quick-start/
Notice we are passing the cast content as the base64 encoded string stored in drupalSettings.asciinema_player.src.
Media Type
After setting this up, I found a module that converts a url into an embed.
https://www.drupal.org/project/media_remote
You have to create custom plugins. I added one for Asciinema.
https://git.drupalcode.org/project/media_remote
Considerations
The player can use the asciinema cast content as a string, or url to the code.
A file upload field may be better for performance, since the file could be fetched separately.
Maybe it could me a new Media type with an edit field that updates the file.