Remote controlled frontend framework for Phoenix.
The essential of Drab.Core changed:
execjs/2
-> exec_js/3
, brodcastjs/2
-> broadcast_js/3
exec_js/3
returns tuple {:ok, result} or {:error, reason}exec_js!/3
raises exceptions on JS errorexec_js/3
and exec_js!/3
Bug fixes:
execute!
allows string as the method with parametersexecjs/2
- it caused troubles aNew features:
:same_url
, :same_controller
or to user defined "topic"
. The behaviour is set in the Commander with broadcasting
macro.execjs/2
(and so for the most of Drab.Query functions); default is 5000 ms and can be changed with config :drab, timeout: xxx|:infinity
This release is a hudge step towards Stable version, as it brings automated tests to Drab. Because of its nature (working both on JS and Elixir), most of them are end-to-end (integration) tests. To run it you'll need a chromedriver
.
In addition, there is a build-in Phoenix server. Now to play with Drab in IEx, you don't need to create your own Phoenix application and add drab to it, anymore. You can just clone the github repo and run the server on it:
git clone [email protected]:grych/drab.git
cd drab
mix deps.get
npm install && node_modules/brunch/bin/brunch build
iex -S mix phoenix.server
Open the browser, navigate to http://localhost:4000 and follow the instruction in IEX:
import Drab.Core; import Drab.Query; import Drab.Modal; import Drab.Waiter
socket = GenServer.call(pid("0.xxxxx.0"), :get_socket)
Now you can remote control the browser from IEx:
iex(5)> socket |> alert("Title", "WOW!")
{:ok, %{}}
iex(6)> socket |> select(:text, from: "h3")
"Drab Tests"
iex(7)> socket |> update(:text, set: "It is set from IEx, wow!", on: "h3")
%Phoenix.Socket{assigns: %{__action: :index, .........
IEx
console:When starting Phoenix+Drab from iex -S mix phoenix.server
the following debug instructions appear:
[debug]
Started Drab for /drab, handling events in DrabPoc.PageCommander
You may debug Drab functions in IEx by copy/paste the following:
import Drab.Core; import Drab.Query; import Drab.Modal; import Drab.Waiter
socket = GenServer.call(pid("0.666.0"), :get_socket)
Examples:
socket |> select(:htmls, from: "h4")
socket |> execjs("alert('hello from IEx!')")
socket |> alert("Title", "Sure?", buttons: [ok: "Azaliż", cancel: "Poniechaj"])
You may use it to debug. Just copy/paste this lines and you may remote control your browser from IEx REPL:
iex(1)> import Drab.Core; import Drab.Query; import Drab.Modal; import Drab.Waiter
Drab.Waiter
iex(2)> socket = GenServer.call(pid("0.666.0"), :get_socket)
%Phoenix.Socket{assigns: %{__action: :index,
__controller: DrabPoc.PageController, __drab_pid: #PID<0.666.0>,
...
transport_pid: #PID<0.1548.0>}
iex(3)> socket |> select(:htmls, from: "h4")
%{"__undefined_0" => "\n The jQuery in Elixir\n",
"__undefined_1" => "Async task status: <span id=\"async_task_status\" class=\"label label-primary\">ready</span>",
"__undefined_2" => "\n ©2016 Tomek \"Grych\" Gryszkiewicz, <a href=\"mailto:[email protected]\">[email protected]</a>\n",
...
"tail_dash_f" => "Server-Side Events: Display the Growing File (tail -F)",
"tens_of_processes" => "Tens of Tasks Running in Parallel on the Server and Communicating Back to the Browser",
"waiter" => "Drab Waiter"}
More info on https://tg.pl/drab#debugging
More info on https://tg.pl/drab#errors
This version gives a new features, such as Waiter, before and after- callbacks. There is also a change in the API, again: introduced singular and plural versions of jQuery select methods. The way how you inject Drab into your Phoenix code changed - now it should be done in your UserSocket
to reflect #8
select(:val)
returns first value instead of the list, but all jQuery methods have corresponding plural methods, which return a Map of %{name|id|__undefined_XX => value}
### <span name="first_span" class="qs_2 small-border">First span with class qs_2</span>
### <span id="second_span" class="qs_2 small-border">Second span with class qs_2</span>
socket |> select(:html, from: ".qs_2")
# "First span with class qs_2"
socket |> select(:htmls, from: ".qs_2")
# %{"first_span" => "First span with class qs_2", "second_span" => "Second span with class qs_2"}
depreciated Drab.Endpoint
; Drab now injects in the UserSocket
with use Drab.Socket
(#8). Now
it is possible to share Drab socket with your code (create your channels)
moved Commander setup to macros instead of use options
use Drab.Commander
onload :page_loaded
access_session :userid
launch_event()
to run_handler()
Drab.Waiter
module adds ability to wait for an user response in your function, so you can have a reply
and continue processing.return = waiter(socket) do
on "selector1", "event_name1", fn (sender) ->
# run when this event is triggered on selector1
end
on "selector2", "event_name2", fn (sender) ->
# run when that event is triggered on selector2
end
on_timeout 5000, fn ->
# run after timeout, default: infinity
end
end
before_handler
callback (to run before each handler); do not process the even handler if before_handler
returns nil or falsebefore_handler :check_login, except: [:log_in]
def check_login(socket, _dom_sender) do
get_session(socket, :userid)
end
after_handler
, getting the return value of handler as an argumentafter_handler :clean_up
def clean_up(_socket, _dom_sender, handler_return) do
# some cleanup
end
Drab.Query.select(:all)
- returns a map of return values of all known jQuery methodssocket |> select(:all, from: "span")
%{"first_span" => %{"height" => 16, "html" => "First span with class qs_2", "innerHeight" => 20, ...
Changes:
debounce
function as an option to the event handler (#6)Changes:
Drab.Core.get_session/2
Fixes: