Adding JS libraries

Integrating third-party JavaScript libraries into your Genie applications can unlock new levels of interactivity and functionality. There exist two way to do this in Stipple: using the page function, which is simpler and results in less code, or with a layout, which offers more customization.

Using the page function

With this method, you can pass an array of links to the page function that generates the page's code in the route definition:

head= [
script(src = "https://cdn.library.com/lib.js"),
link(href = "https://cdn.library.com/style.css", rel="stylesheet")
]

route("/") do
    page(@init, ui, head_content = join(cesium_head))
end

page takes a ReactiveModel as first argument, which holds a representation of the reactive variables and handlers in our code. This model is generated with the @initmacro, see the page on Reactivity for more information.

Additionally, you can include scripts in the page using the @deps macro as:

lib_module() = [
    script(type ="module", "
    // script code goes here
    Console.log('hello world')
    ")
]

@deps lib_module

Here's a full example that incorporates the CesiumJS library to create a 3D globe:

using GenieFramework

@genietools

cesium_token = "your token"

cesium_head = [
  script(src = "https://cesium.com/downloads/cesiumjs/releases/1.113/Build/Cesium/Cesium.js", ),
  link(href = "https://cesium.com/downloads/cesiumjs/releases/1.113/Build/Cesium/Widgets/widgets.css", rel = "stylesheet", )
]

cesium_module() = [
  script(type = "module", "
    Cesium.Ion.defaultAccessToken = '$cesium_token';

    // Initialize the Cesium Viewer in the HTML element with the `cesiumContainer` ID.
    const viewer = new Cesium.Viewer('cesiumContainer', {
      terrain: Cesium.Terrain.fromWorldTerrain(),
    });    

    // Fly the camera to San Francisco at the given longitude, latitude, and height.
    viewer.camera.flyTo({
      destination: Cesium.Cartesian3.fromDegrees(-122.4175, 37.655, 400),
      orientation: {
        heading: Cesium.Math.toRadians(0.0),
        pitch: Cesium.Math.toRadians(-15.0),
      }
    });

    // Add Cesium OSM Buildings, a global 3D buildings layer.
    const buildingTileset = await Cesium.createOsmBuildingsAsync();
    viewer.scene.primitives.add(buildingTileset);
  ")
]

@deps cesium_module


@app begin
  @in mybutton = false

  @onbutton mybutton begin
        println("button clicked")
  end
end

ui() = [
  row(cell(class = "st-module",
    h1("My first Cesium App")
  ))

  row(cell(class = "st-module", [
    h3("Demo")
    htmldiv(id="cesiumContainer")
  ]))
]

@page("/", ui, DEFAULT_LAYOUT(head_content = cesium_head))

up()

Using a layout

An alternative way to include third-party libraries is to use a layout. As a starting point, you can use the one returned by the function Stipple.ReactiveTools.BASE_LAYOUT, which includes everything a Stipple app needs. Then, you can edit its head and footer to include your JS libraries and code.

app.jl
@page("/", "ui.jl", layout = "layout.html")
layout.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">

    <% Stipple.sesstoken() %>
    <title>Genie App</title>
    <% if isfile(joinpath(Genie.config.server_document_root, "css", "genieapp.css")) %>
    <link rel='stylesheet' href='/css/genieapp.css'>
    <% else %>
    <% end %>
    <% if isfile(joinpath(Genie.config.server_document_root, "css", "autogenerated.css")) %>
    <link rel='stylesheet' href='/css/autogenerated.css'>
    <% else %>
    <% end %>
    <style>
      ._genie_logo {
        background:url('https://genieframework.com/logos/genie/logo-simple-with-padding.svg') no-repeat;background-size:40px;
        padding-top:22px;padding-right:10px;color:transparent;font-size:9pt;
      }
      ._genie .row .col-12 { width:50%;margin:auto; }
    </style>
  </head>
  <body>
    <div class='container'>
      <div class='row'>
        <div class='col-12'>
          <% page(model, partial = true, v__cloak = true, [@yield], @iif(:isready)) %>
        </div>
      </div>
    </div>
    <% if isfile(joinpath(Genie.config.server_document_root, "js", "genieapp.js")) %>
    <script src='/js/genieapp.js'></script>
    <% else %>
    <% end %>
    <footer class='_genie container'>
      <div class='row'>
        <div class='col-12'>
          <p class='text-muted credit' style='text-align:center;color:#8d99ae;'>Built with
            <a href='https://genieframework.com' target='_blank' class='_genie_logo' ref='nofollow'>Genie</a>
          </p>
        </div>
      </div>
    </footer>
  </body>
</html>