Dynamic execution of embedded gists

Gists are short code snippets that are useful for quick and simple code sharing. However, with all the functions provided by GitHub, gists are useful for much more than that: they are git repositories that have limited functions, but are versioned, can be forked, can be public/private, and can have their code embedded in web pages. It is this last feature I will use to show how the code that is stored and managed in a gist can be executed on a page.

First of all, embedding of a gist is very easy: you add <script src="https://gist.github.com/2278953.js"> tag to your page; 2278953 here is the unique ID of a gist I'm using in this example. Each public gist has "embed" or "show embed" link that gives your the code to use in your page. You can also embed individual files (<script src="https://gist.github.com/2278953.js?file=01-init-canvas.lua"></script>). If you access that URL you get back several document.write calls that have the content of your gist and the code to do styling and syntax highlighting.

For this example I created a gist that has two files with some Lua code that I want to execute in a browser. To execute this Lua code I use the mechanism I described earlier.

Now, with the code of our gist available on the client, all we need to do is to write some JavaScript code to parse and execute the gist. This may look something like this:

function luagist() {
  var gists = document.getElementsByClassName("gist-data");
  for (var i = 0; i < gists.length; i++) {
    var text = [];
    var lines = gists[i].getElementsByClassName("line");
    for (var l = 0; l < lines.length; l++)
      text.push("textContent" in lines[l] ? lines[l].textContent : lines[l].innerText);
    (lua_load(text.join('\n')))();
  }
}

The logic here is simple: GitHub returns elements with gist-data class (one per each file in your gist). One complication is that every file is split into multiple lines and then split into tokens to provide syntax highlighting. It can be quite cumbersome to assemble the original content from all these fragments, but fortunately HTML provides textContent and innerText methods that do all the heavy lifting. The script processes every line and then joins all the lines in one script that then gets interpreted and executed. This execution is done one per file, in the same order as your files are presented in a gist (hence you may want to use 01-, 02-, or similar prefixes to make sure the files are loaded in the order you need).

The last step, which you may not need, is to hide the content on the page; this is done with .gist { display: none }. You can see the complete demo here. The disadvantage is that the access may be occasionally slow; the advantage is that any changes done to the "gisted" script become immediately available to the users.

Another way to embed the Lua code you may want to execute is to use a <script> tag with a different type specific for your scripts. I picked text/x-luascript; the script code may look similar to this:

<script type="text/x-luascript">
local canvas = document:getElementById("canvas")
canvas.width = canvas.width -- clear the canvas
local ctx = canvas:getContext("2d")

ctx.fillStyle = "rgb(200,0,0)"
ctx:fillRect(130, 130, 50, 50)
ctx.fillStyle = "rgba(0, 0, 200, 0.1)"

for i = 1, 100 do
  ctx:fillRect(math.random(0, 300), math.random(0, 300), 50, 50)
end
</script>

The JavaScript code to process this content is only few lines long:

function luascript() {
  var tags = document.getElementsByTagName("script");
  for (var i = 0; i < tags.length; i++) {
    if (tags[i].type == "text/x-luascript") (lua_load(tags[i].text))();
  }
}

The code loops through all <script> elements, finds those that have the type we are interested in, and evaluates the content of those elements. You can see this code in action here.

You should get a copy of my slick ZeroBrane Studio IDE.

Leave a comment

what will you say?
(required)
(required)
Close