diff --git a/README.md b/README.md
index 3296c38..3dc9cf7 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@ smoother for your content editing experience.
* No Database Required: NeoCMS works without a database, so you don’t have to worry about setup hassles or performance
slowdowns.
* Easy Content Editing: With our intuitive WYSIWYG editor, anyone can update content without writing a single line of
- code.
+ code. Adding the additional class *neo-dupe* will allow an element and it's children to be cloned.
* Seamless Integration: Simply add the CMS to any existing static website. Just assign a special class to the elements
you want to make editable, and you’re all set.
* Consistent Layouts: NeoCMS supports page templates to keep your layouts neat and uniform across all pages.
diff --git a/cms/js/cms.js b/cms/js/cms.js
index 001515c..4a292c5 100644
--- a/cms/js/cms.js
+++ b/cms/js/cms.js
@@ -11,9 +11,15 @@ $(document).ready(function () {
// Set up click handler on divs with class 'editable' in the iframe
$(iframeDoc).find('.editable').css('cursor', 'pointer').click(function (event) {
+ editElement(event, $(this));
+ });
+
+ // Edit Element Shared functionality
+
+ function editElement(event, element) {
event.preventDefault();
- currentDiv = $(this);
+ currentDiv = element;
// Get the content of the div
const content = currentDiv.html();
@@ -21,7 +27,7 @@ $(document).ready(function () {
// Set the content in TinyMCE
$('#editor').val(content);
- // Open the modal and init tinyMCE
+ // Open the modal and init TinyMCE
$('#editModal').modal('show')
.on('shown.bs.modal', function () {
tinymce.init({
@@ -37,13 +43,65 @@ $(document).ready(function () {
images_upload_credentials: true,
force_br_newlines: false,
force_p_newlines: false,
+ forced_root_block: 'aaa',
newline_behavior: 'linebreak'
});
});
+ }
+ regenerateButtons();
+
+ // Set up event handlers for duplication buttons inside the iframe
+ $(iframeDoc).on('click', '.duplicate-btn-before', function () {
+ var parentElement = $(this).closest('.neo-dupe');
+ var clonedElement = $(parentElement).clone();
+
+ // Remove buttons from the cloned element
+ clonedElement.find('.button-container').remove();
+
+ // Add system classes
+ clonedElement.addClass("neo-dupe");
+ clonedElement.addClass("editable");
+
+ // Insert the cloned element before the original parent element
+ clonedElement.insertBefore(parentElement);
+
+ // Trigger an event on the new duplicated element
+ clonedElement.trigger('elementDuplicated');
});
+
+ $(iframeDoc).on('click', '.duplicate-btn-after', function () {
+ var parentElement = $(this).closest('.neo-dupe');
+ var clonedElement = $(parentElement).clone();
+
+ // Remove buttons from the cloned element
+ clonedElement.find('.button-container').remove();
+
+ // Add system classes
+ clonedElement.addClass("neo-dupe");
+ clonedElement.addClass("editable");
+
+ // Insert the cloned element after the original parent element
+ clonedElement.insertAfter(parentElement);
+
+ // Trigger an event on the new duplicated element
+ clonedElement.trigger('elementDuplicated');
+ });
+
+ // Handle the custom 'elementDuplicated' event
+ $(iframeDoc).on('elementDuplicated', '.neo-dupe', function (event) {
+ // Example action: Animate the new element
+ $(this).hide().fadeIn('slow');
+
+ // Remove buttons if they are there
+ $(this).find('.button-container').remove();
+
+ editElement(event, $(this));
+ });
+ // Here for addButtonsForNeoDupe
});
+
// Save changes made to a div, but not save to the file on the server
$('#saveBtn').click(function () {
// Get the data from TinyMCE
@@ -70,7 +128,11 @@ $(document).ready(function () {
// Handle Saving changes to the page
$('#savePage').click(() => {
- frameContainerElement = $('#frameContainer').contents().get(0);
+
+ // Remove the buttons container as not to make things awks
+ $(iframeDoc).find('.button-container').remove();
+
+ let frameContainerElement = $('#frameContainer').contents().get(0);
$.post("/cms/controller/", {
action: "save",
uri: frameContainerElement.location.pathname,
@@ -81,8 +143,8 @@ $(document).ready(function () {
} else {
showMessage(data.message, "error");
}
- // alert(data)
});
+ regenerateButtons();
});
// Show dialog for page templates
@@ -139,11 +201,11 @@ $(document).ready(function () {
radioList.empty(); // Clear previous content
data.forEach(function (item, index) {
radioList.append(`
-
- `);
+
+ `);
});
},
error: function () {
@@ -192,10 +254,48 @@ $(document).ready(function () {
});
});
+ // Add buttons to all existing neo-dupe elements inside the iframe
+ function regenerateButtons() {
+ $(iframeDoc).find('.neo-dupe').each(function () {
+ $(this).find('.buttonContainer').remove();
+ addButtonsToNeoDupe(this);
+ });
+ }
+
+ // Function to add buttons to a neo-dupe element inside the iframe
+ function addButtonsToNeoDupe(element) {
+
+ /**
+ * DANGER WILL ROBINSON: This may break stuff, but is needed for the buttons to be positioned properly
+ * Since this is alpha, lets see how we go.
+ */
+ if ($(element).css('position') === 'static') {
+ $(element).css('position', 'relative');
+ }
+
+ var $buttonContainer = $(iframeDoc.createElement('div'));
+ $buttonContainer.addClass('button-container');
+ $buttonContainer.css("position", "absolute");
+ $buttonContainer.css("top", "5px");
+ $buttonContainer.css("right", "5px");
+
+ var $duplicateBeforeButton = $(iframeDoc.createElement('button'));
+ $duplicateBeforeButton.addClass('duplicate-btn-before').text('◀️').prop('title', 'Clone before');
+
+ var $duplicateAfterButton = $(iframeDoc.createElement('button'));
+ $duplicateAfterButton.addClass('duplicate-btn-after').text('▶️').prop('title', 'Clone after');
+
+ // Append buttons to the container
+ $buttonContainer.append($duplicateBeforeButton, $duplicateAfterButton);
+
+ // Prepend the container to the neo-dupe element
+ $(element).prepend($buttonContainer);
+ }
+
});
/**
- * Show A message bar across the top of the screen for a few seconds
+ * Show a message bar across the top of the screen for a few seconds
* @param message - string - message to be shown
* @param type - string "success" or "error"
*/
@@ -231,4 +331,5 @@ function showMessage(message, type) {
setTimeout(function () {
messageBar.slideUp();
}, 5000);
-}
\ No newline at end of file
+}
+