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

working webio #208

Closed
wants to merge 14 commits into from
Closed

working webio #208

wants to merge 14 commits into from

Conversation

SimonDanisch
Copy link
Member

The currently tagged webio has certain problems e.g. the unsafe-script #200 or #206.
This branch combines those fixes, but it's still a work in progress, since there is still a bug when updating an observable via a widget (e.g. Interact.slider). This currently works fine on IJulia but doesn't work with the http provider.

@SimonDanisch SimonDanisch requested a review from shashi October 2, 2018 12:46
@SimonDanisch
Copy link
Member Author

ok, so this is the mwe:

input = Observable(w, "grr", "hi")
obs = map(input) do x
  println("update: $x")
  x
end
nothing

Then test:

input[] = "hi" # works fine
obs # <- display obs with WebIO.render(obs)
input[] = "heyyy" # <- doesn't work anymore

This does actually work in IJulia - not sure if I just mess something up in the http server, of it's hitting one of those IJulia specific code paths.

@SimonDanisch
Copy link
Member Author

Of course no error anywhere :P @shashi do you have any idea how this could be so flimsy?
How can a display interrupt the Observable message propagation? I wouldn't be surprised if the websocket connection fails or something, but it seems like the very basic Observable propagation stops

@SimonDanisch
Copy link
Member Author

With Atom + generic_http I get:
image

Not sure if that's a new problem, or firefox + generic_http just doesn't show me those messages

@SimonDanisch
Copy link
Member Author

Nevermind, the url for the websocket was wrong...
So now it has some sort of reasonable behaviour:

using WebSockets, WebIO, Interact

s = slider(1:100)
obs = map(s) do x
    println("value: $x")
    node(:div, x)
end;
vbox(s, obs)

Prints the value whenever the slider changes - but doesn't actually update the rendering of obs...

@SimonDanisch
Copy link
Member Author

So I think it boils down to the classic that onjs doesn't work:

onjs(scope["obs-output"], output_updater)

This logging never gets called:

console.log(updated_htmlstr)

@SimonDanisch
Copy link
Member Author

This is the html it currently renders:

    <!doctype html>
    <html>
    <head>
    <meta charset="UTF-8">
    <script>var websocket_url = 'ws://localhost:8791/webio_websocket/'</script>
    <script src="/assetserver/aad9d897e8b65de5079d15bc68cc342cfd6c50e9-bundle.js"></script>
    <script src="/assetserver/e6fe35b5877e12bb2845c707efdc6e52f553f3a1-websocket_connection.js"></script>
    </head>
    <body>
