Skip to content
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ dist.zip

# dependencies
node_modules
/__interactive-code-batteries

# IDEs and editors
/.idea
Expand Down
29 changes: 28 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,17 @@
},
"private": true,
"dependencies": {
"@codemirror/autocomplete": "6.4.2",
"@codemirror/commands": "6.2.2",
"@codemirror/lang-css": "6.1.1",
"@codemirror/lang-html": "6.4.2",
"@codemirror/lang-javascript": "6.1.4",
"@codemirror/lang-php": "6.0.1",
"@codemirror/lang-sql": "6.4.0",
"@codemirror/language": "6.6.0",
"@codemirror/state": "6.2.0",
"@codemirror/theme-one-dark": "6.1.1",
"@codemirror/view": "6.9.3",
"classnames": "^2.3.2",
"comlink": "^4.4.1",
"express-fileupload": "1.4.0",
Expand All @@ -47,6 +58,11 @@
"request": "2.88.2",
"unzipper": "0.10.11"
},
"resolutions": {
"@codemirror/state": "6.2.0",
"@codemirror/theme-one-dark": "6.1.1",
"@codemirror/view": "6.9.3"
},
"devDependencies": {
"@convex-dev/typedoc-plugin-markdown": "3.14.0",
"@knodes/typedoc-plugin-pages": "0.23.1",
Expand Down Expand Up @@ -74,11 +90,20 @@
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"@types/react-modal": "^3.13.1",
"@types/wordpress__block-editor": "11.5.0",
"@types/wordpress__blocks": "12.5.0",
"@typescript-eslint/eslint-plugin": "^5.36.1",
"@typescript-eslint/parser": "^5.36.1",
"@vitejs/plugin-react": "^3.1.0",
"@vitest/coverage-c8": "~0.25.8",
"@vitest/ui": "^0.25.8",
"@wordpress/block-editor": "11.6.0",
"@wordpress/blocks": "12.6.0",
"@wordpress/components": "23.6.0",
"@wordpress/core-data": "6.6.0",
"@wordpress/data": "8.6.0",
"@wordpress/element": "5.6.0",
"@wordpress/notices": "3.29.0",
"chalk": "5.2.0",
"dts-bundle-generator": "^7.2.0",
"esbuild": "^0.17.5",
Expand All @@ -104,6 +129,7 @@
"react-test-renderer": "18.2.0",
"rimraf": "^4.4.0",
"rollup-plugin-dts": "^5.2.0",
"rollup-plugin-external-globals": "0.7.3",
"rollup-plugin-ts": "^3.2.0",
"ts-jest": "^29.0.5",
"ts-json-schema-generator": "1.2.0",
Expand All @@ -116,7 +142,8 @@
"vite": "^4.0.1",
"vite-plugin-dts": "~1.7.1",
"vite-plugin-eslint": "^1.8.1",
"vite-plugin-static-copy": "^0.13.1",
"vite-plugin-external": "1.2.8",
"vite-plugin-static-copy": "0.13.1",
"vite-plugin-wasm": "^3.2.2",
"vite-tsconfig-paths": "^4.0.2",
"vitepress": "1.0.0-alpha.60",
Expand Down
18 changes: 18 additions & 0 deletions packages/interactive-code-block/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"extends": ["../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
}
]
}
11 changes: 11 additions & 0 deletions packages/interactive-code-block/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# interactive-code-block

This library was generated with [Nx](https://nx.dev).

## Building

Run `nx build interactive-code-block` to build the library.

## Running unit tests

Run `nx test interactive-code-block` to execute the unit tests via [Jest](https://jestjs.io).
6 changes: 6 additions & 0 deletions packages/interactive-code-block/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "@wp-playground/interactive-code-block",
"version": "0.0.1",
"type": "module",
"private": true
}
55 changes: 55 additions & 0 deletions packages/interactive-code-block/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"name": "interactive-code-block",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "packages/interactive-code-block/src",
"projectType": "library",
"targets": {
"build": {
"executor": "nx:noop",
"dependsOn": ["build:zip"]
},
"build:zip": {
"executor": "@nrwl/workspace:run-commands",
"options": {
"cwd": "dist/packages",
"commands": [
"rm interactive-code-block.zip || true",
"zip interactive-code-block.zip -r interactive-code-block"
]
},
"dependsOn": ["build:bundle"]
},
"build:bundle": {
"executor": "@nrwl/vite:build",
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": "dist/packages/interactive-code-block"
}
},
"dev": {
"executor": "@nrwl/vite:build",
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": "dist/packages/interactive-code-block",
"watch": true,
"minify": false
}
},
"test": {
"executor": "@nrwl/vite:test",
"outputs": ["coverage/packages/interactive-code-block"],
"options": {
"passWithNoTests": true,
"reportsDirectory": "../../coverage/packages/interactive-code-block"
}
},
"lint": {
"executor": "@nrwl/linter:eslint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["packages/interactive-code-block/**/*.ts"]
}
}
},
"tags": []
}
115 changes: 115 additions & 0 deletions packages/interactive-code-block/public/block.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<?php

