Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drag drop builder for ASP mvc core 8 / 9 LTS #372

Open
papyr opened this issue Aug 5, 2024 · 5 comments
Open

Drag drop builder for ASP mvc core 8 / 9 LTS #372

papyr opened this issue Aug 5, 2024 · 5 comments

Comments

@papyr
Copy link

papyr commented Aug 5, 2024

Hello I have managed with some help, but need to persist as structured content so its easy to recreate and version the pages like wordpress in our .net core CMS.

I think this will also help others, but its just an initial cut, I wanted to get the richer structured aspects of the content like imaged and formatting capture/rendered/options etc stored, can you you please help. I will make it a nuget package


using Microsoft.AspNetCore.Mvc;
using System.Text.Json;

namespace MyAspCMS.Controllers
{
    public class VvvebController : Controller
    {
        [HttpGet]
        public IActionResult Index()
        {
            return View();
        }

        [HttpPost]
        public IActionResult SaveContent(string content)
        {
            // Save the content to the database or file system
            // For example:
            var vvvebContent = new VvvebContent
            {
                Content = content
            };
            _dbContext.VvvebContents.Add(vvvebContent);
            _dbContext.SaveChanges();

            return RedirectToAction("Index");
        }
    }
}


namespace MyMvcApp.Models
{
    public class VvvebContent
    {
        [Key]
        public int Id { get; set; }
        public string Content { get; set; }
    }
}

//Index.cshtml

@{
    ViewData["Title"] = "ASP with Vvveb Editor";
}

<div id="vvveb-editor"></div>

<script src="https://cdn.jsdelivr.net/npm/vvveb@1.0.0/dist/vvveb.min.js"></script>
<script>
    var vvvebEditor = new VvvebEditor(document.getElementById('vvveb-editor'), {
        // Options for the editor
    });

    // Save the content when the user clicks the save button
    document.getElementById('save-button').addEventListener('click', function() {
        var content = vvvebEditor.getJson();
        fetch('/Vvveb/SaveContent', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(content)
        })
        .then(response => response.json())
        .then(data => console.log(data))
        .catch(error => console.error('Error:', error));
    });
</script>



///# Startup.cs
namespace MyCMSVvvebJs
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();
            services.AddDbContext<MyDbContext>(options =>
                options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseRouting();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}
@givanz
Copy link
Owner

givanz commented Aug 21, 2024

Thank you for the C# example.

I wanted to get the richer structured aspects of the content like imaged and formatting capture/rendered/options etc stored

The editor only exports the page html it does not export other states like changed component properties or assets.

If you want to save page assets like images, css, javascript files you can check the jszip plugin code https://github.com/givanz/VvvebJs/blob/master/libs/builder/plugin-jszip.js#L29-L43 that gets all page assets and generates a zip file with the page and all assets.

@papyr
Copy link
Author

papyr commented Aug 23, 2024

ok thanks, I need some help and I can map it on my own, and share if you want.

I need to store newly created forms in the Vvvebjs as tables, and table data.

how do I get the table/div or dom structure as a json object for the user created forms, so that I can save the fields of the form in a table.

My plan is to auto script (new table, from form Json structure, date, text, input etc), the save user data from the forms.

@givanz
Copy link
Owner

givanz commented Sep 3, 2024

You can use Vvveb.Builder.frameBody to access page body and iterate over form elements and serialize fields to json.

Vvveb.Builder.frameBody.querySelectorAll("form").forEach(f => {
   console.log( JSON.stringify(Object.fromEntries(new FormData(f))) ); 
});

@papyr
Copy link
Author

papyr commented Oct 1, 2024

Hello @givanz , sorry for the delay

I was able to capture this on the backend, I also put a version number to let user update their forms. They can use this code in any web app or mobile app or even CMS.

