You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
190 lines
5.8 KiB
190 lines
5.8 KiB
/** |
|
* @file |
|
* Provides UI/UX progressive enhancements on Olivera's theme settings by |
|
* creating an HTMLColorInput element and synchronizing its input with a text |
|
* input to provide an accessible and user-friendly interface. Additionally, |
|
* provides a select element with pre-defined color values for easy color |
|
* switching. |
|
*/ |
|
|
|
((Drupal, settings, once) => { |
|
const colorSchemeOptions = settings.olivera.colorSchemes; |
|
|
|
/** |
|
* Announces the text value of the field's label. |
|
* |
|
* @param {HTMLElement} changedInput |
|
* The form element that was changed. |
|
*/ |
|
function announceFieldChange(changedInput) { |
|
const fieldTitle = |
|
changedInput.parentElement.querySelector('label').innerText; |
|
const fieldValue = changedInput.value; |
|
const announcement = Drupal.t('@fieldName has changed to @fieldValue', { |
|
'@fieldName': fieldTitle, |
|
'@fieldValue': fieldValue, |
|
}); |
|
Drupal.announce(announcement); |
|
} |
|
|
|
/** |
|
* `input` event callback to keep text & color inputs in sync. |
|
* |
|
* @param {HTMLElement} changedInput input element changed by user |
|
* @param {HTMLElement} inputToSync input element to synchronize |
|
*/ |
|
function synchronizeInputs(changedInput, inputToSync) { |
|
inputToSync.value = changedInput.value; |
|
|
|
changedInput.setAttribute('data-olivera-custom-color', changedInput.value); |
|
inputToSync.setAttribute('data-olivera-custom-color', changedInput.value); |
|
|
|
const colorSchemeSelect = document.querySelector( |
|
'[data-drupal-selector="edit-color-scheme"]', |
|
); |
|
|
|
if (colorSchemeSelect.value !== '') { |
|
colorSchemeSelect.value = ''; |
|
announceFieldChange(colorSchemeSelect); |
|
} |
|
} |
|
|
|
/** |
|
* Set individual colors when a pre-defined color scheme is selected. |
|
* |
|
* @param {Event.target} target input element for which the value has changed. |
|
*/ |
|
function setColorScheme({ target }) { |
|
if (!target.value) return; |
|
|
|
const selectedColorScheme = colorSchemeOptions[target.value].colors; |
|
|
|
if (selectedColorScheme) { |
|
Object.entries(selectedColorScheme).forEach(([key, color]) => { |
|
document |
|
.querySelectorAll(`input[name="${key}"], input[name="${key}_visual"]`) |
|
.forEach((input) => { |
|
if (input.value !== color) { |
|
input.value = color; |
|
if (input.type === 'text') { |
|
announceFieldChange(input); |
|
} |
|
} |
|
}); |
|
}); |
|
} else { |
|
document |
|
.querySelectorAll(`input[data-olivera-custom-color]`) |
|
.forEach((input) => { |
|
input.value = input.getAttribute('data-olivera-custom-color'); |
|
}); |
|
} |
|
} |
|
|
|
/** |
|
* Displays and initializes the color scheme selector. |
|
* |
|
* @param {HTMLSelectElement} selectElement div[data-drupal-selector="edit-color-scheme"] |
|
*/ |
|
function initColorSchemeSelect(selectElement) { |
|
selectElement.closest('[style*="display:none;"]').style.display = ''; |
|
selectElement.addEventListener('change', setColorScheme); |
|
Object.entries(colorSchemeOptions).forEach((option) => { |
|
const [key, values] = option; |
|
|
|
const { label, colors } = values; |
|
|
|
let allColorsMatch = true; |
|
Object.entries(colors).forEach(([colorName, colorHex]) => { |
|
const field = document.querySelector( |
|
`input[type="text"][name="${colorName}"]`, |
|
); |
|
if (field.value !== colorHex) { |
|
allColorsMatch = false; |
|
} |
|
}); |
|
|
|
if (allColorsMatch) { |
|
selectElement.value = key; |
|
} |
|
}); |
|
} |
|
|
|
/** |
|
* Initializes Olivera theme-settings color picker. |
|
* creates a color-type input and inserts it after the original text field. |
|
* modifies aria values to make label apply to both inputs. |
|
* adds event listeners to keep text & color inputs in sync. |
|
* |
|
* @param {HTMLElement} textInput The textfield input from the Drupal form API |
|
*/ |
|
function initColorPicker(textInput) { |
|
// Create input element. |
|
const colorInput = document.createElement('input'); |
|
|
|
// Set new input's attributes. |
|
colorInput.type = 'color'; |
|
colorInput.classList.add( |
|
'form-color', |
|
'form-element', |
|
'form-element--type-color', |
|
'form-element--api-color', |
|
); |
|
colorInput.value = textInput.value; |
|
colorInput.setAttribute('name', `${textInput.name}_visual`); |
|
colorInput.setAttribute( |
|
'data-olivera-custom-color', |
|
textInput.getAttribute('data-olivera-custom-color'), |
|
); |
|
|
|
// Insert new input into DOM. |
|
textInput.after(colorInput); |
|
|
|
// Make field label apply to textInput and colorInput. |
|
const fieldID = textInput.id; |
|
const label = document.querySelector(`label[for="${fieldID}"]`); |
|
label.removeAttribute('for'); |
|
label.setAttribute('id', `${fieldID}-label`); |
|
|
|
textInput.setAttribute('aria-labelledby', `${fieldID}-label`); |
|
colorInput.setAttribute('aria-labelledby', `${fieldID}-label`); |
|
|
|
// Add `input` event listener to keep inputs synchronized. |
|
textInput.addEventListener('input', () => { |
|
synchronizeInputs(textInput, colorInput); |
|
}); |
|
|
|
colorInput.addEventListener('input', () => { |
|
synchronizeInputs(colorInput, textInput); |
|
}); |
|
} |
|
|
|
/** |
|
* Olivera Color Picker behavior. |
|
* |
|
* @type {Drupal~behavior} |
|
* @prop {Drupal~behaviorAttach} attach |
|
* Initializes color picker fields. |
|
*/ |
|
Drupal.behaviors.oliveraColorPicker = { |
|
attach: () => { |
|
const colorSchemeSelect = once( |
|
'olivera-color-picker', |
|
'[data-drupal-selector="edit-color-scheme"]', |
|
); |
|
|
|
colorSchemeSelect.forEach((selectElement) => { |
|
initColorSchemeSelect(selectElement); |
|
}); |
|
|
|
const colorTextInputs = once( |
|
'olivera-color-picker', |
|
'[data-drupal-selector="olivera-color-picker"] input[type="text"]', |
|
); |
|
|
|
colorTextInputs.forEach((textInput) => { |
|
initColorPicker(textInput); |
|
}); |
|
}, |
|
}; |
|
})(Drupal, drupalSettings, once);
|
|
|