add_action('init', function () {
$asset_file = require plugin_dir_path(__FILE__) . 'index.asset.php';
foreach ($asset_file['dependencies'] as $dep) {
if (wp_script_is($dep, 'registered')) {
$deps[] = $dep;
}
}
// Register block scripts
$scripts = [
'interactive-code-block' => $asset_file['files']['view'],
'interactive-code-block-editor' => $asset_file['files']['editor'],
];
foreach ($scripts as $script => $file) {
wp_register_script(
$script,
plugins_url($file, __FILE__),
$deps,
'' // Version is included in the file name
);
}

// Load block scripts as ES modules
add_filter('script_loader_tag', function ($tag, $handle, $src) use ($scripts) {
if (!array_key_exists($handle, $scripts)) {
return $tag;
}

// Remove any query string from the URL
$new_url = current(explode('?', $src));
$tag = '<script type="module" src="' . esc_url($new_url) . '"></script>';
return $tag;
}, 10, 3);

$asset_file = require plugin_dir_path(__FILE__) . 'index.asset.php';
$deps = [];
foreach ($asset_file['dependencies'] as $dep) {
if (wp_style_is($dep, 'registered')) {
$deps[] = $dep;
}
}

// Register block styles
$styles = [
'interactive-code-block' => 'view',
'interactive-code-block-editor' => 'editor',
];
foreach ($styles as $style => $file) {
wp_register_style(
$style,
plugins_url('assets/' . $file . '.css', __FILE__),
$deps,
$asset_file['version']
);
}

// Register the block itself
register_block_type_from_metadata(__DIR__ . '/assets/block.json', [
'render_callback' => function ($attributes) {
if (!isset($attributes['code'])) {
return '';
}

$execution_scripts = get_option(LCS_Execution_Scripts_Endpoint::OPTION_KEY, []);
$script_id = $attributes['executionScript'];
$script = $execution_scripts[$script_id] ?? '';

$all_libraries = lcs_get_libraries_list();
$library_ids = array_unique(
array_merge(
$attributes['libraries'],
$script['libraries'] ?? []
)
);
$libraries = array_values(array_filter($all_libraries, function ($library) use ($library_ids) {
return in_array($library['id'], $library_ids);
}));

// The base64_decode is to prevent incorrect escaping by Gutenberg
// E.g. representing <h1 title="&lt;div&gt; &quot;html&quot;"> seems
// to be a problem for Gutenberg – it will store it as
// &lt;h1 title=&quot;&amp;lt;div&amp;gt; &amp;quot;html&amp;quot;&quot;$gt;
return '
<div
class="wp-playground-interactive-code-snippet"
data-code="' . esc_attr($attributes['code']) . '"
data-file-type="' . esc_attr($attributes['fileType']) . '"
data-libraries="' . esc_attr(json_encode($libraries)) . '"
data-execution-script="' . esc_attr(json_encode($script)) . '"
data-execution-script-id="' . esc_attr(json_encode($script_id)) . '"
data-cached-output="' . esc_attr($attributes['cachedOutput']) . '"
data-show-cached-output="' . esc_attr($attributes['showCachedOutput']) . '"
>
<b>Loading interactive code snippet...</b>
</div>
';
}
// Render a static code snippet while the interactive one is loading:
// Useful only for PHP and only if the PHP version >= webhost version.
// ' . highlight_string(base64_decode($attributes['code']), true) . '
]);
});


function lce_editor_init($hook)
{
global $current_screen;
if (!$current_screen->is_block_editor()) {
return;
}

lce_preload_endpoints_data();
}
add_action('admin_enqueue_scripts', 'lce_editor_init');
Loading