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.
191 lines
5.8 KiB
191 lines
5.8 KiB
12 months ago
|
/**
|
||
|
* @file
|
||
|
* Provides UI/UX progressive enhancements on Olives'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.olives.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-olives-custom-color', changedInput.value);
|
||
|
inputToSync.setAttribute('data-olives-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-olives-custom-color]`)
|
||
|
.forEach((input) => {
|
||
|
input.value = input.getAttribute('data-olives-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 Olives 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-olives-custom-color',
|
||
|
textInput.getAttribute('data-olives-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);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Olives Color Picker behavior.
|
||
|
*
|
||
|
* @type {Drupal~behavior}
|
||
|
* @prop {Drupal~behaviorAttach} attach
|
||
|
* Initializes color picker fields.
|
||
|
*/
|
||
|
Drupal.behaviors.olivesColorPicker = {
|
||
|
attach: () => {
|
||
|
const colorSchemeSelect = once(
|
||
|
'olives-color-picker',
|
||
|
'[data-drupal-selector="edit-color-scheme"]',
|
||
|
);
|
||
|
|
||
|
colorSchemeSelect.forEach((selectElement) => {
|
||
|
initColorSchemeSelect(selectElement);
|
||
|
});
|
||
|
|
||
|
const colorTextInputs = once(
|
||
|
'olives-color-picker',
|
||
|
'[data-drupal-selector="olives-color-picker"] input[type="text"]',
|
||
|
);
|
||
|
|
||
|
colorTextInputs.forEach((textInput) => {
|
||
|
initColorPicker(textInput);
|
||
|
});
|
||
|
},
|
||
|
};
|
||
|
})(Drupal, drupalSettings, once);
|