Hacker News new | ask | show | jobs
by nosir33 4066 days ago
Sample code to execute some Javascript code inside PyPy.js. I couldn't find any examples.

    import js
    js.eval("console.log(\"hi!\")")
4 comments

It's a bit messy, but:

    js.eval('var div = document.createElement("div"); div.style.width = "100px"; div.style.height = "100px"; div.style.background = "red"; div.style.color = "white"; div.innerHTML = "Hello"; document.body.appendChild(div);');
manages to append a div.

--

Directly modifying document.body.innerHTML in any way seems to hang it. Both:

    js.eval('document.body.innerHTML += "<div></div>";');
    js.globals.document.body.innerHTML += "<div></div>"
Cause it to hang, though the javascript console shows it was added (or using an img tag instead).

(ChromeOS v43 beta)

It's more fun doing this, since jQuery is already on the page:

    import js
    jq = js.eval("$")
    first_line = jq(jq(".container p")[0])
    first_line.text("jQuery was here")
Just playing around:

    import js
    c = js.globals.document.createElement("canvas")
    js.globals.document.body.appendChild(c)
    ctx = c.getContext("2d")
    ctx.fillRect(10, 10, 10, 10)
Edit: Here is a simple animation:

    import js
    import math
    import time
    c = js.globals.document.createElement("canvas")
    js.globals.document.body.appendChild(c)
    ctx = c.getContext("2d")
    
    def render():
      ctx.clearRect(0, 0, c.width, c.height)
      t = time.time()
      ctx.fillRect(20+math.sin(t*10)*10, 20+math.cos(t*10)*10, 10, 10)
    
    js.globals.window.setInterval(render, 20)
Here's a version you can paste in properly: http://pastebin.com/raw.php?i=67GadSUV
Sadly, if I paste that in, I get:

    >>> import js 
    ... c = js.globals.document.createElement("canvas") 
    ... 
    debug: OperationError:
    debug:  operror-type: SyntaxError
    debug:  operror-value: ('EOL while scanning string literal', ('c callback', 1, 12, "r = c.push('import js\n", 0))
    debug: OperationError:
    debug:  operror-type: KeyError
    debug:  operror-value: 'r'
And then the input window hangs. Strangely enough, if I type it in instead, it's okay.

(ChromeOS v43 beta-channel)

I think the only way around it is to paste each line separately. It seems to be caused by newline characters in the wrong place
'that' refers to

    import js
    c = js.globals.document.createElement("canvas")
and not the pastebin. The pastebin works for me, but only the first time. Subsequent runs result in:

    <RuntimeError object at 0x15d648>
    RPython traceback:
      ...
    Fatal RPython error:
Or this:

    import js
    js.globals.console.log('hi!')
I'm loving this, my head is reeling with the glint of possibilities

    import js
    js.globals.console.log('hi!'*5)
Seems to be some issues with the interop still, eg:

  import js
  >>> "globals" in dir(js)
  True
  >>> "console" in dir(js.globals)
  False
  >>> js
  <module 'js' (built-in)>
  >>> js.globals.console
  <js.Object handle=14>
So apparently introspection doesn't quite work with the wrapped js. Also, if you try: "[ i for i in js.globals]" (or equivalently iterate/loop over the globals-object) - the whole repl/tab hangs.

Not really an issue for running business logic in the browser, but if this was a full python repl-interface (with ipython support!) to the whole browser DOM -- that'd be a fantastic tool.

The introspection bit is because js.globals is implemented with a fancy __getattr__ but doesn't have a __dir__. In general, dir() is not reliable in the face of custom __getattr__ implementations unless the implementor goes out of the way to make it work.
Oh, right. I didn't consider that:

  Welcome to PyPy.js!
  >>> import js
  >>> "console" in js.globals
  True
  >>> "console" in dir(js.globals)
  False
It would be good if they could support a common api with brython, which has "import web" and some other bits...

I guess these things will take a while to shake out, but I'd imagine a python-in-browser-api PEP at some point.