| 1 |
/* global beyondwordsSettingsFields */ |
| 2 |
|
| 3 |
/* |
| 4 |
* Classic-editor dynamic behaviour for the Content/Format/Player settings |
| 5 |
* fields (show/hide + Embed recompute). Mirrors settings-panel/helpers.js. |
| 6 |
*/ |
| 7 |
( function () { |
| 8 |
'use strict'; |
| 9 |
|
| 10 |
const SOURCE_POST = 'post'; |
| 11 |
const SOURCE_POST_AND_SCRIPT = 'post_and_script'; |
| 12 |
|
| 13 |
const OUTPUT_AUDIO = 'audio'; |
| 14 |
const OUTPUT_VIDEO = 'video'; |
| 15 |
const OUTPUT_AUDIO_AND_VIDEO = 'audio_and_video'; |
| 16 |
|
| 17 |
const EMBED_NONE = 'none'; |
| 18 |
|
| 19 |
const labels = |
| 20 |
( typeof beyondwordsSettingsFields !== 'undefined' && |
| 21 |
beyondwordsSettingsFields.embedLabels ) || |
| 22 |
{}; |
| 23 |
|
| 24 |
// PHP normalises the rendered value, so the select only holds an offered source. |
| 25 |
const sourceIncludesScript = ( source ) => |
| 26 |
source === SOURCE_POST_AND_SCRIPT; |
| 27 |
|
| 28 |
const outputIncludesAudio = ( output ) => |
| 29 |
output === OUTPUT_AUDIO || output === OUTPUT_AUDIO_AND_VIDEO; |
| 30 |
|
| 31 |
const outputIncludesVideo = ( output ) => |
| 32 |
output === OUTPUT_VIDEO || output === OUTPUT_AUDIO_AND_VIDEO; |
| 33 |
|
| 34 |
/** |
| 35 |
* Toggle an element's visibility by id. |
| 36 |
* |
| 37 |
* @param {string} id The element id. |
| 38 |
* @param {boolean} show Whether the element should be visible. |
| 39 |
*/ |
| 40 |
const toggle = ( id, show ) => { |
| 41 |
const el = document.getElementById( id ); |
| 42 |
if ( el ) { |
| 43 |
el.style.display = show ? '' : 'none'; |
| 44 |
} |
| 45 |
}; |
| 46 |
|
| 47 |
/** |
| 48 |
* Derive the valid Embed options from the current Source × Output. |
| 49 |
* |
| 50 |
* @param {string} source The current source value. |
| 51 |
* @param {string} output The current output value. |
| 52 |
* |
| 53 |
* @return {Array<{label: string, value: string}>} Embed options. |
| 54 |
*/ |
| 55 |
const getEmbedOptions = ( source, output ) => { |
| 56 |
const options = [ { label: labels.none || 'None', value: EMBED_NONE } ]; |
| 57 |
const includesScript = sourceIncludesScript( source ); |
| 58 |
|
| 59 |
if ( outputIncludesAudio( output ) ) { |
| 60 |
options.push( { |
| 61 |
label: labels.audio_post || 'Audio (post)', |
| 62 |
value: 'audio_post', |
| 63 |
} ); |
| 64 |
if ( includesScript ) { |
| 65 |
options.push( { |
| 66 |
label: labels.audio_script || 'Audio (script)', |
| 67 |
value: 'audio_script', |
| 68 |
} ); |
| 69 |
} |
| 70 |
} |
| 71 |
|
| 72 |
if ( outputIncludesVideo( output ) ) { |
| 73 |
options.push( { |
| 74 |
label: labels.video_post || 'Video (post)', |
| 75 |
value: 'video_post', |
| 76 |
} ); |
| 77 |
if ( includesScript ) { |
| 78 |
options.push( { |
| 79 |
label: labels.video_script || 'Video (script)', |
| 80 |
value: 'video_script', |
| 81 |
} ); |
| 82 |
} |
| 83 |
} |
| 84 |
|
| 85 |
return options; |
| 86 |
}; |
| 87 |
|
| 88 |
/** |
| 89 |
* The first produced asset, or None when the options hold no asset. |
| 90 |
* |
| 91 |
* @param {Array<{label: string, value: string}>} options The Embed options. |
| 92 |
* |
| 93 |
* @return {string} The default embed value. |
| 94 |
*/ |
| 95 |
const getDefaultEmbed = ( options ) => { |
| 96 |
const asset = options.find( ( option ) => option.value !== EMBED_NONE ); |
| 97 |
|
| 98 |
return asset ? asset.value : EMBED_NONE; |
| 99 |
}; |
| 100 |
|
| 101 |
const settingsFields = { |
| 102 |
init() { |
| 103 |
this.source = document.getElementById( 'beyondwords_source' ); |
| 104 |
this.output = document.getElementById( 'beyondwords_output' ); |
| 105 |
this.embed = document.getElementById( 'beyondwords_embed' ); |
| 106 |
this.embedTouched = document.getElementById( |
| 107 |
'beyondwords_embed_touched' |
| 108 |
); |
| 109 |
|
| 110 |
// Set before the guard below: the flag gates the whole save() write. |
| 111 |
if ( this.embed && this.embedTouched ) { |
| 112 |
this.embed.addEventListener( 'change', () => { |
| 113 |
this.embedTouched.value = '1'; |
| 114 |
} ); |
| 115 |
} |
| 116 |
|
| 117 |
if ( ! this.source && ! this.output ) { |
| 118 |
return; |
| 119 |
} |
| 120 |
|
| 121 |
if ( this.source ) { |
| 122 |
this.source.addEventListener( 'change', () => { |
| 123 |
this.toggleScriptTemplate(); |
| 124 |
this.recomputeEmbed(); |
| 125 |
} ); |
| 126 |
} |
| 127 |
|
| 128 |
if ( this.output ) { |
| 129 |
this.output.addEventListener( 'change', () => { |
| 130 |
this.toggleVideoFields(); |
| 131 |
this.recomputeEmbed(); |
| 132 |
} ); |
| 133 |
} |
| 134 |
|
| 135 |
// Sync initial visibility in case meta and markup drift. |
| 136 |
this.toggleScriptTemplate(); |
| 137 |
this.toggleVideoFields(); |
| 138 |
}, |
| 139 |
|
| 140 |
toggleScriptTemplate() { |
| 141 |
const show = this.source |
| 142 |
? sourceIncludesScript( this.source.value ) |
| 143 |
: false; |
| 144 |
toggle( |
| 145 |
'beyondwords-metabox-settings--beyondwords-script-template-id', |
| 146 |
show |
| 147 |
); |
| 148 |
}, |
| 149 |
|
| 150 |
toggleVideoFields() { |
| 151 |
const show = this.output |
| 152 |
? outputIncludesVideo( this.output.value ) |
| 153 |
: false; |
| 154 |
toggle( |
| 155 |
'beyondwords-metabox-settings--beyondwords-video-template-id', |
| 156 |
show |
| 157 |
); |
| 158 |
toggle( |
| 159 |
'beyondwords-metabox-settings--beyondwords-video-size', |
| 160 |
show |
| 161 |
); |
| 162 |
}, |
| 163 |
|
| 164 |
recomputeEmbed() { |
| 165 |
if ( ! this.embed ) { |
| 166 |
return; |
| 167 |
} |
| 168 |
|
| 169 |
const source = this.source ? this.source.value : SOURCE_POST; |
| 170 |
const output = this.output ? this.output.value : OUTPUT_AUDIO; |
| 171 |
const options = getEmbedOptions( source, output ); |
| 172 |
const previous = this.embed.value; |
| 173 |
const stillValid = options.some( ( o ) => o.value === previous ); |
| 174 |
// Only a stale value lands here — None is valid for every combination. |
| 175 |
const selected = stillValid ? previous : getDefaultEmbed( options ); |
| 176 |
|
| 177 |
this.embed.replaceChildren( |
| 178 |
...options.map( ( option ) => { |
| 179 |
const el = document.createElement( 'option' ); |
| 180 |
el.value = option.value; |
| 181 |
el.textContent = option.label; |
| 182 |
el.selected = option.value === selected; |
| 183 |
return el; |
| 184 |
} ) |
| 185 |
); |
| 186 |
}, |
| 187 |
}; |
| 188 |
|
| 189 |
if ( document.readyState !== 'loading' ) { |
| 190 |
settingsFields.init(); |
| 191 |
} else { |
| 192 |
document.addEventListener( 'DOMContentLoaded', () => |
| 193 |
settingsFields.init() |
| 194 |
); |
| 195 |
} |
| 196 |
} )(); |
| 197 |
|