/**
* editableString browser helper.
*
* Mirrors gnexus-ui-kit editableString public surface.
*
* @param {HTMLElement} stringContainer - Container to replace with editable component
* @param {boolean} [isMultiString=false] - Use textarea instead of input
* @returns {HTMLElement} Component root element
*/
function template(originalText, isMultiString) {
const placeholder = "Write something";
const input = !isMultiString
? `<input type="text" class="input" placeholder="${placeholder}">`
: `<textarea class="input" placeholder="${placeholder}" rows="3"></textarea>`;
return `
<div class="editable-string-content">
<span class="editable-string">${originalText}</span>
<button type="button" class="btn-icon edit-text-btn" aria-label="Edit"><i class="ph ph-pencil-simple"></i></button>
</div>
<div class="editable-string-form d-none">
<div class="form-group">
<label class="label">
${input}
</label>
</div>
<button type="button" class="btn-icon apply-changes-btn" aria-label="Apply"><i class="ph ph-check"></i></button>
<button type="button" class="btn-icon cancel-changes-btn" aria-label="Cancel"><i class="ph ph-x"></i></button>
</div>
`;
}
export default function editableString(stringContainer, isMultiString = false) {
const originalText = stringContainer.innerHTML;
const component = document.createElement("div");
component.className = "editable-string-component";
component.innerHTML = template(originalText, isMultiString);
stringContainer.innerHTML = "";
stringContainer.append(component);
const editBtn = component.querySelector(".edit-text-btn");
const applyBtn = component.querySelector(".apply-changes-btn");
const cancelBtn = component.querySelector(".cancel-changes-btn");
const content = component.querySelector(".editable-string-content");
const editableStringEl = component.querySelector(".editable-string");
const form = component.querySelector(".editable-string-form");
const input = component.querySelector(".input");
const api = {
formIsDisplaying: false,
value: originalText,
input,
eventsHandlers: {
onChange: [],
onSwitch: []
},
switch: () => {
if(api.formIsDisplaying) {
form.classList.add("d-none");
content.classList.remove("d-none");
editableStringEl.textContent = api.value;
} else {
form.classList.remove("d-none");
content.classList.add("d-none");
input.value = api.value;
input.focus();
}
api.formIsDisplaying = !api.formIsDisplaying;
api.runEventHandler("onSwitch");
},
setValue: val => {
api.value = val;
input.value = val;
editableStringEl.textContent = val;
},
apply: () => {
const previousValue = api.value;
api.value = input.value;
api.switch();
if(input.value !== previousValue) {
api.runEventHandler("onChange");
}
},
onChange: cb => {
api.eventsHandlers.onChange.push(cb);
},
onSwitch: cb => {
api.eventsHandlers.onSwitch.push(cb);
},
runEventHandler: evName => {
api.eventsHandlers[evName].forEach(handler => handler(api));
}
};
component.editableString = api;
editBtn.addEventListener("click", () => api.switch());
cancelBtn.addEventListener("click", () => api.switch());
applyBtn.addEventListener("click", () => api.apply());
input.addEventListener("keydown", event => {
if(event.key === "Enter" && !isMultiString) {
input.blur();
api.apply();
}
if(event.key === "Escape") {
api.switch();
}
});
return component;
}