using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
public class VvvebFormCaptureV2
    {
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly YourDbContext _dbContext;

        public VvvebFormCaptureV2(IHttpContextAccessor httpContextAccessor, YourDbContext dbContext)
        {
            _httpContextAccessor = httpContextAccessor;
            _dbContext = dbContext;
        }

        public async Task CaptureFormsAsync()
        {
            var forms = await GetFormsFromHtmlAsync();
            await SaveFormsToDatabaseAsync(forms);
        }

        private async Task<List<FormModel>> GetFormsFromHtmlAsync()
        {
            var html = await GetHtmlFromRequestAsync();
            var forms = new List<FormModel>();

            // Use HtmlAgilityPack to parse the HTML and extract forms
            var htmlDoc = new HtmlDocument();
            htmlDoc.LoadHtml(html);
            var formNodes = htmlDoc.DocumentNode.SelectNodes("//form");

            foreach (var formNode in formNodes)
            {
                var formModel = new FormModel();
                formModel.Id = Guid.NewGuid();
                formModel.Html = formNode.OuterHtml;

                // Extract form data using vvveb.js approach
                var formData = new FormData(formNode);
                var entries = formData.Entries;
                var formJson = JsonSerializer.Serialize(Object.FromEntries(entries));

                formModel.Json = formJson;
                forms.Add(formModel);
            }

            return forms;
        }

        private async Task<string> GetHtmlFromRequestAsync()
        {
            var request = _httpContextAccessor.HttpContext.Request;
            var html = await new StreamReader(request.Body).ReadToEndAsync();
            return html;
        }

        private async Task SaveFormsToDatabaseAsync(List<FormModel> forms)
        {
            _dbContext.Forms.AddRange(forms);
            await _dbContext.SaveChangesAsync();
        }
    }

    public class FormModel
    {
        public Int Version { get; set; }
        public Guid Id { get; set; }
        public string Html { get; set; }
        public string Json { get; set; }
    }

but when we get the form back from DB, if i display on browser, how does the builder know which components correspond to which icons in the drag drop, if the user wants to edit a previous form.

Also how to extend with other icons, like user wants add something like apex charts, https://echarts.apache.org/examples/en/index.html

in my use case the user creates the HTML, and then I have add the C# data models back to it

@givanz
Copy link
Owner

givanz commented Oct 6, 2024

Hi

Components can match page elements by tag name, class or attributes.

For custom components a convention with data-component-name attribute is used for example maps component uses data-component-maps https://github.com/givanz/VvvebJs/blob/master/libs/builder/components-widgets.js#L23

  • nodes - An array with dom node names to allow the editor to detect the Component when clicking on the corresponding node, example nodes: ["h1", "h2","h3", "h4","h5","h6"], or nodes: ["img"],
  • classes - An array with class names to allow the editor to detect the Component when clicking on the corresponding node, example classes: ["btn", "btn-link"]
  • classesRegex - An array with regexs used for class names to allow the editor to detect the Component when clicking on the corresponding node, example classesRegex: ["col-"], this regex is used by Grid Component to detect bootstrap columns such as col-md-3 or col-sm-6.
  • attributes - An array with attributes names to allow the editor to detect the Component when clicking on the corresponding node, example attributes: ["data-component-maps"], this attribute is used by maps component.

https://github.com/givanz/VvvebJs/wiki/Components#component-definition

You can adapt the existing chartjs component to work with apex charts https://github.com/givanz/VvvebJs/blob/master/libs/builder/components-widgets.js#L626

You can add new components with Vvveb.Components.extend or Vvveb.Components.add

Vvveb.Components.extend("_base", "mygroup/mycomponent1", {
    nodes: ["img"],
    name: "Image",
    html: '<img src="../libs/builder/icons/image.svg" height="128" width="128">',
    image: "icons/image.svg",
    properties: [{
        name: "Image",
        key: "src",
        htmlAttr: "src",
        inputtype: FileUploadInput
    }, {
        name: "Width",
        key: "width",
        htmlAttr: "width",
        inputtype: TextInput
    }, {
        name: "Height",
        key: "height",
        htmlAttr: "height",
        inputtype: TextInput
    }, {
        name: "Alt",
        key: "alt",
        htmlAttr: "alt",
        inputtype: TextInput
    }]
});

then add the component to a group

Vvveb.ComponentsGroup['Mygroup'] = ["mygroup/mycomponent1", "mygroup/mycomponent2"];

https://github.com/givanz/VvvebJs/wiki/Components

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants