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

Possibility to include content from a different file verbatim #99

Open
BeastyBlacksmith opened this issue Jul 20, 2022 · 9 comments
Open

Comments

@BeastyBlacksmith
Copy link

There should be some mechanism to include content from a different file in the document.

For example code from an already written source file or data from a csv-file.
Ideally this would be somewhat intelligent and wrap the content in the corresponding fence, but that is just icing on the cake.

@andre-dietrich
Copy link
Member

Well actually there is a way ... you can use scripts for this:

<script style="width: 100%; display: block" run-once="true" modify="false">
let table = `<!-- data-show="true" -->
| x | y |
|---|---|
`

for(let x=0; x<100; x++) {
    table += "|" + x + "|" + Math.random() * 100 + "|" + "\n"
}

"LIASCRIPT: " + table
</script>

image

this might look a bid weird at the beginning... If the result of your script starts with LIASCRIPT: then the internal interpreter is applied on the result. Thus in this case a string of a Markdown-table is generated randomly. In the same sense, this could also be a CSV file, which is loaded from an external resource, parsed and displayed this way. As an alternative, you can also use HTML: , which will interpret the result as ... HTML ...

Scripts are used a bit different here, they can be styled and also associated with an input:

Shift the sin by
<script input="range" default="0" value="0" output="shift">
0.1 * @input
</script>.

<script style="width: 100%; display: block" run-once="true">
let table = `<!-- data-show="true" -->
| x | y |
|---|---|
`

for(let x=0.1; x<10; x+=0.1) {
    table += "|" + x + "|" + Math.sin(x + @input(`shift`)) + "|" + "\n"
}

"LIASCRIPT: " + table
</script>

image

In the example above, the first script is combined with an input-slider, when the user clicks on it, then it revealed and interactive. By defining output="shift" a topic is defined, which is used in the other script as an input-value ... Whenever this published input-value changes, all of its siblings or who is using the topic, gets updated.

modify as a parameter of a script is set to false, if it is deleted or set to true, the user can inspect and modify the script by double-clicking on it... Run-once means, the state is stored persistently and only calculated on the first appearance of a script or if something is changed. This comes handy if you need to load or calculate a lot ...


Thus, the scripts can also be put into a macro:

<!--
author:   Your Name

email:    your@mail.org

version:  0.0.1

language: en

@table
<script style="width: 100%; display: block" run-once="true" modify="false">
let table = `| x | y |
|---|---|
`

for(let x=0; x<@0; x++) {
    table += "|" + x + "|" + Math.random() * @1 + "|" + "\n"
}

"LIASCRIPT: " + table
</script>
@end

-->

# Course Main Title

@table(100,25)

@table(500, 500)

image

In this case two tables will be generated, with different parameters. Within the macro-definition, the @0 and @1 are placeholders for the two parameters.

Such macros can then be shared with other courses, by using import: url within the main header definition, this @table macro can then also be imported into other courses ...

@BeastyBlacksmith
Copy link
Author

My javascript is weak...

This is as far as I came

<!-- 
@include
<script style="width: 100%; display: block" run-once="true" modify="false">
let data = fetch('../home/' + @0)
  .then(response => response.text())
  .then(data => {
  	console.log(data);
  });
</script>
@end
-->
# Test

@include("path/to/file")

Which actually does print the file to console.. but that's not where I want to have it ^^.

@andre-dietrich
Copy link
Member

There is only one thing missing ... send.lia("LIASCRIPT: ...") this object is associated to every script and if you need to deal with async behavior, you can use this, to send back any kind of string.

I had updated your example a bit with some random CSV...

<!--
script: https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.3.2/papaparse.min.js

@CSV: @CSV_as( ,false,@0)

@CSV_as
<script style="width: 100%; display: block" run-once="true" modify="false">
            // this is a proxy to deal with CORS
Papa.parse("https://api.allorigins.win/raw?url=@2", {
	download: true,
	complete: function(data) {
        // this is only used to deal with lines with the same size
        // others will be ignored
        const columns = data.data[0].length

        // define the header
        let table = "|"
        for (let i=0; i < columns; i++) {
            table += data.data[0][i] + "|"
        }

        table += "\n|"
        for (let i=0; i < columns; i++) {
            table += "---|"
        }

        // read the body
        for (let i=1; i < data.data.length; i++) {
            // will ignore empty rows
            if (data.data[i].length == columns) {
                table += "\n|"

                for(let j=0; j< data.data[i].length; j++) {
                    table += data.data[i][j] + "|"
                }
            }
        }

        // this is used to deal with async elements
        // every script will have its own send object...
        send.lia(`LIASCRIPT: <!-- data-type='@0' @1 -->`+table)
    }
});

</script>
@end

-->

# Course 

basic macro call:

@CSV(https://filesamples.com/samples/document/csv/sample3.csv)

macros as Links ... the last parameter is the URL

@[CSV](https://filesamples.com/samples/document/csv/sample3.csv)

@[CSV_as(barchart,data-transpose="true")](https://filesamples.com/samples/document/csv/sample1.csv)

This uses papa parse to parse and download the CSV file, and then also uses the data to construct a markdown-table. If you deal with URLs, you can also use the second notation for macros. The benefit is, that that to other Markdown-Interpreters this will look like a link on which they can click ...

There are two macros, a more complex @CSV_as, while @CSV is only used as a shortcut, which uses the first one and passes some default values and then its URL param as the third one ...

I added an CORS-proxy, so that it is possible to load CSV files from everywhere ...

hope this helps ...

image

@sspeiser
Copy link

I adapted this to my goal of loading a LiaScript-chapter from another file into my course. This works fine, however the table of content is not updated if the chapter contains sections. Can I trigger a rebuild of the table of contents somehow?
Minimal code example:

# Course

<script>
    send.lia("LIASCRIPT: ## New section" )
</script>

## Initial section
```0

I would like to have "New section" in the table of contents. Thanks.

@andre-dietrich
Copy link
Member

Hi @sspeiser ... 🙈 unfortunately, this is not possible, you can only create elements dynamically for a certain site/section but there is atm no possibility to insert this as a new element into the document-structure itself ... this would destroy the linear structure of slides, which is required for routing messages ... Internally LiaScript uses the section number for (#1 ... #n) for sending messages ...

@sspeiser
Copy link

sspeiser commented Mar 14, 2024 via email

@andre-dietrich
Copy link
Member

Hi ... Can you explain me what you are trying to build, maybe we can figure out a way to achieve this? At the moment it is not possible to inject new slides and to create a document structure dynamically. You can use scripts only to inject new content into an existing slide. The @onload hook is a way of executing JavaScript that needs to define global functions or to do some initialization of other libraries (loaded with the script: macro) ...

However, in order to create dynamical content, you could use Data-URIs. LiaScript allows to encode content within the URL in different formats. I created the following example with the help of https://phind.com, since I was not aware that the browser now has native support for zipping ... The content that is passed as a string to the window.compress function return a gzipped and Base64 encoded version of the string, which can then be used to create a LiaScript-URL for the dynamic content ... You can try out this example here

<!--

@onload
window.compress = async function(text) {
    const stream = new Blob([text], { type: 'text/plain' }).stream();

    // Compress the stream using CompressionStream:
    // Next, you pipe the stream through a CompressionStream to compress it.
    const compressedStream = stream.pipeThrough(new CompressionStream("gzip"));

    // Convert the compressed stream to a base64 string:
    // After compression, you need to convert the compressed stream back to a Blob,
    // then to an ArrayBuffer, and finally to a base64 string.
    const compressedResponse = new Response(compressedStream);
    const blob = await compressedResponse.blob();
    const buffer = await blob.arrayBuffer();
    const compressedBase64 = btoa(String.fromCharCode(...new Uint8Array(buffer)));

    return "https://liascript.github.io/course/?data:text/plain;charset=utf-8;Content-Encoding=gzip;base64," + compressedBase64
}
@end

-->

# Dynamical Documents

<script>
let document = `# New documents

This is an example of a new document.

| Animal          | weight in kg | Lifespan years | Mitogen |
| --------------- | ------------:| --------------:| -------:|
| Mouse           |        0.028 |             02 |      95 |
| Flying squirrel |        0.085 |             15 |      50 |
| Brown bat       |        0.020 |             30 |      10 |
| Sheep           |           90 |             12 |      95 |
| Human           |           68 |             70 |      10 |`

window.compress(document)
.then((e) => {
    send.lia(`LIASCRIPT: [Link to my new course](${e})`)
})

"LIA: wait"
</script>

I tried this out with the first paragraphs of the documentation. It seems, that at the moment GitHub allows for 8000 character wide URLs before the server complains, that the URL is too long. Don't know if this solves your problem ;-)

8011 Bytes long URL

@sspeiser
Copy link

Thanks. I built an initial proof of concept for a preprocessor that includes other course files and then generates a Data-URI. The length restriction comes from window.location in the browsers. The compression should help to extend this further.

The basic idea is to have reusable pages/sections that can be combined into different courses.

The code is at:
https://github.com/sspeiser/modular-content

The preprocessor is at:
https://sspeiser.github.io/modular-content/

Here we can load the example course:
https://sspeiser.github.io/modular-content/example.md

For a larger file, I use an anonymous file hoster but after 1 access the file is deleted. Can be tested with:
https://sspeiser.github.io/modular-content/big.md

@andre-dietrich
Copy link
Member

I see, if you want to create content dynamically, you could also try the following:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>LiaScript - Live</title>
  </head>
  <body>
    <iframe
      id="lia-script"
      allow="cross-origin"
      src="https://unpkg.com/@liascript/editor@1.1.4--0.14.10/dist/index.html"
      style="width: 100%; height: 800px; display: none"
    ></iframe>

    <script>
      const course = `# Hello World

This is a simple course.

## Chapter 1

This is the first chapter.

## Chapter 2

This is the second chapter.
`

      const iframe = document.getElementById('lia-script')
      iframe.onload = () => {
        iframe.contentWindow.postMessage(
          {
            cmd: 'jit',
            param: course,
          },
          '*'
        )

        iframe.style.display = 'block'
      }
    </script>
  </body>
</html>

This is only a fast trial, but you could use the editor module for this, which is documented in branch editor:

https://www.npmjs.com/package/@liascript/editor

This is also the tool we are using for all editor-plugins ... Using unpack you can also directly load this from npmjs.com and load it within an iframe. In the example, the iframe is hidden until it is loaded and this is also the place, where you can send messages, such as jit with a string param that contains your dynamically generated course ... In long term, we would like to make a web-component out of LiaScript, to simplify such tasks and show and store documents on different sites ...

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

3 participants