<div class='display:inherit; margin: inherit' id='div-992d8d4d-9219-4560-af24-14d095a5b38e'></div><script>WebIO.mount(document.getElementById('div-992d8d4d-9219-4560-af24-14d095a5b38e'),{"props":{"style":{"display":"flex","flex-direction":"column"}},"nodeType":"DOM","type":"node","instanceArgs":{"namespace":"html","tag":"div"},"children":[{"props":{"className":"field"},"nodeType":"DOM","type":"node","instanceArgs":{"namespace":"html","tag":"div"},"children":[{"props":{},"nodeType":"Scope","type":"node","instanceArgs":{"imports":{"data":[{"name":"knockout","type":"js","url":"/assetserver/be504447b3b815a2eae4e05550bb2706aaaade39-knockout.js"},{"name":"knockout_punches","type":"js","url":"/assetserver/144e3e324c518268f78cf7c69f198b41d9045339-knockout_punches.js"},{"name":null,"type":"js","url":"/assetserver/124e0c44ae2b35136990564b438c6d2429068eb8-all.js"},{"name":null,"type":"css","url":"/assetserver/3d427370a2a54818bb58a97b20a59616e9486698-style.css"},{"name":null,"type":"css","url":"/assetserver/58648952b845acb6091b4e98e94f6ac90e0d9bae-bulma.min.css"},{"name":null,"type":"css","url":"/assetserver/3d9bf9f99cbd47a4dac10a94b8278309e248387a-bulma-slider.min.css"},{"name":null,"type":"css","url":"/assetserver/975d43df4c928580b452a5ec7ab2c4869d8fd5a3-bulma-switch.min.css"},{"name":null,"type":"css","url":"/assetserver/9e51b57e658e9d61b7b429f5ea25dc2df21dcd0b-bulma-accordion.min.css"},{"name":null,"type":"css","url":"/assetserver/cb4637c6ffff7d1874ac9dd05392f4e1208fa159-bulma-checkradio.min.css"},{"name":null,"type":"css","url":"/assetserver/c3c93a7a208411543f420eeb21e010988cd230f7-bulma-tooltip.min.css"}],"type":"async_block"},"id":"knockout-component-51b2b00f-aa2c-4aea-94a9-eb7578f94e2a","handlers":{"_promises":{"importsLoaded":[function (ko, koPunches) {
    ko.punches.enableAll();
    ko.bindingHandlers.numericValue = {
        init : function(element, valueAccessor, allBindings, data, context) {
            var stringified = ko.observable(ko.unwrap(valueAccessor()));
            stringified.subscribe(function(value) {
                var val = parseFloat(value);
                if (!isNaN(val)) {
                    valueAccessor()(val);
                }
            })
            valueAccessor().subscribe(function(value) {
                var str = JSON.stringify(value);
                if ((str == "0") && (["-0", "-0."].indexOf(stringified()) >= 0))
                     return;
                 if (["null", ""].indexOf(str) >= 0)
                     return;
                stringified(str);
            })
            ko.applyBindingsToNode(element, { value: stringified, valueUpdate: allBindings.get('valueUpdate')}, context);
        }
    };
    var json_data = JSON.parse("{\"changes\":0,\"value\":50}");
    var self = this;
    function AppViewModel() {
        for (var key in json_data) {
            var el = json_data[key];
            this[key] = Array.isArray(el) ? ko.observableArray(el) : ko.observable(el);
        }
        
        
        [this["changes"].subscribe((function (val){!(this.valueFromJulia["changes"]) ? (WebIO.setval({"name":"changes","scope":"knockout-component-51b2b00f-aa2c-4aea-94a9-eb7578f94e2a","id":"ob_06","type":"observable"},val)) : undefined; return this.valueFromJulia["changes"]=false}),self),this["value"].subscribe((function (val){!(this.valueFromJulia["value"]) ? (WebIO.setval({"name":"value","scope":"knockout-component-51b2b00f-aa2c-4aea-94a9-eb7578f94e2a","id":"ob_05","type":"observable"},val)) : undefined; return this.valueFromJulia["value"]=false}),self)]
        
    }
    self.model = new AppViewModel();
    self.valueFromJulia = {};
    for (var key in json_data) {
        self.valueFromJulia[key] = false;
    }
    ko.applyBindings(self.model, self.dom);
}
]},"changes":[(function (val){return (val!=this.model["changes"]()) ? (this.valueFromJulia["changes"]=true, this.model["changes"](val)) : undefined})],"value":[(function (val){return (val!=this.model["value"]()) ? (this.valueFromJulia["value"]=true, this.model["value"](val)) : undefined})]},"systemjs_options":null,"observables":{"changes":{"sync":false,"id":"ob_06","value":0},"value":{"sync":true,"id":"ob_05","value":53}}},"children":[{"props":{"attributes":{"style":"display:flex; justify-content:center; align-items:center;"}},"nodeType":"DOM","type":"node","instanceArgs":{"namespace":"html","tag":"div"},"children":[{"props":{"attributes":{"style":"text-align:right;width:18%"}},"nodeType":"DOM","type":"node","instanceArgs":{"namespace":"html","tag":"div"},"children":[{"props":{"className":"interact ","style":{"padding":"5px 10px 0px 10px"}},"nodeType":"DOM","type":"node","instanceArgs":{"namespace":"html","tag":"label"},"children":[""]}]},{"props":{"attributes":{"style":"flex-grow:1; margin: 0 2%"}},"nodeType":"DOM","type":"node","instanceArgs":{"namespace":"html","tag":"div"},"children":[{"props":{"max":100,"min":1,"attributes":{"type":"range","data-bind":"numericValue: value, valueUpdate: 'input', event: {change : function () {this.changes(this.changes()+1)}}","orient":"horizontal"},"step":1,"className":"slider slider is-fullwidth","style":{}},"nodeType":"DOM","type":"node","instanceArgs":{"namespace":"html","tag":"input"},"children":[]}]},{"props":{"attributes":{"style":"width:18%"}},"nodeType":"DOM","type":"node","instanceArgs":{"namespace":"html","tag":"div"},"children":[{"props":{"attributes":{"data-bind":"text: value"}},"nodeType":"DOM","type":"node","instanceArgs":{"namespace":"html","tag":"p"},"children":[]}]}]}]}]},{"props":{},"nodeType":"Scope","type":"node","instanceArgs":{"imports":{"data":[],"type":"async_block"},"id":"scope-7d14c72c-7322-465a-a7f8-8777edf34a73","handlers":{"obs-output":[function (updated_htmlstr) {
        console.log(updated_htmlstr)
        var el = this.dom.querySelector("#out");
        WebIO.propUtils.setInnerHtml(el, updated_htmlstr);
    }]},"systemjs_options":null,"observables":{"obs-output":{"sync":true,"id":"ob_08","value":"<div class='display:inherit; margin: inherit' id='div-8936aa3a-2c08-4763-a869-60b5a91189f6'></div><script>WebIO.mount(document.getElementById('div-8936aa3a-2c08-4763-a869-60b5a91189f6'),{\"props\":{},\"nodeType\":\"DOM\",\"type\":\"node\",\"instanceArgs\":{\"namespace\":\"html\",\"tag\":\"div\"},\"children\":[{\"props\":{\"setInnerHtml\":\"<pre>53</pre>\"},\"nodeType\":\"DOM\",\"type\":\"node\",\"instanceArgs\":{\"namespace\":\"html\",\"tag\":\"div\"},\"children\":[]}]})</_script>"}}},"children":[{"props":{"id":"out","setInnerHtml":"<div class='display:inherit; margin: inherit' id='div-d0629bef-eb04-486b-bd35-1d259fa04b75'></div><script>WebIO.mount(document.getElementById('div-d0629bef-eb04-486b-bd35-1d259fa04b75'),{\"props\":{},\"nodeType\":\"DOM\",\"type\":\"node\",\"instanceArgs\":{\"namespace\":\"html\",\"tag\":\"div\"},\"children\":[{\"props\":{\"setInnerHtml\":\"<pre>50</pre>\"},\"nodeType\":\"DOM\",\"type\":\"node\",\"instanceArgs\":{\"namespace\":\"html\",\"tag\":\"div\"},\"children\":[]}]})</_script>"},"nodeType":"DOM","type":"node","instanceArgs":{"namespace":"html","tag":"div"},"children":[]}]}]})</script>    </body>
    </html>

