From af9276de95e669d89a1971247c6d381986f21ac8 Mon Sep 17 00:00:00 2001 From: Andy Dixon Date: Mon, 11 Nov 2024 19:06:12 +0000 Subject: [PATCH 1/2] Added element and child cloning with .neo-dupe - resolves issue #29 --- README.md | 2 +- cms/js/cms.js | 123 +++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 113 insertions(+), 12 deletions(-) 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..00176b5 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 +} + From 290a74cb29d6a361399962629200e90ab9b3900f Mon Sep 17 00:00:00 2001 From: Andy Dixon Date: Mon, 11 Nov 2024 19:06:59 +0000 Subject: [PATCH 2/2] Code cleanup --- cms/js/cms.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/cms/js/cms.js b/cms/js/cms.js index 00176b5..4a292c5 100644 --- a/cms/js/cms.js +++ b/cms/js/cms.js @@ -11,12 +11,12 @@ $(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)); + editElement(event, $(this)); }); // Edit Element Shared functionality - function editElement(event,element) { + function editElement(event, element) { event.preventDefault(); currentDiv = element; @@ -52,7 +52,7 @@ $(document).ready(function () { regenerateButtons(); // Set up event handlers for duplication buttons inside the iframe - $(iframeDoc).on('click', '.duplicate-btn-before', function() { + $(iframeDoc).on('click', '.duplicate-btn-before', function () { var parentElement = $(this).closest('.neo-dupe'); var clonedElement = $(parentElement).clone(); @@ -70,7 +70,7 @@ $(document).ready(function () { clonedElement.trigger('elementDuplicated'); }); - $(iframeDoc).on('click', '.duplicate-btn-after', function() { + $(iframeDoc).on('click', '.duplicate-btn-after', function () { var parentElement = $(this).closest('.neo-dupe'); var clonedElement = $(parentElement).clone(); @@ -89,14 +89,14 @@ $(document).ready(function () { }); // Handle the custom 'elementDuplicated' event - $(iframeDoc).on('elementDuplicated', '.neo-dupe', function(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)); + editElement(event, $(this)); }); // Here for addButtonsForNeoDupe }); @@ -275,15 +275,15 @@ $(document).ready(function () { var $buttonContainer = $(iframeDoc.createElement('div')); $buttonContainer.addClass('button-container'); - $buttonContainer.css("position","absolute"); - $buttonContainer.css("top","5px"); - $buttonContainer.css("right","5px"); + $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'); + $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'); + $duplicateAfterButton.addClass('duplicate-btn-after').text('▶️').prop('title', 'Clone after'); // Append buttons to the container $buttonContainer.append($duplicateBeforeButton, $duplicateAfterButton);