gristlabs / grist-core

Grist is the evolution of spreadsheets.
https://www.getgrist.com/
Apache License 2.0
7.1k stars 316 forks source link

Liquid support for widgets #197

Open jalberto opened 2 years ago

jalberto commented 2 years ago

Currently, it is possible to use LiquidJS to create a widget using Liquid, but is a bit cumbersome and unnatural as it requires to ass all the code into a scrtip tag.

Will be great to add native support to Liquid in Grist so files with liquid extension get to render natively y Grist.

This will make it much simpler to build custom widgets and will require fewer dependencies for simpler widgets.

It also opens the path to store custom widgets directly in Grist

paulfitz commented 2 years ago

Interesting idea @jalberto. One possibility might be to use the onEditOptions hook of custom widgets https://support.getgrist.com/widget-custom/#widget-options and write a single generic custom widget for liquid support, with an editing mode for the liquid code only, not the common html boilerplate. My colleague @berhalak wrote an even more generic custom widget like this that saved javascript html in the document as configuration, see an example in https://docs.getgrist.com/r6QRps5rKMj1/Jareks-fiddle-widget/m/fork The source code for that is in https://github.com/berhalak/my-widgets/

All that said, I'd be interested to hear more about your workflow, and how you'd see a polished liquid-supporting widget working. For files with a liquid extension, do you mean having attachments that are that kind of file render in some way, with fields filled from the row they are in?

jalberto commented 2 years ago

I can see 2 uses cases:

  1. a way to bundle a widget (a single liquid file with css/html) into Grist, maybe using a specific DB to store it as liquid is design to be safe to store and just getting the required JS from Grist to access the records
  2. a liquid file (or the liquid itself) stored in a (hidden?) attribute or maybe as a formula, that will show the content of the row in a specific way

I am playing with the Invoicing template right now, and as a freelance, I may need to invoice to companies in different countries, and each one requires different format or detail ls or language, so to be able to customize each invoice individually add a lot of flexibility.

Right now, I am playing with this idea:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Grist Invoice</title>

    <!-- A template for showing an invoice in a Custom Widget in Grist. -->
    <script src="https://cdn.jsdelivr.net/npm/liquidjs/dist/liquid.browser.umd.js"></script>
    <script src="https://docs.getgrist.com/grist-plugin-api.js"></script>

    <script src="widget.js?ver=1"></script>
    <link rel="stylesheet" href="widget.css?ver=1">
  </head>
  <body class="d-none">
    <h2>Welcome to {{ data.Name | capitalize }}</h2>
  </body>
</html>
document.addEventListener('DOMContentLoaded', () => {
  var Liquid = window.liquidjs.Liquid
  var engine = new Liquid({
    extname: '.html',
    cache: true
  });
  var src = document.body.innerHTML

  grist.ready({requiredAccess: 'read table'});

  grist.onRecord(function(record) {
    var ctx = {
      data: record
    };
    engine.parseAndRender(src, ctx)
      .then(function(html) {
        document.body.innerHTML = html
        document.body.classList.remove('d-none')
      });
  });
})

It can become a new type of widget with only the liquid/css part editable and will all the JS already embedded to get access to the records or even to create custom forms.

jalberto commented 2 years ago
    <table>
      {% tablerow i in (3..5) %}
      {{ i }}
      {% endtablerow %}
    </table>

This simple snippet fails hard, do not render the rows and the content somehow sit outside table. Similar oddities happen with every iterator in particular when used inside table (it works well with div thou.

I tried different way to render the result, but I cannot find what is happening. Using LiquidJs outside of Grist works as expected (ie in the official playground)

I wonder if something is creating a conflict or dying silently

jalberto commented 2 years ago

It seems like Grist is somehow modifying the html once embedded, you can see here the logs: https://github.com/harttle/liquidjs/issues/504

Is that expected?

paulfitz commented 2 years ago

Could you make the https://docs.getgrist.com/a8X5yeTvzGx2/Invoicing-copy doc mentioned in that thread public?

No, I wouldn't expect Grist to touch anything within your custom widget, which is a distinct iframe.

jalberto commented 2 years ago

Now public, the only way I found to make it work is to wrap everything in a script tag, but that is not ideal.

paulfitz commented 2 years ago

Thanks! Maybe you could narrow the problem down further by removing the grist parts and calling function(record) with a static record? Just for testing. Then you could view the page outside of Grist entirely.

I notice my browser isn't happy about the syntax of the page from a HTML perspective, don't know if that is relevant: Screenshot from 2022-05-14 10-39-16