Thinking out aloud: a JavaScript based console?

  • code • console • qt • phantomjs • javascript • idea • project • coffeescript • source • example
  • 624 words

In the last month or two I started contributing to PhantomJS:

PhantomJS logo PhantomJS logo
PhantomJS is a headless WebKit with JavaScript API. It has fast and native support for various web standards: DOM handling, CSS selector, JSON, Canvas, and SVG. PhantomJS is an optimal solution for headless testing of web-based applications, site scraping, pages capture, SVG renderer, PDF converter and many other use cases.

The project is really interesting and we are seeing a steady growth in terms of:

The mind behind PhantomJS is Ariya Hidayat, a brilliant guy that I first met when he was still working for Trolltech/Nokia. I will not spend a lot of time here explaining why it’s idea is so great: for that there is the official wiki.

To share some awesomeness, here is my favourite example. Do you want to know what’s the weather like in London from your command line? Type something like this:

$ phantomjs examples/weather.js London, UK

City: London, UK
Current condition: Clear
Temperature: 61 F
Humidity: 45%
Wind: N at 4 mph

Thu: 52-66 F  Partly Sunny
Fri: 57-72 F  Partly Sunny
Sat: 55-72 F  Partly Sunny
Sun: 50-70 F  Chance of Rain

How does that work? Here is the PhantomJS script source:

if phantom.state.length is 0
    city = 'Mountain View'
    if phantom.args.length > 0
        city = phantom.args.join ' '
    phantom.state = city
    console.log "Loading #{ city }"
    phantom.open encodeURI "http://www.google.com/ig/api?weather=#{ city }"
else
    if phantom.loadStatus is 'fail'
        console.log 'Unable to access network'
    else
        if document.querySelectorAll('problem_cause').length > 0
            console.log "No data available for #{ phantom.state }"
        else
            data = (s, e) ->
                e = e or document
                el = e.querySelector s
                if el then el.attributes.data.value else null

            console.log ''
            console.log 'City: ' + data 'weather > forecast_information > city'
            console.log 'Current condition ' + data 'weather > current_conditions > condition'
            console.log 'Temperature: ' + data('weather > current_conditions > temp_f') + ' F'
            console.log data 'weather > current_conditions > humidity'
            console.log data 'weather > current_conditions > wind_condition'
            console.log ''

            forecasts = document.querySelectorAll 'weather > forecast_conditions'
            for f in forecasts
                console.log "#{ data 'day_of_week', f }: " +
                            "#{ data 'low', f }-" +
                            "#{ data 'high', f } F  " +
                            "#{ data 'condition', f }"

    phantom.exit()

This scripts uses the undocumented Google Weather API. Nothing special given nowdays Javascript… but this is bring the result to your CLI! And yep, PhantomJS supports Coffee Script, as well as Javascript.

Isn’t this enough to make your eyes sparkly?

a JavaScript based console?

Anyway, I’m not here to show what’s available. I’m here to throw an idea out.

PhantomJS is based on the super-awesome Qt. And Qt provides a superb API set. The one that makes PhantomJS possible is QtWebKit, a WebKit flavour that is developed side by side with the Google Chrome and the Apple Safari WebKits, on the official WebKit repo. QtWebKit API make it extremely easy to build software based on WebKit.

Qt also provides other great modules, and one of them is QtScript. Based on? Yes, it’s based on Javascript! Actually, it wraps in a great API the “standard” WebKit JavascriptCode.

So, if you do 1+1 what happens? PhantomJS can become a fully fledged Javascript interpreter! The WebPage could just be an object to manipulate as a “resource”, like any other object. The developer could do thinks like:

var page = require("WebPage");
page.load("www.google.com");
page.input("Lady Gaga", "#inputTextField");
page.click("#submitSearch");
...
var rasterizer = require("Rasterizer");
rasterizer.print(page, "~/ladyGagaSearchResult.png");
...

Do you see where I’m heading here?

Put into the picture the CommonJS specs, still cooking, and you can imagine JavaScript reaching places that no one would have imagined few years ago.

We are discussing this here on the official group. Come on, join in?