-
-
Notifications
You must be signed in to change notification settings - Fork 75
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #168 from NHDaly/documenter
Add a docs/ site for Blink using Documenter.jl!
- Loading branch information
Showing
6 changed files
with
351 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
build |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
using Documenter, Blink | ||
|
||
makedocs( | ||
modules = [Blink], | ||
format = :html, | ||
sitename = "Blink", | ||
pages = [ | ||
"index.md", | ||
"guide.md", | ||
"Communication" => "communication.md", | ||
"api.md", | ||
#"Subsection" => [ | ||
# ... | ||
#] | ||
], | ||
) | ||
|
||
#deploydocs( | ||
# repo = "github.com/NHDaly/Blink.jl.git", | ||
# julia = "1.0" | ||
#) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# API | ||
|
||
## Window | ||
|
||
```@docs | ||
Window | ||
``` | ||
|
||
```@docs | ||
title | ||
progress | ||
flashframe | ||
``` | ||
|
||
### Misc | ||
|
||
```@docs | ||
opentools | ||
closetools | ||
tools | ||
``` | ||
|
||
## RPC | ||
|
||
```@docs | ||
@js | ||
@js_ | ||
js | ||
Blink.JSString | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,204 @@ | ||
# [Communication between Julia and Javascript](@id Communication) | ||
|
||
After creating a Window and loading HTML and JS, you may want to interact with | ||
julia code (e.g. by clicking a button in HTML, or displaying a plot from julia). | ||
|
||
This section covers this two-way communication. | ||
|
||
## Julia to Javascript | ||
```@setup Blink-win | ||
using Blink | ||
win = Window(Dict(:show=>false), async=false) | ||
``` | ||
|
||
The easiest way to communicate to javascript from julia is with the [`@js`](@ref) and | ||
[`@js_`](@ref) macros. These macros allow you to execute arbitrary javascript code in a | ||
given Window. | ||
|
||
```@repl Blink-win | ||
@js win x = 5; | ||
@js win x | ||
``` | ||
|
||
The `@js_` macro executes its code asynchronously, but doesn't return its | ||
result: | ||
```@repl Blink-win | ||
@time @js win begin # Blocks until finished; `i` is returned | ||
for i in 0:1000000 end # waste time | ||
i # return i | ||
end | ||
@time @js_ win begin # Returns immediately, but `i` is not returned. | ||
for i in 0:1000000 end # waste time | ||
i # This is ignored | ||
end | ||
``` | ||
|
||
If your javascript expression is complex, or you want to copy-paste existing | ||
javascript, it can be easier to represent it as a pure javascript string. | ||
For that, you can call the [`js`](@ref) function with a [`JSString`](@ref Blink.JSString): | ||
```@repl Blink-win | ||
body!(win, """<div id="box" style="color:red;"></div>""", async=false); | ||
div_id = "box"; | ||
js(win, Blink.JSString("""document.getElementById("$div_id").style.color""")) | ||
``` | ||
|
||
Note that the code passed to these macros runs in its own scope, so any | ||
javascript variables you create with `var` (or the `@var` equivalent for `@js`) | ||
will be inaccessible after returning: | ||
```@repl Blink-win | ||
@js win (@var x_var = 5; x_var) # x_var is only accessible within this scope. | ||
@js win x_var | ||
``` | ||
|
||
## Javascript to Julia | ||
Communication from javascript to julia currently works via a message passing | ||
interface. | ||
|
||
To invoke julia code from javascript, you specify a julia callback via `handle`: | ||
```julia-repl | ||
julia> handle(w, "press") do args | ||
@show args | ||
end | ||
``` | ||
This callback can then be triggered from javscript via `Blink.msg()`: | ||
```@setup handler | ||
using Blink | ||
w = Window(Dict(:show=>false), async=false) | ||
handle(w, "press") do args | ||
@show args | ||
end | ||
``` | ||
```@repl handler | ||
@js w Blink.msg("press", "Hello from JS"); | ||
``` | ||
Note that the javascript function `Blink.msg` takes _exactly_ 1 argument. To | ||
pass more or fewer arguments, pass your arguments as an array: | ||
```@repl handler | ||
handle(w, "event") do count, values, message | ||
# ... | ||
end | ||
@js w Blink.msg("event", [1, ['a','b'], "Hi"]); | ||
``` | ||
|
||
Finally, here is an example that uses a button to call back to julia: | ||
```@setup Blink-w | ||
using Blink | ||
w = Window(Dict(:show=>false), async=false) | ||
``` | ||
```@repl Blink-w | ||
handle(w, "press") do arg | ||
println(arg) | ||
end | ||
body!(w, """<button onclick='Blink.msg("press", "HELLO")'>go</button>""", async=false); | ||
``` | ||
Now, clicking the button will print `HELLO` to julia's STDOUT. | ||
|
||
|
||
## Back-and-forth | ||
|
||
Note that you cannot make a synchronous call to javascript from _within_ a julia | ||
callback, or you'll cause julia to hang: | ||
|
||
**BAD**: | ||
```julia-repl | ||
julia> @js w x = 5 | ||
julia> handle(w, "press") do args... | ||
# Increment x and get its new value | ||
x = @js w (x += 1; x) # ERROR: Cannot make synchronous calls within a callback. | ||
println("New value: $x") | ||
end | ||
#9 (generic function with 1 method) | ||
julia> @js w Blink.msg("press", []) | ||
# JULIA HANGS UNTIL CTRL-C, WHICH KILLS YOUR BLINK WINDOW. | ||
``` | ||
|
||
**GOOD**: Instead, if you need to access the value of `x`, you should simply | ||
provide it when invoking the `press` handler: | ||
```@repl Blink-w | ||
@js w x = 5 | ||
handle(w, "press") do args... | ||
x = args[1] | ||
# Increment x | ||
@js_ w (x = $x + 1) # Note the _asynchronous_ call. | ||
println("New value: $x") | ||
end | ||
@js w Blink.msg("press", x) | ||
# JULIA HANGS UNTIL CTRL-C, WHICH KILLS YOUR BLINK WINDOW. | ||
``` | ||
|
||
|
||
## Tasks | ||
|
||
The julia webserver is implemented via Julia | ||
[Tasks](https://docs.julialang.org/en/v1/manual/control-flow/#man-tasks-1). This | ||
means that julia code invoked from javascript will run _sort of_ in parallel to | ||
your main julia code. | ||
|
||
In particular: | ||
- Tasks are _coroutines, not threads_, so they aren't truly running in parallel. | ||
- Instead, execution can switch between your code and the coroutine's code whenever a piece of computation is _interruptible_. | ||
|
||
So, if your Blink callback handler performs uninterruptible work, it will fully | ||
occupy your CPU, preventing any other computation from occuring, and can | ||
potentially hang your computation. | ||
|
||
### Examples: | ||
|
||
**BAD**: If your callback runs a long loop, it won't be uninterruptible while | ||
it's running: | ||
```julia-repl | ||
julia> handle(w, "press") do args... | ||
println("Start") | ||
while true end # infinite loop | ||
println("End") | ||
end | ||
#40 (generic function with 1 method) | ||
julia> body!(w, """<button onclick='Blink.msg("press", 1)'>go</button>""", async=false); | ||
julia> # CLICK THE go BUTTON, AND YOUR PROCESS WILL FREEZE | ||
Start | ||
``` | ||
|
||
**BAD**: The same is true if your _main_ julia computation is hogging the CPU, then | ||
your callback can't run: | ||
```julia-repl | ||
julia> handle(w, "press") do args... | ||
println("Start") | ||
sleep(5) # This will happily yield to any other computation. | ||
println("End") | ||
end | ||
#41 (generic function with 1 method) | ||
julia> body!(w, """<button onclick='Blink.msg("press", 1)'>go</button>""", async=false); | ||
julia> while true end # Infinite loop | ||
# NOW, CLICK THE go BUTTON, AND NOTHING HAPPENS, SINCE THE CPU IS BEING HOGGED! | ||
``` | ||
|
||
**GOOD**: So to allow for happy communication, all your computations should be interruptible, which you can achieve with calls such as `yield`, or `sleep`: | ||
```julia-repl | ||
julia> handle(w, "press") do args... | ||
println("Start") | ||
sleep(5) # This will happily yield to any other computation. | ||
println("End") | ||
end | ||
#39 (generic function with 1 method) | ||
julia> body!(w, """<button onclick='Blink.msg("press", 1)'>go</button>""", async=false); | ||
julia> while true # Still an infinite loop, but a _fair_ one. | ||
yield() # This will yield to any other computation, allowing the callback to run. | ||
end | ||
# NOW, CLICKING THE go BUTTON WILL WORK CORRECTLY ✅ | ||
Start | ||
End | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
# Usage Guide | ||
|
||
Using Blink to build a local web app has two basic steps: | ||
1. Create a window and load all your HTML and JS. | ||
2. Handle interaction between julia and your window. | ||
|
||
## 1. Setting up a new Blink Window | ||
|
||
Create a new window via [`Window`](@ref), and load some html via [`body!`](@ref). | ||
|
||
```julia-repl | ||
julia> using Blink | ||
julia> w = Window(async=false) # Open a new window | ||
Blink.AtomShell.Window(...) | ||
julia> body!(w, "Hello World", async=false) # Set the body content | ||
``` | ||
|
||
The main functions for setting content on a window are [`content!(w, | ||
querySelector, html)`](@ref) and [`body!(w, html)`](@ref). `body!` is just | ||
shorthand for `content!(w, "body", html)`. | ||
|
||
You can also load an external url via `loadurl`, which will replace the current | ||
content of the window: | ||
```julia | ||
loadurl(w, "http://julialang.org") # Load a web page | ||
``` | ||
|
||
Note the use of `async=false` in the examples above. By default, these functions | ||
return immediately, but setting `async=false` will block until the function has | ||
completed. This is important if you are executing multiple statements in a row | ||
that depend on the previous statement having completed. | ||
|
||
|
||
### Loading stadalone HTML, CSS & JS files | ||
|
||
You can load complete standalone files via the [`load!`](@ref) function. Blink | ||
will handle the file correctly based on its file type suffix: | ||
```julia | ||
load!(w, "ui/app.css") | ||
load!(w, "ui/frameworks/jquery-3.3.1.js") | ||
``` | ||
|
||
You can also call the corresponding `importhtml!`, `loadcss!`, and `loadjs!` directly. | ||
|
||
## 2. Setting up interaction between Julia and JS | ||
|
||
```@setup Blink-w | ||
using Blink | ||
w = Window(Dict(:show=>false), async=false) | ||
``` | ||
|
||
This topic is covered in more detail in the [Communication](@ref) page. | ||
|
||
Just as you can directly write to the DOM via `content!`, you can | ||
directly execute javscript via the [`@js`](@ref) macro. | ||
|
||
```@repl Blink-w | ||
@js w Math.log(10) | ||
``` | ||
|
||
To invoke julia code from javascript, you can pass a "message" to julia: | ||
|
||
```julia | ||
# Set up julia to handle the "press" message: | ||
handle(w, "press") do args | ||
@show args | ||
end | ||
# Invoke the "press" message from javascript whenever this button is pressed: | ||
body!(w, """<button onclick='Blink.msg("press", "HELLO")'>go</button>"""); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Blink.jl Documentation | ||
|
||
## Overview | ||
|
||
Blink.jl is the Julia wrapper around [Electron](https://electronjs.org/). It | ||
can serve HTML content in a local window, and allows for communication between | ||
Julia and the web page. In this way, therefore, Blink can be used as a GUI | ||
toolkit for building HTML-based applications for the desktop. | ||
|
||
## Installation | ||
To install Blink, run: | ||
|
||
```julia-repl | ||
julia> Pkg.add("Blink") | ||
julia> Blink.AtomShell.install() | ||
``` | ||
|
||
This will install the package, and its dependencies: namely, `Electron`. | ||
|
||
## Documentation Outline | ||
|
||
```@contents | ||
``` |