| 1 |
document.addEventListener( 'DOMContentLoaded', (): void => { |
| 2 |
addContentHelperTabEventHandlers(); |
| 3 |
setActiveTab(); |
| 4 |
window.addEventListener( 'hashchange', setActiveTab ); |
| 5 |
document.querySelector( '.media-single-image button.browse' )?.addEventListener( 'click', selectImage ); |
| 6 |
} ); |
| 7 |
|
| 8 |
function setActiveTab(): void { |
| 9 |
const activeTab = location.hash !== '' ? location.hash.substring( 1 ) : 'basic-section'; |
| 10 |
|
| 11 |
document.querySelectorAll( '.nav-tab' )?.forEach( ( t: Element ): void => { |
| 12 |
if ( t.classList.contains( activeTab + '-tab' ) ) { |
| 13 |
t.classList.add( 'nav-tab-active' ); |
| 14 |
} else { |
| 15 |
t.classList.remove( 'nav-tab-active' ); |
| 16 |
} |
| 17 |
} ); |
| 18 |
|
| 19 |
document.querySelectorAll( '.tab-content' )?.forEach( ( t: Element ): void => { |
| 20 |
if ( t.classList.contains( activeTab ) ) { |
| 21 |
t.setAttribute( 'style', 'display: initial' ); |
| 22 |
} else { |
| 23 |
t.setAttribute( 'style', 'display: none' ); |
| 24 |
} |
| 25 |
} ); |
| 26 |
|
| 27 |
const form = document.querySelector( 'form[name="parsely"]' ); |
| 28 |
if ( form ) { |
| 29 |
form.removeAttribute( 'hidden' ); |
| 30 |
form.setAttribute( 'action', `options.php#${ activeTab }` ); |
| 31 |
} |
| 32 |
} |
| 33 |
|
| 34 |
function selectImage( event: Event ) { |
| 35 |
const optionName = ( event.target as HTMLButtonElement ).dataset.option; |
| 36 |
|
| 37 |
const imageFrame = window.wp.media( { |
| 38 |
multiple: false, |
| 39 |
library: { |
| 40 |
type: 'image', |
| 41 |
}, |
| 42 |
} ); |
| 43 |
|
| 44 |
imageFrame.on( 'select', function() { |
| 45 |
const url = imageFrame.state().get( 'selection' ).first().toJSON().url; |
| 46 |
const inputSelector: string = '#media-single-image-' + optionName + ' input.file-path'; |
| 47 |
|
| 48 |
const inputElement: HTMLInputElement | null = document.querySelector( inputSelector ); |
| 49 |
if ( inputElement ) { |
| 50 |
inputElement.value = url; |
| 51 |
} |
| 52 |
} ); |
| 53 |
|
| 54 |
imageFrame.open(); |
| 55 |
} |
| 56 |
|
| 57 |
/** |
| 58 |
* Adds the necessary event handlers to the Content Helper tab. |
| 59 |
* |
| 60 |
* @since 3.16.0 |
| 61 |
*/ |
| 62 |
function addContentHelperTabEventHandlers(): void { |
| 63 |
// Selector for the checkbox that enables/disables all AI features. |
| 64 |
const aiFeaturesCheckbox = document.querySelector<HTMLInputElement>( |
| 65 |
'input#content_helper_ai_features_enabled' |
| 66 |
); |
| 67 |
|
| 68 |
// Selector for the checkboxes that enable/disable individual AI features. |
| 69 |
const featureCheckboxes = document.querySelectorAll<HTMLInputElement>( |
| 70 |
'input#content_helper_smart_linking_enabled, ' + |
| 71 |
'input#content_helper_title_suggestions_enabled, ' + |
| 72 |
'input#content_helper_excerpt_suggestions_enabled' |
| 73 |
); |
| 74 |
|
| 75 |
// Selector for all fieldsets in the Content Helper section. |
| 76 |
const fieldsets = document.querySelectorAll( |
| 77 |
'div.content-helper-section fieldset' |
| 78 |
); |
| 79 |
|
| 80 |
// Event handlers. |
| 81 |
enableAllFormFieldsOnSubmit(); |
| 82 |
updateAllFeatureSections(); // Must run on load to update the UI. |
| 83 |
|
| 84 |
aiFeaturesCheckbox?.addEventListener( 'change', (): void => { |
| 85 |
updateAllFeatureSections(); |
| 86 |
} ); |
| 87 |
|
| 88 |
featureCheckboxes.forEach( ( checkbox ): void => { |
| 89 |
checkbox.addEventListener( 'change', (): void => { |
| 90 |
updateFeatureSection( checkbox ); |
| 91 |
} ); |
| 92 |
} ); |
| 93 |
|
| 94 |
/** |
| 95 |
* Turns on/off all AI feature sections in the UI. |
| 96 |
* |
| 97 |
* @since 3.16.0 |
| 98 |
*/ |
| 99 |
function updateAllFeatureSections(): void { |
| 100 |
if ( ! aiFeaturesCheckbox ) { |
| 101 |
return; |
| 102 |
} |
| 103 |
|
| 104 |
if ( aiFeaturesCheckbox.checked ) { |
| 105 |
// Enable all applicable fieldsets. |
| 106 |
fieldsets.forEach( ( fieldset: Element ): void => { |
| 107 |
setDisabled( fieldset, false ); |
| 108 |
|
| 109 |
featureCheckboxes.forEach( ( checkbox ): void => { |
| 110 |
updateFeatureSection( checkbox ); |
| 111 |
} ); |
| 112 |
} ); |
| 113 |
} else { |
| 114 |
// Disable all fieldsets. |
| 115 |
fieldsets.forEach( ( fieldset: Element ): void => { |
| 116 |
if ( ! fieldset.querySelector( `#${ aiFeaturesCheckbox.id }` ) ) { |
| 117 |
setDisabled( fieldset ); |
| 118 |
} |
| 119 |
} ); |
| 120 |
|
| 121 |
// Disable "Enabled" labels. |
| 122 |
document.querySelectorAll( 'label.prevent-disable' ) |
| 123 |
.forEach( ( label: Element ): void => { |
| 124 |
setPreventDisable( label, false ); |
| 125 |
} ); |
| 126 |
} |
| 127 |
} |
| 128 |
|
| 129 |
/** |
| 130 |
* Turns on/off a specific feature section in the UI. |
| 131 |
* |
| 132 |
* @since 3.16.0 |
| 133 |
* |
| 134 |
* @param {HTMLInputElement} checkbox The checkbox controlling the feature. |
| 135 |
*/ |
| 136 |
function updateFeatureSection( checkbox: HTMLInputElement ): void { |
| 137 |
const userRolesFieldset = checkbox |
| 138 |
.closest( 'fieldset' )?.nextSibling?.nextSibling as HTMLElement; |
| 139 |
|
| 140 |
if ( checkbox.checked ) { |
| 141 |
setDisabled( [ checkbox, userRolesFieldset ], false ); |
| 142 |
} else { |
| 143 |
setDisabled( userRolesFieldset ); |
| 144 |
|
| 145 |
// Keep enabled styling on "Enabled" labels for visibility. |
| 146 |
const enabledLabel = checkbox.parentElement as HTMLLabelElement; |
| 147 |
setPreventDisable( enabledLabel ); |
| 148 |
} |
| 149 |
} |
| 150 |
|
| 151 |
/** |
| 152 |
* Allows or prevents an element from being shown as disabled. |
| 153 |
* |
| 154 |
* This is done by injecting a class into the element, which is used in CSS. |
| 155 |
* |
| 156 |
* @since 3.16.0 |
| 157 |
* |
| 158 |
* @param {Element} element The target element. |
| 159 |
* @param {boolean} status true to prevent disabled style, false to allow. |
| 160 |
*/ |
| 161 |
function setPreventDisable( element: Element, status: boolean = true ): void { |
| 162 |
if ( status ) { |
| 163 |
element.classList.add( 'prevent-disable' ); |
| 164 |
} else { |
| 165 |
element.classList.remove( 'prevent-disable' ); |
| 166 |
} |
| 167 |
} |
| 168 |
|
| 169 |
/** |
| 170 |
* Sets the disabled attribute on an element. |
| 171 |
* |
| 172 |
* @since 3.16.0 |
| 173 |
* |
| 174 |
* @param {Element | Element[]} element The target element. |
| 175 |
* @param {boolean} status true to disable, false to enable. |
| 176 |
*/ |
| 177 |
function setDisabled( element: Element | Element[], status: boolean = true ): void { |
| 178 |
if ( ! Array.isArray( element ) ) { |
| 179 |
element = [ element ]; |
| 180 |
} |
| 181 |
|
| 182 |
element.forEach( ( el: Element ): void => { |
| 183 |
if ( status ) { |
| 184 |
el.setAttribute( 'disabled', 'disabled' ); |
| 185 |
} else { |
| 186 |
el.removeAttribute( 'disabled' ); |
| 187 |
} |
| 188 |
} ); |
| 189 |
} |
| 190 |
|
| 191 |
/** |
| 192 |
* Allows the form to post its whole data. |
| 193 |
* |
| 194 |
* When elements are disabled, they are not included when submitting the |
| 195 |
* form, resulting in missing data. |
| 196 |
* |
| 197 |
* This workaround removes any disabled attribute so the form can submit its |
| 198 |
* whole data. It also prevents styling changes while the data is being |
| 199 |
* submitted, in order to avoid visual glitches. |
| 200 |
* |
| 201 |
* @since 3.16.0 |
| 202 |
*/ |
| 203 |
function enableAllFormFieldsOnSubmit(): void { |
| 204 |
document.querySelector( '.wp-admin form[name="parsely"]' ) |
| 205 |
?.addEventListener( 'submit', (): void => { |
| 206 |
const baseSelector = '.wp-admin .content-helper-section fieldset'; |
| 207 |
|
| 208 |
document.querySelectorAll( `${ baseSelector }[disabled]` ) |
| 209 |
.forEach( ( fieldset: Element ): void => { |
| 210 |
// Style the whole setting table row as disabled. |
| 211 |
fieldset.parentElement?.parentElement?.classList.add( |
| 212 |
'disabled-before-posting' |
| 213 |
); |
| 214 |
|
| 215 |
// Avoid disabled checkbox styling changes. |
| 216 |
fieldset.querySelectorAll( |
| 217 |
`${ baseSelector } label input[type="checkbox"]` |
| 218 |
).forEach( ( input: Element ): void => { |
| 219 |
input.classList.add( 'disabled' ); |
| 220 |
} ); |
| 221 |
|
| 222 |
fieldset.removeAttribute( 'disabled' ); |
| 223 |
} ); |
| 224 |
} ); |
| 225 |
} |
| 226 |
} |
| 227 |
|