((dn, schema, inputs, ldifOutput, classContainer, addClassSelect, addClassBtn) => { let changes = [], multipleValues = {}, maxInputId = 0, newClasses = {}, attributeCount = {}; function ComputeChanges() { let classChanges = []; let actualChanges = []; for (let i in newClasses) classChanges.push(`add: objectClass\nobjectClass: ${i}`); for (let i = 0; i < changes.length; ++i) { let ch = changes[i]; if (!ch) continue; if (ch.initialValue.length && ch.newValue.length && (multipleValues[ch.attrName] || 0) === 1) { actualChanges.push(`replace: ${ch.attrName}\n${ch.attrName}: ${ch.newValue}`); } else { if (ch.initialValue.length) { if ((multipleValues[ch.attrName] || 0) === 1) actualChanges.push(`delete: ${ch.attrName}`); else actualChanges.push(`delete: ${ch.attrName}\n${ch.attrName}: ${ch.initialValue}`); } if (ch.newValue.length) actualChanges.push(`add: ${ch.attrName}\n${ch.attrName}: ${ch.newValue}`); } } let totalChanges = classChanges.concat(actualChanges.sort((a, b) => b.localeCompare(a))); if (!totalChanges.length) return ""; return `dn: ${dn}\nchangetype: modify\n` + totalChanges.join("\n-\n"); } function UpdateLdif() { ldifOutput.textContent = ComputeChanges(); ldifOutput.style.height = ldifOutput.scrollHeight + "px" } function onValueChanged(input) { let initialValue = input.dataset.initialValue || "", inputId = input.dataset.inputId, newValue = input.value || "", attrName = input.dataset.attributeName; if (initialValue === newValue) changes[inputId] = undefined; else changes[inputId] = { initialValue: initialValue, newValue: newValue, attrName: attrName }; UpdateLdif(); } function getEditLink(className, attrName) { for (var i in window.editlinks) { if (window.editlinks[i].indexOf(`${className}.${attrName}`) >= 0) return i; } return null; } function manageEditLink(input) { const editLink = getEditLink(input.dataset.klass, input.dataset.attributeName); if (!editLink) return; let linkWrapper = document.createElement("div"); let link = document.createElement("a"); input.disabled = true; linkWrapper.className = "editlink"; link.textContent = editLink; link.href = editLink; link.target = "_blank"; linkWrapper.appendChild(link); input.parentNode.appendChild(linkWrapper); } let prevItem = null; // input field function removeButtonHandler(input, li) { return (e) => { e?.preventDefault(); if (multipleValues[input.dataset.attributeName]) multipleValues[input.dataset.attributeName]--; if (!multipleValues[input.dataset.attributeName] && input.dataset.mandatory) { // remove last remove button } input.value = ""; onValueChanged(input); li.bsTooltip.hide(); li.parentNode.removeChild(li); }; } function addAddButton(input, li) { let addButton = document.createElement("a"); addButton.innerText = ""; addButton.className = "button button-add bi bi-plus-circle"; addButton.src = "#"; addButton.parentInput = input; addButton.addEventListener("click", (e) => { e.preventDefault(); let line = addButton.parentInput.parentNode.parentNode; let copy = line.cloneNode(true); line.parentNode.insertBefore(copy, line); let input = copy.querySelector("label input"); input.value = ""; input.dataset.initialValue = ""; input.addEventListener("change", e => onValueChanged(e.currentTarget)); input.dataset.inputId = ++maxInputId; multipleValues[input.dataset.attributeName] = (multipleValues[input.dataset.attributeName] || 1) + 1; if (!copy.querySelector(".button-remove")) { addRemoveButton(line.querySelector("label > input"), line); addRemoveButton(input, copy); } else { copy.querySelector(".button-remove")?.addEventListener("click", removeButtonHandler(input, copy)); } let button = copy.querySelector("label > span > .button-add"); button.parentNode.removeChild(button); setTooltipFromInput(input); }); li.querySelector(".LDAPAttribute > span").appendChild(addButton); } function addRemoveButton(input, li) { if (input.dataset.isMandatory == "true" && (multipleValues[input.dataset.attributeName] || 1) <= 1) return; let button = document.createElement("a"); button.innerText = ""; button.className = "button button-remove bi bi-dash-circle"; button.src = "#"; button.addEventListener("click", removeButtonHandler(input, li)); li.querySelector(".LDAPAttribute > span").appendChild(button); } function manageDuplicateAttributes(li, input) { attributeCount[input.dataset.attributeName] = (attributeCount[input.dataset.attributeName] || {}); attributeCount[input.dataset.attributeName][input.dataset.klass] = true; if (Object.keys(attributeCount[input.dataset.attributeName]).length > 1) li.style.display = "none"; } function setTooltip(li, description) { if (!description) return; li.dataset.bsTitle = description; li.dataset.bsToggle = "tooltip"; li.bsTooltip = new bootstrap.Tooltip(li, { trigger: "hover" }); } function setTooltipFromInput(input) { setTooltip(input.parentNode.parentNode, schema[input.dataset.klass]?.descriptions?.[input.dataset.attributeName]); } inputs.forEach(i => { maxInputId = Math.max(i.dataset.inputId, maxInputId); i.dataset.isMandatory = i.parentNode.children[0].classList.contains("mandatory"); let attrName = i.dataset.attributeName; if ((i.dataset.initialValue || "").length) multipleValues[attrName] = (multipleValues[attrName] || 0) + 1; i.addEventListener("change", e => onValueChanged(e.currentTarget)) if (prevItem != null && prevItem.dataset.attributeName !== i.dataset.attributeName) { addAddButton(prevItem, prevItem.parentNode.parentNode); } prevItem = i; manageDuplicateAttributes(i.parentElement.parentElement.parentElement, i); setTooltipFromInput(i); manageEditLink(i); }); inputs.forEach(i => { addRemoveButton(i, i.parentNode.parentNode); }); prevItem && addAddButton(prevItem, prevItem.parentNode.parentNode); function CreateClassAttributeDom(className, name, init, isMandatory) { let li = document.createElement("li"); let label = document.createElement("label"); label.classList.add("LDAPAttribute"); label.classList.add("form-label"); li.appendChild(label); let span = document.createElement("span"); if (isMandatory) span.classList.add("mandatory"); span.innerText = name; let inputWrapper = document.createElement("span"); let input = document.createElement("input"); inputWrapper.className = "form-input-wrapper"; input.type = "text"; input.value = init; input.dataset.initialValue = init; input.dataset.inputId = ++maxInputId; input.dataset.name = name; input.dataset.klass = className; input.dataset.attributeName = name; input.required = isMandatory; input.className = "form-control"; input.addEventListener("change", e => onValueChanged(e.currentTarget)) label.appendChild(span); label.appendChild(inputWrapper); inputWrapper.appendChild(input); addAddButton(input, li); if (!isMandatory) addRemoveButton(input, li); manageDuplicateAttributes(li, input); manageEditLink(input); setTooltipFromInput(input); return li; } function CreateClassDom(schema, className) { let classDom = document.createElement("fieldset"); classDom.classList.add("LDAPClass"); let legend = document.createElement("legend"); let legendInner = document.createElement("h3"); legendInner.innerText = className +' (' +schema["type"] +')'; legend.appendChild(legendInner); classDom.appendChild(legend); let list = document.createElement("ul"); for (let i of schema["must"]) list.appendChild(CreateClassAttributeDom(className, i, "", true)); for (let i of schema["may"]) list.appendChild(CreateClassAttributeDom(className, i, "", false)); classDom.appendChild(list); return classDom; } addClassBtn.addEventListener("click", () => { let targetClass = addClassSelect.value; if (!schema[targetClass]) return; for (let i of addClassSelect.children) { if (i.value === targetClass) { addClassSelect.removeChild(i); break; } } newClasses[targetClass] = true; let dom = CreateClassDom(schema[targetClass], targetClass); classContainer.appendChild(dom); UpdateLdif(); }); })( window['dn'], window['schema'], document.querySelectorAll(".LDAPAttribute input"), document.getElementById("ldifOutput"), document.getElementById("classContainer"), document.getElementById("addClassSelect"), document.getElementById("addClassBtn"));