# speechkit/7.2.0/src/editor/components/settings-fields/classic-metabox.js

BeyondWords – AI audio for publishers, version 7.2.0. 197 lines.

- Page: https://pluginprobe.com/plugins/speechkit/7.2.0/code/src/editor/components/settings-fields/classic-metabox.js
- Raw: https://pluginprobe.com/plugins/speechkit/7.2.0/raw/src/editor/components/settings-fields/classic-metabox.js
- Modified: 2026-09-25T15:14:58+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/speechkit/7.2.0/code/src/editor/components/settings-fields/classic-metabox.js#L10-L20`.

```javascript
/* global beyondwordsSettingsFields */

/*
 * Classic-editor dynamic behaviour for the Content/Format/Player settings
 * fields (show/hide + Embed recompute). Mirrors settings-panel/helpers.js.
 */
( function () {
	'use strict';

	const SOURCE_POST = 'post';
	const SOURCE_POST_AND_SCRIPT = 'post_and_script';

	const OUTPUT_AUDIO = 'audio';
	const OUTPUT_VIDEO = 'video';
	const OUTPUT_AUDIO_AND_VIDEO = 'audio_and_video';

	const EMBED_NONE = 'none';

	const labels =
		( typeof beyondwordsSettingsFields !== 'undefined' &&
			beyondwordsSettingsFields.embedLabels ) ||
		{};

	// PHP normalises the rendered value, so the select only holds an offered source.
	const sourceIncludesScript = ( source ) =>
		source === SOURCE_POST_AND_SCRIPT;

	const outputIncludesAudio = ( output ) =>
		output === OUTPUT_AUDIO || output === OUTPUT_AUDIO_AND_VIDEO;

	const outputIncludesVideo = ( output ) =>
		output === OUTPUT_VIDEO || output === OUTPUT_AUDIO_AND_VIDEO;

	/**
	 * Toggle an element's visibility by id.
	 *
	 * @param {string}  id   The element id.
	 * @param {boolean} show Whether the element should be visible.
	 */
	const toggle = ( id, show ) => {
		const el = document.getElementById( id );
		if ( el ) {
			el.style.display = show ? '' : 'none';
		}
	};

	/**
	 * Derive the valid Embed options from the current Source × Output.
	 *
	 * @param {string} source The current source value.
	 * @param {string} output The current output value.
	 *
	 * @return {Array<{label: string, value: string}>} Embed options.
	 */
	const getEmbedOptions = ( source, output ) => {
		const options = [ { label: labels.none || 'None', value: EMBED_NONE } ];
		const includesScript = sourceIncludesScript( source );

		if ( outputIncludesAudio( output ) ) {
			options.push( {
				label: labels.audio_post || 'Audio (post)',
				value: 'audio_post',
			} );
			if ( includesScript ) {
				options.push( {
					label: labels.audio_script || 'Audio (script)',
					value: 'audio_script',
				} );
			}
		}

		if ( outputIncludesVideo( output ) ) {
			options.push( {
				label: labels.video_post || 'Video (post)',
				value: 'video_post',
			} );
			if ( includesScript ) {
				options.push( {
					label: labels.video_script || 'Video (script)',
					value: 'video_script',
				} );
			}
		}

		return options;
	};

	/**
	 * The first produced asset, or None when the options hold no asset.
	 *
	 * @param {Array<{label: string, value: string}>} options The Embed options.
	 *
	 * @return {string} The default embed value.
	 */
	const getDefaultEmbed = ( options ) => {
		const asset = options.find( ( option ) => option.value !== EMBED_NONE );

		return asset ? asset.value : EMBED_NONE;
	};

	const settingsFields = {
		init() {
			this.source = document.getElementById( 'beyondwords_source' );
			this.output = document.getElementById( 'beyondwords_output' );
			this.embed = document.getElementById( 'beyondwords_embed' );
			this.embedTouched = document.getElementById(
				'beyondwords_embed_touched'
			);

			// Set before the guard below: the flag gates the whole save() write.
			if ( this.embed && this.embedTouched ) {
				this.embed.addEventListener( 'change', () => {
					this.embedTouched.value = '1';
				} );
			}

			if ( ! this.source && ! this.output ) {
				return;
			}

			if ( this.source ) {
				this.source.addEventListener( 'change', () => {
					this.toggleScriptTemplate();
					this.recomputeEmbed();
				} );
			}

			if ( this.output ) {
				this.output.addEventListener( 'change', () => {
					this.toggleVideoFields();
					this.recomputeEmbed();
				} );
			}

			// Sync initial visibility in case meta and markup drift.
			this.toggleScriptTemplate();
			this.toggleVideoFields();
		},

		toggleScriptTemplate() {
			const show = this.source
				? sourceIncludesScript( this.source.value )
				: false;
			toggle(
				'beyondwords-metabox-settings--beyondwords-script-template-id',
				show
			);
		},

		toggleVideoFields() {
			const show = this.output
				? outputIncludesVideo( this.output.value )
				: false;
			toggle(
				'beyondwords-metabox-settings--beyondwords-video-template-id',
				show
			);
			toggle(
				'beyondwords-metabox-settings--beyondwords-video-size',
				show
			);
		},

		recomputeEmbed() {
			if ( ! this.embed ) {
				return;
			}

			const source = this.source ? this.source.value : SOURCE_POST;
			const output = this.output ? this.output.value : OUTPUT_AUDIO;
			const options = getEmbedOptions( source, output );
			const previous = this.embed.value;
			const stillValid = options.some( ( o ) => o.value === previous );
			// Only a stale value lands here — None is valid for every combination.
			const selected = stillValid ? previous : getDefaultEmbed( options );

			this.embed.replaceChildren(
				...options.map( ( option ) => {
					const el = document.createElement( 'option' );
					el.value = option.value;
					el.textContent = option.label;
					el.selected = option.value === selected;
					return el;
				} )
			);
		},
	};

	if ( document.readyState !== 'loading' ) {
		settingsFields.init();
	} else {
		document.addEventListener( 'DOMContentLoaded', () =>
			settingsFields.init()
		);
	}
} )();

```