@SimonDanisch
Copy link
Member Author

Ok so this seems to be a problem very early on... evaljs seems to be broken, since the logging statement from: https://github.com/JuliaGizmos/WebIO.jl/blob/master/src/scope.jl#L181 never gets called at all.

@SimonDanisch
Copy link
Member Author

The simplest test for evaljs doesn't seem to work

w = Scope()
# display(w)
evaljs(w, js"console.log(\"hi\")")

@SimonDanisch
Copy link
Member Author

ok thanks to @pfitzseb everything seems to work now!
@shashi what needs to happen to merge this? this is based on your branch, so I'm not sure why you haven't merged yours yet ;)

@SimonDanisch
Copy link
Member Author

One big pain point is of course, that because of JuliaWeb/HTTP.jl#294 we currently don't print any errors inside the webstack, which lead to the silent failure of writeguarded.
But I hope to just get JuliaWeb/HTTP.jl#294 fixed and then use the normal logging level.

@shashi
Copy link
Member

shashi commented Oct 24, 2018

@SimonDanisch @travigd is #211 going to make this obsolete?

@SimonDanisch
Copy link
Member Author

I guess... if it works :D not sure what the timeline is for #211, but I've been on this branch forever and it seems to work well - so we might consider merging this first if #211 takes much longer

@shashi
Copy link
Member

shashi commented Oct 24, 2018

Yeah once this branch passes CI, we can go ahead and release it. I figured rebasing #211 should not be too much pain since most of these files are deleted there.

@shashi shashi closed this Nov 5, 2018
@twavv twavv deleted the sd-no-unsafe-script branch December 22, 2019 00:17
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

Successfully merging this pull request may close these issues.

3 participants