<structr:shared-template name="Tailwind Main Page" data-structr-meta-content-type="text/html">
<!DOCTYPE html>
<html class="h-full bg-gray-100">
<head>
<title>Structr - ${localize(titleize(
page.name, '-'))}
</title> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<script>
tailwind.config = {
theme: {
extend: {
colors: {
green: '#84ba39',
greenhover: '#97cc4d'
}
}
}
}
$(document).ready(function () {
console.log('tessssss')
});
</script>
</head>
<body class="h-full antialiased font-sans"
onclick="document.querySelectorAll('.dynamic-menu:not(.hidden)').forEach(m => m.classList.toggle('hidden'))">
${render(children)}
</body>
</html>
</structr:shared-template>
<structr:template src="Tailwind Main Page">
<form id="dynamicForm" class="bg-white p-4 rounded shadow-md mb-6">
<div class="flex flex-col md:flex-row bg-white rounded-lg justify-between font-bold mb-4" id="formHeader">
<p class="py-2 px-4"><span class="text-red-500">*</span> Level</p>
<p class="py-2 px-4"><span class="text-red-500">*</span> Title</p>
<p class="py-2 px-4"><span class="text-red-500">*</span> Content Type</p>
<p class="py-2 px-4">Action</p>
</div>
<div class="w-full border-t mt-4" id="form-row">
<div class="flex flex-col md:flex-row justify-between items-center" id="form-input">
<div>
<select name="levelType[]" class="border rounded p-2 m-3 required">
<option value="1">1</option>
<option value="2">2</option>
</select>
</div>
<div>
<textarea name="text[]" class="w-full border text-sm rounded p-2 m-3 required"></textarea>
</div>
<div>
<select name="listType[]" class="border rounded p-2 m-3 required">
<option value="bullet">Bullet</option>
<option value="numerical">Numerical</option>
<option value="alphabetical">Alphabetical</option>
<option value="roman">Roman Numeral</option>
</select>
</div>
<div>
<button type="button" onclick="addRow()" class="bg-green-500 text-white px-4 py-2 rounded m-1">Add Row</button>
<button type="button" onclick="deleteRow(this)" class="bg-red-500 text-white px-4 py-2 rounded m-1" disabled>Delete</button>
</div>
</div>
<div id="accordion-collapse" data-accordion="collapse">
<h2 id="accordion-collapse-heading-1">
<button onclick="initAccord()" type="button" id="accordion1" class="flex items-center justify-between w-full p-2 text-sm font-medium rtl:text-right text-gray-500 border border-gray-200 rounded-t-xl active:text-white active:bg-blue-500 active:font-bold" data-accordion-target="#accordion-collapse-body-1" aria-expanded="true" aria-controls="accordion-collapse-body-1">
<span>Subcontent</span>
<svg data-accordion-icon class="w-3 h-3 shrink-0" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 10 6"> <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5 5 1 1 5"/>
</svg>
</button>
</h2>
<div id="accordion-collapse-body-1" class="hidden" aria-labelledby="accordion-collapse-heading-1">
<div class="bg-white" id="subList">
<div class="flex flex-row justify-between border-b p-4">
<h2 class="text-lg font-bold mb-4">Subcontent List</h2>
<button type="button" onclick="addSubcontent(this)" class="bg-blue-500 text-white px-4 py-2 rounded">Add Subcontent</button>
</div>
<div id="subcontentList-1" class="m-4"></div>
</div>
<div id="subcontent-form" class="bg-white p-6 hidden">
<h3 class="text-lg font-bold mb-4">Add Subcontent</h3>
<div class="mb-4">
<div class="flex">
<div class="flex items-center me-4">
<input id="toggleImage" type="checkbox" class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500">
<label for="toggleImage" class="ms-2 text-sm font-medium text-gray-900">Image</label>
</div>
<div class="flex items-center me-4">
<input checked id="toggleParagraph" type="checkbox" class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500">
<label for="toggleParagraph" class="ms-2 text-sm font-medium text-gray-900">Paragraph</label>
</div>
</div>
</div>
<div class="mb-4 border-black rounded" id="image-id" hidden>
<label class="block mb-2 text-sm font-medium text-gray-900" for="file_input">Upload Image</label>
<input class="block w-full text-sm text-gray-900 border border-gray-300 rounded-lg cursor-pointer bg-gray-50 focus:outline-none" id="file_input" type="file">
<p class="mt-1 text-sm text-gray-500 mb-2">JPEG, PNG, JPG or SVG (MAX. 800x400px).</p>
<label class="block mb-2 text-sm font-normal text-gray-900">Image Description</label>
<textarea id="imageDescription" class="w-full border rounded p-2"></textarea>
</div>
<div class="mb-6" id="paragraph-id">
<label class="block mb-2 text-sm font-medium text-gray-900">Add Paragraph</label>
<div id="richTextEditor"></div>
</div>
<button type="button" onclick="addSubcontentToList(this)" class="bg-green-500 text-white px-4 py-2 rounded">Add</button>
</div>
</div>
</div>
</div>
</form>
integrity="sha256-eKhayi8LEQwp4NKxN+CfCh+3qOVUtJn3QNZ0TciWLP4=" crossorigin="anonymous"></script>
<script>
let quill;
const subcontentMap = new Map();
let editIndex = null;
let accordionIndex = 2;
let subcontentListIndex = 1;
function initializeQuill() {
if (!$(".ql-toolbar").length) {
quill = new Quill("#richTextEditor", {
theme: "snow"
});
} else {
quill.root.innerHTML = "";
}
}
function addSubcontent(button) {
const rowElement = $(button).closest('#form-row');
rowElement.find(`#subcontent-form`).removeClass("hidden");
initializeQuill();
}
function addSubcontentToList() {
const content = quill.root.innerHTML;
const isImageChecked = $("#toggleImage").is(":checked");
const isParagraphChecked = $("#toggleParagraph").is(":checked");
let imagePreview = "";
let imageDescription = "";
if (isImageChecked) {
const fileInput = $("#file_input")[0].files;
const imageDescriptionInput = $("#imageDescription").val();
if (fileInput.length > 0) {
const reader = new FileReader();
reader.onload = function (e) {
imagePreview = `<img src="${e.target.result}" style="max-height: 400px; max-width: 400px;" alt="Uploaded Image"/>`;
imageDescription = imageDescriptionInput
? `<span class="text-gray-700 mt-2">${imageDescriptionInput}</span>`
: "";
saveSubcontent(imagePreview, isParagraphChecked ? content : "");
};
reader.readAsDataURL(fileInput[0]);
} else {
alert("Please select an image to upload.");
return;
}
} else {
saveSubcontent("", isParagraphChecked ? content : "");
}
}
function saveSubcontent(imageContent, paragraphContent) {
const combinedContent = `
${imageContent ? `<div>${imageContent}</div>` : ""}
${paragraphContent ? `<div>${paragraphContent}</div>` : ""}
`;
const subcontents = subcontentMap.get(subcontentListIndex) || [];
if (editIndex !== null) {
subcontents[editIndex] = combinedContent;
} else {
subcontents.push(combinedContent);
}
subcontentMap.set(subcontentListIndex, subcontents);
showSubcontentList();
}
function editSubcontent(index) {
const subcontents = subcontentMap.get(subcontentListIndex);
const contentToEdit = subcontents[index];
const doc = $("<div>").html(contentToEdit);
const image = doc.find("img");
const description = doc.find("span"); //no span detected to contentToEdit ("currVal: 'undefined'")
const paragraph = doc.find("p");
const imageSrc = image.attr("src");
const descriptionText = description.text();
const paragraphContent = paragraph.html();
console.log("Content to edit:", contentToEdit);
console.log("Paragraph content:", paragraphContent);
console.log("Description text:", descriptionText);
if (image.length) {
$("#toggleImage").prop("checked", true).trigger("change");
$("#file_input").val("");
$("#imageDescription").val(descriptionText);
} else {
$("#toggleImage").prop("checked", false).trigger("change");
}
if (paragraph.length) {
$("#toggleParagraph").prop("checked", true).trigger("change");
quill.root.innerHTML = paragraphContent;
} else {
$("#toggleParagraph").prop("checked", false).trigger("change");
quill.root.innerHTML = "Error fetching paragraph content.";
}
editIndex = index;
$("#subcontent-form").removeClass("hidden");
}
function showSubcontentList() {
console.log("Previous:", subcontentListIndex);
const subcontentList = $(`#subcontentList-${subcontentListIndex}`);
const newSubcontentList = `subcontentList-${subcontentListIndex}`;
const currSubList = subcontentList;
const subcontents = subcontentMap.get(subcontentListIndex) || [];
subcontents.forEach((content, index) => {
const item = $("<div></div>")
.addClass("p-2 border rounded bg-gray-100 flex justify-between items-center overflow-hidden m-2")
.html(`
<div class="overflow-hidden truncate" style="max-width: 70%;">${content}</div>
<div>
<button type="button" onclick="editSubcontent(${index})" class="bg-blue-500 text-white px-2 py-1 rounded mr-1">
<i class="fas fa-edit"></i>
</button>
<button type="button" onclick="deleteSubcontent(this, ${index})" class="bg-red-500 text-white px-2 py-1 rounded">
<i class="fas fa-trash"></i>
</button>
</div>
`);
currSubList.append(item);
});
subcontentListIndex++;
console.log("Current:", subcontentListIndex);
}
function deleteSubcontent(button, index) {
const subcontents = subcontentMap.get(subcontentListIndex);
subcontents.splice(index, 1);
subcontentMap.set(subcontentListIndex, subcontents);
$(button).closest("div").parent().remove();
}
function toggleVisibility(checkboxId, divId) {
$("#" + checkboxId).on("change", function() {
if ($(this).is(":checked")) {
$("#" + divId).show();
} else {
$("#" + divId).hide();
}
});
}
function initAccord() {
$(document).on("click", "[data-accordion-target]", function () {
const target = $(this).data("accordion-target");
$(target).toggleClass("hidden");
$(this).find("svg").toggleClass("rotate-180");
});
}
function addRow() {
const row = $("#dynamicForm").find("#form-row").first();
const newRow = row.clone();
newRow.attr("data-row-id", subcontentListIndex);
newRow.find("textarea").val("");
newRow.find("select").prop("selectedIndex", 0);
const accordionHeading = newRow.find('[id^="accordion-collapse-heading"]');
const accordionBody = newRow.find('[id^="accordion-collapse-body"]');
const subcontentList = newRow.find('[id^="subcontentList"]');
const newAccordionHeadingId = `accordion-collapse-heading-${accordionIndex}`;
const newAccordionBodyId = `accordion-collapse-body-${accordionIndex}`;
accordionHeading.attr("id", newAccordionHeadingId);
accordionHeading.attr("aria-controls", newAccordionHeadingId);
accordionBody.attr("id", newAccordionBodyId);
accordionBody.attr("aria-labelledby", newAccordionHeadingId);
$(`#${newAccordionBodyId}`).addClass("hidden");
const accordionButton = newRow.find("[data-accordion-target]");
accordionButton.attr("data-accordion-target", `#${newAccordionBodyId}`);
const buttons = newRow.find("button");
buttons.eq(0).attr("onclick", "addRow()");
buttons.eq(1).attr("onclick", "deleteRow(this)").prop("disabled", false);
subcontentMap.set(subcontentListIndex, []);
$("#dynamicForm").append(newRow);
accordionIndex++;
}
function deleteRow(button) {
const row = $(button).closest("#form-row");
row.remove();
}
function generateNewRowId() {
return `row-${Date.now()}`;
}
$(document).ready(function () {
console.log('tges')
const firstRowLevelType = $("#dynamicForm").find("#form-row").first().find('select[name="levelType[]"]');
firstRowLevelType.val("1").prop("disabled", true);
toggleVisibility("toggleParagraph", "paragraph-id");
toggleVisibility("toggleImage", "image-id");
initializeQuill();
});
</script>
</structr:template>