@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace Reservair\Forms;
|
||||
|
||||
/**
|
||||
* Wraps WordPress' bundled CodeMirror (wp_enqueue_code_editor) as a drop-in
|
||||
* replacement for a <textarea>.
|
||||
*
|
||||
* The textarea stays the source of truth: CodeMirror mirrors its content back
|
||||
* on every edit, so any form serialization that reads the textarea's value
|
||||
* keeps working unchanged. When the user has turned syntax highlighting off in
|
||||
* their profile, this degrades to the plain textarea.
|
||||
*/
|
||||
class RsvCodeEditor
|
||||
{
|
||||
/**
|
||||
* Renders a code-editor-backed <textarea> and arranges for it to be
|
||||
* upgraded to CodeMirror on the page.
|
||||
*
|
||||
* @param array{name?:string,value?:string,mode?:string,rows?:int,class?:string} $args
|
||||
* mode is a MIME type understood by wp_enqueue_code_editor, e.g.
|
||||
* 'text/html' or 'text/css'.
|
||||
*/
|
||||
public static function render(string $id, array $args = []): string
|
||||
{
|
||||
$name = $args['name'] ?? $id;
|
||||
$value = $args['value'] ?? '';
|
||||
$mode = $args['mode'] ?? 'text/html';
|
||||
$rows = $args['rows'] ?? 8;
|
||||
$class = $args['class'] ?? 'large-text code';
|
||||
|
||||
$textarea = '<textarea id="' . esc_attr($id) . '" name="' . esc_attr($name) . '"'
|
||||
. ' rows="' . $rows . '" class="' . esc_attr($class) . '">'
|
||||
. esc_textarea($value)
|
||||
. '</textarea>';
|
||||
|
||||
$settings = wp_enqueue_code_editor(['type' => $mode]);
|
||||
|
||||
// Syntax highlighting disabled in the user's profile — keep it plain.
|
||||
if ($settings === false) {
|
||||
return $textarea;
|
||||
}
|
||||
|
||||
self::schedule_init($id, $settings);
|
||||
|
||||
return $textarea;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes CodeMirror on $id after the code editor script loads, and
|
||||
* keeps the underlying textarea in sync — including dispatching `input` so
|
||||
* listeners (live previews, change tracking) still fire while typing.
|
||||
*
|
||||
* @param array<array-key,mixed> $settings As returned by wp_enqueue_code_editor.
|
||||
*/
|
||||
private static function schedule_init(string $id, array $settings): void
|
||||
{
|
||||
$id_json = wp_json_encode($id);
|
||||
$settings_json = wp_json_encode($settings);
|
||||
if ($id_json === false || $settings_json === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
$script = '(function(){'
|
||||
. 'var ta=document.getElementById(' . $id_json . ');'
|
||||
. 'if(!ta||!window.wp||!wp.codeEditor)return;'
|
||||
. 'var ed=wp.codeEditor.initialize(ta,' . $settings_json . ');'
|
||||
. 'ed.codemirror.on("change",function(cm){'
|
||||
. 'cm.save();'
|
||||
. 'ta.dispatchEvent(new Event("input",{bubbles:true}));'
|
||||
. '});'
|
||||
. '})();';
|
||||
|
||||
wp_add_inline_script('code-editor', $script);
|
||||
}
|
||||
}
|
||||
@@ -194,6 +194,30 @@ class RsvFormBuilder
|
||||
return $this->row($id, $label, $ctrl, $desc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Syntax-highlighted editor backed by WordPress' bundled CodeMirror.
|
||||
*
|
||||
* Serializes exactly like {@see textarea()} — the underlying <textarea>
|
||||
* stays the source of truth.
|
||||
*
|
||||
* @param string $mode MIME type for highlighting, e.g. 'text/html'.
|
||||
*/
|
||||
public function code(
|
||||
string $id,
|
||||
string $label,
|
||||
string $desc = '',
|
||||
string $value = '',
|
||||
string $mode = 'text/html',
|
||||
int $rows = 8
|
||||
): static {
|
||||
$ctrl = RsvCodeEditor::render($id, [
|
||||
'value' => $value,
|
||||
'mode' => $mode,
|
||||
'rows' => $rows,
|
||||
]);
|
||||
return $this->row($id, $label, $ctrl, $desc);
|
||||
}
|
||||
|
||||
public function custom(string $label, callable $fn) : static {
|
||||
$this->rows[] = '<tr>'
|
||||
. '<th>' . esc_html($label) . '</th>'
|
||||
|
||||
Reference in New Issue
Block a user