Last weeks

During the last weeks I was actively fixing bugs, adding small features, refactoring the existing code and writing docs.

I’ve refactored my event listeners approach to support element.node:addEventListener() and element.node:removeEventListener(). Now, you can add more than one event listener for the specified event, which, I think, is great.

Also, I’ve refactored the HTML Element creation process. Now, HTML elements are created in the tab#evaljs method which is the main method for evaluating JavaScript code across the application. Because of that you can do something like:

local div = splash:evaljs('document.createElement("div")')
div.node.id = 'myDiv'
div.node.style.background = '#ff00ff'
splash.select('body').node:appendChild(div)

And, finally, documentation. I wrote about 800 lines of documentation and now my PR has almost 4,000 line changes. I understand how hard is to review it and I appreciate how much time the reviewer should spend on it.

Final Submission

During this summer I was working on the following pull requests for Splash:

splash:with_timeout()

  • Pull Request: srapinghub/splash#465
  • Status: fully implemented and merged.
  • Abstract: allows to set timeout to any Lua function. It will let the executable function to run only (sometimes more) the specified amount of time.
  • Blog post: post
  • Comments: Implementing this helped me to deeply understand how Splash scripts work and, particularly, how is the scripts event loop is implemented.

DOM elements: take 1

  • Pull Request: srapinghub/splash#471
  • Status: switched to another API interface, closed.
  • Abstract: allows to manipulate with DOM elements in Lua scripts.
  • Blog post: post
  • Comments: I have created a branch of API that allows to work DOM elements in the following manner:
local form = splash:select('form')
local input = splash:select('form > input[name="name"]')
local ok, name = assert(form:node_property('value'))
assert(input:field_value('mr. ' .. name))
local ok, submit = assert(form:node_method('submit'))
submit()

As you can see you should write pretty much code for (in this case) getting the form values, changing it and then submitting the form. And it was the main reason to change the API interface.

Bug #1

  • Pull Request: srapinghub/splash#482
  • Status: fixed and merged.
  • Abstract: In Lua all methods of all tables of the particular class was bound to one Python objects.
  • Blog post: post
  • Comments: This bug was pretty significant for my further work as it wouldn’t allow to work with multiple elements in the same time:
local el1 = splash:select('#el1') 
local el2 = splash:select('#el2') 

el1:form_values() -- calls el2:form_values()

I’ve changed the followings things: 1. Getters and Setters of the table (that are assinged from Python) now are assigned to the table itself rather than their was in closure scope. 2. Changed the __index and __newindex metamethods so that they are assigned to the table itself rather than to its metatable. 3. Made tables’ metatable as a metatable of itself.

Overall during fixing this bug I’ve learned many things about how OOP and metamethods works in Lua.

Bug #2

  • Pull Request: srapinghub/splash#487
  • Status: succeeded by another fix implementation, still open.
  • Abstract: Private methods in Lua are bounded to the last wrapped exposed object.
  • Comments: The problem was with private methods of exposed objects (objects that are exposed from Python to Lua). They were bounded to the last created object. I’ve tried to fix this bug by assigning these private methods to the exposed object (table) itself in __private method. However, in that case they would be accessed from user scripts. One of my menters – @immerrr did fantastic and mind-blown job fixing this bug in srapinghub/splash#495, you should have a look if you are familiar with Lua and its OOP implementation :smile:.

DOM elements: take 2

  • Pull Request: srapinghub/splash#490
  • Status: wip, fixing last comments on Pull Request, open.
  • Abstract: Allows to manipulate DOM elements using Lua properties and methods.
  • Comments: after discussion with my mentors we decided to make API as simple as possible. In comparison with old API in the new one you can set node properties just by assigning to the table and calling node methods by just calling lua methods. You can even assign event handlers as pure Lua functions:

The previous example with the new interface:

local input = input.node:querySelector('input[name="name"]')
input.node.value = 'mr. ' .. input.node.value
assert(input.node.parentElement:submit())

And this is how you can assign event handlers (with addEventListener):

local button = splash:select('button')
local tooltip = splash:select('.tooltip')
buton.node:addEventListener('click', function(event)
    event:preventDefault()
    tooltip.node.style.left = event.clientX
    tooltip.node.style.top = event.clientY
end) 

Pretty impressive, huh? :smile:

Overall

I finished almost everything that I was planning to do. Some of the features that I’ve planned was implemented by other Splash contributors (event system reworking) or was already present in the project (plugin system). However, I also did more than supposed to do, like splash:with_timeout() which originally was only a flag for splash:go() command and event listeners for element.

Final Thoughts

This summer was the most intensive one in my entire life. I was working almost all days in a week and I’m not regretting it.

GSOC was a unique experience for me for several reasons.

First of all, I’ve never worked with Python and Lua in a such big project like Splash. During the coding period my Python and Lua skill level increased significantly. I want to thanks Mikhail and Dennis for helping me with every question I asked from them. You guys rock :sunglasses: :muscle:.

The second reason is working on open source project. Particularly, writing so much documentation and tests. I’d never thought that it can take so much time. On the other hand, during test and documentation writing you better understand your implemented feature and things that will be good to add or remove.

Finally, thank you Google for giving such opportunity to students all over the world to code and learn.